]> git.proxmox.com Git - libgit2.git/blob - src/thread.h
New upstream version 1.3.0+dfsg.1
[libgit2.git] / src / thread.h
1 /*
2 * Copyright (C) the libgit2 contributors. All rights reserved.
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 #ifndef INCLUDE_thread_h__
8 #define INCLUDE_thread_h__
9
10 #if defined(GIT_THREADS)
11
12 #if defined(__clang__)
13
14 # if (__clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 1))
15 # error Atomic primitives do not exist on this version of clang; configure libgit2 with -DTHREADSAFE=OFF
16 # else
17 # define GIT_BUILTIN_ATOMIC
18 # endif
19
20 #elif defined(__GNUC__)
21
22 # if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1))
23 # error Atomic primitives do not exist on this version of gcc; configure libgit2 with -DTHREADSAFE=OFF
24 # elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
25 # define GIT_BUILTIN_ATOMIC
26 # else
27 # define GIT_BUILTIN_SYNC
28 # endif
29
30 #endif
31
32 #endif /* GIT_THREADS */
33
34 /* Common operations even if threading has been disabled */
35 typedef struct {
36 #if defined(GIT_WIN32)
37 volatile long val;
38 #else
39 volatile int val;
40 #endif
41 } git_atomic32;
42
43 #ifdef GIT_ARCH_64
44
45 typedef struct {
46 #if defined(GIT_WIN32)
47 volatile __int64 val;
48 #else
49 volatile int64_t val;
50 #endif
51 } git_atomic64;
52
53 typedef git_atomic64 git_atomic_ssize;
54
55 #define git_atomic_ssize_set git_atomic64_set
56 #define git_atomic_ssize_add git_atomic64_add
57 #define git_atomic_ssize_get git_atomic64_get
58
59 #else
60
61 typedef git_atomic32 git_atomic_ssize;
62
63 #define git_atomic_ssize_set git_atomic32_set
64 #define git_atomic_ssize_add git_atomic32_add
65 #define git_atomic_ssize_get git_atomic32_get
66
67 #endif
68
69 #ifdef GIT_THREADS
70
71 #ifdef GIT_WIN32
72 # include "win32/thread.h"
73 #else
74 # include "unix/pthread.h"
75 #endif
76
77 /*
78 * Atomically sets the contents of *a to be val.
79 */
80 GIT_INLINE(void) git_atomic32_set(git_atomic32 *a, int val)
81 {
82 #if defined(GIT_WIN32)
83 InterlockedExchange(&a->val, (LONG)val);
84 #elif defined(GIT_BUILTIN_ATOMIC)
85 __atomic_store_n(&a->val, val, __ATOMIC_SEQ_CST);
86 #elif defined(GIT_BUILTIN_SYNC)
87 __sync_lock_test_and_set(&a->val, val);
88 #else
89 # error "Unsupported architecture for atomic operations"
90 #endif
91 }
92
93 /*
94 * Atomically increments the contents of *a by 1, and stores the result back into *a.
95 * @return the result of the operation.
96 */
97 GIT_INLINE(int) git_atomic32_inc(git_atomic32 *a)
98 {
99 #if defined(GIT_WIN32)
100 return InterlockedIncrement(&a->val);
101 #elif defined(GIT_BUILTIN_ATOMIC)
102 return __atomic_add_fetch(&a->val, 1, __ATOMIC_SEQ_CST);
103 #elif defined(GIT_BUILTIN_SYNC)
104 return __sync_add_and_fetch(&a->val, 1);
105 #else
106 # error "Unsupported architecture for atomic operations"
107 #endif
108 }
109
110 /*
111 * Atomically adds the contents of *a and addend, and stores the result back into *a.
112 * @return the result of the operation.
113 */
114 GIT_INLINE(int) git_atomic32_add(git_atomic32 *a, int32_t addend)
115 {
116 #if defined(GIT_WIN32)
117 return InterlockedAdd(&a->val, addend);
118 #elif defined(GIT_BUILTIN_ATOMIC)
119 return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST);
120 #elif defined(GIT_BUILTIN_SYNC)
121 return __sync_add_and_fetch(&a->val, addend);
122 #else
123 # error "Unsupported architecture for atomic operations"
124 #endif
125 }
126
127 /*
128 * Atomically decrements the contents of *a by 1, and stores the result back into *a.
129 * @return the result of the operation.
130 */
131 GIT_INLINE(int) git_atomic32_dec(git_atomic32 *a)
132 {
133 #if defined(GIT_WIN32)
134 return InterlockedDecrement(&a->val);
135 #elif defined(GIT_BUILTIN_ATOMIC)
136 return __atomic_sub_fetch(&a->val, 1, __ATOMIC_SEQ_CST);
137 #elif defined(GIT_BUILTIN_SYNC)
138 return __sync_sub_and_fetch(&a->val, 1);
139 #else
140 # error "Unsupported architecture for atomic operations"
141 #endif
142 }
143
144 /*
145 * Atomically gets the contents of *a.
146 * @return the contents of *a.
147 */
148 GIT_INLINE(int) git_atomic32_get(git_atomic32 *a)
149 {
150 #if defined(GIT_WIN32)
151 return (int)InterlockedCompareExchange(&a->val, 0, 0);
152 #elif defined(GIT_BUILTIN_ATOMIC)
153 return __atomic_load_n(&a->val, __ATOMIC_SEQ_CST);
154 #elif defined(GIT_BUILTIN_SYNC)
155 return __sync_val_compare_and_swap(&a->val, 0, 0);
156 #else
157 # error "Unsupported architecture for atomic operations"
158 #endif
159 }
160
161 GIT_INLINE(void *) git_atomic__compare_and_swap(
162 void * volatile *ptr, void *oldval, void *newval)
163 {
164 #if defined(GIT_WIN32)
165 return InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
166 #elif defined(GIT_BUILTIN_ATOMIC)
167 void *foundval = oldval;
168 __atomic_compare_exchange(ptr, &foundval, &newval, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
169 return foundval;
170 #elif defined(GIT_BUILTIN_SYNC)
171 return __sync_val_compare_and_swap(ptr, oldval, newval);
172 #else
173 # error "Unsupported architecture for atomic operations"
174 #endif
175 }
176
177 GIT_INLINE(volatile void *) git_atomic__swap(
178 void * volatile *ptr, void *newval)
179 {
180 #if defined(GIT_WIN32)
181 return InterlockedExchangePointer(ptr, newval);
182 #elif defined(GIT_BUILTIN_ATOMIC)
183 void * volatile foundval = NULL;
184 __atomic_exchange(ptr, &newval, &foundval, __ATOMIC_SEQ_CST);
185 return foundval;
186 #elif defined(GIT_BUILTIN_SYNC)
187 return (volatile void *)__sync_lock_test_and_set(ptr, newval);
188 #else
189 # error "Unsupported architecture for atomic operations"
190 #endif
191 }
192
193 GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr)
194 {
195 #if defined(GIT_WIN32)
196 void *newval = NULL, *oldval = NULL;
197 return (volatile void *)InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
198 #elif defined(GIT_BUILTIN_ATOMIC)
199 return (volatile void *)__atomic_load_n(ptr, __ATOMIC_SEQ_CST);
200 #elif defined(GIT_BUILTIN_SYNC)
201 return (volatile void *)__sync_val_compare_and_swap(ptr, 0, 0);
202 #else
203 # error "Unsupported architecture for atomic operations"
204 #endif
205 }
206
207 #ifdef GIT_ARCH_64
208
209 /*
210 * Atomically adds the contents of *a and addend, and stores the result back into *a.
211 * @return the result of the operation.
212 */
213 GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
214 {
215 #if defined(GIT_WIN32)
216 return InterlockedAdd64(&a->val, addend);
217 #elif defined(GIT_BUILTIN_ATOMIC)
218 return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST);
219 #elif defined(GIT_BUILTIN_SYNC)
220 return __sync_add_and_fetch(&a->val, addend);
221 #else
222 # error "Unsupported architecture for atomic operations"
223 #endif
224 }
225
226 /*
227 * Atomically sets the contents of *a to be val.
228 */
229 GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val)
230 {
231 #if defined(GIT_WIN32)
232 InterlockedExchange64(&a->val, val);
233 #elif defined(GIT_BUILTIN_ATOMIC)
234 __atomic_store_n(&a->val, val, __ATOMIC_SEQ_CST);
235 #elif defined(GIT_BUILTIN_SYNC)
236 __sync_lock_test_and_set(&a->val, val);
237 #else
238 # error "Unsupported architecture for atomic operations"
239 #endif
240 }
241
242 /*
243 * Atomically gets the contents of *a.
244 * @return the contents of *a.
245 */
246 GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
247 {
248 #if defined(GIT_WIN32)
249 return (int64_t)InterlockedCompareExchange64(&a->val, 0, 0);
250 #elif defined(GIT_BUILTIN_ATOMIC)
251 return __atomic_load_n(&a->val, __ATOMIC_SEQ_CST);
252 #elif defined(GIT_BUILTIN_SYNC)
253 return __sync_val_compare_and_swap(&a->val, 0, 0);
254 #else
255 # error "Unsupported architecture for atomic operations"
256 #endif
257 }
258
259 #endif
260
261 #else
262
263 #define git_threads_global_init git__noop
264
265 #define git_thread unsigned int
266 #define git_thread_create(thread, start_routine, arg) git__noop()
267 #define git_thread_join(id, status) git__noop()
268
269 /* Pthreads Mutex */
270 #define git_mutex unsigned int
271 #define git_mutex_init(a) git__noop()
272 #define git_mutex_init(a) git__noop()
273 #define git_mutex_lock(a) git__noop()
274 #define git_mutex_unlock(a) git__noop()
275 #define git_mutex_free(a) git__noop()
276
277 /* Pthreads condition vars */
278 #define git_cond unsigned int
279 #define git_cond_init(c) git__noop()
280 #define git_cond_free(c) git__noop()
281 #define git_cond_wait(c, l) git__noop()
282 #define git_cond_signal(c) git__noop()
283 #define git_cond_broadcast(c) git__noop()
284
285 /* Pthreads rwlock */
286 #define git_rwlock unsigned int
287 #define git_rwlock_init(a) git__noop()
288 #define git_rwlock_rdlock(a) git__noop()
289 #define git_rwlock_rdunlock(a) git__noop()
290 #define git_rwlock_wrlock(a) git__noop()
291 #define git_rwlock_wrunlock(a) git__noop()
292 #define git_rwlock_free(a) git__noop()
293 #define GIT_RWLOCK_STATIC_INIT 0
294
295
296 GIT_INLINE(void) git_atomic32_set(git_atomic32 *a, int val)
297 {
298 a->val = val;
299 }
300
301 GIT_INLINE(int) git_atomic32_inc(git_atomic32 *a)
302 {
303 return ++a->val;
304 }
305
306 GIT_INLINE(int) git_atomic32_add(git_atomic32 *a, int32_t addend)
307 {
308 a->val += addend;
309 return a->val;
310 }
311
312 GIT_INLINE(int) git_atomic32_dec(git_atomic32 *a)
313 {
314 return --a->val;
315 }
316
317 GIT_INLINE(int) git_atomic32_get(git_atomic32 *a)
318 {
319 return (int)a->val;
320 }
321
322 GIT_INLINE(void *) git_atomic__compare_and_swap(
323 void * volatile *ptr, void *oldval, void *newval)
324 {
325 void *foundval = *ptr;
326 if (foundval == oldval)
327 *ptr = newval;
328 return foundval;
329 }
330
331 GIT_INLINE(volatile void *) git_atomic__swap(
332 void * volatile *ptr, void *newval)
333 {
334 volatile void *old = *ptr;
335 *ptr = newval;
336 return old;
337 }
338
339 GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr)
340 {
341 return *ptr;
342 }
343
344 #ifdef GIT_ARCH_64
345
346 GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
347 {
348 a->val += addend;
349 return a->val;
350 }
351
352 GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val)
353 {
354 a->val = val;
355 }
356
357 GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
358 {
359 return (int64_t)a->val;
360 }
361
362 #endif
363
364 #endif
365
366 /*
367 * Atomically replace the contents of *ptr (if they are equal to oldval) with
368 * newval. ptr must point to a pointer or a value that is the same size as a
369 * pointer. This is semantically compatible with:
370 *
371 * #define git_atomic_compare_and_swap(ptr, oldval, newval) \
372 * ({ \
373 * void *foundval = *ptr; \
374 * if (foundval == oldval) \
375 * *ptr = newval; \
376 * foundval; \
377 * })
378 *
379 * @return the original contents of *ptr.
380 */
381 #define git_atomic_compare_and_swap(ptr, oldval, newval) \
382 git_atomic__compare_and_swap((void * volatile *)ptr, oldval, newval)
383
384 /*
385 * Atomically replace the contents of v with newval. v must be the same size as
386 * a pointer. This is semantically compatible with:
387 *
388 * #define git_atomic_swap(v, newval) \
389 * ({ \
390 * volatile void *old = v; \
391 * v = newval; \
392 * old; \
393 * })
394 *
395 * @return the original contents of v.
396 */
397 #define git_atomic_swap(v, newval) \
398 (void *)git_atomic__swap((void * volatile *)&(v), newval)
399
400 /*
401 * Atomically reads the contents of v. v must be the same size as a pointer.
402 * This is semantically compatible with:
403 *
404 * #define git_atomic_load(v) v
405 *
406 * @return the contents of v.
407 */
408 #define git_atomic_load(v) \
409 (void *)git_atomic__load((void * volatile *)&(v))
410
411 #if defined(GIT_THREADS)
412
413 # if defined(GIT_WIN32)
414 # define GIT_MEMORY_BARRIER MemoryBarrier()
415 # elif defined(GIT_BUILTIN_ATOMIC)
416 # define GIT_MEMORY_BARRIER __atomic_thread_fence(__ATOMIC_SEQ_CST)
417 # elif defined(GIT_BUILTIN_SYNC)
418 # define GIT_MEMORY_BARRIER __sync_synchronize()
419 # endif
420
421 #else
422
423 # define GIT_MEMORY_BARRIER /* noop */
424
425 #endif
426
427 /* Thread-local data */
428
429 #if !defined(GIT_THREADS)
430 # define git_tlsdata_key int
431 #elif defined(GIT_WIN32)
432 # define git_tlsdata_key DWORD
433 #elif defined(_POSIX_THREADS)
434 # define git_tlsdata_key pthread_key_t
435 #else
436 # error unknown threading model
437 #endif
438
439 /**
440 * Create a thread-local data key. The destroy function will be
441 * called upon thread exit. On some platforms, it may be called
442 * when all threads have deleted their keys.
443 *
444 * Note that the tlsdata functions do not set an error message on
445 * failure; this is because the error handling in libgit2 is itself
446 * handled by thread-local data storage.
447 *
448 * @param key the tlsdata key
449 * @param destroy_fn function pointer called upon thread exit
450 * @return 0 on success, non-zero on failure
451 */
452 int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *));
453
454 /**
455 * Set a the thread-local value for the given key.
456 *
457 * @param key the tlsdata key to store data on
458 * @param value the pointer to store
459 * @return 0 on success, non-zero on failure
460 */
461 int git_tlsdata_set(git_tlsdata_key key, void *value);
462
463 /**
464 * Get the thread-local value for the given key.
465 *
466 * @param key the tlsdata key to retrieve the value of
467 * @return the pointer stored with git_tlsdata_set
468 */
469 void *git_tlsdata_get(git_tlsdata_key key);
470
471 /**
472 * Delete the given thread-local key.
473 *
474 * @param key the tlsdata key to dispose
475 * @return 0 on success, non-zero on failure
476 */
477 int git_tlsdata_dispose(git_tlsdata_key key);
478
479 #endif