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