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