Roc Toolkit internal modules
Roc Toolkit: real-time audio streaming
seqlock.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Roc Streaming authors
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7  */
8 
9 //! @file roc_core/seqlock.h
10 //! @brief Seqlock.
11 
12 #ifndef ROC_CORE_SEQLOCK_H_
13 #define ROC_CORE_SEQLOCK_H_
14 
15 #include "roc_core/noncopyable.h"
16 #include "roc_core/seqlock_impl.h"
17 
18 namespace roc {
19 namespace core {
20 
21 //! Seqlock.
22 //!
23 //! Provides safe concurrent access to a single value.
24 //! Provides sequential consistency.
25 //! Optimized for infrequent writes and frequent reads.
26 //! Writes are lock-free and take priority over reads.
27 //!
28 //! See details on the barriers here:
29 //! https://elixir.bootlin.com/linux/latest/source/include/linux/seqlock.h
30 //! https://www.hpl.hp.com/techreports/2012/HPL-2012-68.pdf
31 template <class T> class Seqlock : public NonCopyable<> {
32 public:
33  //! Initialize with given value.
34  explicit Seqlock(T value)
35  : val_(value) {
36  }
37 
38  //! Load value version.
39  //! Wait-free.
40  inline seqlock_version_t version() const {
41  return impl_.version();
42  }
43 
44  //! Store value.
45  //! Can be called concurrently, but only one concurrent call will succeed.
46  //! Is both lock-free and wait-free, i.e. it never waits for sleeping threads
47  //! and never spins.
48  //! After this call returns, any thread calling wait_load() is guaranteed to
49  //! get the updated value, and try_load() is guaranteed either return the
50  //! updated value or fail (if changes are not fully published yet).
51  inline bool try_store(const T& value) {
53  return impl_.try_store(ver, &val_, sizeof(val_), &value);
54  }
55 
56  //! Store value.
57  //! Like try_store(), but also returns updated version.
58  inline bool try_store_v(const T& value, seqlock_version_t& ver) {
59  return impl_.try_store(ver, &val_, sizeof(val_), &value);
60  }
61 
62  //! Store value.
63  //! Can NOT be called concurrently, assumes that writes are serialized.
64  //! Is both lock-free and wait-free, i.e. it never waits for sleeping threads
65  //! and never spins.
66  //! After this call returns, any thread calling wait_load() is guaranteed to
67  //! get the updated value, and try_load() is guaranteed either return the
68  //! updated value or fail (if changes are not fully published yet).
69  inline void exclusive_store(const T& value) {
71  impl_.exclusive_store(ver, &val_, sizeof(val_), &value);
72  }
73 
74  //! Store value.
75  //! Like exclusive_store(), but also returns updated version.
76  inline void exclusive_store_v(const T& value, seqlock_version_t& ver) {
77  impl_.exclusive_store(ver, &val_, sizeof(val_), &value);
78  }
79 
80  //! Try to load value.
81  //! Returns true if the value was loaded.
82  //! May return false if concurrent store is currently in progress.
83  //! Is both lock-free and wait-free, i.e. it never waits for sleeping threads
84  //! and never spins.
85  inline bool try_load(T& value) const {
87  return impl_.try_load_repeat(ver, &val_, sizeof(val_), &value);
88  }
89 
90  //! Try to load value and version.
91  //! Like try_load(), but also returns version.
92  inline bool try_load_v(T& value, seqlock_version_t& ver) const {
93  return impl_.try_load_repeat(ver, &val_, sizeof(val_), &value);
94  }
95 
96  //! Load value.
97  //! May spin until concurrent store completes.
98  //! Is NOT lock-free (or wait-free).
99  inline T wait_load() const {
100  T value;
101  seqlock_version_t ver;
102  impl_.wait_load(ver, &val_, sizeof(val_), &value);
103  return value;
104  }
105 
106  //! Load value and version.
107  //! Like wait_load(), but also returns version.
108  inline void wait_load_v(T& value, seqlock_version_t& ver) const {
109  impl_.wait_load(ver, &val_, sizeof(val_), &value);
110  }
111 
112 private:
113  T val_;
114  SeqlockImpl impl_;
115 };
116 
117 } // namespace core
118 } // namespace roc
119 
120 #endif // ROC_CORE_SEQLOCK_H_
Base class for non-copyable objects.
Definition: noncopyable.h:23
Seqlock implementation class.
Definition: seqlock_impl.h:34
bool try_store(seqlock_version_t &ver, void *current_value, size_t value_size, const void *new_value)
Try to store value.
void exclusive_store(seqlock_version_t &ver, void *current_value, size_t value_size, const void *new_value)
Store value.
bool try_load_repeat(seqlock_version_t &ver, const void *current_value, size_t value_size, void *return_value) const
Try to load value and version.
void wait_load(seqlock_version_t &ver, const void *current_value, size_t value_size, void *return_value) const
Load value and version.
seqlock_version_t version() const
Load value version.
Seqlock.
Definition: seqlock.h:31
bool try_store(const T &value)
Store value. Can be called concurrently, but only one concurrent call will succeed....
Definition: seqlock.h:51
bool try_load_v(T &value, seqlock_version_t &ver) const
Try to load value and version. Like try_load(), but also returns version.
Definition: seqlock.h:92
void exclusive_store(const T &value)
Store value. Can NOT be called concurrently, assumes that writes are serialized. Is both lock-free an...
Definition: seqlock.h:69
void exclusive_store_v(const T &value, seqlock_version_t &ver)
Store value. Like exclusive_store(), but also returns updated version.
Definition: seqlock.h:76
seqlock_version_t version() const
Load value version. Wait-free.
Definition: seqlock.h:40
Seqlock(T value)
Initialize with given value.
Definition: seqlock.h:34
bool try_store_v(const T &value, seqlock_version_t &ver)
Store value. Like try_store(), but also returns updated version.
Definition: seqlock.h:58
T wait_load() const
Load value. May spin until concurrent store completes. Is NOT lock-free (or wait-free).
Definition: seqlock.h:99
void wait_load_v(T &value, seqlock_version_t &ver) const
Load value and version. Like wait_load(), but also returns version.
Definition: seqlock.h:108
bool try_load(T &value) const
Try to load value. Returns true if the value was loaded. May return false if concurrent store is curr...
Definition: seqlock.h:85
uint32_t seqlock_version_t
Type for holding seqlock value version. Version is changed each value update. May wrap.
Definition: seqlock_impl.h:23
Root namespace.
Non-copyable object.
Seqlock implementation.