]> git.proxmox.com Git - libgit2.git/blob - src/thread-utils.h
New upstream version 1.1.0+dfsg.1
[libgit2.git] / src / thread-utils.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_utils_h__
8 #define INCLUDE_thread_utils_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_atomic;
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_atomic git_atomic_ssize;
62
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
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 GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
78 {
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);
85 #else
86 # error "Unsupported architecture for atomic operations"
87 #endif
88 }
89
90 GIT_INLINE(int) git_atomic_inc(git_atomic *a)
91 {
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);
98 #else
99 # error "Unsupported architecture for atomic operations"
100 #endif
101 }
102
103 GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend)
104 {
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);
111 #else
112 # error "Unsupported architecture for atomic operations"
113 #endif
114 }
115
116 GIT_INLINE(int) git_atomic_dec(git_atomic *a)
117 {
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);
124 #else
125 # error "Unsupported architecture for atomic operations"
126 #endif
127 }
128
129 GIT_INLINE(int) git_atomic_get(git_atomic *a)
130 {
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);
137 #else
138 # error "Unsupported architecture for atomic operations"
139 #endif
140 }
141
142 GIT_INLINE(void *) git___compare_and_swap(
143 void * volatile *ptr, void *oldval, void *newval)
144 {
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;
156 #else
157 # error "Unsupported architecture for atomic operations"
158 #endif
159 }
160
161 GIT_INLINE(volatile void *) git___swap(
162 void * volatile *ptr, void *newval)
163 {
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);
169 return foundval;
170 #elif defined(GIT_BUILTIN_SYNC)
171 return __sync_lock_test_and_set(ptr, newval);
172 #else
173 # error "Unsupported architecture for atomic operations"
174 #endif
175 }
176
177 GIT_INLINE(volatile void *) git___load(void * volatile *ptr)
178 {
179 #if defined(GIT_WIN32)
180 void *newval = NULL, *oldval = NULL;
181 volatile void *foundval = NULL;
182 foundval = InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
183 return foundval;
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);
188 #else
189 # error "Unsupported architecture for atomic operations"
190 #endif
191 }
192
193 #ifdef GIT_ARCH_64
194
195 GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
196 {
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);
203 #else
204 # error "Unsupported architecture for atomic operations"
205 #endif
206 }
207
208 GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val)
209 {
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);
216 #else
217 # error "Unsupported architecture for atomic operations"
218 #endif
219 }
220
221 GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
222 {
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);
229 #else
230 # error "Unsupported architecture for atomic operations"
231 #endif
232 }
233
234 #endif
235
236 #else
237
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
241
242 /* Pthreads Mutex */
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
250
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
258
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
268
269
270 GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
271 {
272 a->val = val;
273 }
274
275 GIT_INLINE(int) git_atomic_inc(git_atomic *a)
276 {
277 return ++a->val;
278 }
279
280 GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend)
281 {
282 a->val += addend;
283 return a->val;
284 }
285
286 GIT_INLINE(int) git_atomic_dec(git_atomic *a)
287 {
288 return --a->val;
289 }
290
291 GIT_INLINE(int) git_atomic_get(git_atomic *a)
292 {
293 return (int)a->val;
294 }
295
296 GIT_INLINE(void *) git___compare_and_swap(
297 void * volatile *ptr, void *oldval, void *newval)
298 {
299 if (*ptr == oldval)
300 *ptr = newval;
301 else
302 oldval = newval;
303 return oldval;
304 }
305
306 GIT_INLINE(volatile void *) git___swap(
307 void * volatile *ptr, void *newval)
308 {
309 volatile void *old = *ptr;
310 *ptr = newval;
311 return old;
312 }
313
314 #ifdef GIT_ARCH_64
315
316 GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
317 {
318 a->val += addend;
319 return a->val;
320 }
321
322 GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val)
323 {
324 a->val = val;
325 }
326
327 GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
328 {
329 return (int64_t)a->val;
330 }
331
332 #endif
333
334 #endif
335
336 /* Atomically replace oldval with newval
337 * @return oldval if it was replaced or newval if it was not
338 */
339 #define git__compare_and_swap(P,O,N) \
340 git___compare_and_swap((void * volatile *)P, O, N)
341
342 #define git__swap(ptr, val) (void *)git___swap((void * volatile *)&ptr, val)
343
344 #define git__load(ptr) (void *)git___load((void * volatile *)&ptr)
345
346 extern int git_online_cpus(void);
347
348 #if defined(GIT_THREADS)
349
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()
356 # endif
357
358 #else
359
360 # define GIT_MEMORY_BARRIER /* noop */
361
362 #endif
363
364 #endif