diff options
author | Henning Baldersheim <balder@yahoo-inc.com> | 2017-08-11 12:29:46 +0200 |
---|---|---|
committer | Henning Baldersheim <balder@yahoo-inc.com> | 2017-08-11 12:30:24 +0200 |
commit | 41709673f0165f16496ecf37162ed7dac06b5295 (patch) | |
tree | c213da683873bbe88927a3de58eb93f3f231a693 /vespalib | |
parent | 2fe073e8e1875bc891c38099c880d156bd228e9d (diff) |
Use std::atomic all over and completely get rid of homegrown atomics.
Diffstat (limited to 'vespalib')
21 files changed, 14 insertions, 1495 deletions
diff --git a/vespalib/CMakeLists.txt b/vespalib/CMakeLists.txt index 93ac717d9ef..cab5ce0ff4a 100644 --- a/vespalib/CMakeLists.txt +++ b/vespalib/CMakeLists.txt @@ -16,7 +16,6 @@ vespa_define_module( src/tests/approx src/tests/array src/tests/arrayqueue - src/tests/atomic src/tests/barrier src/tests/benchmark_timer src/tests/box @@ -98,7 +97,6 @@ vespa_define_module( src/tests/util/generationhandler src/tests/util/generationhandler_stress src/tests/valgrind - src/tests/weakref src/tests/websocket src/tests/zcurve diff --git a/vespalib/src/testlist.txt b/vespalib/src/testlist.txt index 02e66607eeb..68a1136e025 100644 --- a/vespalib/src/testlist.txt +++ b/vespalib/src/testlist.txt @@ -6,7 +6,6 @@ tests/alloc tests/approx tests/array tests/arrayqueue -tests/atomic tests/barrier tests/benchmark_timer tests/box diff --git a/vespalib/src/tests/atomic/.gitignore b/vespalib/src/tests/atomic/.gitignore deleted file mode 100644 index 7ec00432065..00000000000 --- a/vespalib/src/tests/atomic/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -.depend -Makefile -atomic_test -/atomic_bench -vespalib_atomic_test_app -vespalib_atomic_bench_app diff --git a/vespalib/src/tests/atomic/CMakeLists.txt b/vespalib/src/tests/atomic/CMakeLists.txt deleted file mode 100644 index b20a5891318..00000000000 --- a/vespalib/src/tests/atomic/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -vespa_add_executable(vespalib_atomic_test_app TEST - SOURCES - atomic_test.cpp - DEPENDS - vespalib -) -vespa_add_test(NAME vespalib_atomic_test_app COMMAND vespalib_atomic_test_app) -vespa_add_executable(vespalib_atomic_bench_app - SOURCES - atomic_bench.cpp - DEPENDS - vespalib -) -vespa_add_test(NAME vespalib_atomic_bench_app COMMAND vespalib_atomic_bench_app BENCHMARK) diff --git a/vespalib/src/tests/atomic/DESC b/vespalib/src/tests/atomic/DESC deleted file mode 100644 index ec5b4379673..00000000000 --- a/vespalib/src/tests/atomic/DESC +++ /dev/null @@ -1 +0,0 @@ -atomic test. Take a look at atomic.cpp for details. diff --git a/vespalib/src/tests/atomic/FILES b/vespalib/src/tests/atomic/FILES deleted file mode 100644 index 83c6c518c67..00000000000 --- a/vespalib/src/tests/atomic/FILES +++ /dev/null @@ -1 +0,0 @@ -atomic.cpp diff --git a/vespalib/src/tests/atomic/atomic_bench.cpp b/vespalib/src/tests/atomic/atomic_bench.cpp deleted file mode 100644 index 24fe67cfb77..00000000000 --- a/vespalib/src/tests/atomic/atomic_bench.cpp +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#include <vespa/vespalib/testkit/testapp.h> -#include <vespa/vespalib/util/atomic.h> -#include <vespa/fastos/thread.h> -#include <vector> -#include <algorithm> -#include <sstream> - -#include <vespa/log/log.h> -LOG_SETUP("atomic_bench"); - -class Test : public vespalib::TestApp -{ -public: - template<typename C, typename T> - void testInc(size_t threads, size_t loops); - int Main() override; -}; - -template <typename T> -class Changer : public FastOS_Runnable -{ -protected: - volatile T * const _idata; - const int _times; -public: - Changer(int times, T *data) - : _idata(data), _times(times) {} -}; - -template <typename T> -class Incrementer : public Changer<T> -{ -public: - Incrementer(int times, T *data) : Changer<T>(times, data) {} - void Run(FastOS_ThreadInterface *, void *) override { - using vespalib::Atomic; - for (int i = 0; i < this->_times; ++i) { - Atomic::postInc(this->_idata); - } - } -}; - -template <typename T> -class IncrementerByCmpSwap : public Changer<T> -{ -public: - IncrementerByCmpSwap(int times, T *data) : Changer<T>(times, data) {} - void Run(FastOS_ThreadInterface *, void *) override { - using vespalib::Atomic; - T oldVal(0); - for (int i = 0; i < this->_times; ++i) { - do { - oldVal = *this->_idata; - } while ( ! Atomic::cmpSwap(this->_idata, oldVal+1, oldVal)); - } - } -}; - -int -Test::Main() -{ - TEST_INIT("atomic_bench"); - size_t concurrency(1); - size_t numRuns(10000000ul); - size_t benchType(0); - if (_argc > 1) { - benchType = strtoul(_argv[1], NULL, 0); - if (_argc > 2) { - numRuns = strtoul(_argv[2], NULL, 0); - if (_argc > 3) { - concurrency = strtoul(_argv[3], NULL, 0); - } - } - } - LOG(info, "Running test number %ld with %ld loops and concurrency of %ld", benchType, numRuns, concurrency); - if (benchType == 1) { - testInc<IncrementerByCmpSwap<uint64_t>, uint64_t>(concurrency, numRuns); - } else { - testInc<Incrementer<uint64_t>, uint64_t>(concurrency, numRuns); - } - - TEST_FLUSH(); - TEST_DONE(); -} - - -template<typename C, typename T> -void -Test::testInc(size_t numThreads, size_t loopCount) -{ - std::vector<std::unique_ptr<C>> threads3(numThreads); - T uintcounter = 0; - FastOS_ThreadPool tpool3(65000, numThreads); - for (size_t i = 0; i < numThreads; i++) { - threads3[i] = std::make_unique<C>(loopCount, &uintcounter); - tpool3.NewThread(threads3[i].get()); - } - tpool3.Close(); - EXPECT_TRUE(uintcounter == numThreads * loopCount); - TEST_FLUSH(); -} - -TEST_APPHOOK(Test) diff --git a/vespalib/src/tests/atomic/atomic_test.cpp b/vespalib/src/tests/atomic/atomic_test.cpp deleted file mode 100644 index 0cd3b9f3e98..00000000000 --- a/vespalib/src/tests/atomic/atomic_test.cpp +++ /dev/null @@ -1,339 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#include <vespa/vespalib/testkit/testapp.h> -#include <vespa/vespalib/util/atomic.h> -#include <vespa/fastos/thread.h> -#include <vector> -#include <algorithm> -#include <sstream> - -#include <vespa/log/log.h> -LOG_SETUP("atomic_test"); - -class Test : public vespalib::TestApp -{ -public: - template<typename T, typename U> - void testAdd(); - template<typename T, typename U> - void testAddSub(); - template<typename T> - void testInc(); - template<typename T> - void testDec(); - template<typename T> - void testSemantics(); - int Main() override; -}; - -static const int numadders = 7; -static const int loopcnt = 100000; - -int -Test::Main() -{ - TEST_INIT("atomic_test"); - - testSemantics<int32_t>(); - testSemantics<int64_t>(); - testAdd<int32_t, uint32_t>(); - testAdd<int64_t, uint64_t>(); - testAddSub<int32_t, uint32_t>(); - testAddSub<int64_t, uint64_t>(); - testInc<uint32_t>(); - testInc<uint64_t>(); - testDec<uint32_t>(); - testDec<uint64_t>(); - - TEST_FLUSH(); - TEST_DONE(); -} - -template<typename T> -void -Test::testSemantics() -{ - using vespalib::Atomic; - volatile T value(0); - EXPECT_EQUAL(0, value); - EXPECT_EQUAL(0, Atomic::postInc(&value)); - EXPECT_EQUAL(1, Atomic::postInc(&value)); - EXPECT_EQUAL(2, value); - EXPECT_EQUAL(2, Atomic::postDec(&value)); - EXPECT_EQUAL(1, value); - EXPECT_EQUAL(1, Atomic::postAdd(&value, 17)); - EXPECT_EQUAL(18, value); - EXPECT_EQUAL(18, Atomic::postAdd(&value, 17)); - EXPECT_EQUAL(35, value); - EXPECT_EQUAL(35, Atomic::postAdd(&value, -7)); - EXPECT_EQUAL(28, value); -} - -class NotAtomic -{ -public: - static inline void add(volatile int *data, int xdelta) { - (*data) += xdelta; - } - static inline void sub(volatile int *data, int xdelta) { - (*data) -= xdelta; - } - static inline void add(volatile unsigned int *data, unsigned int xdelta) { - (*data) += xdelta; - } - static inline void sub(volatile unsigned int *data, unsigned int xdelta) { - (*data) -= xdelta; - } - static inline unsigned int postDec(volatile unsigned int *data) { - return (*data)--; - } - static inline unsigned int postInc(volatile unsigned int *data) { - return (*data)++; - } -}; - -template<typename T, typename U> -class Adder : public FastOS_Runnable -{ -private: - int _added; - const T _toadd; - const int _times; - volatile T * const _idata; - volatile U * const _udata; -public: - Adder(T toadd, int times, T *i, U *u) : - _added(0), - _toadd(toadd), - _times(times), - _idata(i), - _udata(u) - {} - void Run(FastOS_ThreadInterface *, void *) override { - using vespalib::Atomic; - for (int i = 0; i < _times; ++i) { - Atomic::add(_idata, _toadd); - Atomic::add(_udata, _toadd); - _added += _toadd; - } - } - int getAdded() { return _added; } -}; - - -template<typename T, typename U> -class Subtracter : public FastOS_Runnable -{ -private: - int _subed; - const T _tosub; - const int _times; - volatile T * const _idata; - volatile U * const _udata; -public: - Subtracter(T tosub, int times, T *i, U *u) : - _subed(0), - _tosub(tosub), - _times(times), - _idata(i), - _udata(u) - {} - void Run(FastOS_ThreadInterface *, void *) override { - using vespalib::Atomic; - for (int i = 0; i < _times; ++i) { - Atomic::sub(_idata, _tosub); - Atomic::sub(_udata, _tosub); - _subed += _tosub; - } - } - int getSubtracted() { return _subed; } -}; - -template <typename T> -class Changer : public FastOS_Runnable -{ -protected: - std::vector<T> _counts; - volatile T * const _idata; - const int _times; -public: - Changer(int times, T *data) - : _counts(), _idata(data), _times(times) {} - const std::vector<T> & getCounts() const { return _counts; } -}; - - -template <typename T> -class Incrementer : public Changer<T> -{ -public: - Incrementer(int times, T *data) : Changer<T>(times, data) {} - void Run(FastOS_ThreadInterface *, void *) override { - using vespalib::Atomic; - for (int i = 0; i < this->_times; ++i) { - this->_counts.push_back(Atomic::postInc(this->_idata)); - } - } -}; - - -template <typename T> -class Decrementer : public Changer<T> -{ -public: - Decrementer(int times, T *data) : Changer<T>(times, data) {} - void Run(FastOS_ThreadInterface *, void *) override { - using vespalib::Atomic; - for (int i = 0; i < this->_times; ++i) { - this->_counts.push_back(Atomic::postDec(this->_idata)); - } - } -}; - - -template<typename T, typename U> -void -Test::testAdd() -{ - Adder<T, U> *threads1[numadders]; - - T intcounter = 0; - U uintcounter = 0; - - FastOS_ThreadPool tpool1(65000, numadders); - for (int i = 0; i < numadders; i++) { - threads1[i] = new Adder<T, U>(2+i, loopcnt, &intcounter, &uintcounter); - tpool1.NewThread(threads1[i]); - } - tpool1.Close(); - T intcorrect = 0; - U uintcorrect = 0; - for (int i = 0; i < numadders; i++) { - intcorrect += threads1[i]->getAdded(); - uintcorrect += threads1[i]->getAdded(); - } - for (int i = 0; i < numadders; i++) { - delete threads1[i]; - } - std::ostringstream os; - os << "intcounter = " << intcounter << ", intcorrect = " << intcorrect; - LOG(debug, "%s", os.str().c_str()); - EXPECT_TRUE( intcounter == intcorrect); - std::ostringstream uos; - uos << "uintcounter = " << uintcounter << ", uintcorrect = " << uintcorrect; - LOG(debug, "%s", uos.str().c_str()); - EXPECT_TRUE(uintcounter == uintcorrect); -} - - -template<typename T, typename U> -void -Test::testAddSub() -{ - FastOS_Runnable *threads2[numadders*2]; - T intcounter = 0; - U uintcounter = 0; - - FastOS_ThreadPool tpool2(65000, 2*numadders); - for (int i = 0; i < numadders; i++) { - threads2[i] = new Adder<T, U>(2+i, loopcnt, &intcounter, &uintcounter); - threads2[numadders+i] = new Subtracter<T, U>(2+i, loopcnt, - &intcounter, &uintcounter); - } - for (int i = 0; i < numadders*2; i++) { - tpool2.NewThread(threads2[i]); - } - tpool2.Close(); - - for (int i = 0; i < numadders*2; i++) { - delete threads2[i]; - } - std::ostringstream os; - os << "intcounter = " << intcounter << ", uintcounter = " << uintcounter; - LOG(debug, "%s", os.str().c_str()); - EXPECT_TRUE( intcounter == 0); - EXPECT_TRUE(uintcounter == 0); -} - - -template<typename T> -void -Test::testInc() -{ - Incrementer<T> *threads3[numadders]; - T uintcounter = 0; - FastOS_ThreadPool tpool3(65000, numadders); - for (int i = 0; i < numadders; i++) { - threads3[i] = new Incrementer<T>(loopcnt, &uintcounter); - tpool3.NewThread(threads3[i]); - } - tpool3.Close(); - std::vector<T> all; - for (int i = 0; i < numadders; i++) { - const std::vector<T> & cnts = threads3[i]->getCounts(); - typename std::vector<T>::const_iterator it = cnts.begin(); - while (it != cnts.end()) { - all.push_back(*it); - ++it; - } - } - for (int i = 0; i < numadders; i++) { - delete threads3[i]; - } - std::sort(all.begin(), all.end()); - for (unsigned int n = 0; n < all.size(); ++n) { - EXPECT_TRUE(all[n] == n); - if (all[n] != n) { - std::ostringstream os; - os << all[n]; - LOG(info, "all[%d] = %s", n, os.str().c_str()); - break; - } - } - TEST_FLUSH(); - EXPECT_TRUE(uintcounter == numadders * loopcnt); - TEST_FLUSH(); -} - -template<typename T> -void -Test::testDec() -{ - T uintcounter = numadders * loopcnt; - Decrementer<T> *threads4[numadders]; - FastOS_ThreadPool tpool4(65000, numadders); - for (int i = 0; i < numadders; i++) { - threads4[i] = new Decrementer<T>(loopcnt, &uintcounter); - tpool4.NewThread(threads4[i]); - } - tpool4.Close(); - std::vector<T> all; - for (int i = 0; i < numadders; i++) { - const std::vector<T> & cnts = threads4[i]->getCounts(); - typename std::vector<T>::const_iterator it = cnts.begin(); - while (it != cnts.end()) { - all.push_back(*it); - ++it; - } - } - for (int i = 0; i < numadders; i++) { - delete threads4[i]; - } - std::sort(all.begin(), all.end()); - for (size_t n = 0; n < all.size(); ++n) { - EXPECT_TRUE(all[n] == n+1); - if (all[n] != n+1) { - for (size_t i = n; i < std::min(n+20, all.size()); ++i) { - std::ostringstream os; - os << std::dec << "all[" << i << "] = " << std::hex << all[i]; - LOG(warning, "%s", os.str().c_str()); - } - break; - } - } - TEST_FLUSH(); - EXPECT_TRUE(uintcounter == 0); -} - - -TEST_APPHOOK(Test) diff --git a/vespalib/src/tests/executor/threadstackexecutor_test.cpp b/vespalib/src/tests/executor/threadstackexecutor_test.cpp index cfdcd8ba79d..3e092ef145f 100644 --- a/vespalib/src/tests/executor/threadstackexecutor_test.cpp +++ b/vespalib/src/tests/executor/threadstackexecutor_test.cpp @@ -1,10 +1,10 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/vespalib/testkit/test_kit.h> -#include <vespa/vespalib/util/atomic.h> #include <vespa/vespalib/util/threadstackexecutor.h> #include <vespa/vespalib/util/sync.h> #include <vespa/vespalib/util/backtrace.h> +#include <atomic> using namespace vespalib; @@ -13,24 +13,24 @@ typedef Executor::Task Task; struct MyTask : public Executor::Task { Gate &gate; CountDownLatch &latch; - static uint32_t runCnt; - static uint32_t deleteCnt; + static std::atomic<uint32_t> runCnt; + static std::atomic<uint32_t> deleteCnt; MyTask(Gate &g, CountDownLatch &l) : gate(g), latch(l) {} void run() override { - Atomic::postInc(&runCnt); + runCnt++; latch.countDown(); gate.await(); } ~MyTask() { - Atomic::postInc(&deleteCnt); + deleteCnt++; } static void resetStats() { runCnt = 0; deleteCnt = 0; } }; -uint32_t MyTask::runCnt = 0; -uint32_t MyTask::deleteCnt = 0; +std::atomic<uint32_t> MyTask::runCnt(0); +std::atomic<uint32_t> MyTask::deleteCnt(0); struct MyState { Gate gate; // to block workers diff --git a/vespalib/src/tests/weakref/.gitignore b/vespalib/src/tests/weakref/.gitignore deleted file mode 100644 index 8ef27437213..00000000000 --- a/vespalib/src/tests/weakref/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.depend -Makefile -weakref_test -vespalib_weakref_test_app diff --git a/vespalib/src/tests/weakref/CMakeLists.txt b/vespalib/src/tests/weakref/CMakeLists.txt deleted file mode 100644 index 5fea9d2299a..00000000000 --- a/vespalib/src/tests/weakref/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -vespa_add_executable(vespalib_weakref_test_app TEST - SOURCES - weakref_test.cpp - DEPENDS - vespalib -) -vespa_add_test(NAME vespalib_weakref_test_app COMMAND vespalib_weakref_test_app) diff --git a/vespalib/src/tests/weakref/DESC b/vespalib/src/tests/weakref/DESC deleted file mode 100644 index d2a0b5757a6..00000000000 --- a/vespalib/src/tests/weakref/DESC +++ /dev/null @@ -1 +0,0 @@ -Unit test for the WeakRef class. diff --git a/vespalib/src/tests/weakref/FILES b/vespalib/src/tests/weakref/FILES deleted file mode 100644 index 82209bcb6ae..00000000000 --- a/vespalib/src/tests/weakref/FILES +++ /dev/null @@ -1 +0,0 @@ -weakref.cpp diff --git a/vespalib/src/tests/weakref/weakref_test.cpp b/vespalib/src/tests/weakref/weakref_test.cpp deleted file mode 100644 index bf85edbc15f..00000000000 --- a/vespalib/src/tests/weakref/weakref_test.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#include <vespa/vespalib/util/weakref.h> -#include <vespa/vespalib/testkit/testapp.h> - -using vespalib::WeakRef; - -class Test : public vespalib::TestApp -{ -public: - int getFive() { return 5; } - void testSimple(); - int Main() override; -}; - - -void -Test::testSimple() -{ - WeakRef<Test>::Owner owner(this); - WeakRef<Test> ref(owner); - { - WeakRef<Test>::Usage use(ref); - ASSERT_TRUE(use.valid()); - EXPECT_TRUE(use->getFive() == 5); - } - owner.clear(); - { - WeakRef<Test>::Usage use(ref); - EXPECT_TRUE(!use.valid()); - } -} - - -int -Test::Main() -{ - TEST_INIT("weakref_test"); - testSimple(); - TEST_DONE(); -} - -TEST_APPHOOK(Test) diff --git a/vespalib/src/vespa/vespalib/util/CMakeLists.txt b/vespalib/src/vespa/vespalib/util/CMakeLists.txt index 7f42385b1fc..310e1dde68d 100644 --- a/vespalib/src/vespa/vespalib/util/CMakeLists.txt +++ b/vespalib/src/vespa/vespalib/util/CMakeLists.txt @@ -6,7 +6,6 @@ vespa_add_library(vespalib_vespalib_util OBJECT alloc.cpp approx.cpp array.cpp - atomic.cpp backtrace.cpp barrier.cpp benchmark_timer.cpp diff --git a/vespalib/src/vespa/vespalib/util/atomic.cpp b/vespalib/src/vespa/vespalib/util/atomic.cpp deleted file mode 100644 index 8bf245fcc72..00000000000 --- a/vespalib/src/vespa/vespalib/util/atomic.cpp +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#include "atomic.h" - -namespace vespalib { - -// here are 5 operation, on unsigned 32-bit integers: -/** - * @fn void Atomic::add(volatile uint32_t *data, uint32_t xdelta) - * @brief perform atomic add instruction - * - * Atomically perform { *data += xdelta } - * @param data pointer to the integer the add should be performed on - * @param xdelta the delta to add - **/ -/** - * @fn void Atomic::sub(volatile uint32_t *data, uint32_t xdelta) - * @brief perform atomic substract instruction - * - * Atomically perform { *data -= xdelta } - * @param data pointer to the integer the subtract should be performed on - * @param xdelta the delta to subtract - **/ -/** - * @fn uint32_t Atomic::postDec(volatile uint32_t *data) - * @brief perform atomic post-decrement - * - * Atomically perform { (*data)-- } - * @param data pointer to the integer the decrement should be performed on - **/ -/** - * @fn uint32_t Atomic::postInc(volatile uint32_t *data) - * @brief perform atomic post-increment - * - * Atomically perform { (*data)++ } - * @param data pointer to the integer the increment should be performed on - **/ -/** - * @fn bool Atomic::cmpSwap(volatile uint32_t * dest, uint32_t newVal, uint32_t oldVal) - * @brief atomic compare and set - * - * Compares the current contents of the destination with oldVal; if they are - * equal, change destination to newVal. - * See http://en.wikipedia.org/wiki/Compare-and-swap for more details. - * @param dest pointer to memory that shall be compared and set - * @param newVal new value to store in dest - * @param oldVal expected old value in dest - * @return true if the swap was performed, false if the destination data had changed - **/ - - -// the rest is variants with slightly different argument types - -// signed 32-bit: - -/** - * @fn void Atomic::add(volatile int32_t *data, int32_t xdelta) - * @brief perform atomic add instruction - * - * Atomically perform { *data += xdelta } - * @param data pointer to the integer the add should be performed on - * @param xdelta the delta to add - **/ -/** - * @fn void Atomic::sub(volatile int32_t *data, int32_t xdelta) - * @brief perform atomic substract instruction - * - * Atomically perform { *data -= xdelta } - * @param data pointer to the integer the subtract should be performed on - * @param xdelta the delta to subtract - **/ -/** - * @fn int32_t Atomic::postDec(volatile int32_t *data) - * @brief perform atomic post-decrement - * - * Atomically perform { (*data)-- } - * @param data pointer to the integer the decrement should be performed on - **/ -/** - * @fn int32_t Atomic::postInc(volatile int32_t *data) - * @brief perform atomic post-increment - * - * Atomically perform { (*data)++ } - * @param data pointer to the integer the increment should be performed on - **/ -/** - * @fn bool Atomic::cmpSwap(volatile int32_t * dest, int32_t newVal, int32_t oldVal) - * @brief atomic compare and set - * @param dest pointer to memory that shall be compared and set - * @param newVal new value to store in dest - * @param oldVal expected old value in dest - * @return true if the swap was performed, false if the destination data had changed - **/ - -// unsigned 64-bit: - -/** - * @fn void Atomic::add(volatile uint64_t *data, uint64_t xdelta) - * @brief perform atomic add instruction - * - * Atomically perform { *data += xdelta } - * @param data pointer to the integer the add should be performed on - * @param xdelta the delta to add - **/ -/** - * @fn void Atomic::sub(volatile uint64_t *data, uint64_t xdelta) - * @brief perform atomic substract instruction - * - * Atomically perform { *data -= xdelta } - * @param data pointer to the integer the subtract should be performed on - * @param xdelta the delta to subtract - **/ -/** - * @fn uint64_t Atomic::postInc(volatile uint64_t *data) - * @brief perform atomic post-increment - * - * Atomically perform { (*data)++ } - * @param data pointer to the integer the increment should be performed on - * @return old value of memory location - **/ -/** - * @fn uint64_t Atomic::postDec(volatile uint64_t *data) - * @brief perform atomic post-decrement - * - * Atomically perform { (*data)-- } - * @param data pointer to the integer the decrement should be performed on - * @return old value of memory location - **/ -/** - * @fn bool Atomic::cmpSwap(volatile uint64_t * dest, uint64_t newVal, uint64_t oldVal) - * @brief atomic compare and set - * @param dest pointer to memory that shall be compared and set - * @param newVal new value to store in dest - * @param oldVal expected old value in dest - * @return true if the swap was performed, false if the destination data had changed - **/ - -// signed 64-bit: - -/** - * @fn void Atomic::add(volatile int64_t *data, int64_t xdelta) - * @brief perform atomic add instruction - * - * Atomically perform { *data += xdelta } - * @param data pointer to the integer the add should be performed on - * @param xdelta the delta to add - **/ -/** - * @fn void Atomic::sub(volatile int64_t *data, int64_t xdelta) - * @brief perform atomic substract instruction - * - * Atomically perform { *data -= xdelta } - * @param data pointer to the integer the subtract should be performed on - * @param xdelta the delta to subtract - **/ -/** - * @fn int64_t Atomic::postInc(volatile int64_t *data) - * @brief perform atomic post-increment - * - * Atomically perform { (*data)++ } - * @param data pointer to the integer the increment should be performed on - * @return old value of memory location - **/ -/** - * @fn int64_t Atomic::postDec(volatile int64_t *data) - * @brief perform atomic post-decrement - * - * Atomically perform { (*data)-- } - * @param data pointer to the integer the decrement should be performed on - * @return old value of memory location - **/ -/** - * @fn bool Atomic::cmpSwap(volatile int64_t * dest, int64_t newVal, int64_t oldVal) - * @brief atomic compare and set - * @param dest pointer to memory that shall be compared and set - * @param newVal new value to store in dest - * @param oldVal expected old value in dest - * @return true if the swap was performed, false if the destination data had changed - **/ - - - - - -// signed 128-bit: - -/** - * @fn bool Atomic::cmpSwap(volatile long long * dest, long long newVal, long long oldVal) - * @brief atomic compare and set - * @param dest pointer to memory that shall be compared and set - * @param newVal new value to store in dest - * @param oldVal expected old value in dest - * @return true if the swap was performed, false if the destination data had changed - **/ - -// pointer plus tag: -/** - * @fn bool Atomic::cmpSwap(volatile TaggedPtr * dest, TaggedPtr newVal, TaggedPtr oldVal) - * @brief atomic compare and set - * - * Compares the current contents of the destination with oldVal; if they are - * equal, change destination to newVal. Note that the entire TaggedPtr struct - * (pointer plus tag) is compared and set in one atomic opertion. - * See http://en.wikipedia.org/wiki/Compare-and-swap for more details. - * - * @param dest pointer to memory that shall be compared and set - * @param newVal new value to store in dest - * @param oldVal expected old value in dest - * @return true if the swap was performed, false if the destination data had changed - **/ -/** - * @fn bool Atomic::cmpSwap(volatile unsigned long long * dest, unsigned long long newVal, unsigned long long oldVal) - * @brief atomic compare and set - * @param dest pointer to memory that shall be compared and set - * @param newVal new value to store in dest - * @param oldVal expected old value in dest - * @return true if the swap was performed, false if the destination data had changed - **/ - - -} // end namespace diff --git a/vespalib/src/vespa/vespalib/util/atomic.h b/vespalib/src/vespa/vespalib/util/atomic.h deleted file mode 100644 index 5a89b41d274..00000000000 --- a/vespalib/src/vespa/vespalib/util/atomic.h +++ /dev/null @@ -1,468 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -// Copyright (C) 2003 Fast Search & Transfer ASA -// Copyright (C) 2003 Overture Services Norway AS - -#pragma once - -#include <sys/types.h> -#include <stdint.h> - -namespace vespalib { - -/** - * @brief Atomic instructions class - * - * To avoid mutexes around simple counters, use these functions. - * Currently only implemented for GCC on i386 and x86_64 platforms. - * To check if instructions are available, test the feature macro - * HAVE_VESPALIB_ATOMIC with \#ifdef. - **/ -class Atomic -{ -public: - /** - * @brief Pointer and tag - use instead of bare pointer for cmpSwap() - * - * When making a lock-free data structure by using cmpSwap - * on pointers, you'll often run into the "ABA problem", see - * http://en.wikipedia.org/wiki/ABA_problem for details. - * The TaggedPtr makes it easy to do the woraround with tag bits, - * but requires the double-word compare-and-swap instruction. - * Very early Amd K7/8 CPUs are lacking this and will fail (Illegal Instruction). - **/ - struct TaggedPtr - { - TaggedPtr() : _ptr(nullptr), _tag(0) { } - TaggedPtr(void * h, size_t t) : _ptr(h), _tag(t) { } - TaggedPtr(const TaggedPtr & h) : _ptr(h._ptr), _tag(h._tag) { } - TaggedPtr & operator = (const TaggedPtr & h) { if (this != &h) {_ptr = h._ptr; _tag = h._tag; }; return *this; } - - void * _ptr; - size_t _tag; - }; - static inline bool cmpSwap(volatile TaggedPtr * dest, TaggedPtr newVal, TaggedPtr oldVal); - - static inline void add(volatile uint32_t *data, uint32_t xdelta); - static inline void sub(volatile uint32_t *data, uint32_t xdelta); - static inline uint32_t postInc(volatile uint32_t *data); - static inline uint32_t postDec(volatile uint32_t *data); - static inline bool cmpSwap(volatile uint32_t * dest, uint32_t newVal, uint32_t oldVal); - - static inline int32_t postAdd(volatile int32_t *data, int32_t xdelta); - static inline void add(volatile int32_t *data, int32_t xdelta); - static inline void sub(volatile int32_t *data, int32_t xdelta); - static inline int32_t postInc(volatile int32_t *data); - static inline int32_t postDec(volatile int32_t *data); - static inline bool cmpSwap(volatile int32_t * dest, int32_t newVal, int32_t oldVal); - - static inline void add(volatile uint64_t *data, uint64_t xdelta); - static inline void sub(volatile uint64_t *data, uint64_t xdelta); - static inline uint64_t postInc(volatile uint64_t *data); - static inline uint64_t postDec(volatile uint64_t *data); - static inline bool cmpSwap(volatile uint64_t * dest, uint64_t newVal, uint64_t oldVal); - - static inline int64_t postAdd(volatile int64_t *data, int64_t xdelta); - static inline void add(volatile int64_t *data, int64_t xdelta); - static inline void sub(volatile int64_t *data, int64_t xdelta); - static inline int64_t postInc(volatile int64_t *data); - static inline int64_t postDec(volatile int64_t *data); - static inline bool cmpSwap(volatile int64_t * dest, int64_t newVal, int64_t oldVal); - -#if defined(__x86_64__) - static inline bool cmpSwap(volatile long long * dest, long long newVal, long long oldVal); - static inline bool cmpSwap(volatile unsigned long long * dest, unsigned long long newVal, unsigned long long oldVal); -#endif -}; - -#if defined(__x86_64__) - #define VESPALIB_ATOMIC_TAGGEDPTR_ALIGNMENT __attribute__ ((aligned (16))) -#else - #error "VESPALIB_ATOMIC_TAGGEDPTR_ALIGNMENT can not be defined." -#endif - -/** - * @fn void Atomic::add(volatile int32_t *data, int32_t xdelta) - * @brief perform atomic add instruction - * - * Atomically perform { *data += xdelta } - * @param data pointer to the integer the add should be performed on - * @param xdelta the delta to add - **/ - -/** - * @fn void Atomic::sub(volatile int32_t *data, int32_t xdelta) - * @brief perform atomic substract instruction - * - * Atomically perform { *data -= xdelta } - * @param data pointer to the integer the subtract should be performed on - * @param xdelta the delta to subtract - **/ - -/** - * @fn void Atomic::add(volatile uint32_t *data, uint32_t xdelta) - * @brief perform atomic add instruction - * - * Atomically perform { *data += xdelta } - * @param data pointer to the integer the add should be performed on - * @param xdelta the delta to add - **/ - -/** - * @fn void Atomic::sub(volatile uint32_t *data, uint32_t xdelta) - * @brief perform atomic substract instruction - * - * Atomically perform { *data -= xdelta } - * @param data pointer to the integer the subtract should be performed on - * @param xdelta the delta to subtract - **/ - - -/** - * @fn uint32_t Atomic::postDec(volatile uint32_t *data) - * @brief perform atomic post-decrement - * - * Atomically perform { (*data)-- } - * @param data pointer to the integer the decrement should be performed on - **/ - -/** - * @fn uint32_t Atomic::postInc(volatile uint32_t *data) - * @brief perform atomic post-increment - * - * Atomically perform { (*data)++ } - * @param data pointer to the integer the increment should be performed on - **/ - -#if defined(__x86_64__) - -#define HAVE_VESPALIB_ATOMIC - -inline int32_t -Atomic::postAdd(volatile int32_t *data, int32_t xdelta) -{ - __asm__("lock ; xaddl %0,%1" - : "+r" (xdelta), - "+m" (*data) - : : "memory"); - return xdelta; -} - -inline void -Atomic::add(volatile int32_t *data, int32_t xdelta) -{ - __asm__("lock ; addl %1,%0" - : "=m" (*data) - : "ir" (xdelta), "m" (*data)); -} - -inline void -Atomic::add(volatile uint32_t *data, uint32_t xdelta) -{ - __asm__("lock ; addl %1,%0" - : "=m" (*data) - : "ir" (xdelta), "m" (*data)); -} - -inline void -Atomic::sub(volatile int32_t *data, int32_t xdelta) -{ - __asm__("lock ; subl %1,%0" - : "=m" (*data) - : "ir" (xdelta), "m" (*data)); -} - -inline void -Atomic::sub(volatile uint32_t *data, uint32_t xdelta) -{ - __asm__("lock ; subl %1,%0" - : "=m" (*data) - : "ir" (xdelta), "m" (*data)); -} - - -inline int -Atomic::postDec(volatile int32_t *data) -{ - int32_t result; - - __asm__("lock ; xaddl %0, %1" - : "=r" (result), "=m" (*data) : "0" (-1), "m" (*data)); - return result; -} - -inline uint32_t -Atomic::postDec(volatile uint32_t *data) -{ - int32_t result; - - __asm__("lock ; xaddl %0, %1" - : "=r" (result), "=m" (*data) : "0" (-1), "m" (*data)); - return result; -} - -inline int -Atomic::postInc(volatile int32_t *data) -{ - int32_t result; - - __asm__("lock ; xaddl %0, %1" - : "=r" (result), "=m" (*data) : "0" (1), "m" (*data)); - return result; -} - -inline uint32_t -Atomic::postInc(volatile uint32_t *data) -{ - int32_t result; - - __asm__("lock ; xaddl %0, %1" - : "=r" (result), "=m" (*data) : "0" (1), "m" (*data)); - return result; -} - -inline bool -Atomic::cmpSwap(volatile int32_t * dest, int32_t newVal, int32_t oldVal) -{ - char result; - __asm__ __volatile__("lock; cmpxchgl %2, %0;" - "setz %1" - : "+m"(*dest), "=q"(result) - : "r" (newVal), "a"(oldVal) : "memory"); - return result; -} - -inline bool -Atomic::cmpSwap(volatile uint32_t * dest, uint32_t newVal, uint32_t oldVal) -{ - char result; - __asm__ __volatile__("lock; cmpxchgl %2, %0;" - "setz %1" - : "+m"(*dest), "=q"(result) - : "r" (newVal), "a"(oldVal) : "memory"); - return result; -} - -inline int64_t -Atomic::postAdd(volatile int64_t *data, int64_t xdelta) -{ - __asm__("lock ; xaddq %0,%1" - : "+r" (xdelta), - "+m" (*data) - : : "memory"); - return xdelta; -} - -inline void -Atomic::add(volatile int64_t *data, int64_t xdelta) -{ - __asm__("lock ; addq %1,%0" - : "=m" (*data) - : "ir" (xdelta), "m" (*data)); -} - -inline void -Atomic::add(volatile uint64_t *data, uint64_t xdelta) -{ - __asm__("lock ; addq %1,%0" - : "=m" (*data) - : "ir" (xdelta), "m" (*data)); -} - -inline void -Atomic::sub(volatile int64_t *data, int64_t xdelta) -{ - __asm__("lock ; subq %1,%0" - : "=m" (*data) - : "ir" (xdelta), "m" (*data)); -} - -inline void -Atomic::sub(volatile uint64_t *data, uint64_t xdelta) -{ - __asm__("lock ; subq %1,%0" - : "=m" (*data) - : "ir" (xdelta), "m" (*data)); -} - - -inline int64_t -Atomic::postDec(volatile int64_t *data) -{ - int64_t result; - - __asm__("lock ; xaddq %0, %1" - : "=r" (result), "=m" (*data) : "0" (int64_t(-1)), "m" (*data)); - return result; -} - -inline uint64_t -Atomic::postDec(volatile uint64_t *data) -{ - uint64_t result; - -#if defined(__i386__) - do { - result = *data; - } while(!cmpSwap(data, result-1, result)); -#else - __asm__("lock ; xaddq %0, %1" - : "=r" (result), "=m" (*data) : "0" (uint64_t(-1)), "m" (*data)); -#endif - return result; -} - -inline int64_t -Atomic::postInc(volatile int64_t *data) -{ - int64_t result; - -#if defined(__i386__) - do { - result = *data; - } while(!cmpSwap(data, result+1, result)); -#else - __asm__("lock ; xaddq %0, %1" - : "=r" (result), "=m" (*data) : "0" (1), "m" (*data)); -#endif - return result; -} - -inline uint64_t -Atomic::postInc(volatile uint64_t *data) -{ - uint64_t result; - -#if defined(__i386__) - do { - result = *data; - } while(!cmpSwap(data, result+1, result)); -#else - __asm__("lock ; xaddq %0, %1" - : "=r" (result), "=m" (*data) : "0" (1), "m" (*data)); -#endif - return result; -} - -inline bool -Atomic::cmpSwap(volatile uint64_t * dest, uint64_t newVal, uint64_t oldVal) { - bool result; - __asm__ __volatile__("lock; cmpxchgq %3, %0;" - "setz %1" - : "+m"(*dest), "=q"(result), "+a"(oldVal) - : "r" (newVal) - : "memory", "cc"); - return result; -} - -inline bool -Atomic::cmpSwap(volatile int64_t * dest, int64_t newVal, int64_t oldVal) -{ - return cmpSwap((volatile uint64_t *) dest, newVal, oldVal); -} - -#if defined(__x86_64__) -inline bool -Atomic::cmpSwap(volatile unsigned long long * dest, unsigned long long newVal, unsigned long long oldVal) -{ - char result; - unsigned long long res; - union pair { - uint64_t v64[2]; - unsigned long long v128; - }; - pair nv; - nv.v128 = newVal; - __asm__ volatile ( - "lock ;" - "cmpxchg16b %6;" - "setz %2;" - : "=A" (res), - "=m" (*dest), - "=q" (result) - : "0" (oldVal), - "b" (nv.v64[0]), - "c" (nv.v64[1]), - "m" (*dest) - : "memory" - ); - return result; -} - -inline bool -Atomic::cmpSwap(volatile long long * dest, long long newVal, long long oldVal) -{ - return cmpSwap((volatile unsigned long long *) dest, newVal, oldVal); -} - -#endif - -inline bool -Atomic::cmpSwap(volatile TaggedPtr * dest, TaggedPtr newVal, TaggedPtr oldVal) -{ - char result; - void * ptr; - size_t tag; -#if defined(__x86_64__) - __asm__ volatile ( - "lock ;" - "cmpxchg16b %8;" - "setz %1;" - : "=m" (*dest), - "=q" (result), - "=a" (ptr), - "=d" (tag) - : "a" (oldVal._ptr), - "d" (oldVal._tag), - "b" (newVal._ptr), - "c" (newVal._tag), - "m" (*dest) - : "memory" - ); -#else -#ifdef __pic__ - __asm__ volatile ( - "pushl %%ebx;" - "movl %6, %%ebx;" - "lock ;" - "cmpxchg8b %8;" - "setz %1;" - "popl %%ebx;" - : "=m" (*dest), - "=q" (result), - "=a" (ptr), - "=d" (tag) - : "2" (oldVal._ptr), - "3" (oldVal._tag), - "m" (newVal._ptr), - "c" (newVal._tag), - "m" (*dest) - : "memory" - ); -#else - __asm__ volatile ( - "lock ;" - "cmpxchg8b %8;" - "setz %1;" - : "=m" (*dest), - "=q" (result), - "=a" (ptr), - "=d" (tag) - : "a" (oldVal._ptr), - "d" (oldVal._tag), - "b" (newVal._ptr), - "c" (newVal._tag), - "m" (*dest) - : "memory" - ); -#endif - -#endif - - return result; -} -#else - #error "Atomic methods has not been defined for this platform." -#endif // #ifdef __x86_64__ - -} // namespace vespalib - diff --git a/vespalib/src/vespa/vespalib/util/overview.h b/vespalib/src/vespa/vespalib/util/overview.h index 8c1cf2daf70..7fc48e2f19e 100644 --- a/vespalib/src/vespa/vespalib/util/overview.h +++ b/vespalib/src/vespa/vespalib/util/overview.h @@ -33,20 +33,17 @@ * <BR> vespalib::RWLockReader * <BR> vespalib::RWLockWriter * - * Reference counting and atomic operations + * Reference counting * - * vespalib::Atomic * <BR> vespalib::ReferenceCounter * * Simple smart pointers (deprecated) * - * \ref vespalib::SharedPtr<T> * <BR> \ref vespalib::LinkedPtr<T> * * Advanced pointer utilities * * \ref vespalib::PtrHolder<T> - * <BR> \ref vespalib::WeakRef<T> * * Simple hashmap * diff --git a/vespalib/src/vespa/vespalib/util/ptrholder.h b/vespalib/src/vespa/vespalib/util/ptrholder.h index 7f2f413a00b..7a1ef8b0ccd 100644 --- a/vespalib/src/vespa/vespalib/util/ptrholder.h +++ b/vespalib/src/vespa/vespalib/util/ptrholder.h @@ -6,7 +6,6 @@ #include <algorithm> #include <memory> #include <vespa/vespalib/util/sync.h> -#include <vespa/vespalib/util/atomic.h> namespace vespalib { diff --git a/vespalib/src/vespa/vespalib/util/referencecounter.h b/vespalib/src/vespa/vespalib/util/referencecounter.h index cd704a37613..63353d51cf8 100644 --- a/vespalib/src/vespa/vespalib/util/referencecounter.h +++ b/vespalib/src/vespa/vespalib/util/referencecounter.h @@ -8,8 +8,8 @@ #pragma once -#include <vespa/vespalib/util/atomic.h> -#include <assert.h> +#include <atomic> +#include <cassert> namespace vespalib { @@ -28,7 +28,7 @@ public: /** * @brief Constructor. The object will initially have 1 reference. **/ - ReferenceCounter() : _refs(1) {}; + ReferenceCounter() : _refs(1) {} /** * @brief Add an owner of this object. @@ -36,7 +36,7 @@ public: * When the owner is finished with the * object, call subRef(). **/ - void addRef() { vespalib::Atomic::postInc(&_refs); }; + void addRef() { _refs.fetch_add(1); } /** * @brief Remove an owner of this object. @@ -44,8 +44,7 @@ public: * If that was the last owner, delete the object. **/ void subRef() { - unsigned oldVal = vespalib::Atomic::postDec(&_refs); - if (oldVal == 1) { + if (_refs.fetch_sub(1) == 1) { delete this; } } @@ -56,7 +55,7 @@ protected: **/ virtual ~ReferenceCounter() { assert (_refs == 0); }; private: - volatile unsigned _refs; + std::atomic<unsigned> _refs; }; } // namespace vespalib diff --git a/vespalib/src/vespa/vespalib/util/weakref.h b/vespalib/src/vespa/vespalib/util/weakref.h deleted file mode 100644 index 4bcc8a8e0fb..00000000000 --- a/vespalib/src/vespa/vespalib/util/weakref.h +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -// Copyright (C) 2005 Overture Services Norway AS - -#pragma once - -#include <algorithm> -#include <vespa/vespalib/util/sync.h> -#include <vespa/vespalib/util/atomic.h> - -namespace vespalib { - -/** - * @brief A WeakRef is a pointer to an object that may disappear - * - * The object pointer is owned by a WeakRef::Owner. The owner can - * decide to remove the pointer at any time, but not while it is being - * used. To signal that a WeakRef is being used, you need to create a - * WeakRef::Usage. This will ensure that the pointer is not removed - * until you are done using it. - **/ -template <typename T> -class WeakRef -{ -public: - class Usage; - friend class WeakRef::Usage; -private: - struct Core { - Monitor monitor; - uint32_t refcnt; - uint32_t usecnt; - bool dead; - T *pt; - - Core(T *p) : monitor("WeakRef::Core", true), - refcnt(1), usecnt(0), dead(false), pt(p) {} - ~Core() { - assert(refcnt == 0); - assert(usecnt == 0); - assert(dead); - assert(pt == 0); - } - - Core *getRef() { - Atomic::postInc(&refcnt); - return this; - } - - void dropRef() { - if (Atomic::postDec(&refcnt) != 1) { - return; - } - delete this; - } - - Core *getUse() { - MonitorGuard mon(monitor); - if (dead) { - return 0; - } - ++usecnt; - return getRef(); - } - - void dropUse() { - { - MonitorGuard mon(monitor); - --usecnt; - if (dead && usecnt == 0) { - mon.signal(); - } - } - dropRef(); - } - - void kill() { - { - MonitorGuard mon(monitor); - dead = true; - while (usecnt != 0) { - mon.wait(); - } - pt = 0; - } - dropRef(); - } - - private: - Core(const Core &); - Core &operator=(const Core &); - }; - -public: - /** - * @brief A WeakRef::Owner owns the object pointer used by WeakRef - * instances. - **/ - class Owner { - friend class WeakRef; - - private: - Core *_core; - Owner(const Owner &); - Owner &operator=(const Owner &); - - Core *getRef() const { return (_core != 0) ? _core->getRef() : 0; } - - public: - /** - * @brief Create an owner with the given pointer - * - * @param pt object pointer - **/ - Owner(T *pt) : _core(new Core(pt)) {} - - /** - * @brief Remove the object pointer - * - * This method will block until all current usage of the - * object pointer is complete (All WeakRef::Usage instances - * created from WeakRef instances based on this WeakRef::Owner - * has been destructed). Any further usage of the object - * pointer will be denied. - **/ - void clear() { - if (_core != 0) { - _core->kill(); - _core = 0; - } - } - - /** - * @brief Remove the object pointer if it is not yet removed - * - * Note that if you use an embedded owner to point to the - * embedding object, you should invoke the clear method at an - * earlier stage in the destruction process of the embedding - * object to avoid a weak reference to a half-destructed - * object. - **/ - ~Owner() { clear(); } - }; - - /** - * @brief A WeakRef::Usage signals that a WeakRef is in use - **/ - class Usage { - private: - Core *_core; - Usage(const Usage &); - Usage &operator=(const Usage &); - - public: - /** - * @brief Start using the given WeakRef - * - * @param rhs the WeakRef you want to use - **/ - Usage(const WeakRef &rhs) : _core(rhs.getUse()) {} - - /** - * @brief Stop using the underlying WeakRef - * - * This will signal that the WeakRef given in the constructor - * is no longer in use. - **/ - ~Usage() { - if (_core != 0) { - _core->dropUse(); - } - } - - /** - * @brief Check if the object pointer is valid - * - * This method will return false if we try to use a WeakRef - * after the WeakRef::Owner has cleared the object pointer. If - * this method returns true, the object pointer will not - * become invalid while this object is alive. - * - * @return true if the object pointer is still valid - **/ - bool valid() const { return (_core != 0); } - - /** - * @brief Access the weakly referenced object - * - * This is the preferred way to access the weakly referenced - * object as it makes the usage object act as a smart pointer. - * - * @return object pointer - **/ - T *operator->() const { return _core->pt; } - - /** - * @brief Obtain the weakly referenced object - * - * @return object pointer - **/ - T *get() const { return _core->pt; } - }; - -private: - Core *_core; - - Core *getRef() const { return (_core != 0) ? _core->getRef() : 0; } - Core *getUse() const { return (_core != 0) ? _core->getUse() : 0; } - -public: - /** - * @brief Create a WeakRef not pointing to anything - **/ - WeakRef() : _core(0) {} - - /** - * @brief Copy constructor - * - * This will result in a WeakRef pointing to the same object as - * <i>rhs</i> - * - * @param rhs copy this - **/ - WeakRef(const WeakRef &rhs) : _core(rhs.getRef()) {} - - /** - * @brief Create a WeakRef based on the given WeakRef::Owner - * - * This WeakRef will point to the object dictated by rhs - * - * @param rhs pointer owner - **/ - WeakRef(const WeakRef::Owner &rhs) : _core(rhs.getRef()) {} - - /** - * @brief Assignment operator - * - * This is implemented as a copy-swap-delete operation. - * - * @return reference to this - * @param rhs copy this - **/ - WeakRef &operator=(const WeakRef &rhs) { - WeakRef tmp(rhs); - std::swap(tmp._core, _core); - return *this; - } - - /** - * @brief Perform internal cleanup. - **/ - ~WeakRef() { - if (_core != 0) { - _core->dropRef(); - } - } -}; - -} // namespace vespalib - |