1 /* This file is part of Jellyfish. 2 3 This work is dual-licensed under 3-Clause BSD License or GPL 3.0. 4 You can choose between one of them if you use this work. 5 6 `SPDX-License-Identifier: BSD-3-Clause OR GPL-3.0` 7 */ 8 9 10 #ifndef _JFLIB_COMPARE_AND_SWAP_H_ 11 #define _JFLIB_COMPARE_AND_SWAP_H_ 12 13 #include <sys/types.h> 14 #include <stdint.h> 15 16 namespace jflib { 17 // // Atomic load (get) and store (set). For now assume that the 18 // // architecture does this based on the virtual key word (true for 19 // // x86_64). TODO: improve on other architectures. 20 // template<typename T> 21 // T a_get(const T &x) { return *(volatile T*)&x; } 22 // template<typename T, typename U> 23 // T &a_set(T &lhs, const U &rhs) { 24 // *(volatile T*)&lhs = rhs; 25 // return lhs; 26 // } 27 28 // Numeric type of length rounded up to the size of a 29 // word. Undefined, and raise a compilation error, if the length is 30 // not a machine word size 31 template<typename T, size_t n> union word_t; 32 template<typename T> union word_t<T, 1> { typedef uint8_t w_t; T v; w_t w; }; 33 template<typename T> union word_t<T, 2> { typedef uint16_t w_t; T v; w_t w; }; 34 template<typename T> union word_t<T, 4> { typedef uint32_t w_t; T v; w_t w; }; 35 template<typename T> union word_t<T, 8> { typedef uint64_t w_t; T v; w_t w; }; 36 37 /** Type safe version of CAS. 38 * @param [in] ptr Memory location. 39 * @param [in] ov Presumed value at location. 40 * @param [in] nv Value to write. 41 * @param [out] cv Value at location at time of call. 42 * @return true if CAS is successful. 43 * 44 * The CAS operation is successful if, at the time of call, ov is 45 * equal to *ptr, the value at the memory location. In that case, nv 46 * is written to *ptr, and when the call returns, cv == ov. 47 * 48 * If it fails, cv contains *ptr at the time of call. 49 */ 50 template<typename T> cas(T * ptr,const T & ov,const T & nv,T * cv)51 bool cas(T *ptr, const T &ov, const T &nv, T *cv) { 52 typedef word_t<T, sizeof(T)> val_t; 53 val_t _cv, _ov, _nv; 54 _ov.v = ov; 55 _nv.v = nv; 56 _cv.w = __sync_val_compare_and_swap((typename val_t::w_t *)ptr, _ov.w, _nv.w); 57 *cv = _cv.v; 58 return _cv.w == _ov.w; 59 } 60 61 /** Type safe version of CAS. Identical to 4 argument version, 62 * except does not return the previous value. 63 */ 64 template<typename T> cas(T * ptr,const T & ov,const T & nv)65 bool cas(T *ptr, const T &ov, const T &nv) { 66 T cv; 67 return cas(ptr, ov, nv, &cv); 68 } 69 } 70 71 72 #endif /* _JFLIB_COMPARE_AND_SWAP_H_ */ 73