libfoedus-core
FOEDUS Core Library
raw_atomics.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2015, Hewlett-Packard Development Company, LP.
3  * This program is free software; you can redistribute it and/or modify it
4  * under the terms of the GNU General Public License as published by the Free
5  * Software Foundation; either version 2 of the License, or (at your option)
6  * any later version.
7  *
8  * This program is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11  * more details. You should have received a copy of the GNU General Public
12  * License along with this program; if not, write to the Free Software
13  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14  *
15  * HP designates this particular file as subject to the "Classpath" exception
16  * as provided by HP in the LICENSE.txt file that accompanied this code.
17  */
19 
20 #include <stdint.h>
21 
22 namespace foedus {
23 namespace assorted {
24 
26  uint64_t *ptr,
27  const uint64_t *old_value,
28  const uint64_t *new_value) {
29  bool ret;
30 #if defined(__GNUC__) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16)
31  // gcc-x86 (-mcx16), then simply use __sync_bool_compare_and_swap.
32  __uint128_t* ptr_casted = reinterpret_cast<__uint128_t*>(ptr);
33  __uint128_t old_casted = *reinterpret_cast<const __uint128_t*>(old_value);
34  __uint128_t new_casted = *reinterpret_cast<const __uint128_t*>(new_value);
35  ret = ::__sync_bool_compare_and_swap(ptr_casted, old_casted, new_casted);
36 #elif defined(__GNUC__) && defined(__aarch64__)
37  // gcc-AArch64 doesn't allow -mcx16. But, it supports __atomic_compare_exchange_16 with
38  // libatomic.so. We need to link to it in that case.
39  __uint128_t* ptr_casted = reinterpret_cast<__uint128_t*>(ptr);
40  __uint128_t old_casted = *reinterpret_cast<const __uint128_t*>(old_value);
41  __uint128_t new_casted = *reinterpret_cast<const __uint128_t*>(new_value);
42  ret = ::__atomic_compare_exchange_16(
43  ptr_casted,
44  &old_casted,
45  new_casted,
46  false, // strong CAS
47  __ATOMIC_ACQ_REL, // to make it atomic, of course acq_rel
48  __ATOMIC_ACQUIRE); // matters only when it fails. acquire is enough.
49 #else // everything else
50  // oh well, then resort to assembly, assuming x86. clang on ARMv8? oh please...
51  // see: linux/arch/x86/include/asm/cmpxchg_64.h
52  uint64_t junk;
53  asm volatile("lock; cmpxchg16b %2;setz %1"
54  : "=d"(junk), "=a"(ret), "+m" (*ptr)
55  : "b"(new_value[0]), "c"(new_value[1]), "a"(old_value[0]), "d"(old_value[1]));
56  // Note on roll-our-own non-gcc ARMv8 cas16. It's doable, but...
57  // ARMv8 does have 128bit atomic instructions, called "pair" operations, such as ldaxp and stxp.
58  // There is actually a library that uses it:
59  // https://github.com/ivmai/libatomic_ops/blob/master/src/atomic_ops/sysdeps/gcc/aarch64.h
60  // (but this is GPL. Don't open the URL unless you are ready for it.)
61  // As of now (May 2014), GCC can't handle them, nor provide __uint128_t in ARMv8.
62  // I think it's coming, however. I'm waiting for it... if it's not coming, let's do ourselves.
63 #endif
64  return ret;
65 }
66 
67 } // namespace assorted
68 } // namespace foedus
69 
Root package of FOEDUS (Fast Optimistic Engine for Data Unification Services).
Definition: assert_nd.hpp:44
bool raw_atomic_compare_exchange_strong_uint128(uint64_t *ptr, const uint64_t *old_value, const uint64_t *new_value)
Atomic 128-bit CAS, which is not in the standard yet.
Definition: raw_atomics.cpp:25
Raw atomic operations that work for both C++11 and non-C++11 code.