]>
Commit | Line | Data |
---|---|---|
bb742ede | 1 | /* |
359fc2d2 | 2 | * Copyright (C) the libgit2 contributors. All rights reserved. |
bb742ede VM |
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 | */ | |
36f0f61f AE |
7 | #ifndef INCLUDE_thread_utils_h__ |
8 | #define INCLUDE_thread_utils_h__ | |
9 | ||
aa5ea47f ET |
10 | #if defined(__GNUC__) && defined(GIT_THREADS) |
11 | # if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1)) | |
12 | # error Atomic primitives do not exist on this version of gcc; configure libgit2 with -DTHREADSAFE=OFF | |
13 | # endif | |
14 | #endif | |
15 | ||
bb3de0c4 VM |
16 | /* Common operations even if threading has been disabled */ |
17 | typedef struct { | |
7a6f51de | 18 | #if defined(GIT_WIN32) |
b932ef5b VM |
19 | volatile long val; |
20 | #else | |
bb3de0c4 | 21 | volatile int val; |
b932ef5b | 22 | #endif |
bb3de0c4 VM |
23 | } git_atomic; |
24 | ||
eb63fda2 ET |
25 | #ifdef GIT_ARCH_64 |
26 | ||
f9774eea VM |
27 | typedef struct { |
28 | #if defined(GIT_WIN32) | |
29 | __int64 val; | |
30 | #else | |
31 | int64_t val; | |
32 | #endif | |
33 | } git_atomic64; | |
34 | ||
eb63fda2 ET |
35 | typedef git_atomic64 git_atomic_ssize; |
36 | ||
37 | #define git_atomic_ssize_add git_atomic64_add | |
38 | ||
39 | #else | |
40 | ||
41 | typedef git_atomic git_atomic_ssize; | |
42 | ||
43 | #define git_atomic_ssize_add git_atomic_add | |
44 | ||
45 | #endif | |
46 | ||
bb3de0c4 VM |
47 | #ifdef GIT_THREADS |
48 | ||
1c135405 | 49 | #ifdef GIT_WIN32 |
8aaa9fb6 | 50 | # include "win32/thread.h" |
1c135405 | 51 | #else |
faebc1c6 | 52 | # include "unix/pthread.h" |
fb591767 | 53 | #endif |
bbcc7ffc | 54 | |
814de0bc RB |
55 | GIT_INLINE(void) git_atomic_set(git_atomic *a, int val) |
56 | { | |
57 | #if defined(GIT_WIN32) | |
58 | InterlockedExchange(&a->val, (LONG)val); | |
59 | #elif defined(__GNUC__) | |
60 | __sync_lock_test_and_set(&a->val, val); | |
61 | #else | |
62 | # error "Unsupported architecture for atomic operations" | |
63 | #endif | |
64 | } | |
65 | ||
72a3fe42 | 66 | GIT_INLINE(int) git_atomic_inc(git_atomic *a) |
bb3de0c4 | 67 | { |
7a6f51de | 68 | #if defined(GIT_WIN32) |
bb3de0c4 | 69 | return InterlockedIncrement(&a->val); |
7a6f51de VM |
70 | #elif defined(__GNUC__) |
71 | return __sync_add_and_fetch(&a->val, 1); | |
bb3de0c4 VM |
72 | #else |
73 | # error "Unsupported architecture for atomic operations" | |
74 | #endif | |
75 | } | |
76 | ||
f9774eea VM |
77 | GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend) |
78 | { | |
79 | #if defined(GIT_WIN32) | |
eb63fda2 | 80 | return InterlockedExchangeAdd(&a->val, addend); |
f9774eea VM |
81 | #elif defined(__GNUC__) |
82 | return __sync_add_and_fetch(&a->val, addend); | |
83 | #else | |
84 | # error "Unsupported architecture for atomic operations" | |
85 | #endif | |
86 | } | |
87 | ||
72a3fe42 | 88 | GIT_INLINE(int) git_atomic_dec(git_atomic *a) |
bb3de0c4 | 89 | { |
7a6f51de | 90 | #if defined(GIT_WIN32) |
bb3de0c4 | 91 | return InterlockedDecrement(&a->val); |
7a6f51de VM |
92 | #elif defined(__GNUC__) |
93 | return __sync_sub_and_fetch(&a->val, 1); | |
bb3de0c4 VM |
94 | #else |
95 | # error "Unsupported architecture for atomic operations" | |
96 | #endif | |
97 | } | |
98 | ||
e976b56d | 99 | GIT_INLINE(void *) git___compare_and_swap( |
814de0bc | 100 | void * volatile *ptr, void *oldval, void *newval) |
e976b56d | 101 | { |
38eef611 | 102 | volatile void *foundval; |
e976b56d | 103 | #if defined(GIT_WIN32) |
c4ac556e | 104 | foundval = InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval); |
e976b56d | 105 | #elif defined(__GNUC__) |
c6289186 | 106 | foundval = __sync_val_compare_and_swap(ptr, oldval, newval); |
e976b56d RB |
107 | #else |
108 | # error "Unsupported architecture for atomic operations" | |
109 | #endif | |
c6289186 | 110 | return (foundval == oldval) ? oldval : newval; |
e976b56d RB |
111 | } |
112 | ||
814de0bc RB |
113 | GIT_INLINE(volatile void *) git___swap( |
114 | void * volatile *ptr, void *newval) | |
115 | { | |
116 | #if defined(GIT_WIN32) | |
117 | return InterlockedExchangePointer(ptr, newval); | |
118 | #else | |
119 | return __sync_lock_test_and_set(ptr, newval); | |
120 | #endif | |
121 | } | |
122 | ||
eb63fda2 ET |
123 | #ifdef GIT_ARCH_64 |
124 | ||
125 | GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) | |
f9774eea VM |
126 | { |
127 | #if defined(GIT_WIN32) | |
eb63fda2 | 128 | return InterlockedExchangeAdd64(&a->val, addend); |
f9774eea VM |
129 | #elif defined(__GNUC__) |
130 | return __sync_add_and_fetch(&a->val, addend); | |
131 | #else | |
132 | # error "Unsupported architecture for atomic operations" | |
133 | #endif | |
134 | } | |
135 | ||
eb63fda2 ET |
136 | #endif |
137 | ||
bb3de0c4 VM |
138 | #else |
139 | ||
140 | #define git_thread unsigned int | |
faebc1c6 | 141 | #define git_thread_create(thread, start_routine, arg) 0 |
bb3de0c4 VM |
142 | #define git_thread_join(id, status) (void)0 |
143 | ||
144 | /* Pthreads Mutex */ | |
145 | #define git_mutex unsigned int | |
369b0217 ET |
146 | GIT_INLINE(int) git_mutex_init(git_mutex *mutex) \ |
147 | { GIT_UNUSED(mutex); return 0; } | |
148 | GIT_INLINE(int) git_mutex_lock(git_mutex *mutex) \ | |
149 | { GIT_UNUSED(mutex); return 0; } | |
bb3de0c4 VM |
150 | #define git_mutex_unlock(a) (void)0 |
151 | #define git_mutex_free(a) (void)0 | |
152 | ||
bbcc7ffc | 153 | /* Pthreads condition vars */ |
bb3de0c4 VM |
154 | #define git_cond unsigned int |
155 | #define git_cond_init(c, a) (void)0 | |
156 | #define git_cond_free(c) (void)0 | |
157 | #define git_cond_wait(c, l) (void)0 | |
158 | #define git_cond_signal(c) (void)0 | |
159 | #define git_cond_broadcast(c) (void)0 | |
160 | ||
8d9a85d4 RB |
161 | /* Pthreads rwlock */ |
162 | #define git_rwlock unsigned int | |
163 | #define git_rwlock_init(a) 0 | |
164 | #define git_rwlock_rdlock(a) 0 | |
165 | #define git_rwlock_rdunlock(a) (void)0 | |
166 | #define git_rwlock_wrlock(a) 0 | |
167 | #define git_rwlock_wrunlock(a) (void)0 | |
168 | #define git_rwlock_free(a) (void)0 | |
169 | #define GIT_RWLOCK_STATIC_INIT 0 | |
170 | ||
171 | ||
814de0bc RB |
172 | GIT_INLINE(void) git_atomic_set(git_atomic *a, int val) |
173 | { | |
174 | a->val = val; | |
175 | } | |
176 | ||
72a3fe42 | 177 | GIT_INLINE(int) git_atomic_inc(git_atomic *a) |
bb3de0c4 VM |
178 | { |
179 | return ++a->val; | |
180 | } | |
181 | ||
f9774eea VM |
182 | GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend) |
183 | { | |
184 | a->val += addend; | |
185 | return a->val; | |
186 | } | |
187 | ||
72a3fe42 | 188 | GIT_INLINE(int) git_atomic_dec(git_atomic *a) |
bb3de0c4 VM |
189 | { |
190 | return --a->val; | |
191 | } | |
192 | ||
e976b56d | 193 | GIT_INLINE(void *) git___compare_and_swap( |
814de0bc | 194 | void * volatile *ptr, void *oldval, void *newval) |
e976b56d RB |
195 | { |
196 | if (*ptr == oldval) | |
197 | *ptr = newval; | |
198 | else | |
199 | oldval = newval; | |
200 | return oldval; | |
201 | } | |
202 | ||
814de0bc RB |
203 | GIT_INLINE(volatile void *) git___swap( |
204 | void * volatile *ptr, void *newval) | |
205 | { | |
206 | volatile void *old = *ptr; | |
207 | *ptr = newval; | |
208 | return old; | |
209 | } | |
210 | ||
eb63fda2 ET |
211 | #ifdef GIT_ARCH_64 |
212 | ||
213 | GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) | |
f9774eea VM |
214 | { |
215 | a->val += addend; | |
216 | return a->val; | |
217 | } | |
218 | ||
bb3de0c4 | 219 | #endif |
36f0f61f | 220 | |
eb63fda2 ET |
221 | #endif |
222 | ||
814de0bc RB |
223 | GIT_INLINE(int) git_atomic_get(git_atomic *a) |
224 | { | |
225 | return (int)a->val; | |
226 | } | |
227 | ||
e976b56d RB |
228 | /* Atomically replace oldval with newval |
229 | * @return oldval if it was replaced or newval if it was not | |
230 | */ | |
231 | #define git__compare_and_swap(P,O,N) \ | |
814de0bc | 232 | git___compare_and_swap((void * volatile *)P, O, N) |
e976b56d | 233 | |
814de0bc | 234 | #define git__swap(ptr, val) (void *)git___swap((void * volatile *)&ptr, val) |
e976b56d | 235 | |
e035685f | 236 | extern int git_online_cpus(void); |
36f0f61f | 237 | |
6e0fc1a6 | 238 | #if defined(GIT_THREADS) && defined(_MSC_VER) |
e976b56d RB |
239 | # define GIT_MEMORY_BARRIER MemoryBarrier() |
240 | #elif defined(GIT_THREADS) | |
241 | # define GIT_MEMORY_BARRIER __sync_synchronize() | |
242 | #else | |
243 | # define GIT_MEMORY_BARRIER /* noop */ | |
244 | #endif | |
245 | ||
eae0bfdc | 246 | #endif |