2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
7 #ifndef INCLUDE_thread_h__
8 #define INCLUDE_thread_h__
10 #if defined(GIT_THREADS)
12 #if defined(__clang__)
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
17 # define GIT_BUILTIN_ATOMIC
20 #elif defined(__GNUC__)
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
27 # define GIT_BUILTIN_SYNC
32 #endif /* GIT_THREADS */
34 /* Common operations even if threading has been disabled */
36 #if defined(GIT_WIN32)
46 #if defined(GIT_WIN32)
53 typedef git_atomic64 git_atomic_ssize
;
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
61 typedef git_atomic32 git_atomic_ssize
;
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
72 # include "win32/thread.h"
74 # include "unix/pthread.h"
78 * Atomically sets the contents of *a to be val.
80 GIT_INLINE(void) git_atomic32_set(git_atomic32
*a
, int val
)
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
);
89 # error "Unsupported architecture for atomic operations"
94 * Atomically increments the contents of *a by 1, and stores the result back into *a.
95 * @return the result of the operation.
97 GIT_INLINE(int) git_atomic32_inc(git_atomic32
*a
)
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);
106 # error "Unsupported architecture for atomic operations"
111 * Atomically adds the contents of *a and addend, and stores the result back into *a.
112 * @return the result of the operation.
114 GIT_INLINE(int) git_atomic32_add(git_atomic32
*a
, int32_t addend
)
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
);
123 # error "Unsupported architecture for atomic operations"
128 * Atomically decrements the contents of *a by 1, and stores the result back into *a.
129 * @return the result of the operation.
131 GIT_INLINE(int) git_atomic32_dec(git_atomic32
*a
)
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);
140 # error "Unsupported architecture for atomic operations"
145 * Atomically gets the contents of *a.
146 * @return the contents of *a.
148 GIT_INLINE(int) git_atomic32_get(git_atomic32
*a
)
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);
157 # error "Unsupported architecture for atomic operations"
161 GIT_INLINE(void *) git_atomic__compare_and_swap(
162 void * volatile *ptr
, void *oldval
, void *newval
)
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
);
170 #elif defined(GIT_BUILTIN_SYNC)
171 return __sync_val_compare_and_swap(ptr
, oldval
, newval
);
173 # error "Unsupported architecture for atomic operations"
177 GIT_INLINE(volatile void *) git_atomic__swap(
178 void * volatile *ptr
, void *newval
)
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
);
186 #elif defined(GIT_BUILTIN_SYNC)
187 return (volatile void *)__sync_lock_test_and_set(ptr
, newval
);
189 # error "Unsupported architecture for atomic operations"
193 GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr
)
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);
203 # error "Unsupported architecture for atomic operations"
210 * Atomically adds the contents of *a and addend, and stores the result back into *a.
211 * @return the result of the operation.
213 GIT_INLINE(int64_t) git_atomic64_add(git_atomic64
*a
, int64_t addend
)
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
);
222 # error "Unsupported architecture for atomic operations"
227 * Atomically sets the contents of *a to be val.
229 GIT_INLINE(void) git_atomic64_set(git_atomic64
*a
, int64_t val
)
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
);
238 # error "Unsupported architecture for atomic operations"
243 * Atomically gets the contents of *a.
244 * @return the contents of *a.
246 GIT_INLINE(int64_t) git_atomic64_get(git_atomic64
*a
)
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);
255 # error "Unsupported architecture for atomic operations"
263 #define git_threads_global_init git__noop
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()
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()
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()
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
296 GIT_INLINE(void) git_atomic32_set(git_atomic32
*a
, int val
)
301 GIT_INLINE(int) git_atomic32_inc(git_atomic32
*a
)
306 GIT_INLINE(int) git_atomic32_add(git_atomic32
*a
, int32_t addend
)
312 GIT_INLINE(int) git_atomic32_dec(git_atomic32
*a
)
317 GIT_INLINE(int) git_atomic32_get(git_atomic32
*a
)
322 GIT_INLINE(void *) git_atomic__compare_and_swap(
323 void * volatile *ptr
, void *oldval
, void *newval
)
325 void *foundval
= *ptr
;
326 if (foundval
== oldval
)
331 GIT_INLINE(volatile void *) git_atomic__swap(
332 void * volatile *ptr
, void *newval
)
334 volatile void *old
= *ptr
;
339 GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr
)
346 GIT_INLINE(int64_t) git_atomic64_add(git_atomic64
*a
, int64_t addend
)
352 GIT_INLINE(void) git_atomic64_set(git_atomic64
*a
, int64_t val
)
357 GIT_INLINE(int64_t) git_atomic64_get(git_atomic64
*a
)
359 return (int64_t)a
->val
;
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:
371 * #define git_atomic_compare_and_swap(ptr, oldval, newval) \
373 * void *foundval = *ptr; \
374 * if (foundval == oldval) \
379 * @return the original contents of *ptr.
381 #define git_atomic_compare_and_swap(ptr, oldval, newval) \
382 git_atomic__compare_and_swap((void * volatile *)ptr, oldval, newval)
385 * Atomically replace the contents of v with newval. v must be the same size as
386 * a pointer. This is semantically compatible with:
388 * #define git_atomic_swap(v, newval) \
390 * volatile void *old = v; \
395 * @return the original contents of v.
397 #define git_atomic_swap(v, newval) \
398 (void *)git_atomic__swap((void * volatile *)&(v), newval)
401 * Atomically reads the contents of v. v must be the same size as a pointer.
402 * This is semantically compatible with:
404 * #define git_atomic_load(v) v
406 * @return the contents of v.
408 #define git_atomic_load(v) \
409 (void *)git_atomic__load((void * volatile *)&(v))
411 #if defined(GIT_THREADS)
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()
423 # define GIT_MEMORY_BARRIER /* noop */
427 /* Thread-local data */
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
436 # error unknown threading model
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.
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.
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
452 int git_tlsdata_init(git_tlsdata_key
*key
, void (GIT_SYSTEM_CALL
*destroy_fn
)(void *));
455 * Set a the thread-local value for the given key.
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
461 int git_tlsdata_set(git_tlsdata_key key
, void *value
);
464 * Get the thread-local value for the given key.
466 * @param key the tlsdata key to retrieve the value of
467 * @return the pointer stored with git_tlsdata_set
469 void *git_tlsdata_get(git_tlsdata_key key
);
472 * Delete the given thread-local key.
474 * @param key the tlsdata key to dispose
475 * @return 0 on success, non-zero on failure
477 int git_tlsdata_dispose(git_tlsdata_key key
);