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