File Coverage

deps/libgit2/src/util/thread.h
Criterion Covered Total %
statement 4 4 100.0
branch n/a
condition n/a
subroutine n/a
pod n/a
total 4 4 100.0


line stmt bran cond sub pod time code
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 -DUSE_THREADS=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 -DUSE_THREADS=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 85           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 85           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 82           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 82           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 * 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