thread-utils.h 5.61 KB
Newer Older
Vicent Marti committed
1
/*
Edward Thomson committed
2
 * Copyright (C) the libgit2 contributors. All rights reserved.
Vicent Marti committed
3 4 5 6
 *
 * This file is part of libgit2, distributed under the GNU GPL v2 with
 * a Linking Exception. For full terms see the included COPYING file.
 */
7 8 9
#ifndef INCLUDE_thread_utils_h__
#define INCLUDE_thread_utils_h__

Vicent Marti committed
10 11
/* Common operations even if threading has been disabled */
typedef struct {
12
#if defined(GIT_WIN32)
13 14
	volatile long val;
#else
Vicent Marti committed
15
	volatile int val;
16
#endif
Vicent Marti committed
17 18
} git_atomic;

19 20
#ifdef GIT_ARCH_64

21 22 23 24 25 26 27 28
typedef struct {
#if defined(GIT_WIN32)
	__int64 val;
#else
	int64_t val;
#endif
} git_atomic64;

29 30 31 32 33 34 35 36 37 38 39 40
typedef git_atomic64 git_atomic_ssize;

#define git_atomic_ssize_add git_atomic64_add

#else

typedef git_atomic git_atomic_ssize;

#define git_atomic_ssize_add git_atomic_add

#endif

Vicent Marti committed
41 42
#ifdef GIT_THREADS

43 44 45 46 47 48 49 50
#define git_thread pthread_t
#define git_thread_create(thread, attr, start_routine, arg) pthread_create(thread, attr, start_routine, arg)
#define git_thread_kill(thread) pthread_cancel(thread)
#define git_thread_exit(status)	pthread_exit(status)
#define git_thread_join(id, status) pthread_join(id, status)

/* Pthreads Mutex */
#define git_mutex pthread_mutex_t
Vicent Marti committed
51 52
#define git_mutex_init(a)	pthread_mutex_init(a, NULL)
#define git_mutex_lock(a)	pthread_mutex_lock(a)
53
#define git_mutex_unlock(a) pthread_mutex_unlock(a)
Vicent Marti committed
54
#define git_mutex_free(a)	pthread_mutex_destroy(a)
55

56 57 58 59 60 61 62
/* Pthreads condition vars */
#define git_cond pthread_cond_t
#define git_cond_init(c)	pthread_cond_init(c, NULL)
#define git_cond_free(c) 	pthread_cond_destroy(c)
#define git_cond_wait(c, l)	pthread_cond_wait(c, l)
#define git_cond_signal(c)	pthread_cond_signal(c)
#define git_cond_broadcast(c)	pthread_cond_broadcast(c)
Vicent Marti committed
63

64 65 66 67 68 69 70 71 72 73 74
GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
{
#if defined(GIT_WIN32)
	InterlockedExchange(&a->val, (LONG)val);
#elif defined(__GNUC__)
	__sync_lock_test_and_set(&a->val, val);
#else
#	error "Unsupported architecture for atomic operations"
#endif
}

Vicent Marti committed
75
GIT_INLINE(int) git_atomic_inc(git_atomic *a)
Vicent Marti committed
76
{
77
#if defined(GIT_WIN32)
Vicent Marti committed
78
	return InterlockedIncrement(&a->val);
79 80
#elif defined(__GNUC__)
	return __sync_add_and_fetch(&a->val, 1);
Vicent Marti committed
81 82 83 84 85
#else
#	error "Unsupported architecture for atomic operations"
#endif
}

86 87 88
GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend)
{
#if defined(GIT_WIN32)
89
	return InterlockedExchangeAdd(&a->val, addend);
90 91 92 93 94 95 96
#elif defined(__GNUC__)
	return __sync_add_and_fetch(&a->val, addend);
#else
#	error "Unsupported architecture for atomic operations"
#endif
}

Vicent Marti committed
97
GIT_INLINE(int) git_atomic_dec(git_atomic *a)
Vicent Marti committed
98
{
99
#if defined(GIT_WIN32)
Vicent Marti committed
100
	return InterlockedDecrement(&a->val);
101 102
#elif defined(__GNUC__)
	return __sync_sub_and_fetch(&a->val, 1);
Vicent Marti committed
103 104 105 106 107
#else
#	error "Unsupported architecture for atomic operations"
#endif
}

