]> git.proxmox.com Git - libgit2.git/blame - src/thread.h
New upstream version 1.4.3+dfsg.1
[libgit2.git] / src / thread.h
CommitLineData
c25aa7cd
PP
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))
e579e0f7 15# error Atomic primitives do not exist on this version of clang; configure libgit2 with -DUSE_THREADS=OFF
c25aa7cd
PP
16# else
17# define GIT_BUILTIN_ATOMIC
18# endif
19
20#elif defined(__GNUC__)
21
22# if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1))
e579e0f7 23# error Atomic primitives do not exist on this version of gcc; configure libgit2 with -DUSE_THREADS=OFF
c25aa7cd
PP
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 */
35typedef 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
45typedef struct {
46#if defined(GIT_WIN32)
47 volatile __int64 val;
48#else
49 volatile int64_t val;
50#endif
51} git_atomic64;
52
53typedef 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
61typedef 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 */
80GIT_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 */
97GIT_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 */
114GIT_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 */
131GIT_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 */
148GIT_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
161GIT_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
177GIT_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)
e579e0f7 183 void * foundval = NULL;
c25aa7cd
PP
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
193GIT_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 */
213GIT_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 */
229GIT_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 */
246GIT_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
296GIT_INLINE(void) git_atomic32_set(git_atomic32 *a, int val)
297{
298 a->val = val;
299}
300
301GIT_INLINE(int) git_atomic32_inc(git_atomic32 *a)
302{
303 return ++a->val;
304}
305
306GIT_INLINE(int) git_atomic32_add(git_atomic32 *a, int32_t addend)
307{
308 a->val += addend;
309 return a->val;
310}
311
312GIT_INLINE(int) git_atomic32_dec(git_atomic32 *a)
313{
314 return --a->val;
315}
316
317GIT_INLINE(int) git_atomic32_get(git_atomic32 *a)
318{
319 return (int)a->val;
320}
321
322GIT_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
331GIT_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
339GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr)
340{
341 return *ptr;
342}
343
344#ifdef GIT_ARCH_64
345
346GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
347{
348 a->val += addend;
349 return a->val;
350}
351
352GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val)
353{
354 a->val = val;
355}
356
357GIT_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 */
452int 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 */
461int 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 */
469void *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 */
477int git_tlsdata_dispose(git_tlsdata_key key);
478
479#endif