about summary refs log tree commit diff
path: root/third_party/nix/src/libutil/sync.hh
diff options
context:
space:
mode:
authorVincent Ambo <tazjin@google.com>2020-05-17T14·52+0100
committerVincent Ambo <tazjin@google.com>2020-05-17T14·52+0100
commit7994fd1d545cc5c876d6f21db7ddf9185d23dad6 (patch)
tree32dd695785378c5b9c8be97fc583e9dfc62cb105 /third_party/nix/src/libutil/sync.hh
parentcf8cd640c1adf74a3706efbcb0ea4625da106fb2 (diff)
parent90b3b31dc27f31e9b11653a636025d29ddb087a3 (diff)
Add 'third_party/nix/' from commit 'be66c7a6b24e3c3c6157fd37b86c7203d14acf10' r/724
git-subtree-dir: third_party/nix
git-subtree-mainline: cf8cd640c1adf74a3706efbcb0ea4625da106fb2
git-subtree-split: be66c7a6b24e3c3c6157fd37b86c7203d14acf10
Diffstat (limited to 'third_party/nix/src/libutil/sync.hh')
-rw-r--r--third_party/nix/src/libutil/sync.hh88
1 files changed, 88 insertions, 0 deletions
diff --git a/third_party/nix/src/libutil/sync.hh b/third_party/nix/src/libutil/sync.hh
new file mode 100644
index 0000000000..e1d591d77a
--- /dev/null
+++ b/third_party/nix/src/libutil/sync.hh
@@ -0,0 +1,88 @@
+#pragma once
+
+#include <cstdlib>
+#include <mutex>
+#include <condition_variable>
+#include <cassert>
+
+namespace nix {
+
+/* This template class ensures synchronized access to a value of type
+   T. It is used as follows:
+
+     struct Data { int x; ... };
+
+     Sync<Data> data;
+
+     {
+       auto data_(data.lock());
+       data_->x = 123;
+     }
+
+   Here, "data" is automatically unlocked when "data_" goes out of
+   scope.
+*/
+
+template<class T, class M = std::mutex>
+class Sync
+{
+private:
+    M mutex;
+    T data;
+
+public:
+
+    Sync() { }
+    Sync(const T & data) : data(data) { }
+    Sync(T && data) noexcept : data(std::move(data)) { }
+
+    class Lock
+    {
+    private:
+        Sync * s;
+        std::unique_lock<M> lk;
+        friend Sync;
+        Lock(Sync * s) : s(s), lk(s->mutex) { }
+    public:
+        Lock(Lock && l) : s(l.s) { abort(); }
+        Lock(const Lock & l) = delete;
+        ~Lock() { }
+        T * operator -> () { return &s->data; }
+        T & operator * () { return s->data; }
+
+        void wait(std::condition_variable & cv)
+        {
+            assert(s);
+            cv.wait(lk);
+        }
+
+        template<class Rep, class Period>
+        std::cv_status wait_for(std::condition_variable & cv,
+            const std::chrono::duration<Rep, Period> & duration)
+        {
+            assert(s);
+            return cv.wait_for(lk, duration);
+        }
+
+        template<class Rep, class Period, class Predicate>
+        bool wait_for(std::condition_variable & cv,
+            const std::chrono::duration<Rep, Period> & duration,
+            Predicate pred)
+        {
+            assert(s);
+            return cv.wait_for(lk, duration, pred);
+        }
+
+        template<class Clock, class Duration>
+        std::cv_status wait_until(std::condition_variable & cv,
+            const std::chrono::time_point<Clock, Duration> & duration)
+        {
+            assert(s);
+            return cv.wait_until(lk, duration);
+        }
+    };
+
+    Lock lock() { return Lock(this); }
+};
+
+}