77#ifndef INCLUDE_thread_utils_h__
88#define INCLUDE_thread_utils_h__
99
10- #if defined(__GNUC__ ) && defined(GIT_THREADS )
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+
1122# if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1 ))
1223# error Atomic primitives do not exist on this version of gcc; configure libgit2 with -DTHREADSAFE=OFF
1324# endif
25+ # if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7 ))
26+ # define GIT_BUILTIN_ATOMIC
27+ # else
28+ # define GIT_BUILTIN_SYNC
29+ # endif
30+
1431#endif
1532
33+ #endif /* GIT_THREADS */
34+
1635/* Common operations even if threading has been disabled */
1736typedef struct {
1837#if defined(GIT_WIN32 )
@@ -26,21 +45,25 @@ typedef struct {
2645
2746typedef struct {
2847#if defined(GIT_WIN32 )
29- __int64 val ;
48+ volatile __int64 val ;
3049#else
31- int64_t val ;
50+ volatile int64_t val ;
3251#endif
3352} git_atomic64 ;
3453
3554typedef git_atomic64 git_atomic_ssize ;
3655
56+ #define git_atomic_ssize_set git_atomic64_set
3757#define git_atomic_ssize_add git_atomic64_add
58+ #define git_atomic_ssize_get git_atomic64_get
3859
3960#else
4061
4162typedef git_atomic git_atomic_ssize ;
4263
64+ #define git_atomic_ssize_set git_atomic_set
4365#define git_atomic_ssize_add git_atomic_add
66+ #define git_atomic_ssize_get git_atomic_get
4467
4568#endif
4669
@@ -56,7 +79,9 @@ GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
5679{
5780#if defined(GIT_WIN32 )
5881 InterlockedExchange (& a -> val , (LONG )val );
59- #elif defined(__GNUC__ )
82+ #elif defined(GIT_BUILTIN_ATOMIC )
83+ __atomic_store_n (& a -> val , val , __ATOMIC_SEQ_CST );
84+ #elif defined(GIT_BUILTIN_SYNC )
6085 __sync_lock_test_and_set (& a -> val , val );
6186#else
6287# error "Unsupported architecture for atomic operations"
@@ -67,7 +92,9 @@ GIT_INLINE(int) git_atomic_inc(git_atomic *a)
6792{
6893#if defined(GIT_WIN32 )
6994 return InterlockedIncrement (& a -> val );
70- #elif defined(__GNUC__ )
95+ #elif defined(GIT_BUILTIN_ATOMIC )
96+ return __atomic_add_fetch (& a -> val , 1 , __ATOMIC_SEQ_CST );
97+ #elif defined(GIT_BUILTIN_SYNC )
7198 return __sync_add_and_fetch (& a -> val , 1 );
7299#else
73100# error "Unsupported architecture for atomic operations"
@@ -78,7 +105,9 @@ GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend)
78105{
79106#if defined(GIT_WIN32 )
80107 return InterlockedExchangeAdd (& a -> val , addend );
81- #elif defined(__GNUC__ )
108+ #elif defined(GIT_BUILTIN_ATOMIC )
109+ return __atomic_add_fetch (& a -> val , addend , __ATOMIC_SEQ_CST );
110+ #elif defined(GIT_BUILTIN_SYNC )
82111 return __sync_add_and_fetch (& a -> val , addend );
83112#else
84113# error "Unsupported architecture for atomic operations"
@@ -89,34 +118,76 @@ GIT_INLINE(int) git_atomic_dec(git_atomic *a)
89118{
90119#if defined(GIT_WIN32 )
91120 return InterlockedDecrement (& a -> val );
92- #elif defined(__GNUC__ )
121+ #elif defined(GIT_BUILTIN_ATOMIC )
122+ return __atomic_sub_fetch (& a -> val , 1 , __ATOMIC_SEQ_CST );
123+ #elif defined(GIT_BUILTIN_SYNC )
93124 return __sync_sub_and_fetch (& a -> val , 1 );
94125#else
95126# error "Unsupported architecture for atomic operations"
96127#endif
97128}
98129
130+ GIT_INLINE (int ) git_atomic_get (git_atomic * a )
131+ {
132+ #if defined(GIT_WIN32 )
133+ return (int )InterlockedCompareExchange (& a -> val , 0 , 0 );
134+ #elif defined(GIT_BUILTIN_ATOMIC )
135+ return __atomic_load_n (& a -> val , __ATOMIC_SEQ_CST );
136+ #elif defined(GIT_BUILTIN_SYNC )
137+ return __sync_val_compare_and_swap (& a -> val , 0 , 0 );
138+ #else
139+ # error "Unsupported architecture for atomic operations"
140+ #endif
141+ }
142+
99143GIT_INLINE (void * ) git___compare_and_swap (
100144 void * volatile * ptr , void * oldval , void * newval )
101145{
102- volatile void * foundval ;
103146#if defined(GIT_WIN32 )
147+ volatile void * foundval ;
104148 foundval = InterlockedCompareExchangePointer ((volatile PVOID * )ptr , newval , oldval );
105- #elif defined(__GNUC__ )
149+ return (foundval == oldval ) ? oldval : newval ;
150+ #elif defined(GIT_BUILTIN_ATOMIC )
151+ bool success = __atomic_compare_exchange (ptr , & oldval , & newval , false, __ATOMIC_SEQ_CST , __ATOMIC_SEQ_CST );
152+ return success ? oldval : newval ;
153+ #elif defined(GIT_BUILTIN_SYNC )
154+ volatile void * foundval ;
106155 foundval = __sync_val_compare_and_swap (ptr , oldval , newval );
156+ return (foundval == oldval ) ? oldval : newval ;
107157#else
108158# error "Unsupported architecture for atomic operations"
109159#endif
110- return (foundval == oldval ) ? oldval : newval ;
111160}
112161
113162GIT_INLINE (volatile void * ) git___swap (
114163 void * volatile * ptr , void * newval )
115164{
116165#if defined(GIT_WIN32 )
117166 return InterlockedExchangePointer (ptr , newval );
118- #else
167+ #elif defined(GIT_BUILTIN_ATOMIC )
168+ void * volatile foundval ;
169+ __atomic_exchange (ptr , & newval , & foundval , __ATOMIC_SEQ_CST );
170+ return foundval ;
171+ #elif defined(GIT_BUILTIN_SYNC )
119172 return __sync_lock_test_and_set (ptr , newval );
173+ #else
174+ # error "Unsupported architecture for atomic operations"
175+ #endif
176+ }
177+
178+ GIT_INLINE (volatile void * ) git___load (void * volatile * ptr )
179+ {
180+ #if defined(GIT_WIN32 )
181+ void * newval = NULL , * oldval = NULL ;
182+ volatile void * foundval = NULL ;
183+ foundval = InterlockedCompareExchangePointer ((volatile PVOID * )ptr , newval , oldval );
184+ return foundval ;
185+ #elif defined(GIT_BUILTIN_ATOMIC )
186+ return (volatile void * )__atomic_load_n (ptr , __ATOMIC_SEQ_CST );
187+ #elif defined(GIT_BUILTIN_SYNC )
188+ return (volatile void * )__sync_val_compare_and_swap (ptr , 0 , 0 );
189+ #else
190+ # error "Unsupported architecture for atomic operations"
120191#endif
121192}
122193
@@ -126,13 +197,41 @@ GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
126197{
127198#if defined(GIT_WIN32 )
128199 return InterlockedExchangeAdd64 (& a -> val , addend );
129- #elif defined(__GNUC__ )
200+ #elif defined(GIT_BUILTIN_ATOMIC )
201+ return __atomic_add_fetch (& a -> val , addend , __ATOMIC_SEQ_CST );
202+ #elif defined(GIT_BUILTIN_SYNC )
130203 return __sync_add_and_fetch (& a -> val , addend );
131204#else
132205# error "Unsupported architecture for atomic operations"
133206#endif
134207}
135208
209+ GIT_INLINE (void ) git_atomic64_set (git_atomic64 * a , int64_t val )
210+ {
211+ #if defined(GIT_WIN32 )
212+ InterlockedExchange64 (& a -> val , val );
213+ #elif defined(GIT_BUILTIN_ATOMIC )
214+ __atomic_store_n (& a -> val , val , __ATOMIC_SEQ_CST );
215+ #elif defined(GIT_BUILTIN_SYNC )
216+ __sync_lock_test_and_set (& a -> val , val );
217+ #else
218+ # error "Unsupported architecture for atomic operations"
219+ #endif
220+ }
221+
222+ GIT_INLINE (int64_t ) git_atomic64_get (git_atomic64 * a )
223+ {
224+ #if defined(GIT_WIN32 )
225+ return (int64_t )InterlockedCompareExchange64 (& a -> val , 0 , 0 );
226+ #elif defined(GIT_BUILTIN_ATOMIC )
227+ return __atomic_load_n (& a -> val , __ATOMIC_SEQ_CST );
228+ #elif defined(GIT_BUILTIN_SYNC )
229+ return __sync_val_compare_and_swap (& a -> val , 0 , 0 );
230+ #else
231+ # error "Unsupported architecture for atomic operations"
232+ #endif
233+ }
234+
136235#endif
137236
138237#else
@@ -190,6 +289,11 @@ GIT_INLINE(int) git_atomic_dec(git_atomic *a)
190289 return -- a -> val ;
191290}
192291
292+ GIT_INLINE (int ) git_atomic_get (git_atomic * a )
293+ {
294+ return (int )a -> val ;
295+ }
296+
193297GIT_INLINE (void * ) git___compare_and_swap (
194298 void * volatile * ptr , void * oldval , void * newval )
195299{
@@ -216,15 +320,20 @@ GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
216320 return a -> val ;
217321}
218322
219- #endif
220-
221- #endif
323+ GIT_INLINE (void ) git_atomic64_set (git_atomic64 * a , int64_t val )
324+ {
325+ a -> val = val ;
326+ }
222327
223- GIT_INLINE (int ) git_atomic_get ( git_atomic * a )
328+ GIT_INLINE (int64_t ) git_atomic64_get ( git_atomic64 * a )
224329{
225- return (int )a -> val ;
330+ return (int64_t )a -> val ;
226331}
227332
333+ #endif
334+
335+ #endif
336+
228337/* Atomically replace oldval with newval
229338 * @return oldval if it was replaced or newval if it was not
230339 */
@@ -233,14 +342,24 @@ GIT_INLINE(int) git_atomic_get(git_atomic *a)
233342
234343#define git__swap (ptr , val ) (void *)git___swap((void * volatile *)&ptr, val)
235344
345+ #define git__load (ptr ) (void *)git___load((void * volatile *)&ptr)
346+
236347extern int git_online_cpus (void );
237348
238- #if defined(GIT_THREADS ) && defined(_MSC_VER )
239- # define GIT_MEMORY_BARRIER MemoryBarrier()
240- #elif defined(GIT_THREADS )
241- # define GIT_MEMORY_BARRIER __sync_synchronize()
349+ #if defined(GIT_THREADS )
350+
351+ # if defined(GIT_WIN32 )
352+ # define GIT_MEMORY_BARRIER MemoryBarrier()
353+ # elif defined(GIT_BUILTIN_ATOMIC )
354+ # define GIT_MEMORY_BARRIER __atomic_thread_fence(__ATOMIC_SEQ_CST)
355+ # elif defined(GIT_BUILTIN_SYNC )
356+ # define GIT_MEMORY_BARRIER __sync_synchronize()
357+ # endif
358+
242359#else
360+
243361# define GIT_MEMORY_BARRIER /* noop */
362+
244363#endif
245364
246365#endif
0 commit comments