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
24+ # elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7 ))
25+ # define GIT_BUILTIN_ATOMIC
26+ # else
27+ # define GIT_BUILTIN_SYNC
1328# endif
29+
1430#endif
1531
32+ #endif /* GIT_THREADS */
33+
1634/* Common operations even if threading has been disabled */
1735typedef struct {
1836#if defined(GIT_WIN32 )
@@ -26,21 +44,25 @@ typedef struct {
2644
2745typedef struct {
2846#if defined(GIT_WIN32 )
29- __int64 val ;
47+ volatile __int64 val ;
3048#else
31- int64_t val ;
49+ volatile int64_t val ;
3250#endif
3351} git_atomic64 ;
3452
3553typedef git_atomic64 git_atomic_ssize ;
3654
55+ #define git_atomic_ssize_set git_atomic64_set
3756#define git_atomic_ssize_add git_atomic64_add
57+ #define git_atomic_ssize_get git_atomic64_get
3858
3959#else
4060
4161typedef git_atomic git_atomic_ssize ;
4262
63+ #define git_atomic_ssize_set git_atomic_set
4364#define git_atomic_ssize_add git_atomic_add
65+ #define git_atomic_ssize_get git_atomic_get
4466
4567#endif
4668
@@ -56,7 +78,9 @@ GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
5678{
5779#if defined(GIT_WIN32 )
5880 InterlockedExchange (& a -> val , (LONG )val );
59- #elif defined(__GNUC__ )
81+ #elif defined(GIT_BUILTIN_ATOMIC )
82+ __atomic_store_n (& a -> val , val , __ATOMIC_SEQ_CST );
83+ #elif defined(GIT_BUILTIN_SYNC )
6084 __sync_lock_test_and_set (& a -> val , val );
6185#else
6286# error "Unsupported architecture for atomic operations"
@@ -67,7 +91,9 @@ GIT_INLINE(int) git_atomic_inc(git_atomic *a)
6791{
6892#if defined(GIT_WIN32 )
6993 return InterlockedIncrement (& a -> val );
70- #elif defined(__GNUC__ )
94+ #elif defined(GIT_BUILTIN_ATOMIC )
95+ return __atomic_add_fetch (& a -> val , 1 , __ATOMIC_SEQ_CST );
96+ #elif defined(GIT_BUILTIN_SYNC )
7197 return __sync_add_and_fetch (& a -> val , 1 );
7298#else
7399# error "Unsupported architecture for atomic operations"
@@ -78,7 +104,9 @@ GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend)
78104{
79105#if defined(GIT_WIN32 )
80106 return InterlockedExchangeAdd (& a -> val , addend );
81- #elif defined(__GNUC__ )
107+ #elif defined(GIT_BUILTIN_ATOMIC )
108+ return __atomic_add_fetch (& a -> val , addend , __ATOMIC_SEQ_CST );
109+ #elif defined(GIT_BUILTIN_SYNC )
82110 return __sync_add_and_fetch (& a -> val , addend );
83111#else
84112# error "Unsupported architecture for atomic operations"
@@ -89,34 +117,76 @@ GIT_INLINE(int) git_atomic_dec(git_atomic *a)
89117{
90118#if defined(GIT_WIN32 )
91119 return InterlockedDecrement (& a -> val );
92- #elif defined(__GNUC__ )
120+ #elif defined(GIT_BUILTIN_ATOMIC )
121+ return __atomic_sub_fetch (& a -> val , 1 , __ATOMIC_SEQ_CST );
122+ #elif defined(GIT_BUILTIN_SYNC )
93123 return __sync_sub_and_fetch (& a -> val , 1 );
94124#else
95125# error "Unsupported architecture for atomic operations"
96126#endif
97127}
98128
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+
99142GIT_INLINE (void * ) git___compare_and_swap (
100143 void * volatile * ptr , void * oldval , void * newval )
101144{
102- volatile void * foundval ;
103145#if defined(GIT_WIN32 )
146+ volatile void * foundval ;
104147 foundval = InterlockedCompareExchangePointer ((volatile PVOID * )ptr , newval , oldval );
105- #elif defined(__GNUC__ )
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 ;
106154 foundval = __sync_val_compare_and_swap (ptr , oldval , newval );
155+ return (foundval == oldval ) ? oldval : newval ;
107156#else
108157# error "Unsupported architecture for atomic operations"
109158#endif
110- return (foundval == oldval ) ? oldval : newval ;
111159}
112160
113161GIT_INLINE (volatile void * ) git___swap (
114162 void * volatile * ptr , void * newval )
115163{
116164#if defined(GIT_WIN32 )
117165 return InterlockedExchangePointer (ptr , newval );
118- #else
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 )
119171 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"
120190#endif
121191}
122192
@@ -126,13 +196,41 @@ GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
126196{
127197#if defined(GIT_WIN32 )
128198 return InterlockedExchangeAdd64 (& a -> val , addend );
129- #elif defined(__GNUC__ )
199+ #elif defined(GIT_BUILTIN_ATOMIC )
200+ return __atomic_add_fetch (& a -> val , addend , __ATOMIC_SEQ_CST );
201+ #elif defined(GIT_BUILTIN_SYNC )
130202 return __sync_add_and_fetch (& a -> val , addend );
131203#else
132204# error "Unsupported architecture for atomic operations"
133205#endif
134206}
135207
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+
136234#endif
137235
138236#else
@@ -190,6 +288,11 @@ GIT_INLINE(int) git_atomic_dec(git_atomic *a)
190288 return -- a -> val ;
191289}
192290
291+ GIT_INLINE (int ) git_atomic_get (git_atomic * a )
292+ {
293+ return (int )a -> val ;
294+ }
295+
193296GIT_INLINE (void * ) git___compare_and_swap (
194297 void * volatile * ptr , void * oldval , void * newval )
195298{
@@ -216,15 +319,20 @@ GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
216319 return a -> val ;
217320}
218321
219- #endif
220-
221- #endif
322+ GIT_INLINE (void ) git_atomic64_set (git_atomic64 * a , int64_t val )
323+ {
324+ a -> val = val ;
325+ }
222326
223- GIT_INLINE (int ) git_atomic_get ( git_atomic * a )
327+ GIT_INLINE (int64_t ) git_atomic64_get ( git_atomic64 * a )
224328{
225- return (int )a -> val ;
329+ return (int64_t )a -> val ;
226330}
227331
332+ #endif
333+
334+ #endif
335+
228336/* Atomically replace oldval with newval
229337 * @return oldval if it was replaced or newval if it was not
230338 */
@@ -233,14 +341,24 @@ GIT_INLINE(int) git_atomic_get(git_atomic *a)
233341
234342#define git__swap (ptr , val ) (void *)git___swap((void * volatile *)&ptr, val)
235343
344+ #define git__load (ptr ) (void *)git___load((void * volatile *)&ptr)
345+
236346extern int git_online_cpus (void );
237347
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()
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+
242358#else
359+
243360# define GIT_MEMORY_BARRIER /* noop */
361+
244362#endif
245363
246364#endif
0 commit comments