]> git.proxmox.com Git - libgit2.git/blob - src/global.c
Fix workdir notifications and removals
[libgit2.git] / src / global.c
1 /*
2 * Copyright (C) 2009-2012 the libgit2 contributors
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"
9 #include "hash.h"
10 #include "git2/threads.h"
11 #include "thread-utils.h"
12
13
14 git_mutex git__mwindow_mutex;
15
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
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 */
50 #if defined(GIT_THREADS) && defined(GIT_WIN32)
51
52 static DWORD _tls_index;
53 static int _tls_init = 0;
54
55 int git_threads_init(void)
56 {
57 int error;
58
59 if (_tls_init)
60 return 0;
61
62 _tls_index = TlsAlloc();
63 git_mutex_init(&git__mwindow_mutex);
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;
75 }
76
77 void git_threads_shutdown(void)
78 {
79 TlsFree(_tls_index);
80 _tls_init = 0;
81 git_mutex_free(&git__mwindow_mutex);
82
83 /* Shut down any subsystems that have global state */
84 git_hash_global_shutdown();
85 }
86
87 git_global_st *git__global_state(void)
88 {
89 void *ptr;
90
91 assert(_tls_init);
92
93 if ((ptr = TlsGetValue(_tls_index)) != NULL)
94 return ptr;
95
96 ptr = git__malloc(sizeof(git_global_st));
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 {
112 git__free(st);
113 }
114
115 int git_threads_init(void)
116 {
117 int error = 0;
118
119 if (_tls_init)
120 return 0;
121
122 git_mutex_init(&git__mwindow_mutex);
123 pthread_key_create(&_tls_key, &cb__free_status);
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;
132 }
133
134 void git_threads_shutdown(void)
135 {
136 pthread_key_delete(_tls_key);
137 _tls_init = 0;
138 git_mutex_free(&git__mwindow_mutex);
139
140 /* Shut down any subsystems that have global state */
141 git_hash_global_shutdown();
142 }
143
144 git_global_st *git__global_state(void)
145 {
146 void *ptr;
147
148 assert(_tls_init);
149
150 if ((ptr = pthread_getspecific(_tls_key)) != NULL)
151 return ptr;
152
153 ptr = git__malloc(sizeof(git_global_st));
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
166 int git_threads_init(void)
167 {
168 /* noop */
169 return 0;
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 */