108
GIT_INLINE(void *) git___compare_and_swap(
109
	void * volatile *ptr, void *oldval, void *newval)
110
{
111
	volatile void *foundval;
112
#if defined(GIT_WIN32)
nulltoken committed
113
	foundval = InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
114
#elif defined(__GNUC__)
115
	foundval = __sync_val_compare_and_swap(ptr, oldval, newval);
116 117 118
#else
#	error "Unsupported architecture for atomic operations"
#endif
119
	return (foundval == oldval) ? oldval : newval;
120 121
}

122 123 124 125 126 127 128 129 130 131
GIT_INLINE(volatile void *) git___swap(
	void * volatile *ptr, void *newval)
{
#if defined(GIT_WIN32)
	return InterlockedExchangePointer(ptr, newval);
#else
	return __sync_lock_test_and_set(ptr, newval);
#endif
}

132 133 134
#ifdef GIT_ARCH_64

GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
135 136
{
#if defined(GIT_WIN32)
137
	return InterlockedExchangeAdd64(&a->val, addend);
138 139 140 141 142 143 144
#elif defined(__GNUC__)
	return __sync_add_and_fetch(&a->val, addend);
#else
#	error "Unsupported architecture for atomic operations"
#endif
}

145 146
#endif

Vicent Marti committed
147 148 149 150 151 152 153 154 155 156
#else

#define git_thread unsigned int
#define git_thread_create(thread, attr, start_routine, arg) (void)0
#define git_thread_kill(thread) (void)0
#define git_thread_exit(status) (void)0
#define git_thread_join(id, status) (void)0

/* Pthreads Mutex */
#define git_mutex unsigned int
Russell Belfer committed
157
#define git_mutex_init(a) 0
158
#define git_mutex_lock(a) 0
Vicent Marti committed
159 160 161
#define git_mutex_unlock(a) (void)0
#define git_mutex_free(a) (void)0

162
/* Pthreads condition vars */
Vicent Marti committed
163 164 165 166 167 168 169
#define git_cond unsigned int
#define git_cond_init(c, a)	(void)0
#define git_cond_free(c) (void)0
#define git_cond_wait(c, l)	(void)0
#define git_cond_signal(c) (void)0
#define git_cond_broadcast(c) (void)0

170 171 172 173 174
GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
{
	a->val = val;
}

Vicent Marti committed
175
GIT_INLINE(int) git_atomic_inc(git_atomic *a)
Vicent Marti committed
176 177 178 179
{
	return ++a->val;
}

180 181 182 183 184 185
GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend)
{
	a->val += addend;
	return a->val;
}

Vicent Marti committed
186
GIT_INLINE(int) git_atomic_dec(git_atomic *a)
Vicent Marti committed
187 188 189 190
{
	return --a->val;
}

191
GIT_INLINE(void *) git___compare_and_swap(
192
	void * volatile *ptr, void *oldval, void *newval)
193 194 195 196 197 198 199 200
{
	if (*ptr == oldval)
		*ptr = newval;
	else
		oldval = newval;
	return oldval;
}

201 202 203 204 205 206 207 208
GIT_INLINE(volatile void *) git___swap(
	void * volatile *ptr, void *newval)
{
	volatile void *old = *ptr;
	*ptr = newval;
	return old;
}

209 210 211
#ifdef GIT_ARCH_64

GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
212 213 214 215 216
{
	a->val += addend;
	return a->val;
}

Vicent Marti committed
217
#endif
218

219 220
#endif

221 222 223 224 225
GIT_INLINE(int) git_atomic_get(git_atomic *a)
{
	return (int)a->val;
}

226 227 228 229
/* Atomically replace oldval with newval
 * @return oldval if it was replaced or newval if it was not
 */
#define git__compare_and_swap(P,O,N) \
230
	git___compare_and_swap((void * volatile *)P, O, N)
231

232
#define git__swap(ptr, val) (void *)git___swap((void * volatile *)&ptr, val)
233

234
extern int git_online_cpus(void);
235

236 237 238 239 240 241 242 243
#if defined(GIT_THREADS) && defined(GIT_WIN32)
# define GIT_MEMORY_BARRIER MemoryBarrier()
#elif defined(GIT_THREADS)
# define GIT_MEMORY_BARRIER __sync_synchronize()
#else
# define GIT_MEMORY_BARRIER /* noop */
#endif

244
#endif /* INCLUDE_thread_utils_h__ */