rx: Add atomic operations code
[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 typedef struct {
71    volatile int var;
72 } rx_atomic_t;
73
74 static_inline void
75 rx_atomic_set(rx_atomic_t *atomic, int val) {
76    atomic->var = val;
77 }
78
79 static_inline int
80 rx_atomic_read(rx_atomic_t *atomic) {
81    return atomic->var;
82 }
83
84 static_inline void
85 rx_atomic_inc(rx_atomic_t *atomic) {
86    OSAtomicIncrement32(&atomic->var);
87 }
88
89 static_inline int
90 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
91    return OSAtomicIncrement32(&atomic->var);
92 }
93
94 static_inline void
95 rx_atomic_add(rx_atomic_t *atomic, int change) {
96    OSAtomicAdd32(change, &atomic->var);
97 }
98
99 static_inline void
100 rx_atomic_dec(rx_atomic_t *atomic) {
101    OSAtomicDecrement32(&atomic->var);
102 }
103
104 static_inline void
105 rx_atomic_sub(rx_atomic_t *atomic, int change) {
106    OSAtomicAdd32(0 - change, &atomic->var);
107 }
108 #elif defined(AFS_LINUX20_ENV) && defined(KERNEL)
109 #include <asm/atomic.h>
110
111 typedef atomic_t rx_atomic_t;
112
113 #define rx_atomic_set(X)          atomic_set(X)
114 #define rx_atomic_read(X)         atomic_read(X)
115 #define rx_atomic_inc(X)          atomic_inc(X)
116 #define rx_atomic_inc_and_read(X) atomic_inc_return(X)
117 #define rx_atomic_add(X, V)       atomic_add(X, V)
118 #define rx_atomic_dec(X)          atomic_dec(X)
119 #define rx_atomic_sub(X, V)       atomic_sub(X, V)
120
121 #elif defined(AFS_SUN58_ENV)
122 typedef struct {
123    volatile int var;
124 } rx_atomic_t;
125
126 static_inline void
127 rx_atomic_set(rx_atomic_t *atomic, int val) {
128    atomic->var = val;
129 }
130
131 static_inline int
132 rx_atomic_read(rx_atomic_t *atomic) {
133    return atomic->var;
134 }
135
136 static_inline void
137 rx_atomic_inc(rx_atomic_t *atomic) {
138    atomic_inc_32(&atomic->var);
139 }
140
141 static_inline int
142 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
143    return atomic_inc_32_nv(&atomic->var);
144 }
145
146 static_inline void
147 rx_atomic_add(rx_atomic_t *atomic, int change) {
148    atomic_add_32(&atomic->var, change);
149 }
150
151 static_inline void
152 rx_atomic_dec(rx_atomic_t *atomic) {
153    atomic_dec_32(&atomic->var);
154 }
155
156 static_inline void
157 rx_atomic_sub(rx_atomic_t *atomic, int change) {
158    atomic_add_32(&object, 0 - change);
159 }
160
161 #elif defined(__GNUC__) && defined(HAVE_SYNC_FETCH_AND_ADD)
162
163 typedef struct {
164    volatile int var;
165 } rx_atomic_t;
166
167 static_inline void
168 rx_atomic_set(rx_atomic_t *atomic, int val) {
169    atomic->var = val;
170 }
171
172 static_inline int
173 rx_atomic_read(rx_atomic_t *atomic) {
174    return atomic->var;
175 }
176
177 static_inline void
178 rx_atomic_inc(rx_atomic_t *atomic) {
179    (void)__sync_fetch_and_add(&atomic->var, 1);
180 }
181
182 static_inline int
183 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
184    return __sync_add_and_fetch(&atomic->var, 1);
185 }
186
187 static_inline void
188 rx_atomic_add(rx_atomic_t *atomic, int change) {
189    (void)__sync_fetch_and_add(&atomic->var, change);
190 }
191
192 static_inline void
193 rx_atomic_dec(rx_atomic_t *atomic) {
194    (void)__sync_fetch_and_sub(&atomic->var, 1);
195 }
196
197 static_inline void
198 rx_atomic_sub(rx_atomic_t *atomic, int change) {
199    (void)__sync_fetch_and_sub(&atomic->var, change);
200 }
201
202 #else
203
204 /* If we're on a platform where we have no idea how to do atomics,
205  * then we fall back to using a single process wide mutex to protect
206  * all atomic variables. This won't be the quickest thing ever.
207  */
208
209 #ifdef RX_ENABLE_LOCKS
210 extern afs_kmutex_t rx_atomic_mutex;
211 #endif
212
213 typedef struct {
214     int var;
215 } rx_atomic_t;
216
217 static_inline void
218 rx_atomic_set(rx_atomic_t *atomic, int val) {
219     MUTEX_ENTER(&rx_atomic_mutex);
220     atomic->var = val;
221     MUTEX_EXIT(&rx_atomic_mutex);
222 }
223
224 static_inline int
225 rx_atomic_read(rx_atomic_t *atomic) {
226     int out;
227
228     MUTEX_ENTER(&rx_atomic_mutex);
229     out = atomic->var;
230     MUTEX_EXIT(&rx_atomic_mutex);
231
232     return out;
233 }
234
235 static_inline void
236 rx_atomic_inc(rx_atomic_t *atomic) {
237    MUTEX_ENTER(&rx_atomic_mutex);
238    atomic->var++;
239    MUTEX_EXIT(&rx_atomic_mutex);
240 }
241
242 static_inline int
243 rx_atomic_inc_and_read(rx_atomic_t *atomic) {
244     int retval;
245     MUTEX_ENTER(&rx_atomic_mutex);
246     atomic->var++;
247     retval = atomic->var;
248     MUTEX_EXIT(&rx_atomic_mutex);
249     return retval;
250 }
251
252 static_inline void
253 rx_atomic_add(rx_atomic_t *atomic, int change) {
254     MUTEX_ENTER(&rx_atomic_mutex);
255     atomic->var += change;
256     MUTEX_EXIT(&rx_atomic_mutex);
257 }
258
259 static_inline void
260 rx_atomic_dec(rx_atomic_t *atomic) {
261     MUTEX_ENTER(&rx_atomic_mutex);
262     atomic->var--;
263     MUTEX_EXIT(&rx_atomic_mutex);
264 }
265
266 static_inline void
267 rx_atomic_sub(rx_atomic_t *atomic, int change) {
268     MUTEX_ENTER(&rx_atomic_mutex);
269     atomic->var -= change;
270     MUTEX_ENTER(&rx_atomic_mutex);
271 }
272
273 #endif