/* Copyright 2014 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #if !defined(MONGO_HAVE_CXX11_ATOMICS) #error "Cannot use atomic_word_cxx11.h without C++11 support" #endif // This file is a bit unusual. Most other source files in this codebase assume that C++11 // things are only usable if __cplusplus >= 201103L. However, we have made an explicit decision // to use when available, even if full C++11 conformance is not advertised. As a // result, we unconditionally include , but guard all other C++11 features under // __cplusplus >= 201103L so that we can work on platforms that don't yet offer those features, but // do offer #include #if __cplusplus >= 201103L #include #endif #include #include "mongo/base/disallow_copying.h" namespace mongo { /** * Implementation of the AtomicWord interface in terms of the C++11 Atomics. */ template class AtomicWord { #if __cplusplus < 201103L // AtomicWords are not copyable in C++03. MONGO_DISALLOW_COPYING(AtomicWord); #endif public: /** * Underlying value type. */ typedef _WordType WordType; /** * Construct a new word with the given initial value. */ explicit AtomicWord(WordType value=WordType(0)) : _value(value) {} #if __cplusplus >= 201103L // In C++11, AtomicWords are not copyable or movable. AtomicWord(AtomicWord&) = delete; AtomicWord& operator=(const AtomicWord&) = delete; AtomicWord(AtomicWord&&) = delete; AtomicWord& operator=(AtomicWord&&) = delete; #endif /** * Gets the current value of this AtomicWord. * * Has acquire and release semantics. */ WordType load() const { return _value.load(); } /** * Gets the current value of this AtomicWord. * * Has relaxed semantics. */ WordType loadRelaxed() const { return _value.load(std::memory_order_relaxed); } /** * Sets the value of this AtomicWord to "newValue". * * Has acquire and release semantics. */ void store(WordType newValue) { return _value.store(newValue); } /** * Atomically swaps the current value of this with "newValue". * * Returns the old value. * * Has acquire and release semantics. */ WordType swap(WordType newValue) { return _value.exchange(newValue); } /** * Atomic compare and swap. * * If this value equals "expected", sets this to "newValue". * Always returns the original of this. * * Has acquire and release semantics. */ WordType compareAndSwap(WordType expected, WordType newValue) { // NOTE: Subtle: compare_exchange mutates its first argument. _value.compare_exchange_strong(expected, newValue); return expected; } /** * Get the current value of this, add "increment" and store it, atomically. * * Returns the value of this before incrementing. * * Has acquire and release semantics. */ WordType fetchAndAdd(WordType increment) { return _value.fetch_add(increment); } /** * Get the current value of this, subtract "decrement" and store it, atomically. * * Returns the value of this before decrementing. * * Has acquire and release semantics. */ WordType fetchAndSubtract(WordType decrement) { return _value.fetch_sub(decrement); } /** * Get the current value of this, add "increment" and store it, atomically. * * Returns the value of this after incrementing. * * Has acquire and release semantics. */ WordType addAndFetch(WordType increment) { return fetchAndAdd(increment) + increment; } /** * Get the current value of this, subtract "decrement" and store it, atomically. * * Returns the value of this after decrementing. * * Has acquire and release semantics. */ WordType subtractAndFetch(WordType decrement) { return fetchAndSubtract(decrement) - decrement; } private: std::atomic _value; }; #if __cplusplus >= 201103L #define _ATOMIC_WORD_DECLARE(NAME, WTYPE) \ typedef class AtomicWord NAME; \ namespace { \ BOOST_STATIC_ASSERT(sizeof(NAME) == sizeof(WTYPE)); \ BOOST_STATIC_ASSERT(std::is_standard_layout::value); \ } // namespace #else #define _ATOMIC_WORD_DECLARE(NAME, WTYPE) \ typedef class AtomicWord NAME; \ namespace { \ BOOST_STATIC_ASSERT(sizeof(NAME) == sizeof(WTYPE)); \ } // namespace #endif _ATOMIC_WORD_DECLARE(AtomicUInt32, unsigned); _ATOMIC_WORD_DECLARE(AtomicUInt64, unsigned long long); _ATOMIC_WORD_DECLARE(AtomicInt32, int); _ATOMIC_WORD_DECLARE(AtomicInt64, long long); #undef _ATOMIC_WORD_DECLARE } // namespace mongo