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_utils_h__
8 #define INCLUDE_thread_utils_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_atomic git_atomic_ssize
;
63 #define git_atomic_ssize_set git_atomic_set
64 #define git_atomic_ssize_add git_atomic_add
65 #define git_atomic_ssize_get git_atomic_get
72 # include "win32/thread.h"
74 # include "unix/pthread.h"
77 GIT_INLINE(void) git_atomic_set(git_atomic
*a
, int val
)
79 #if defined(GIT_WIN32)
80 InterlockedExchange(&a
->val
, (LONG
)val
);
81 #elif defined(GIT_BUILTIN_ATOMIC)
82 __atomic_store_n(&a
->val
, val
, __ATOMIC_SEQ_CST
);
83 #elif defined(GIT_BUILTIN_SYNC)
84 __sync_lock_test_and_set(&a
->val
, val
);
86 # error "Unsupported architecture for atomic operations"
90 GIT_INLINE(int) git_atomic_inc(git_atomic
*a
)
92 #if defined(GIT_WIN32)
93 return InterlockedIncrement(&a
->val
);
94 #elif defined(GIT_BUILTIN_ATOMIC)
95 return __atomic_add_fetch(&a
->val
, 1, __ATOMIC_SEQ_CST
);
96 #elif defined(GIT_BUILTIN_SYNC)
97 return __sync_add_and_fetch(&a
->val
, 1);
99 # error "Unsupported architecture for atomic operations"
103 GIT_INLINE(int) git_atomic_add(git_atomic
*a
, int32_t addend
)
105 #if defined(GIT_WIN32)
106 return InterlockedExchangeAdd(&a
->val
, addend
);
107 #elif defined(GIT_BUILTIN_ATOMIC)
108 return __atomic_add_fetch(&a
->val
, addend
, __ATOMIC_SEQ_CST
);
109 #elif defined(GIT_BUILTIN_SYNC)
110 return __sync_add_and_fetch(&a
->val
, addend
);
112 # error "Unsupported architecture for atomic operations"
116 GIT_INLINE(int) git_atomic_dec(git_atomic
*a
)
118 #if defined(GIT_WIN32)
119 return InterlockedDecrement(&a
->val
);
120 #elif defined(GIT_BUILTIN_ATOMIC)
121 return __atomic_sub_fetch(&a
->val
, 1, __ATOMIC_SEQ_CST
);
122 #elif defined(GIT_BUILTIN_SYNC)
123 return __sync_sub_and_fetch(&a
->val
, 1);
125 # error "Unsupported architecture for atomic operations"
129 GIT_INLINE(int) git_atomic_get(git_atomic
*a
)
131 #if defined(GIT_WIN32)
132 return (int)InterlockedCompareExchange(&a
->val
, 0, 0);
133 #elif defined(GIT_BUILTIN_ATOMIC)
134 return __atomic_load_n(&a
->val
, __ATOMIC_SEQ_CST
);
135 #elif defined(GIT_BUILTIN_SYNC)
136 return __sync_val_compare_and_swap(&a
->val
, 0, 0);
138 # error "Unsupported architecture for atomic operations"
142 GIT_INLINE(void *) git___compare_and_swap(
143 void * volatile *ptr
, void *oldval
, void *newval
)
145 #if defined(GIT_WIN32)
146 volatile void *foundval
;
147 foundval
= InterlockedCompareExchangePointer((volatile PVOID
*)ptr
, newval
, oldval
);
148 return (foundval
== oldval
) ? oldval
: newval
;
149 #elif defined(GIT_BUILTIN_ATOMIC)
150 bool success
= __atomic_compare_exchange(ptr
, &oldval
, &newval
, false, __ATOMIC_SEQ_CST
, __ATOMIC_SEQ_CST
);
151 return success
? oldval
: newval
;
152 #elif defined(GIT_BUILTIN_SYNC)
153 volatile void *foundval
;
154 foundval
= __sync_val_compare_and_swap(ptr
, oldval
, newval
);
155 return (foundval
== oldval
) ? oldval
: newval
;
157 # error "Unsupported architecture for atomic operations"
161 GIT_INLINE(volatile void *) git___swap(
162 void * volatile *ptr
, void *newval
)
164 #if defined(GIT_WIN32)
165 return InterlockedExchangePointer(ptr
, newval
);
166 #elif defined(GIT_BUILTIN_ATOMIC)
167 void * volatile foundval
;
168 __atomic_exchange(ptr
, &newval
, &foundval
, __ATOMIC_SEQ_CST
);
170 #elif defined(GIT_BUILTIN_SYNC)
171 return __sync_lock_test_and_set(ptr
, newval
);
173 # error "Unsupported architecture for atomic operations"
177 GIT_INLINE(volatile void *) git___load(void * volatile *ptr
)
179 #if defined(GIT_WIN32)
180 void *newval
= NULL
, *oldval
= NULL
;
181 volatile void *foundval
= NULL
;
182 foundval
= InterlockedCompareExchangePointer((volatile PVOID
*)ptr
, newval
, oldval
);
184 #elif defined(GIT_BUILTIN_ATOMIC)
185 return (volatile void *)__atomic_load_n(ptr
, __ATOMIC_SEQ_CST
);
186 #elif defined(GIT_BUILTIN_SYNC)
187 return (volatile void *)__sync_val_compare_and_swap(ptr
, 0, 0);
189 # error "Unsupported architecture for atomic operations"
195 GIT_INLINE(int64_t) git_atomic64_add(git_atomic64
*a
, int64_t addend
)
197 #if defined(GIT_WIN32)
198 return InterlockedExchangeAdd64(&a
->val
, addend
);
199 #elif defined(GIT_BUILTIN_ATOMIC)
200 return __atomic_add_fetch(&a
->val
, addend
, __ATOMIC_SEQ_CST
);
201 #elif defined(GIT_BUILTIN_SYNC)
202 return __sync_add_and_fetch(&a
->val
, addend
);
204 # error "Unsupported architecture for atomic operations"
208 GIT_INLINE(void) git_atomic64_set(git_atomic64
*a
, int64_t val
)
210 #if defined(GIT_WIN32)
211 InterlockedExchange64(&a
->val
, val
);
212 #elif defined(GIT_BUILTIN_ATOMIC)
213 __atomic_store_n(&a
->val
, val
, __ATOMIC_SEQ_CST
);
214 #elif defined(GIT_BUILTIN_SYNC)
215 __sync_lock_test_and_set(&a
->val
, val
);
217 # error "Unsupported architecture for atomic operations"
221 GIT_INLINE(int64_t) git_atomic64_get(git_atomic64
*a
)
223 #if defined(GIT_WIN32)
224 return (int64_t)InterlockedCompareExchange64(&a
->val
, 0, 0);
225 #elif defined(GIT_BUILTIN_ATOMIC)
226 return __atomic_load_n(&a
->val
, __ATOMIC_SEQ_CST
);
227 #elif defined(GIT_BUILTIN_SYNC)
228 return __sync_val_compare_and_swap(&a
->val
, 0, 0);
230 # error "Unsupported architecture for atomic operations"
238 #define git_thread unsigned int
239 #define git_thread_create(thread, start_routine, arg) 0
240 #define git_thread_join(id, status) (void)0
243 #define git_mutex unsigned int
244 GIT_INLINE(int) git_mutex_init(git_mutex
*mutex
) \
245 { GIT_UNUSED(mutex
); return 0; }
246 GIT_INLINE(int) git_mutex_lock(git_mutex
*mutex
) \
247 { GIT_UNUSED(mutex
); return 0; }
248 #define git_mutex_unlock(a) (void)0
249 #define git_mutex_free(a) (void)0
251 /* Pthreads condition vars */
252 #define git_cond unsigned int
253 #define git_cond_init(c, a) (void)0
254 #define git_cond_free(c) (void)0
255 #define git_cond_wait(c, l) (void)0
256 #define git_cond_signal(c) (void)0
257 #define git_cond_broadcast(c) (void)0
259 /* Pthreads rwlock */
260 #define git_rwlock unsigned int
261 #define git_rwlock_init(a) 0
262 #define git_rwlock_rdlock(a) 0
263 #define git_rwlock_rdunlock(a) (void)0
264 #define git_rwlock_wrlock(a) 0
265 #define git_rwlock_wrunlock(a) (void)0
266 #define git_rwlock_free(a) (void)0
267 #define GIT_RWLOCK_STATIC_INIT 0
270 GIT_INLINE(void) git_atomic_set(git_atomic
*a
, int val
)
275 GIT_INLINE(int) git_atomic_inc(git_atomic
*a
)
280 GIT_INLINE(int) git_atomic_add(git_atomic
*a
, int32_t addend
)
286 GIT_INLINE(int) git_atomic_dec(git_atomic
*a
)
291 GIT_INLINE(int) git_atomic_get(git_atomic
*a
)
296 GIT_INLINE(void *) git___compare_and_swap(
297 void * volatile *ptr
, void *oldval
, void *newval
)
306 GIT_INLINE(volatile void *) git___swap(
307 void * volatile *ptr
, void *newval
)
309 volatile void *old
= *ptr
;
316 GIT_INLINE(int64_t) git_atomic64_add(git_atomic64
*a
, int64_t addend
)
322 GIT_INLINE(void) git_atomic64_set(git_atomic64
*a
, int64_t val
)
327 GIT_INLINE(int64_t) git_atomic64_get(git_atomic64
*a
)
329 return (int64_t)a
->val
;
336 /* Atomically replace oldval with newval
337 * @return oldval if it was replaced or newval if it was not
339 #define git__compare_and_swap(P,O,N) \
340 git___compare_and_swap((void * volatile *)P, O, N)
342 #define git__swap(ptr, val) (void *)git___swap((void * volatile *)&ptr, val)
344 #define git__load(ptr) (void *)git___load((void * volatile *)&ptr)
346 extern int git_online_cpus(void);
348 #if defined(GIT_THREADS)
350 # if defined(GIT_WIN32)
351 # define GIT_MEMORY_BARRIER MemoryBarrier()
352 # elif defined(GIT_BUILTIN_ATOMIC)
353 # define GIT_MEMORY_BARRIER __atomic_thread_fence(__ATOMIC_SEQ_CST)
354 # elif defined(GIT_BUILTIN_SYNC)
355 # define GIT_MEMORY_BARRIER __sync_synchronize()
360 # define GIT_MEMORY_BARRIER /* noop */