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