-
Notifications
You must be signed in to change notification settings - Fork 2
/
atomic.h
166 lines (130 loc) · 3.68 KB
/
atomic.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/* Copyright (C) Uppsala University
*
* This file is distributed under the terms of the GNU general Public
* License (GPL), see the file LICENSE
*
* Author: Erik Nordström, <[email protected]>
*/
#ifndef _ATOMIC_H_
#define _ATOMIC_H_
#if defined(__linux__) && defined(__KERNEL__)
#include <linux/kernel.h>
#else
#if defined(__linux__) || \
defined(__OpenBSD__) || \
defined(__FreeBSD__) || \
defined(__APPLE__)
#if !defined(__BIONIC__)
#define HAVE_GCC_ATOMICS 1
#endif
#endif
#if defined(HAVE_GCC_ATOMICS)
#define ATOMIC_INIT(i) { (i) }
typedef struct {
int value;
} atomic_t;
static inline int atomic_read(const atomic_t *v)
{
return __sync_add_and_fetch(&((atomic_t *)v)->value, 0);
}
static inline int atomic_add_return(int i, atomic_t *v)
{
return __sync_add_and_fetch(&v->value, i);
}
static inline int atomic_sub_return(int i, atomic_t *v)
{
return __sync_sub_and_fetch(&v->value, i);
}
static inline int atomic_set(atomic_t *v, int i)
{
return __sync_val_compare_and_swap(&v->value, atomic_read(v), i);
}
#elif defined(__BIONIC__)
#include <sys/atomics.h>
typedef struct {
int value;
} atomic_t;
#define ATOMIC_INIT(i) { (i) }
#define atomic_read(v) *((volatile int *)&(v)->value)
static inline int atomic_add_return(int i, atomic_t *v)
{
int old;
do {
old = *(volatile int *)&v->value;
}
while (__atomic_cmpxchg(old, old+i, (volatile int*)&v->value));
return old+i;
}
static inline int atomic_sub_return(int i, atomic_t *v)
{
int old;
do {
old = *(volatile int *)&v->value;
}
while (__atomic_cmpxchg(old, old-i, (volatile int*)&v->value));
return old-i;
}
#define atomic_set(v, i) __atomic_swap(i, &(v)->value)
#else /* GENERIC */
#include <pthread.h>
#define ATOMIC_INIT(i) { (i) , PTHREAD_MUTEX_INITIALIZER }
typedef struct {
int value;
pthread_mutex_t mutex;
} atomic_t;
#warning "using generic atomic.h, consider implementing atomics for this platform"
static inline int atomic_read(const atomic_t *v)
{
int val;
pthread_mutex_lock(&((atomic_t *)v)->mutex);
val = ((atomic_t *)v)->value;
pthread_mutex_unlock(&((atomic_t *)v)->mutex);
return val;
}
static inline int atomic_add_return(int i, atomic_t *v)
{
int val;
pthread_mutex_lock(&v->mutex);
val = ++v->value;
pthread_mutex_unlock(&v->mutex);
return val;
}
static inline int atomic_sub_return(int i, atomic_t *v)
{
int val;
pthread_mutex_lock(&v->mutex);
val = --v->value;
pthread_mutex_unlock(&v->mutex);
return val;
}
/* Probably this is ok for most platforms */
#define atomic_set(v, i) (((v)->value) = (i))
#endif /* __GLIBC__ */
static inline int atomic_add_negative(int i, atomic_t *v)
{
return atomic_add_return(i, v) < 0;
}
static inline void atomic_add(int i, atomic_t *v)
{
atomic_add_return(i, v);
}
static inline void atomic_sub(int i, atomic_t *v)
{
atomic_sub_return(i, v);
}
static inline void atomic_inc(atomic_t *v)
{
atomic_add_return(1, v);
}
static inline void atomic_dec(atomic_t *v)
{
atomic_sub_return(1, v);
}
#define atomic_dec_return(v) atomic_sub_return(1, (v))
#define atomic_inc_return(v) atomic_add_return(1, (v))
#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0)
#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
#define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0)
#endif /* __linux__ && __KERNEL__ */
#endif /* _ATOMIC_H_ */