e59aad632bf950dbdb013c400d8be5547054a147
[openafs.git] / src / rx / rx_atomic.h
1 /*
2  * Copyright (c) 2010 Your Filesystem Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #define RX_ATOMIC_INIT(i) { (i) }
26
27 #ifdef AFS_NT40_ENV
28 typedef struct {
29     volatile int var;
30 } rx_atomic_t;
31
32 static_inline void
33 rx_atomic_set(rx_atomic_t *atomic, int val) {
34     atomic->var = val;
35 }
36
37 static_inline int
38 rx_atomic_read(rx_atomic_t *atomic) {
39     return atomic->var;
40 }
41
42 static_inline void
43 rx_atomic_inc(rx_atomic_t *atomic) {
44     InterlockedIncrement(&atomic->var);
45 }
46
47 static_inline int
48 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
49     return InterlockedIncrement(&atomic->var);
50 }
51
52 static_inline void
53 rx_atomic_add(rx_atomic_t *atomic, int change) {
54     InterlockedExchangeAdd(&atomic->var, change);
55 }
56
57 static_inline void
58 rx_atomic_dec(rx_atomic_t *atomic) {
59     InterlockedDecrement(&atomic->var);
60 }
61
62 static_inline void
63 rx_atomic_sub(rx_atomic_t *atomic, int change) {
64     InterlockedExchangeAdd(&atomic->var, 0 - change);
65 }
66
67 #elif defined(AFS_DARWIN80_ENV) || defined(AFS_USR_DARWIN80_ENV)
68
69 #include <libkern/OSAtomic.h>
70 #if defined(KERNEL) && !defined(UKERNEL)
71 #define OSAtomicIncrement32 OSIncrementAtomic
72 #define OSAtomicAdd32 OSAddAtomic
73 #define OSAtomicDecrement32 OSDecrementAtomic
74 #endif
75
76 typedef struct {
77     volatile int var;
78 } rx_atomic_t;
79
80 static_inline void
81 rx_atomic_set(rx_atomic_t *atomic, int val) {
82     atomic->var = val;
83 }
84
85 static_inline int
86 rx_atomic_read(rx_atomic_t *atomic) {
87     return atomic->var;
88 }
89
90 static_inline void
91 rx_atomic_inc(rx_atomic_t *atomic) {
92     OSAtomicIncrement32(&atomic->var);
93 }
94
95 static_inline int
96 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
97     return OSAtomicIncrement32(&atomic->var);
98 }
99
100 static_inline void
101 rx_atomic_add(rx_atomic_t *atomic, int change) {
102     OSAtomicAdd32(change, &atomic->var);
103 }
104
105 static_inline void
106 rx_atomic_dec(rx_atomic_t *atomic) {
107     OSAtomicDecrement32(&atomic->var);
108 }
109
110 static_inline void
111 rx_atomic_sub(rx_atomic_t *atomic, int change) {
112     OSAtomicAdd32(0 - change, &atomic->var);
113 }
114 #elif defined(AFS_LINUX20_ENV) && defined(KERNEL)
115 #include <asm/atomic.h>
116
117 typedef atomic_t rx_atomic_t;
118
119 #define rx_atomic_set(X)          atomic_set(X)
120 #define rx_atomic_read(X)         atomic_read(X)
121 #define rx_atomic_inc(X)          atomic_inc(X)
122 #define rx_atomic_inc_and_read(X) atomic_inc_return(X)
123 #define rx_atomic_add(X, V)       atomic_add(V, X)
124 #define rx_atomic_dec(X)          atomic_dec(X)
125 #define rx_atomic_sub(X, V)       atomic_sub(V, X)
126
127 #elif defined(AFS_SUN58_ENV)
128
129 # include <atomic.h>
130
131 typedef struct {
132     volatile unsigned int var;
133 } rx_atomic_t;
134
135 static_inline void
136 rx_atomic_set(rx_atomic_t *atomic, int val) {
137     atomic->var = val;
138 }
139
140 static_inline int
141 rx_atomic_read(rx_atomic_t *atomic) {
142     return atomic->var;
143 }
144
145 static_inline void
146 rx_atomic_inc(rx_atomic_t *atomic) {
147     atomic_inc_32(&atomic->var);
148 }
149
150 static_inline int
151 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
152     return atomic_inc_32_nv(&atomic->var);
153 }
154
155 static_inline void
156 rx_atomic_add(rx_atomic_t *atomic, int change) {
157     atomic_add_32(&atomic->var, change);
158 }
159
160 static_inline void
161 rx_atomic_dec(rx_atomic_t *atomic) {
162     atomic_dec_32(&atomic->var);
163 }
164
165 static_inline void
166 rx_atomic_sub(rx_atomic_t *atomic, int change) {
167     atomic_add_32(&atomic->var, 0 - change);
168 }
169
170 #elif defined(__GNUC__) && defined(HAVE_SYNC_FETCH_AND_ADD)
171
172 typedef struct {
173    volatile int var;
174 } rx_atomic_t;
175
176 static_inline void
177 rx_atomic_set(rx_atomic_t *atomic, int val) {
178     atomic->var = val;
179 }
180
181 static_inline int
182 rx_atomic_read(rx_atomic_t *atomic) {
183     return atomic->var;
184 }
185
186 static_inline void
187 rx_atomic_inc(rx_atomic_t *atomic) {
188     (void)__sync_fetch_and_add(&atomic->var, 1);
189 }
190
191 static_inline int
192 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
193     return __sync_add_and_fetch(&atomic->var, 1);
194 }
195
196 static_inline void
197 rx_atomic_add(rx_atomic_t *atomic, int change) {
198     (void)__sync_fetch_and_add(&atomic->var, change);
199 }
200
201 static_inline void
202 rx_atomic_dec(rx_atomic_t *atomic) {
203     (void)__sync_fetch_and_sub(&atomic->var, 1);
204 }
205
206 static_inline void
207 rx_atomic_sub(rx_atomic_t *atomic, int change) {
208     (void)__sync_fetch_and_sub(&atomic->var, change);
209 }
210
211 #else
212
213 /* If we're on a platform where we have no idea how to do atomics,
214  * then we fall back to using a single process wide mutex to protect
215  * all atomic variables. This won't be the quickest thing ever.
216  */
217
218 #ifdef RX_ENABLE_LOCKS
219 extern afs_kmutex_t rx_atomic_mutex;
220 #endif
221
222 typedef struct {
223     int var;
224 } rx_atomic_t;
225
226 static_inline void
227 rx_atomic_set(rx_atomic_t *atomic, int val) {
228     MUTEX_ENTER(&rx_atomic_mutex);
229     atomic->var = val;
230     MUTEX_EXIT(&rx_atomic_mutex);
231 }
232
233 static_inline int
234 rx_atomic_read(rx_atomic_t *atomic) {
235     int out;
236
237     MUTEX_ENTER(&rx_atomic_mutex);
238     out = atomic->var;
239     MUTEX_EXIT(&rx_atomic_mutex);
240
241     return out;
242 }
243
244 static_inline void
245 rx_atomic_inc(rx_atomic_t *atomic) {
246    MUTEX_ENTER(&rx_atomic_mutex);
247    atomic->var++;
248    MUTEX_EXIT(&rx_atomic_mutex);
249 }
250
251 static_inline int
252 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
253     int retval;
254     MUTEX_ENTER(&rx_atomic_mutex);
255     atomic->var++;
256     retval = atomic->var;
257     MUTEX_EXIT(&rx_atomic_mutex);
258     return retval;
259 }
260
261 static_inline void
262 rx_atomic_add(rx_atomic_t *atomic, int change) {
263     MUTEX_ENTER(&rx_atomic_mutex);
264     atomic->var += change;
265     MUTEX_EXIT(&rx_atomic_mutex);
266 }
267
268 static_inline void
269 rx_atomic_dec(rx_atomic_t *atomic) {
270     MUTEX_ENTER(&rx_atomic_mutex);
271     atomic->var--;
272     MUTEX_EXIT(&rx_atomic_mutex);
273 }
274
275 static_inline void
276 rx_atomic_sub(rx_atomic_t *atomic, int change) {
277     MUTEX_ENTER(&rx_atomic_mutex);
278     atomic->var -= change;
279     MUTEX_EXIT(&rx_atomic_mutex);
280 }
281
282 #endif