diff options
44 files changed, 77 insertions, 1687 deletions
diff --git a/config/src/vespa/config/common/configmanager.cpp b/config/src/vespa/config/common/configmanager.cpp index a123a1aab1a..2fa40b503df 100644 --- a/config/src/vespa/config/common/configmanager.cpp +++ b/config/src/vespa/config/common/configmanager.cpp @@ -2,7 +2,6 @@ #include "configmanager.h" #include "exceptions.h" #include "configholder.h" -#include <vespa/vespalib/util/atomic.h> #include <thread> #include <sstream> @@ -30,7 +29,7 @@ ConfigManager::subscribe(const ConfigKey & key, uint64_t timeoutInMillis) { LOG(debug, "subscribing on def %s, configid %s", key.getDefName().c_str(), key.getConfigId().c_str()); - SubscriptionId id(vespalib::Atomic::postInc(&_idGenerator)); + SubscriptionId id(_idGenerator.fetch_add(1)); IConfigHolder::SP holder(new ConfigHolder()); Source::UP source = _sourceFactory->createSource(holder, key); diff --git a/config/src/vespa/config/common/configmanager.h b/config/src/vespa/config/common/configmanager.h index 06ed2d617f7..740445292fe 100644 --- a/config/src/vespa/config/common/configmanager.h +++ b/config/src/vespa/config/common/configmanager.h @@ -34,7 +34,7 @@ public: void reload(int64_t generation) override; private: - SubscriptionId _idGenerator; + std::atomic<SubscriptionId> _idGenerator; SourceFactory::UP _sourceFactory; int64_t _generation; diff --git a/config/src/vespa/config/frt/connection.h b/config/src/vespa/config/frt/connection.h index 3b3e6cd53ff..a5fad5a7ff5 100644 --- a/config/src/vespa/config/frt/connection.h +++ b/config/src/vespa/config/frt/connection.h @@ -1,6 +1,7 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #pragma once +#include <vespa/vespalib/stllike/string.h> class FRT_RPCRequest; class FRT_IRequestWait; diff --git a/config/src/vespa/config/frt/frtconnection.cpp b/config/src/vespa/config/frt/frtconnection.cpp index 3503c95ba61..bcdec9a4537 100644 --- a/config/src/vespa/config/frt/frtconnection.cpp +++ b/config/src/vespa/config/frt/frtconnection.cpp @@ -1,6 +1,5 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "frtconnection.h" -#include <vespa/vespalib/util/atomic.h> #include <vespa/config/common/errorcode.h> #include <vespa/fnet/frt/supervisor.h> #include <vespa/fnet/frt/target.h> @@ -88,7 +87,7 @@ void FRTConnection::calculateSuspension(ErrorType type) int64_t delay = 0; switch(type) { case TRANSIENT: - Atomic::postInc(&_transientFailures); + _transientFailures.fetch_add(1); delay = _transientFailures * getTransientDelay(); if (delay > getMaxTransientDelay()) { delay = getMaxTransientDelay(); @@ -96,7 +95,7 @@ void FRTConnection::calculateSuspension(ErrorType type) LOG(warning, "Connection to %s failed or timed out", _address.c_str()); break; case FATAL: - Atomic::postInc(&_fatalFailures); + _fatalFailures.fetch_add(1); delay = _fatalFailures * getFatalDelay(); if (delay > getMaxFatalDelay()) { delay = getMaxFatalDelay(); diff --git a/config/src/vespa/config/frt/frtconnection.h b/config/src/vespa/config/frt/frtconnection.h index 06f05200252..df57cfae92f 100644 --- a/config/src/vespa/config/frt/frtconnection.h +++ b/config/src/vespa/config/frt/frtconnection.h @@ -1,11 +1,10 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #pragma once -#include <string> +#include "connection.h" #include <vespa/vespalib/util/sync.h> -#include <vespa/vespalib/stllike/string.h> #include <vespa/config/common/timingvalues.h> -#include "connection.h" +#include <atomic> class FRT_Supervisor; class FRT_Target; @@ -23,8 +22,8 @@ private: FRT_Target* _target; int64_t _suspendedUntil; int64_t _suspendWarned; - int _transientFailures; - int _fatalFailures; + std::atomic<int> _transientFailures; + std::atomic<int> _fatalFailures; int64_t _transientDelay; int64_t _fatalDelay; diff --git a/fnet/src/vespa/fnet/frt/rpcrequest.cpp b/fnet/src/vespa/fnet/frt/rpcrequest.cpp index 6243f405639..9553a967413 100644 --- a/fnet/src/vespa/fnet/frt/rpcrequest.cpp +++ b/fnet/src/vespa/fnet/frt/rpcrequest.cpp @@ -129,7 +129,7 @@ void FRT_RPCRequest::SubRef() { assert(_refcnt > 0); - if (vespalib::Atomic::postDec(&_refcnt) == 1) { + if (_refcnt.fetch_sub(1) == 1) { Reset(); delete this; } @@ -162,7 +162,7 @@ FRT_RPCRequest::CreateRequestPacket(bool wantReply) flags |= FLAG_FRT_RPC_LITTLE_ENDIAN; if (wantReply) - AddRef_NoLock(); + AddRef(); else flags |= FLAG_FRT_RPC_NOREPLY; diff --git a/fnet/src/vespa/fnet/frt/rpcrequest.h b/fnet/src/vespa/fnet/frt/rpcrequest.h index 1b636bd9607..a10653ce2f6 100644 --- a/fnet/src/vespa/fnet/frt/rpcrequest.h +++ b/fnet/src/vespa/fnet/frt/rpcrequest.h @@ -5,8 +5,7 @@ #include "values.h" #include "error.h" #include <vespa/fnet/context.h> - -#include <vespa/vespalib/util/atomic.h> +#include <atomic> class FNETConnection; class FNET_Packet; @@ -55,17 +54,17 @@ class FRT_RPCRequest { private: using Stash = vespalib::Stash; - Stash _stash; - FNET_Context _context; - FRT_Values _params; - FRT_Values _return; - int _refcnt; - int _completed; - uint32_t _errorCode; - uint32_t _errorMessageLen; - uint32_t _methodNameLen; - char *_errorMessage; - char *_methodName; + Stash _stash; + FNET_Context _context; + FRT_Values _params; + FRT_Values _return; + std::atomic<int> _refcnt; + std::atomic<int> _completed; + uint32_t _errorCode; + uint32_t _errorMessageLen; + uint32_t _methodNameLen; + char *_errorMessage; + char *_methodName; bool *_detachedPT; FRT_IAbortHandler *_abortHandler; @@ -87,8 +86,7 @@ public: _return.DiscardBlobs(); } - void AddRef_NoLock() { _refcnt++; } // be very carefull - void AddRef() { vespalib::Atomic::postInc(&_refcnt); } + void AddRef() { _refcnt.fetch_add(1); } void SubRef(); void SetContext(FNET_Context context) { _context = context; } @@ -110,7 +108,7 @@ public: return (spec != nullptr) ? spec : ""; } - bool GetCompletionToken() { return (vespalib::Atomic::postInc(&_completed) == 0); } + bool GetCompletionToken() { return (_completed.fetch_add(1) == 0); } void SetError(uint32_t errorCode, const char *errorMessage, uint32_t errorMessageLen); void SetError(uint32_t errorCode, const char *errorMessage); diff --git a/fnet/src/vespa/fnet/frt/target.h b/fnet/src/vespa/fnet/frt/target.h index d8a2eaafa76..00834417122 100644 --- a/fnet/src/vespa/fnet/frt/target.h +++ b/fnet/src/vespa/fnet/frt/target.h @@ -2,8 +2,8 @@ #pragma once -#include <vespa/vespalib/util/atomic.h> #include <vespa/fnet/connection.h> +#include <atomic> class FNET_Scheduler; class FRT_RPCRequest; @@ -12,7 +12,7 @@ class FRT_IRequestWait; class FRT_Target { private: - int _refcnt; + std::atomic<int> _refcnt; FNET_Scheduler *_scheduler; FNET_Connection *_conn; @@ -29,17 +29,16 @@ public: FNET_Connection *GetConnection() const { return _conn; } - void AddRef() { vespalib::Atomic::postInc(&_refcnt); } + void AddRef() { _refcnt++; } void SubRef() { - if (vespalib::Atomic::postDec(&_refcnt) == 1) { + if (_refcnt.fetch_sub(1) == 1) { delete this; } } int GetRefCnt() const { return _refcnt; } - bool IsValid() - { + bool IsValid() { return ((_conn != nullptr) && (_conn->GetState() <= FNET_Connection::FNET_CONNECTED)); } diff --git a/messagebus/src/vespa/messagebus/dynamicthrottlepolicy.cpp b/messagebus/src/vespa/messagebus/dynamicthrottlepolicy.cpp index 3588e5aad40..55720f7d6ca 100644 --- a/messagebus/src/vespa/messagebus/dynamicthrottlepolicy.cpp +++ b/messagebus/src/vespa/messagebus/dynamicthrottlepolicy.cpp @@ -1,5 +1,4 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/util/atomic.h> #include "dynamicthrottlepolicy.h" #include "systemtimer.h" #include <climits> diff --git a/messagebus/src/vespa/messagebus/routing/routingnode.cpp b/messagebus/src/vespa/messagebus/routing/routingnode.cpp index 0f24b47cb94..62efda4aeb9 100644 --- a/messagebus/src/vespa/messagebus/routing/routingnode.cpp +++ b/messagebus/src/vespa/messagebus/routing/routingnode.cpp @@ -7,7 +7,6 @@ #include <vespa/messagebus/emptyreply.h> #include <vespa/messagebus/errorcode.h> #include <vespa/messagebus/tracelevel.h> -#include <vespa/vespalib/util/atomic.h> #include <vespa/vespalib/util/stringfmt.h> #include <vespa/messagebus/network/inetwork.h> #include <stack> @@ -268,7 +267,7 @@ RoutingNode::notifySender() void RoutingNode::notifyMerge() { - if (vespalib::Atomic::postDec(&_pending) > 1) { + if (_pending.fetch_sub(1) > 1) { return; } diff --git a/messagebus/src/vespa/messagebus/routing/routingnode.h b/messagebus/src/vespa/messagebus/routing/routingnode.h index 32fa51881e3..22ff07c26e5 100644 --- a/messagebus/src/vespa/messagebus/routing/routingnode.h +++ b/messagebus/src/vespa/messagebus/routing/routingnode.h @@ -1,21 +1,20 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #pragma once -#include <map> +#include "iroutingpolicy.h" +#include "resender.h" +#include "route.h" +#include "routingcontext.h" +#include "routingnodeiterator.h" #include <vespa/messagebus/idiscardhandler.h> #include <vespa/messagebus/ireplyhandler.h> #include <vespa/messagebus/message.h> #include <vespa/messagebus/messagebus.h> #include <vespa/messagebus/network/iserviceaddress.h> #include <vespa/messagebus/reply.h> -#include <string> -#include <vector> #include <vespa/vespalib/util/sync.h> -#include "iroutingpolicy.h" -#include "resender.h" -#include "route.h" -#include "routingcontext.h" -#include "routingnodeiterator.h" +#include <vector> +#include <map> namespace mbus { @@ -40,7 +39,7 @@ private: IReplyHandler *_replyHandler; IDiscardHandler *_discardHandler; Trace _trace; - volatile uint32_t _pending; + std::atomic<uint32_t> _pending; Message &_msg; Reply::UP _reply; Route _route; diff --git a/persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp b/persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp index 848ac783725..0aec6877367 100644 --- a/persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp +++ b/persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp @@ -9,18 +9,15 @@ #include <vespa/document/fieldset/fieldsetrepo.h> #include <vespa/vespalib/stllike/asciistream.h> #include <vespa/vespalib/util/exceptions.h> -#include <vespa/vespalib/util/atomic.h> #include <vespa/vespalib/stllike/hash_map.hpp> -#include <vespa/log/log.h> using std::binary_search; using std::lower_bound; +#include <vespa/log/log.h> LOG_SETUP(".dummypersistence"); -namespace storage { -namespace spi { -namespace dummy { +namespace storage::spi::dummy { BucketContent::BucketContent() : _entries(), @@ -933,7 +930,8 @@ DummyPersistence::acquireBucketWithLock(const Bucket& b) const // Atomic CAS might be a bit overkill, but since we "release" the bucket // outside of the mutex, we want to ensure the write is visible across all // threads. - bool bucketNotInUse(vespalib::Atomic::cmpSwap(&it->second->_inUse, 1, 0)); + bool my_true(true); + bool bucketNotInUse(it->second->_inUse.compare_exchange_strong(my_true, false)); if (!bucketNotInUse) { LOG(error, "Attempted to acquire %s, but it was already marked as being in use!", b.toString().c_str()); @@ -946,13 +944,12 @@ DummyPersistence::acquireBucketWithLock(const Bucket& b) const void DummyPersistence::releaseBucketNoLock(const BucketContent& bc) const { - bool bucketInUse(vespalib::Atomic::cmpSwap(&bc._inUse, 0, 1)); + bool my_false(false); + bool bucketInUse(bc._inUse.compare_exchange_strong(my_false, true)); assert(bucketInUse); (void) bucketInUse; } -} // dummy -} // spi -} // storage +} VESPALIB_HASH_MAP_INSTANTIATE_H(storage::spi::Bucket, std::shared_ptr<storage::spi::dummy::BucketContent>, document::BucketId::hash) diff --git a/persistence/src/vespa/persistence/dummyimpl/dummypersistence.h b/persistence/src/vespa/persistence/dummyimpl/dummypersistence.h index bd1059d5617..0e2821036ea 100644 --- a/persistence/src/vespa/persistence/dummyimpl/dummypersistence.h +++ b/persistence/src/vespa/persistence/dummyimpl/dummypersistence.h @@ -14,17 +14,14 @@ #include <vespa/document/fieldset/fieldsets.h> #include <vespa/vespalib/util/sync.h> #include <vespa/vespalib/stllike/hash_map.h> +#include <atomic> namespace document { class FieldSet; - namespace select { - class Node; - } + namespace select { class Node; } } -namespace storage { -namespace spi { -namespace dummy { +namespace storage::spi::dummy { struct BucketEntry { @@ -49,7 +46,7 @@ struct BucketContent { std::vector<BucketEntry> _entries; GidMapType _gidMap; mutable BucketInfo _info; - mutable uint32_t _inUse; + mutable std::atomic<bool> _inUse; mutable bool _outdatedInfo; bool _active; @@ -234,6 +231,4 @@ private: mutable BucketIdListResult::List _modifiedBuckets; }; -} // dummy -} // spi -} // storage +} diff --git a/searchcore/src/vespa/searchcore/proton/common/feedtoken.cpp b/searchcore/src/vespa/searchcore/proton/common/feedtoken.cpp index 1e5dc1becf8..be9e2e823a0 100644 --- a/searchcore/src/vespa/searchcore/proton/common/feedtoken.cpp +++ b/searchcore/src/vespa/searchcore/proton/common/feedtoken.cpp @@ -1,7 +1,6 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "feedtoken.h" -#include <vespa/vespalib/util/atomic.h> #include <vespa/searchcore/proton/metrics/feed_metrics.h> namespace proton { diff --git a/searchcore/src/vespa/searchcore/proton/server/rpc_hooks.h b/searchcore/src/vespa/searchcore/proton/server/rpc_hooks.h index b69c6407a0b..ab64c511310 100644 --- a/searchcore/src/vespa/searchcore/proton/server/rpc_hooks.h +++ b/searchcore/src/vespa/searchcore/proton/server/rpc_hooks.h @@ -3,7 +3,6 @@ #pragma once #include <vespa/slobrok/sbregister.h> -#include <vespa/vespalib/util/atomic.h> #include <vespa/vespalib/util/executor.h> #include <vespa/vespalib/util/closure.h> #include <vespa/vespalib/stllike/string.h> diff --git a/searchlib/src/vespa/searchlib/docstore/documentstore.cpp b/searchlib/src/vespa/searchlib/docstore/documentstore.cpp index d07d4658f1f..a13fffdaa24 100644 --- a/searchlib/src/vespa/searchlib/docstore/documentstore.cpp +++ b/searchlib/src/vespa/searchlib/docstore/documentstore.cpp @@ -232,7 +232,7 @@ DocumentStore::read(DocumentIdT lid, const DocumentTypeRepo &repo) const if (useCache()) { value = _cache->read(lid); } else { - vespalib::Atomic::add(&_uncached_lookups, 1UL); + _uncached_lookups.fetch_add(1); _store->read(lid, value); } if ( ! value.empty() ) { diff --git a/searchlib/src/vespa/searchlib/docstore/documentstore.h b/searchlib/src/vespa/searchlib/docstore/documentstore.h index 632e6e266f8..45dfcb35e37 100644 --- a/searchlib/src/vespa/searchlib/docstore/documentstore.h +++ b/searchlib/src/vespa/searchlib/docstore/documentstore.h @@ -110,8 +110,7 @@ private: std::unique_ptr<BackingStore> _store; std::shared_ptr<Cache> _cache; std::shared_ptr<VisitCache> _visitCache; - mutable volatile uint64_t _uncached_lookups; + mutable std::atomic<uint64_t> _uncached_lookups; }; } // namespace search - diff --git a/searchlib/src/vespa/searchlib/engine/transportserver.h b/searchlib/src/vespa/searchlib/engine/transportserver.h index e52134b78e9..76fba4e96fc 100644 --- a/searchlib/src/vespa/searchlib/engine/transportserver.h +++ b/searchlib/src/vespa/searchlib/engine/transportserver.h @@ -4,7 +4,6 @@ #include "transport_metrics.h" #include "source_description.h" -#include <vespa/vespalib/util/atomic.h> #include <vespa/fnet/iserveradapter.h> #include <vespa/fnet/ipackethandler.h> #include <vespa/fnet/task.h> diff --git a/staging_vespalib/src/vespa/vespalib/stllike/cache.h b/staging_vespalib/src/vespa/vespalib/stllike/cache.h index daee7ad7194..832e6ede43d 100644 --- a/staging_vespalib/src/vespa/vespalib/stllike/cache.h +++ b/staging_vespalib/src/vespa/vespalib/stllike/cache.h @@ -3,7 +3,7 @@ #include <vespa/vespalib/stllike/lrucache_map.h> #include <vespa/vespalib/util/sync.h> -#include <vespa/vespalib/util/atomic.h> +#include <atomic> namespace vespalib { @@ -142,7 +142,7 @@ private: size_t _sizeBytes; mutable size_t _hit; mutable size_t _miss; - mutable size_t _noneExisting; + std::atomic<size_t> _noneExisting; mutable size_t _race; mutable size_t _insert; mutable size_t _write; diff --git a/staging_vespalib/src/vespa/vespalib/stllike/cache.hpp b/staging_vespalib/src/vespa/vespalib/stllike/cache.hpp index 46edf740993..06e7e249ec6 100644 --- a/staging_vespalib/src/vespa/vespalib/stllike/cache.hpp +++ b/staging_vespalib/src/vespa/vespalib/stllike/cache.hpp @@ -106,7 +106,7 @@ cache<P>::read(const K & key) _sizeBytes += calcSize(key, value); _insert++; } else { - vespalib::Atomic::postInc(&_noneExisting); + _noneExisting.fetch_add(1); } return value; } 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 - diff --git a/vespamalloc/src/tests/test1/testatomic.cpp b/vespamalloc/src/tests/test1/testatomic.cpp index 448b0776f1a..818af5fe673 100644 --- a/vespamalloc/src/tests/test1/testatomic.cpp +++ b/vespamalloc/src/tests/test1/testatomic.cpp @@ -1,106 +1,8 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/fastos/thread.h> #include <vespa/vespalib/testkit/testapp.h> -#include <vespa/vespalib/util/atomic.h> #include <vespamalloc/malloc/allocchunk.h> -class Test : public vespalib::TestApp -{ -public: - int Main() override; -private: - template<typename T> - void testSwap(T initial); - template<typename T> - void testSwapStress(T v, int numThreads); -}; - -template <typename T> -class Stress : public FastOS_Runnable -{ -private: - void Run(FastOS_ThreadInterface * ti, void * arg) override; - void stressSwap(T & value); -public: - Stress(T * value) : _value(value), _successCount(0), _failedCount(0) { } - void wait() { _wait.Lock(); _wait.Unlock(); } - FastOS_Mutex _wait; - T * _value; - size_t _successCount; - size_t _failedCount; -}; - -TEST_APPHOOK(Test); - -template<typename T> -void Test::testSwap(T initial) -{ - T value(initial); - - ASSERT_TRUE(vespalib::Atomic::cmpSwap(&value, initial+1, initial)); - ASSERT_TRUE(value == initial+1); - - ASSERT_TRUE(!vespalib::Atomic::cmpSwap(&value, initial+2, initial)); - ASSERT_TRUE(value == initial+1); -} - -template<typename T> -void Test::testSwapStress(T v, int numThreads) -{ - T old(v); - std::vector<Stress<T> *> contexts; - std::vector<FastOS_ThreadInterface *> threads; - FastOS_ThreadPool threadPool(512*1024); - - for(int i=0; i < numThreads; i++) { - contexts.push_back(new Stress<T>(&v)); - } - - for(size_t i = 0; i < contexts.size(); i++) { - threads.push_back(threadPool.NewThread(contexts[i])); - } - FastOS_Thread::Sleep(1000); - size_t succesCount(0); - size_t failedCount(0); - for(size_t i = 0; i < contexts.size(); i++) { - Stress<T> * s = contexts[i]; - s->wait(); - succesCount += s->_successCount; - failedCount += s->_failedCount; - } - ASSERT_TRUE(v == 0); - ASSERT_TRUE(old == succesCount); - fprintf(stderr, "%ld threads counting down from %" PRIu64 " had %ld succesfull and %ld unsuccessful attempts\n", - contexts.size(), uint64_t(old), succesCount, failedCount); - for(size_t i = 0; i < contexts.size(); i++) { - delete contexts[i]; - } -} - -template <typename T> -void Stress<T>::Run(FastOS_ThreadInterface *, void *) -{ - _wait.Lock(); - stressSwap(*_value); - _wait.Unlock(); -} - -template <typename T> -void Stress<T>::stressSwap(T & value) -{ - for (T old = value; old > 0; old = value) { - if (vespalib::Atomic::cmpSwap(&value, old-1, old)) { - _successCount++; - } else { - _failedCount++; - } - } -} - -int Test::Main() -{ - TEST_INIT("atomic"); - +TEST("verify lock freeness of atomics"){ { std::atomic<uint32_t> uint32V; ASSERT_TRUE(uint32V.is_lock_free()); @@ -120,16 +22,6 @@ int Test::Main() #endif } - testSwap<uint32_t>(6); - testSwap<uint32_t>(7); - testSwap<uint32_t>(uint32_t(-6)); - testSwap<uint32_t>(uint32_t(-7)); - testSwap<uint64_t>(6); - testSwap<uint64_t>(7); - testSwap<uint64_t>(uint64_t(-6)); - testSwap<uint64_t>(uint64_t(-7)); - testSwapStress<uint64_t>(0x1000000, 4); - testSwapStress<uint32_t>(0x1000000, 4); - - TEST_DONE(); } + +TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/vespamalloc/src/tests/thread/racemanythreads.cpp b/vespamalloc/src/tests/thread/racemanythreads.cpp index fbc8312eb2c..692228ced9e 100644 --- a/vespamalloc/src/tests/thread/racemanythreads.cpp +++ b/vespamalloc/src/tests/thread/racemanythreads.cpp @@ -1,7 +1,6 @@ // 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> using namespace vespalib; diff --git a/vespamalloc/src/tests/thread/thread.cpp b/vespamalloc/src/tests/thread/thread.cpp index 65904df22c7..3a4fa366c38 100644 --- a/vespamalloc/src/tests/thread/thread.cpp +++ b/vespamalloc/src/tests/thread/thread.cpp @@ -1,7 +1,7 @@ // 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 <atomic> using namespace vespalib; @@ -47,18 +47,18 @@ struct wait_info { } pthread_cond_t _cond; pthread_mutex_t _mutex; - volatile uint64_t _count; + std::atomic<uint64_t> _count; }; void * just_wait(void * arg) { wait_info * info = (wait_info *) arg; pthread_mutex_lock(&info->_mutex); - vespalib::Atomic::postInc(&info->_count); + info->_count++; pthread_cond_wait(&info->_cond, &info->_mutex); pthread_mutex_unlock(&info->_mutex); pthread_cond_signal(&info->_cond); - vespalib::Atomic::postDec(&info->_count); + info->_count--; return arg; } |