]> git.proxmox.com Git - libgit2.git/blame - src/thread-utils.h
Merge remote-tracking branch 'upstream/cmn/filebuf-atomic-unlock'
[libgit2.git] / src / thread-utils.h
CommitLineData
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 */
11typedef 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
21typedef struct {
22#if defined(GIT_WIN32)
23 __int64 val;
24#else
25 int64_t val;
26#endif
27} git_atomic64;
28
eb63fda2
ET
29typedef git_atomic64 git_atomic_ssize;
30
31#define git_atomic_ssize_add git_atomic64_add
32
33#else
34
35typedef 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
45typedef 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
101GIT_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 112GIT_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
123GIT_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 134GIT_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 145GIT_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
159GIT_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
171GIT_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
217GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
218{
219 a->val = val;
220}
221
72a3fe42 222GIT_INLINE(int) git_atomic_inc(git_atomic *a)
bb3de0c4
VM
223{
224 return ++a->val;
225}
226
f9774eea
VM
227GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend)
228{
229 a->val += addend;
230 return a->val;
231}
232
72a3fe42 233GIT_INLINE(int) git_atomic_dec(git_atomic *a)
bb3de0c4
VM
234{
235 return --a->val;
236}
237
e976b56d 238GIT_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
248GIT_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
258GIT_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
268GIT_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 281extern 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__ */