]>
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 | ||
bb3de0c4 VM |
10 | /* Common operations even if threading has been disabled */ |
11 | typedef struct { | |
7a6f51de | 12 | #if defined(GIT_WIN32) |
b932ef5b VM |
13 | volatile long val; |
14 | #else | |
bb3de0c4 | 15 | volatile int val; |
b932ef5b | 16 | #endif |
bb3de0c4 VM |
17 | } git_atomic; |
18 | ||
eb63fda2 ET |
19 | #ifdef GIT_ARCH_64 |
20 | ||
f9774eea VM |
21 | typedef struct { |
22 | #if defined(GIT_WIN32) | |
23 | __int64 val; | |
24 | #else | |
25 | int64_t val; | |
26 | #endif | |
27 | } git_atomic64; | |
28 | ||
eb63fda2 ET |
29 | typedef git_atomic64 git_atomic_ssize; |
30 | ||
31 | #define git_atomic_ssize_add git_atomic64_add | |
32 | ||
33 | #else | |
34 | ||
35 | typedef git_atomic git_atomic_ssize; | |
36 | ||
37 | #define git_atomic_ssize_add git_atomic_add | |
38 | ||
39 | #endif | |
40 | ||
bb3de0c4 VM |
41 | #ifdef GIT_THREADS |
42 | ||
1b4e29b7 | 43 | #if !defined(GIT_WIN32) |
fb591767 | 44 | |
1b4e29b7 PK |
45 | typedef struct { |
46 | pthread_t thread; | |
47 | } git_thread; | |
fb591767 | 48 | |
1b4e29b7 PK |
49 | #define git_thread_create(git_thread_ptr, attr, start_routine, arg) \ |
50 | pthread_create(&(git_thread_ptr)->thread, attr, start_routine, arg) | |
51 | #define git_thread_join(git_thread_ptr, status) \ | |
52 | pthread_join((git_thread_ptr)->thread, status) | |
fb591767 PK |
53 | |
54 | #endif | |
bbcc7ffc VM |
55 | |
56 | /* Pthreads Mutex */ | |
57 | #define git_mutex pthread_mutex_t | |
87d9869f VM |
58 | #define git_mutex_init(a) pthread_mutex_init(a, NULL) |
59 | #define git_mutex_lock(a) pthread_mutex_lock(a) | |
bbcc7ffc | 60 | #define git_mutex_unlock(a) pthread_mutex_unlock(a) |
87d9869f | 61 | #define git_mutex_free(a) pthread_mutex_destroy(a) |
bbcc7ffc | 62 | |
fa16a6ec MS |
63 | /* Pthreads condition vars */ |
64 | #define git_cond pthread_cond_t | |
65 | #define git_cond_init(c) pthread_cond_init(c, NULL) | |
66 | #define git_cond_free(c) pthread_cond_destroy(c) | |
67 | #define git_cond_wait(c, l) pthread_cond_wait(c, l) | |
68 | #define git_cond_signal(c) pthread_cond_signal(c) | |
69 | #define git_cond_broadcast(c) pthread_cond_broadcast(c) | |
bb3de0c4 | 70 | |
eb868b1e RB |
71 | /* Pthread (-ish) rwlock |
72 | * | |
73 | * This differs from normal pthreads rwlocks in two ways: | |
74 | * 1. Separate APIs for releasing read locks and write locks (as | |
75 | * opposed to the pure POSIX API which only has one unlock fn) | |
76 | * 2. You should not use recursive read locks (i.e. grabbing a read | |
77 | * lock in a thread that already holds a read lock) because the | |
78 | * Windows implementation doesn't support it | |
79 | */ | |
8d9a85d4 RB |
80 | #define git_rwlock pthread_rwlock_t |
81 | #define git_rwlock_init(a) pthread_rwlock_init(a, NULL) | |
82 | #define git_rwlock_rdlock(a) pthread_rwlock_rdlock(a) | |
972bb689 | 83 | #define git_rwlock_rdunlock(a) pthread_rwlock_rdunlock(a) |
8d9a85d4 | 84 | #define git_rwlock_wrlock(a) pthread_rwlock_wrlock(a) |
972bb689 | 85 | #define git_rwlock_wrunlock(a) pthread_rwlock_wrunlock(a) |
8d9a85d4 RB |
86 | #define git_rwlock_free(a) pthread_rwlock_destroy(a) |
87 | #define GIT_RWLOCK_STATIC_INIT PTHREAD_RWLOCK_INITIALIZER | |
88 | ||
972bb689 RB |
89 | #ifndef GIT_WIN32 |
90 | #define pthread_rwlock_rdunlock pthread_rwlock_unlock | |
91 | #define pthread_rwlock_wrunlock pthread_rwlock_unlock | |
92 | #endif | |
93 | ||
8d9a85d4 | 94 | |
814de0bc RB |
95 | GIT_INLINE(void) git_atomic_set(git_atomic *a, int val) |
96 | { | |
97 | #if defined(GIT_WIN32) | |
98 | InterlockedExchange(&a->val, (LONG)val); | |
99 | #elif defined(__GNUC__) | |
100 | __sync_lock_test_and_set(&a->val, val); | |
101 | #else | |
102 | # error "Unsupported architecture for atomic operations" | |
103 | #endif | |
104 | } | |
105 | ||
72a3fe42 | 106 | GIT_INLINE(int) git_atomic_inc(git_atomic *a) |
bb3de0c4 | 107 | { |
7a6f51de | 108 | #if defined(GIT_WIN32) |
bb3de0c4 | 109 | return InterlockedIncrement(&a->val); |
7a6f51de VM |
110 | #elif defined(__GNUC__) |
111 | return __sync_add_and_fetch(&a->val, 1); | |
bb3de0c4 VM |
112 | #else |
113 | # error "Unsupported architecture for atomic operations" | |
114 | #endif | |
115 | } | |
116 | ||
f9774eea VM |
117 | GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend) |
118 | { | |
119 | #if defined(GIT_WIN32) | |
eb63fda2 | 120 | return InterlockedExchangeAdd(&a->val, addend); |
f9774eea VM |
121 | #elif defined(__GNUC__) |
122 | return __sync_add_and_fetch(&a->val, addend); | |
123 | #else | |
124 | # error "Unsupported architecture for atomic operations" | |
125 | #endif | |
126 | } | |
127 | ||
72a3fe42 | 128 | GIT_INLINE(int) git_atomic_dec(git_atomic *a) |
bb3de0c4 | 129 | { |
7a6f51de | 130 | #if defined(GIT_WIN32) |
bb3de0c4 | 131 | return InterlockedDecrement(&a->val); |
7a6f51de VM |
132 | #elif defined(__GNUC__) |
133 | return __sync_sub_and_fetch(&a->val, 1); | |
bb3de0c4 VM |
134 | #else |
135 | # error "Unsupported architecture for atomic operations" | |
136 | #endif | |
137 | } | |
138 | ||
e976b56d | 139 | GIT_INLINE(void *) git___compare_and_swap( |
814de0bc | 140 | void * volatile *ptr, void *oldval, void *newval) |
e976b56d | 141 | { |
38eef611 | 142 | volatile void *foundval; |
e976b56d | 143 | #if defined(GIT_WIN32) |
c4ac556e | 144 | foundval = InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval); |
e976b56d | 145 | #elif defined(__GNUC__) |
c6289186 | 146 | foundval = __sync_val_compare_and_swap(ptr, oldval, newval); |
e976b56d RB |
147 | #else |
148 | # error "Unsupported architecture for atomic operations" | |
149 | #endif | |
c6289186 | 150 | return (foundval == oldval) ? oldval : newval; |
e976b56d RB |
151 | } |
152 | ||
814de0bc RB |
153 | GIT_INLINE(volatile void *) git___swap( |
154 | void * volatile *ptr, void *newval) | |
155 | { | |
156 | #if defined(GIT_WIN32) | |
157 | return InterlockedExchangePointer(ptr, newval); | |
158 | #else | |
159 | return __sync_lock_test_and_set(ptr, newval); | |
160 | #endif | |
161 | } | |
162 | ||
eb63fda2 ET |
163 | #ifdef GIT_ARCH_64 |
164 | ||
165 | GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) | |
f9774eea VM |
166 | { |
167 | #if defined(GIT_WIN32) | |
eb63fda2 | 168 | return InterlockedExchangeAdd64(&a->val, addend); |
f9774eea VM |
169 | #elif defined(__GNUC__) |
170 | return __sync_add_and_fetch(&a->val, addend); | |
171 | #else | |
172 | # error "Unsupported architecture for atomic operations" | |
173 | #endif | |
174 | } | |
175 | ||
eb63fda2 ET |
176 | #endif |
177 | ||
bb3de0c4 VM |
178 | #else |
179 | ||
180 | #define git_thread unsigned int | |
8d9a85d4 | 181 | #define git_thread_create(thread, attr, start_routine, arg) 0 |
bb3de0c4 VM |
182 | #define git_thread_join(id, status) (void)0 |
183 | ||
184 | /* Pthreads Mutex */ | |
185 | #define git_mutex unsigned int | |
ccd8ba9b SC |
186 | static int git_mutex_init(git_mutex* mutex) { GIT_UNUSED(mutex); return 0; } |
187 | static int git_mutex_lock(git_mutex* mutex) { GIT_UNUSED(mutex); return 0; } | |
bb3de0c4 VM |
188 | #define git_mutex_unlock(a) (void)0 |
189 | #define git_mutex_free(a) (void)0 | |
190 | ||
bbcc7ffc | 191 | /* Pthreads condition vars */ |
bb3de0c4 VM |
192 | #define git_cond unsigned int |
193 | #define git_cond_init(c, a) (void)0 | |
194 | #define git_cond_free(c) (void)0 | |
195 | #define git_cond_wait(c, l) (void)0 | |
196 | #define git_cond_signal(c) (void)0 | |
197 | #define git_cond_broadcast(c) (void)0 | |
198 | ||
8d9a85d4 RB |
199 | /* Pthreads rwlock */ |
200 | #define git_rwlock unsigned int | |
201 | #define git_rwlock_init(a) 0 | |
202 | #define git_rwlock_rdlock(a) 0 | |
203 | #define git_rwlock_rdunlock(a) (void)0 | |
204 | #define git_rwlock_wrlock(a) 0 | |
205 | #define git_rwlock_wrunlock(a) (void)0 | |
206 | #define git_rwlock_free(a) (void)0 | |
207 | #define GIT_RWLOCK_STATIC_INIT 0 | |
208 | ||
209 | ||
814de0bc RB |
210 | GIT_INLINE(void) git_atomic_set(git_atomic *a, int val) |
211 | { | |
212 | a->val = val; | |
213 | } | |
214 | ||
72a3fe42 | 215 | GIT_INLINE(int) git_atomic_inc(git_atomic *a) |
bb3de0c4 VM |
216 | { |
217 | return ++a->val; | |
218 | } | |
219 | ||
f9774eea VM |
220 | GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend) |
221 | { | |
222 | a->val += addend; | |
223 | return a->val; | |
224 | } | |
225 | ||
72a3fe42 | 226 | GIT_INLINE(int) git_atomic_dec(git_atomic *a) |
bb3de0c4 VM |
227 | { |
228 | return --a->val; | |
229 | } | |
230 | ||
e976b56d | 231 | GIT_INLINE(void *) git___compare_and_swap( |
814de0bc | 232 | void * volatile *ptr, void *oldval, void *newval) |
e976b56d RB |
233 | { |
234 | if (*ptr == oldval) | |
235 | *ptr = newval; | |
236 | else | |
237 | oldval = newval; | |
238 | return oldval; | |
239 | } | |
240 | ||
814de0bc RB |
241 | GIT_INLINE(volatile void *) git___swap( |
242 | void * volatile *ptr, void *newval) | |
243 | { | |
244 | volatile void *old = *ptr; | |
245 | *ptr = newval; | |
246 | return old; | |
247 | } | |
248 | ||
eb63fda2 ET |
249 | #ifdef GIT_ARCH_64 |
250 | ||
251 | GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) | |
f9774eea VM |
252 | { |
253 | a->val += addend; | |
254 | return a->val; | |
255 | } | |
256 | ||
bb3de0c4 | 257 | #endif |
36f0f61f | 258 | |
eb63fda2 ET |
259 | #endif |
260 | ||
814de0bc RB |
261 | GIT_INLINE(int) git_atomic_get(git_atomic *a) |
262 | { | |
263 | return (int)a->val; | |
264 | } | |
265 | ||
e976b56d RB |
266 | /* Atomically replace oldval with newval |
267 | * @return oldval if it was replaced or newval if it was not | |
268 | */ | |
269 | #define git__compare_and_swap(P,O,N) \ | |
814de0bc | 270 | git___compare_and_swap((void * volatile *)P, O, N) |
e976b56d | 271 | |
814de0bc | 272 | #define git__swap(ptr, val) (void *)git___swap((void * volatile *)&ptr, val) |
e976b56d | 273 | |
e035685f | 274 | extern int git_online_cpus(void); |
36f0f61f | 275 | |
e976b56d RB |
276 | #if defined(GIT_THREADS) && defined(GIT_WIN32) |
277 | # define GIT_MEMORY_BARRIER MemoryBarrier() | |
278 | #elif defined(GIT_THREADS) | |
279 | # define GIT_MEMORY_BARRIER __sync_synchronize() | |
280 | #else | |
281 | # define GIT_MEMORY_BARRIER /* noop */ | |
282 | #endif | |
283 | ||
36f0f61f | 284 | #endif /* INCLUDE_thread_utils_h__ */ |