summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2017-08-11 12:29:46 +0200
committerHenning Baldersheim <balder@yahoo-inc.com>2017-08-11 12:30:24 +0200
commit41709673f0165f16496ecf37162ed7dac06b5295 (patch)
treec213da683873bbe88927a3de58eb93f3f231a693
parent2fe073e8e1875bc891c38099c880d156bd228e9d (diff)
Use std::atomic all over and completely get rid of homegrown atomics.
-rw-r--r--config/src/vespa/config/common/configmanager.cpp3
-rw-r--r--config/src/vespa/config/common/configmanager.h2
-rw-r--r--config/src/vespa/config/frt/connection.h1
-rw-r--r--config/src/vespa/config/frt/frtconnection.cpp5
-rw-r--r--config/src/vespa/config/frt/frtconnection.h9
-rw-r--r--fnet/src/vespa/fnet/frt/rpcrequest.cpp4
-rw-r--r--fnet/src/vespa/fnet/frt/rpcrequest.h30
-rw-r--r--fnet/src/vespa/fnet/frt/target.h11
-rw-r--r--messagebus/src/vespa/messagebus/dynamicthrottlepolicy.cpp1
-rw-r--r--messagebus/src/vespa/messagebus/routing/routingnode.cpp3
-rw-r--r--messagebus/src/vespa/messagebus/routing/routingnode.h17
-rw-r--r--persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp17
-rw-r--r--persistence/src/vespa/persistence/dummyimpl/dummypersistence.h15
-rw-r--r--searchcore/src/vespa/searchcore/proton/common/feedtoken.cpp1
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/rpc_hooks.h1
-rw-r--r--searchlib/src/vespa/searchlib/docstore/documentstore.cpp2
-rw-r--r--searchlib/src/vespa/searchlib/docstore/documentstore.h3
-rw-r--r--searchlib/src/vespa/searchlib/engine/transportserver.h1
-rw-r--r--staging_vespalib/src/vespa/vespalib/stllike/cache.h4
-rw-r--r--staging_vespalib/src/vespa/vespalib/stllike/cache.hpp2
-rw-r--r--vespalib/CMakeLists.txt2
-rw-r--r--vespalib/src/testlist.txt1
-rw-r--r--vespalib/src/tests/atomic/.gitignore6
-rw-r--r--vespalib/src/tests/atomic/CMakeLists.txt15
-rw-r--r--vespalib/src/tests/atomic/DESC1
-rw-r--r--vespalib/src/tests/atomic/FILES1
-rw-r--r--vespalib/src/tests/atomic/atomic_bench.cpp105
-rw-r--r--vespalib/src/tests/atomic/atomic_test.cpp339
-rw-r--r--vespalib/src/tests/executor/threadstackexecutor_test.cpp14
-rw-r--r--vespalib/src/tests/weakref/.gitignore4
-rw-r--r--vespalib/src/tests/weakref/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/weakref/DESC1
-rw-r--r--vespalib/src/tests/weakref/FILES1
-rw-r--r--vespalib/src/tests/weakref/weakref_test.cpp43
-rw-r--r--vespalib/src/vespa/vespalib/util/CMakeLists.txt1
-rw-r--r--vespalib/src/vespa/vespalib/util/atomic.cpp221
-rw-r--r--vespalib/src/vespa/vespalib/util/atomic.h468
-rw-r--r--vespalib/src/vespa/vespalib/util/overview.h5
-rw-r--r--vespalib/src/vespa/vespalib/util/ptrholder.h1
-rw-r--r--vespalib/src/vespa/vespalib/util/referencecounter.h13
-rw-r--r--vespalib/src/vespa/vespalib/util/weakref.h259
-rw-r--r--vespamalloc/src/tests/test1/testatomic.cpp114
-rw-r--r--vespamalloc/src/tests/thread/racemanythreads.cpp1
-rw-r--r--vespamalloc/src/tests/thread/thread.cpp8
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&lt;T&gt;
* <BR> \ref vespalib::LinkedPtr&lt;T&gt;
*
* Advanced pointer utilities
*
* \ref vespalib::PtrHolder&lt;T&gt;
- * <BR> \ref vespalib::WeakRef&lt;T&gt;
*
* 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;
}