1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Copyright 2010 Couchbase, Inc
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #ifndef SRC_ATOMIC_LIBATOMIC_H_
19 #define SRC_ATOMIC_LIBATOMIC_H_ 1
20
21 /**
22 * atomic.h provides a function interface to the various atomic functions,
23 * but it's a C API and not C++ so I can't use the preprocessor to map
24 * each function. Let's use function overloading instead and let the compiler
25 * pick the one it wants...
26 */
27
28 #include "config.h"
29
30 #include <atomic.h>
31 #include <queue>
32
ep_sync_lock_test_and_set(volatile int *dest, int value)33 inline int ep_sync_lock_test_and_set(volatile int *dest, int value) {
34 return atomic_swap_uint((volatile uint*)dest, value);
35 }
36
ep_sync_lock_release(volatile int *dest)37 inline void ep_sync_lock_release(volatile int *dest) {
38 atomic_swap_uint((volatile uint*)dest, 0);
39 }
40
ep_sync_synchronize(void)41 inline void ep_sync_synchronize(void) {
42 // I don't know how to add this yet...
43
44 }
45
ep_sync_add_and_fetch(volatile uint64_t *dest, uint64_t value)46 inline rel_time_t ep_sync_add_and_fetch(volatile uint64_t *dest, uint64_t value) {
47 if (value == 1) {
48 return atomic_inc_64_nv(dest);
49 } else {
50 return atomic_add_64_nv(dest, value);
51 }
52 }
53
ep_sync_add_and_fetch(volatile uint32_t *dest, uint32_t value)54 inline rel_time_t ep_sync_add_and_fetch(volatile uint32_t *dest, uint32_t value) {
55 if (value == 1) {
56 return atomic_inc_32_nv(dest);
57 } else {
58 return atomic_add_32_nv(dest, value);
59 }
60 }
61
ep_sync_add_and_fetch(volatile int *dest, int value)62 inline int ep_sync_add_and_fetch(volatile int *dest, int value) {
63 if (value == 1) {
64 return atomic_inc_uint_nv((volatile uint_t*)dest);
65 } else {
66 return atomic_add_int_nv((volatile uint_t*)dest, value);
67 }
68 }
69
ep_sync_add_and_fetch(volatile uint8_t *dest, uint8_t value)70 inline uint8_t ep_sync_add_and_fetch(volatile uint8_t *dest, uint8_t value) {
71 if (value == 1) {
72 return atomic_inc_8_nv(dest);
73 } else {
74 return atomic_add_8_nv(dest, value);
75 }
76 }
77
ep_sync_add_and_fetch(volatile hrtime_t *dest, hrtime_t value)78 inline hrtime_t ep_sync_add_and_fetch(volatile hrtime_t *dest, hrtime_t value) {
79 if (value == 1) {
80 return atomic_inc_64_nv((volatile uint64_t*)dest);
81 } else {
82 return atomic_add_64_nv((volatile uint64_t*)dest, value);
83 }
84 }
85
ep_sync_fetch_and_add(volatile int *dest, int value)86 inline int ep_sync_fetch_and_add(volatile int *dest, int value) {
87 size_t original = *dest;
88 if (value == 1) {
89 atomic_inc_uint((volatile uint_t*)dest);
90 } else {
91 atomic_add_int((volatile uint_t*)dest, value);
92 }
93 return original;
94 }
95
ep_sync_fetch_and_add(volatile uint64_t *dest, uint64_t value)96 inline uint64_t ep_sync_fetch_and_add(volatile uint64_t *dest, uint64_t value) {
97 uint64_t original = *dest;
98 if (value == 1) {
99 atomic_inc_64(dest);
100 } else {
101 atomic_add_64(dest, value);
102 }
103
104 return original;
105 }
106
ep_sync_fetch_and_add(volatile uint32_t *dest, uint32_t value)107 inline uint32_t ep_sync_fetch_and_add(volatile uint32_t *dest, uint32_t value) {
108 uint32_t original = *dest;
109 if (value == 1) {
110 atomic_inc_32(dest);
111 } else {
112 atomic_add_32(dest, value);
113 }
114
115 return original;
116 }
117
ep_sync_fetch_and_add(volatile hrtime_t *dest, hrtime_t value)118 inline hrtime_t ep_sync_fetch_and_add(volatile hrtime_t *dest, hrtime_t value) {
119 size_t original = *dest;
120 if (value == 1) {
121 atomic_inc_64((volatile uint64_t*)dest);
122 } else {
123 atomic_add_64((volatile uint64_t*)dest, value);
124 }
125
126 return original;
127 }
128
ep_sync_bool_compare_and_swap(volatile uint8_t *dest, uint8_t prev, uint8_t next)129 inline bool ep_sync_bool_compare_and_swap(volatile uint8_t *dest, uint8_t prev, uint8_t next) {
130 uint8_t original = *dest;
131 if (original == atomic_cas_8((volatile uint8_t*)dest, (uint8_t)prev, (uint8_t)next)) {
132 return true;
133 } else {
134 return false;
135 }
136 }
137
ep_sync_bool_compare_and_swap(volatile bool *dest, bool prev, bool next)138 inline bool ep_sync_bool_compare_and_swap(volatile bool *dest, bool prev, bool next) {
139 return ep_sync_bool_compare_and_swap((volatile uint8_t*)dest,
140 (uint8_t)prev,
141 (uint8_t)next);
142 }
143
ep_sync_bool_compare_and_swap(volatile int *dest, int prev, int next)144 inline bool ep_sync_bool_compare_and_swap(volatile int *dest, int prev, int next) {
145 uint_t original = *dest;
146 if (original == atomic_cas_uint((volatile uint_t*)dest, (uint_t)prev, (uint_t)next)) {
147 return true;
148 } else {
149 return false;
150 }
151 }
152
ep_sync_bool_compare_and_swap(volatile unsigned int *dest, unsigned int prev, unsigned int next)153 inline bool ep_sync_bool_compare_and_swap(volatile unsigned int *dest,
154 unsigned int prev,
155 unsigned int next) {
156 uint_t original = *dest;
157 if (original == atomic_cas_uint((volatile uint_t*)dest, (uint_t)prev, (uint_t)next)) {
158 return true;
159 } else {
160 return false;
161 }
162 }
163
ep_sync_bool_compare_and_swap(volatile uint64_t *dest, uint64_t prev, uint64_t next)164 inline bool ep_sync_bool_compare_and_swap(volatile uint64_t *dest,
165 uint64_t prev,
166 uint64_t next) {
167 uint64_t original = *dest;
168 if (original == atomic_cas_64(dest, prev, next)) {
169 return true;
170 } else {
171 return false;
172 }
173 }
174
ep_sync_bool_compare_and_swap(volatile int64_t *dest, int64_t prev, int64_t next)175 inline bool ep_sync_bool_compare_and_swap(volatile int64_t *dest,
176 int64_t prev,
177 int64_t next) {
178 uint64_t original = (uint64_t)*dest;
179 if (original == atomic_cas_64((volatile uint64_t*)dest,
180 (uint64_t)prev,
181 (uint64_t)next)) {
182 return true;
183 } else {
184 return false;
185 }
186 }
187
188 #ifdef _LP64
ep_sync_bool_compare_and_swap(volatile longlong_t *dest, longlong_t prev, longlong_t next)189 inline bool ep_sync_bool_compare_and_swap(volatile longlong_t *dest,
190 longlong_t prev,
191 longlong_t next) {
192 return ep_sync_bool_compare_and_swap((volatile uint64_t *)dest,
193 (uint64_t)prev,
194 (uint64_t)next);
195 }
196 #endif
197
198 /*
199 * Unfortunately C++ isn't all that happy about assinging everything to/from a
200 * void pointer without a cast, so we need to add extra functions.
201 * Luckily we know that the size_t is big enough to keep a pointer, so
202 * we can reuse the size_t function for we already defined
203 */
204 typedef std::queue<int> IntQueue;
205 class VBucket;
206 class VBucketHolder;
207 class Doodad;
208 class Blob;
209
ep_sync_bool_compare_and_swap(VBucket* volatile* dest, VBucket* prev, VBucket* next)210 inline bool ep_sync_bool_compare_and_swap(VBucket* volatile* dest, VBucket* prev, VBucket* next) {
211 return ep_sync_bool_compare_and_swap((size_t*)dest, (size_t)prev, (size_t)next);
212 }
213
ep_sync_bool_compare_and_swap(Blob* volatile* dest, Blob* prev, Blob* next)214 inline bool ep_sync_bool_compare_and_swap(Blob* volatile* dest, Blob* prev, Blob* next) {
215 return ep_sync_bool_compare_and_swap((size_t*)dest, (size_t)prev, (size_t)next);
216 }
217
ep_sync_bool_compare_and_swap(VBucketHolder* volatile* dest, VBucketHolder* prev, VBucketHolder* next)218 inline bool ep_sync_bool_compare_and_swap(VBucketHolder* volatile* dest, VBucketHolder* prev, VBucketHolder* next) {
219 return ep_sync_bool_compare_and_swap((size_t*)dest, (size_t)prev, (size_t)next);
220 }
221
ep_sync_bool_compare_and_swap(Doodad* volatile* dest, Doodad* prev, Doodad* next)222 inline bool ep_sync_bool_compare_and_swap(Doodad* volatile* dest, Doodad* prev, Doodad* next) {
223 return ep_sync_bool_compare_and_swap((size_t*)dest, (size_t)prev, (size_t)next);
224 }
225
ep_sync_bool_compare_and_swap(IntQueue * volatile *dest, IntQueue *prev, IntQueue *next)226 inline bool ep_sync_bool_compare_and_swap(IntQueue * volatile *dest, IntQueue *prev, IntQueue *next) {
227 return ep_sync_bool_compare_and_swap((size_t*)dest, (size_t)prev, (size_t)next);
228 }
229
230
231 #endif // SRC_ATOMIC_LIBATOMIC_H_
232