@@ -13,34 +13,34 @@ namespace nbl::system
1313// Ugly workaround, structs with constevals can't be nested
1414namespace impl
1515{
16- template <typename U>
17- struct DPWRLStateLock
18- {
19- using type = std::atomic<U>;
20- };
2116
22- // will fail if `atomic_unsiged_lock_free` doesn't exist or its value type has wrong size
23- template <typename U> requires (sizeof (std::atomic_unsigned_lock_free::value_type) >= sizeof(U))
24- struct DPWRLStateLock<U>
25- {
26- using type = std::atomic_unsigned_lock_free;
27- };
17+ template <typename U>
18+ struct DPWRLStateLock
19+ {
20+ using type = std::atomic<U>;
21+ };
2822
29- struct DPWRLStateSemantics
30- {
31- using state_lock_value_t = typename DPWRLStateLock<uint32_t >::type::value_type;
32- uint32_t currentReaders : 10 = 0 ;
33- uint32_t pendingWriters : 10 = 0 ;
34- uint32_t pendingUpgrades : 10 = 0 ;
35- uint32_t writing : 1 = 0 ;
36- uint32_t stateLocked : 1 = 0 ;
37-
38- consteval inline operator state_lock_value_t () const
39- {
40- return static_cast <state_lock_value_t >((currentReaders << 22 ) | (pendingWriters << 12 ) | (pendingUpgrades << 2 ) | (writing << 1 ) | stateLocked);
41- }
42- };
43- } // namespace impl
23+ // will fail if `atomic_unsiged_lock_free` doesn't exist or its value type has wrong size
24+ template <typename U> requires (sizeof (std::atomic_unsigned_lock_free::value_type) >= sizeof(U))
25+ struct DPWRLStateLock<U>
26+ {
27+ using type = std::atomic_unsigned_lock_free;
28+ };
29+
30+ struct DPWRLStateSemantics
31+ {
32+ using state_lock_value_t = typename DPWRLStateLock<uint32_t >::type::value_type;
33+ uint32_t currentReaders : 10 = 0 ;
34+ uint32_t pendingWriters : 10 = 0 ;
35+ uint32_t pendingUpgrades : 10 = 0 ;
36+ uint32_t writing : 1 = 0 ;
37+ uint32_t stateLocked : 1 = 0 ;
38+
39+ consteval inline operator state_lock_value_t () const
40+ {
41+ return static_cast <state_lock_value_t >((currentReaders << 22 ) | (pendingWriters << 12 ) | (pendingUpgrades << 2 ) | (writing << 1 ) | stateLocked);
42+ }
43+ };
4444
4545enum DPWR_LOCK_DEBUG_STAGE
4646{
@@ -51,19 +51,21 @@ enum DPWR_LOCK_DEBUG_STAGE
5151 PREEMPTED
5252};
5353
54- namespace impl
54+ struct DPWRLVoidDebugCallback
5555{
56- template <typename T>
57- concept DPWRLDebugCallback = requires (T t, DPWR_LOCK_DEBUG_STAGE stage) {
58- { t (stage) } -> std::same_as<void >;
59- };
56+ };
57+
58+ template <typename T>
59+ /* *
60+ * @brief A valid debug callback overrides `void operator()(DPWR_LOCK_DEBUG_STAGE stage)`
61+ */
62+ concept DPWRLDebugCallback = requires (T t, DPWR_LOCK_DEBUG_STAGE stage) {
63+ { t (stage) } -> std::same_as<void >;
64+ } || std::is_same_v<T, DPWRLVoidDebugCallback>;
65+
66+ } // namespace impl
67+
6068
61- class DPWRLVoidDebugCallback
62- {
63- public:
64- void operator ()(DPWR_LOCK_DEBUG_STAGE) {};
65- };
66- }
6769
6870template <impl::DPWRLDebugCallback DebugCallback = impl::DPWRLVoidDebugCallback>
6971/* *
@@ -265,7 +267,7 @@ class demote_promote_writer_readers_lock_debug
265267
266268private:
267269
268- constexpr static inline bool usingDebugCallback = std::is_same_v<DebugCallback, impl::DPWRLVoidDebugCallback>;
270+ constexpr static inline bool usingDebugCallback = ! std::is_same_v<DebugCallback, impl::DPWRLVoidDebugCallback>;
269271
270272 struct DefaultPreemptionCheck
271273 {
@@ -286,6 +288,7 @@ class demote_promote_writer_readers_lock_debug
286288 Preempted& preempted = defaultPreempted
287289 )
288290 {
291+ DebugCallback callback = {};
289292 for (uint32_t spinCount = 0 ; true ; spinCount++)
290293 {
291294 const state_lock_value_t oldState = state.fetch_or (flipLock);
@@ -301,14 +304,14 @@ class demote_promote_writer_readers_lock_debug
301304 const state_lock_value_t newState = wasPreempted ? preempted (oldState) : success (oldState);
302305 // new state must unlock the state lock
303306 assert (!(newState & flipLock));
304- if (usingDebugCallback) DebugCallback ( DPWR_LOCK_DEBUG_STAGE::BEFORE_STATE_UPDATE);
307+ if constexpr (usingDebugCallback) callback (impl:: DPWR_LOCK_DEBUG_STAGE::BEFORE_STATE_UPDATE);
305308 state.store (newState);
306- if (usingDebugCallback) DebugCallback ( DPWR_LOCK_DEBUG_STAGE::AFTER_STATE_UPDATE);
309+ if constexpr (usingDebugCallback) callback (impl:: DPWR_LOCK_DEBUG_STAGE::AFTER_STATE_UPDATE);
307310 if (wasPreempted)
308311 {
309- if (usingDebugCallback)
312+ if constexpr (usingDebugCallback)
310313 {
311- DebugCallback ( DPWR_LOCK_DEBUG_STAGE::PREEMPTED);
314+ callback (impl:: DPWR_LOCK_DEBUG_STAGE::PREEMPTED);
312315 }
313316 else
314317 {
@@ -333,34 +336,48 @@ class demote_promote_writer_readers_lock_debug
333336
334337namespace impl
335338{
336- template <impl::DPWRLDebugCallback DebugCallback = impl::DPWRLVoidDebugCallback>
337- class dpwr_lock_guard_base
339+
340+ template <impl::DPWRLDebugCallback DebugCallback = impl::DPWRLVoidDebugCallback>
341+ class dpwr_lock_guard_base
342+ {
343+ dpwr_lock_guard_base () : m_lock(nullptr ) {}
344+
345+ public:
346+ using dpwr_lock_t = demote_promote_writer_readers_lock_debug<DebugCallback>;
347+ dpwr_lock_guard_base& operator =(const dpwr_lock_guard_base&) = delete ;
348+ dpwr_lock_guard_base (const dpwr_lock_guard_base&) = delete ;
349+
350+ dpwr_lock_guard_base& operator =(dpwr_lock_guard_base&& rhs) noexcept
338351 {
339- dpwr_lock_guard_base () : m_lock(nullptr ) {}
352+ m_lock = rhs.m_lock ;
353+ rhs.m_lock = nullptr ;
354+ return *this ;
355+ }
356+ dpwr_lock_guard_base (dpwr_lock_guard_base&& rhs) noexcept : dpwr_lock_guard_base()
357+ {
358+ operator =(std::move (rhs));
359+ }
340360
341- public:
342- using dpwr_lock_t = typename demote_promote_writer_readers_lock_debug<DebugCallback>;
343- dpwr_lock_guard_base& operator =(const dpwr_lock_guard_base&) = delete ;
344- dpwr_lock_guard_base (const dpwr_lock_guard_base&) = delete ;
361+ /* *
362+ * @brief Checks whether this guard is currently locking the lock `lk`
363+ */
364+ bool hasLocked (dpwr_lock_t & lk) const
365+ {
366+ return m_lock == &lk;
367+ }
345368
346- dpwr_lock_guard_base& operator =(dpwr_lock_guard_base&& rhs) noexcept
347- {
348- m_lock = rhs.m_lock ;
349- rhs.m_lock = nullptr ;
350- return *this ;
351- }
352- dpwr_lock_guard_base (dpwr_lock_guard_base&& rhs) noexcept : dpwr_lock_guard_base()
353- {
354- operator =(std::move (rhs));
355- }
369+ protected:
370+ dpwr_lock_guard_base (dpwr_lock_t & lk) noexcept : m_lock(&lk) {}
356371
357- protected:
358- dpwr_lock_guard_base ( dpwr_lock_t & lk) noexcept : m_lock(&lk) {}
372+ dpwr_lock_t * m_lock;
373+ };
359374
360- dpwr_lock_t * m_lock;
361- };
362375} // namespace impl
363376
377+ // Forward declaration required by GCC
378+ template <impl::DPWRLDebugCallback DebugCallback>
379+ class dpwr_write_lock_guard_debug ;
380+
364381template <impl::DPWRLDebugCallback DebugCallback = impl::DPWRLVoidDebugCallback>
365382class dpwr_read_lock_guard_debug : public impl ::dpwr_lock_guard_base<DebugCallback>
366383{
@@ -404,13 +421,13 @@ class dpwr_write_lock_guard_debug : public impl::dpwr_lock_guard_base<DebugCallb
404421};
405422
406423template <impl::DPWRLDebugCallback DebugCallback>
407- inline dpwr_read_lock_guard_debug<DebugCallback>::dpwr_read_lock_guard_debug(dpwr_write_lock_guard_debug<DebugCallback>&& wl) : impl::dpwr_lock_guard_base(std::move(wl))
424+ inline dpwr_read_lock_guard_debug<DebugCallback>::dpwr_read_lock_guard_debug(dpwr_write_lock_guard_debug<DebugCallback>&& wl) : impl::dpwr_lock_guard_base<DebugCallback> (std::move(wl))
408425{
409426 this ->m_lock ->downgrade ();
410427}
411428
412429template <impl::DPWRLDebugCallback DebugCallback>
413- inline dpwr_write_lock_guard_debug<DebugCallback>::dpwr_write_lock_guard_debug(dpwr_read_lock_guard_debug<DebugCallback>&& rl) : impl::dpwr_lock_guard_base(std::move(rl))
430+ inline dpwr_write_lock_guard_debug<DebugCallback>::dpwr_write_lock_guard_debug(dpwr_read_lock_guard_debug<DebugCallback>&& rl) : impl::dpwr_lock_guard_base<DebugCallback> (std::move(rl))
414431{
415432 this ->m_lock ->upgrade ();
416433}
0 commit comments