]>
Commit | Line | Data |
---|---|---|
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 | |
14 | git_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 | ||
52 | static DWORD _tls_index; | |
53 | static int _tls_init = 0; | |
54 | ||
7ebefd22 | 55 | int 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 | ||
77 | void 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 | ||
87 | git_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 | ||
107 | static pthread_key_t _tls_key; | |
108 | static int _tls_init = 0; | |
109 | ||
110 | static void cb__free_status(void *st) | |
111 | { | |
2bc8fa02 | 112 | git__free(st); |
a15c550d VM |
113 | } |
114 | ||
7ebefd22 | 115 | int 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 | ||
134 | void 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 | ||
144 | git_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 | ||
164 | static git_global_st __state; | |
165 | ||
7ebefd22 | 166 | int git_threads_init(void) |
a15c550d VM |
167 | { |
168 | /* noop */ | |
7ebefd22 | 169 | return 0; |
a15c550d VM |
170 | } |
171 | ||
172 | void git_threads_shutdown(void) | |
173 | { | |
174 | /* noop */ | |
175 | } | |
176 | ||
177 | git_global_st *git__global_state(void) | |
178 | { | |
179 | return &__state; | |
180 | } | |
181 | ||
182 | #endif /* GIT_THREADS */ |