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
33inline int ep_sync_lock_test_and_set(volatile int *dest, int value) {
34    return atomic_swap_uint((volatile uint*)dest, value);
35}
36
37inline void ep_sync_lock_release(volatile int *dest) {
38    atomic_swap_uint((volatile uint*)dest, 0);
39}
40
41inline void ep_sync_synchronize(void) {
42    // I don't know how to add this yet...
43
44}
45
46inline 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
54inline 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
62inline 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
70inline 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
78inline 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
86inline 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
96inline 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
107inline 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
118inline 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
129inline 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
138inline 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
144inline 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
153inline 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
164inline 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
175inline 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
189inline 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 */
204typedef std::queue<int> IntQueue;
205class VBucket;
206class VBucketHolder;
207class Doodad;
208class Blob;
209
210inline 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
214inline 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
218inline 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
222inline 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
226inline 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