diff options
author | Tor Egge <Tor.Egge@online.no> | 2021-10-18 14:29:11 +0200 |
---|---|---|
committer | Tor Egge <Tor.Egge@online.no> | 2021-10-18 14:29:11 +0200 |
commit | b8cf8c2dd0ab117ae68cae60f6ef71373e98da48 (patch) | |
tree | b2f3635f6243b5a40412cee1001cb9a5918ff825 /vespalib | |
parent | a6784673e65b55a7812d208c06f76ad903b81cab (diff) |
Move MonitoredRefCount and RetainGuard to vespalib.
Diffstat (limited to 'vespalib')
4 files changed, 119 insertions, 0 deletions
diff --git a/vespalib/src/vespa/vespalib/util/CMakeLists.txt b/vespalib/src/vespa/vespalib/util/CMakeLists.txt index 9e2917775f0..6115c21623d 100644 --- a/vespalib/src/vespa/vespalib/util/CMakeLists.txt +++ b/vespalib/src/vespa/vespalib/util/CMakeLists.txt @@ -38,6 +38,7 @@ vespa_add_library(vespalib_vespalib_util OBJECT memoryusage.cpp mmap_file_allocator.cpp mmap_file_allocator_factory.cpp + monitored_refcount.cpp printable.cpp priority_queue.cpp random.cpp diff --git a/vespalib/src/vespa/vespalib/util/monitored_refcount.cpp b/vespalib/src/vespa/vespalib/util/monitored_refcount.cpp new file mode 100644 index 00000000000..4376e26bb66 --- /dev/null +++ b/vespalib/src/vespa/vespalib/util/monitored_refcount.cpp @@ -0,0 +1,44 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "monitored_refcount.h" +#include <cassert> + +namespace vespalib { + +MonitoredRefCount::MonitoredRefCount() + : _lock(), + _cv(), + _refCount(0u) +{ +} + +MonitoredRefCount::~MonitoredRefCount() +{ + assert(_refCount == 0u); +} + +void +MonitoredRefCount::retain() noexcept +{ + std::lock_guard<std::mutex> guard(_lock); + ++_refCount; +} + +void +MonitoredRefCount::release() noexcept +{ + std::lock_guard<std::mutex> guard(_lock); + --_refCount; + if (_refCount == 0u) { + _cv.notify_all(); + } +} + +void +MonitoredRefCount::waitForZeroRefCount() +{ + std::unique_lock<std::mutex> guard(_lock); + _cv.wait(guard, [this] { return (_refCount == 0u); }); +} + +} diff --git a/vespalib/src/vespa/vespalib/util/monitored_refcount.h b/vespalib/src/vespa/vespalib/util/monitored_refcount.h new file mode 100644 index 00000000000..465284b6fd3 --- /dev/null +++ b/vespalib/src/vespa/vespalib/util/monitored_refcount.h @@ -0,0 +1,29 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include <mutex> +#include <condition_variable> + +namespace vespalib { + +class RetainGuard; +/* + * Class containing a reference count that can be waited on to become zero. + * Typically ancestor or member of a class that has to be careful of when + * portions object can be properly torn down before destruction itself. + */ +class MonitoredRefCount +{ + std::mutex _lock; + std::condition_variable _cv; + uint32_t _refCount; + void retain() noexcept; + void release() noexcept; + friend RetainGuard; +public: + MonitoredRefCount(); + virtual ~MonitoredRefCount(); + void waitForZeroRefCount(); +}; + +} diff --git a/vespalib/src/vespa/vespalib/util/retain_guard.h b/vespalib/src/vespa/vespalib/util/retain_guard.h new file mode 100644 index 00000000000..090f3ce75cf --- /dev/null +++ b/vespalib/src/vespa/vespalib/util/retain_guard.h @@ -0,0 +1,45 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include "monitored_refcount.h" + +namespace vespalib { + +/* + * Class containing a reference to a monitored reference count, + * intended to block teardown of the class owning the monitored + * reference count. + */ +class RetainGuard { +public: + RetainGuard(MonitoredRefCount & refCount) noexcept + : _refCount(&refCount) + { + _refCount->retain(); + } + RetainGuard(const RetainGuard & rhs) = delete; + RetainGuard & operator=(const RetainGuard & rhs) = delete; + RetainGuard(RetainGuard && rhs) noexcept + : _refCount(rhs._refCount) + { + rhs._refCount = nullptr; + } + RetainGuard & operator=(RetainGuard && rhs) noexcept { + release(); + _refCount = rhs._refCount; + rhs._refCount = nullptr; + return *this; + } + ~RetainGuard() { release(); } +private: + void release() noexcept{ + if (_refCount != nullptr) { + _refCount->release(); + _refCount = nullptr; + } + } + MonitoredRefCount * _refCount; +}; + +} |