]> git.proxmox.com Git - libgit2.git/blame - src/global.c
Merge pull request #1208 from ethomson/ppc_sha1_asm_deadness
[libgit2.git] / src / global.c
CommitLineData
a15c550d 1/*
5e0de328 2 * Copyright (C) 2009-2012 the libgit2 contributors
a15c550d
VM
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7#include "common.h"
8#include "global.h"
7ebefd22 9#include "hash.h"
a15c550d
VM
10#include "git2/threads.h"
11#include "thread-utils.h"
12
8cef828d
CMN
13
14git_mutex git__mwindow_mutex;
15
a15c550d
VM
16/**
17 * Handle the global state with TLS
18 *
19 * If libgit2 is built with GIT_THREADS enabled,
20 * the `git_threads_init()` function must be called
21 * before calling any other function of the library.
22 *
23 * This function allocates a TLS index (using pthreads
24 * or the native Win32 API) to store the global state
25 * on a per-thread basis.
26 *
27 * Any internal method that requires global state will
28 * then call `git__global_state()` which returns a pointer
29 * to the global state structure; this pointer is lazily
30 * allocated on each thread.
31 *
32 * Before shutting down the library, the
33 * `git_threads_shutdown` method must be called to free
34 * the previously reserved TLS index.
35 *
36 * If libgit2 is built without threading support, the
37 * `git__global_statestate()` call returns a pointer to a single,
38 * statically allocated global state. The `git_thread_`
39 * functions are not available in that case.
40 */
41
7ebefd22
ET
42/*
43 * `git_threads_init()` allows subsystems to perform global setup,
44 * which may take place in the global scope. An explicit memory
45 * fence exists at the exit of `git_threads_init()`. Without this,
46 * CPU cores are free to reorder cache invalidation of `_tls_init`
47 * before cache invalidation of the subsystems' newly written global
48 * state.
49 */
a15c550d
VM
50#if defined(GIT_THREADS) && defined(GIT_WIN32)
51
52static DWORD _tls_index;
53static int _tls_init = 0;
54
7ebefd22 55int git_threads_init(void)
a15c550d 56{
7ebefd22
ET
57 int error;
58
a15c550d 59 if (_tls_init)
7ebefd22 60 return 0;
a15c550d
VM
61
62 _tls_index = TlsAlloc();
8cef828d 63 git_mutex_init(&git__mwindow_mutex);
7ebefd22
ET
64
65 /* Initialize any other subsystems that have global state */
66 if ((error = git_hash_global_init()) >= 0)
67 _tls_init = 1;
68
69 if (error == 0)
70 _tls_init = 1;
71
72 GIT_MEMORY_BARRIER;
73
74 return error;
a15c550d
VM
75}
76
77void git_threads_shutdown(void)
78{
79 TlsFree(_tls_index);
80 _tls_init = 0;
8cef828d 81 git_mutex_free(&git__mwindow_mutex);
a8527429
ET
82
83 /* Shut down any subsystems that have global state */
84 git_hash_global_shutdown();
a15c550d
VM
85}
86
87git_global_st *git__global_state(void)
88{
89 void *ptr;
90
93b5fabc
VM
91 assert(_tls_init);
92
a15c550d
VM
93 if ((ptr = TlsGetValue(_tls_index)) != NULL)
94 return ptr;
95
2bc8fa02 96 ptr = git__malloc(sizeof(git_global_st));
a15c550d
VM
97 if (!ptr)
98 return NULL;
99
100 memset(ptr, 0x0, sizeof(git_global_st));
101 TlsSetValue(_tls_index, ptr);
102 return ptr;
103}
104
105#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
106
107static pthread_key_t _tls_key;
108static int _tls_init = 0;
109
110static void cb__free_status(void *st)
111{
2bc8fa02 112 git__free(st);
a15c550d
VM
113}
114
7ebefd22 115int git_threads_init(void)
a15c550d 116{
7ebefd22
ET
117 int error = 0;
118
a15c550d 119 if (_tls_init)
7ebefd22 120 return 0;
a15c550d 121
c3320aca 122 git_mutex_init(&git__mwindow_mutex);
a15c550d 123 pthread_key_create(&_tls_key, &cb__free_status);
7ebefd22
ET
124
125 /* Initialize any other subsystems that have global state */
126 if ((error = git_hash_global_init()) >= 0)
127 _tls_init = 1;
128
129 GIT_MEMORY_BARRIER;
130
131 return error;
a15c550d
VM
132}
133
134void git_threads_shutdown(void)
135{
136 pthread_key_delete(_tls_key);
137 _tls_init = 0;
c3320aca 138 git_mutex_free(&git__mwindow_mutex);
a8527429
ET
139
140 /* Shut down any subsystems that have global state */
141 git_hash_global_shutdown();
a15c550d
VM
142}
143
144git_global_st *git__global_state(void)
145{
146 void *ptr;
147
93b5fabc
VM
148 assert(_tls_init);
149
a15c550d
VM
150 if ((ptr = pthread_getspecific(_tls_key)) != NULL)
151 return ptr;
152
2bc8fa02 153 ptr = git__malloc(sizeof(git_global_st));
a15c550d
VM
154 if (!ptr)
155 return NULL;
156
157 memset(ptr, 0x0, sizeof(git_global_st));
158 pthread_setspecific(_tls_key, ptr);
159 return ptr;
160}
161
162#else
163
164static git_global_st __state;
165
7ebefd22 166int git_threads_init(void)
a15c550d
VM
167{
168 /* noop */
7ebefd22 169 return 0;
a15c550d
VM
170}
171
172void git_threads_shutdown(void)
173{
174 /* noop */
175}
176
177git_global_st *git__global_state(void)
178{
179 return &__state;
180}
181
182#endif /* GIT_THREADS */