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