summaryrefslogtreecommitdiffstats
path: root/vespalib
diff options
context:
space:
mode:
authorTor Egge <Tor.Egge@online.no>2021-10-18 14:29:11 +0200
committerTor Egge <Tor.Egge@online.no>2021-10-18 14:29:11 +0200
commitb8cf8c2dd0ab117ae68cae60f6ef71373e98da48 (patch)
treeb2f3635f6243b5a40412cee1001cb9a5918ff825 /vespalib
parenta6784673e65b55a7812d208c06f76ad903b81cab (diff)
Move MonitoredRefCount and RetainGuard to vespalib.
Diffstat (limited to 'vespalib')
-rw-r--r--vespalib/src/vespa/vespalib/util/CMakeLists.txt1
-rw-r--r--vespalib/src/vespa/vespalib/util/monitored_refcount.cpp44
-rw-r--r--vespalib/src/vespa/vespalib/util/monitored_refcount.h29
-rw-r--r--vespalib/src/vespa/vespalib/util/retain_guard.h45
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;
+};
+
+}