Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
AssertExternallySynchronizedMutex.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include <algorithm> // for std::count/std::distance
5
6#include "Sanitizer.h"
7
8namespace Stroika::Foundation::Debug {
9
10 /*
11 ********************************************************************************
12 *********** Debug::AssertExternallySynchronizedMutex::SharedContext ************
13 ********************************************************************************
14 */
15#if qStroika_Foundation_Debug_AssertExternallySynchronizedMutex_Enabled
16 inline AssertExternallySynchronizedMutex::SharedContext ::~SharedContext ()
17 {
18 Assert (fFullLocks_ == 0);
19 Assert (fSharedLocks_.fOverflowThreads_.empty () and fSharedLocks_.fInitialThreadsSize_ == 0);
20 }
21 inline bool AssertExternallySynchronizedMutex ::SharedContext ::GetSharedLockEmpty_ () const
22 {
23 lock_guard<mutex> sharedLockProtect{GetSharedLockMutexThreads_ ()};
24 return fSharedLocks_.fInitialThreadsSize_ == 0 and fSharedLocks_.fOverflowThreads_.empty ();
25 }
26 inline pair<size_t, size_t> AssertExternallySynchronizedMutex ::SharedContext ::CountSharedLockThreads_ () const
27 {
28 auto tid = this_thread::get_id ();
29 lock_guard<mutex> sharedLockProtect{GetSharedLockMutexThreads_ ()};
30 size_t thisThreadCnt = std::count (fSharedLocks_.fInitialThreads_.begin (),
31 fSharedLocks_.fInitialThreads_.begin () + fSharedLocks_.fInitialThreadsSize_, tid) and
32 std::count (fSharedLocks_.fOverflowThreads_.begin (), fSharedLocks_.fOverflowThreads_.end (), tid);
33 size_t otherThreadCnt = fSharedLocks_.fInitialThreadsSize_ +
34 std::distance (fSharedLocks_.fOverflowThreads_.begin (), fSharedLocks_.fOverflowThreads_.end ());
35 otherThreadCnt -= thisThreadCnt;
36 return make_pair (thisThreadCnt, otherThreadCnt);
37 }
38 inline size_t AssertExternallySynchronizedMutex ::SharedContext ::GetSharedLockThreadsCount_ () const
39 {
40 lock_guard<mutex> sharedLockProtect{GetSharedLockMutexThreads_ ()};
41 return fSharedLocks_.fInitialThreadsSize_ + std::distance (fSharedLocks_.fOverflowThreads_.begin (), fSharedLocks_.fOverflowThreads_.end ());
42 }
43 inline size_t AssertExternallySynchronizedMutex ::SharedContext ::CountOfIInSharedLockThreads_ (thread::id i) const
44 {
45 lock_guard<mutex> sharedLockProtect{GetSharedLockMutexThreads_ ()};
46 return std::count (fSharedLocks_.fInitialThreads_.begin (), fSharedLocks_.fInitialThreads_.begin () + fSharedLocks_.fInitialThreadsSize_, i) +
47 std::count (fSharedLocks_.fOverflowThreads_.begin (), fSharedLocks_.fOverflowThreads_.end (), i);
48 }
49 inline void AssertExternallySynchronizedMutex ::SharedContext ::AddSharedLock_ (thread::id i)
50 {
51 lock_guard<mutex> sharedLockProtect{GetSharedLockMutexThreads_ ()};
52 if (fSharedLocks_.fInitialThreadsSize_ < kInlineSharedLockBufSize_) {
53 fSharedLocks_.fInitialThreads_[fSharedLocks_.fInitialThreadsSize_++] = i;
54 }
55 else {
56 fSharedLocks_.fOverflowThreads_.push_front (i);
57 }
58 }
59 inline void AssertExternallySynchronizedMutex ::SharedContext ::RemoveSharedLock_ (thread::id i)
60 {
61 lock_guard<mutex> sharedLockProtect{GetSharedLockMutexThreads_ ()};
62 if constexpr (kInlineSharedLockBufSize_ != 0) {
63 auto re = fSharedLocks_.fInitialThreads_.begin () + fSharedLocks_.fInitialThreadsSize_;
64 auto ri = find (fSharedLocks_.fInitialThreads_.begin (), re, i);
65 if (ri != re) {
66 if (ri + 1 != re) {
67 copy (ri + 1, re, ri); // if test not useful if optimized, but this code mainly used unoptimized and appears to help there
68 }
69 --fSharedLocks_.fInitialThreadsSize_;
70 return;
71 }
72 }
73 auto re = fSharedLocks_.fOverflowThreads_.end ();
74 for (auto beforeI = fSharedLocks_.fOverflowThreads_.before_begin ();; ++beforeI) {
75 Assert (beforeI != re);
76 auto n = beforeI;
77 n++;
78 Assert (n != re);
79 if (*n == i) {
80 fSharedLocks_.fOverflowThreads_.erase_after (beforeI);
81 return;
82 }
83 }
85 }
86#endif
87
88 /*
89 ********************************************************************************
90 **************** Debug::AssertExternallySynchronizedMutex **********************
91 ********************************************************************************
92 */
93#if qStroika_Foundation_Debug_AssertExternallySynchronizedMutex_Enabled
94 inline AssertExternallySynchronizedMutex::AssertExternallySynchronizedMutex (const shared_ptr<SharedContext>& sharedContext) noexcept
95 // http://stroika-bugs.sophists.com/browse/STK-500
96 // NOTE - this will generate a throw and std::unexpected violation if there is no memory and multiset CTOR
97 // throws. There is no good answer in this case. We declare the constructors noexcept so the footprint of
98 // AssertExternallySynchronizedMutex is as light as possible and the same (API/constraints) between debug and release
99 // builds. And if we run out of memory here, there isn't much we can do to continue -- LGP 2018-10-02
100 : fSharedContext_{sharedContext ? sharedContext : make_shared<SharedContext> ()}
101 {
102 }
103 inline AssertExternallySynchronizedMutex::AssertExternallySynchronizedMutex (const shared_ptr<SharedContext>& sharedContext,
104 const AssertExternallySynchronizedMutex& src) noexcept
105 : AssertExternallySynchronizedMutex{sharedContext}
106 {
107 ReadContext readLockSrc{src}; // to copy, the src can have shared_locks, but no (write) locks
108 }
109 inline AssertExternallySynchronizedMutex::AssertExternallySynchronizedMutex (const AssertExternallySynchronizedMutex& src) noexcept
110 : AssertExternallySynchronizedMutex{}
111 {
112 ReadContext readLockSrc{src}; // to copy, the src can have shared_locks, but no (write) locks
113 }
114 inline AssertExternallySynchronizedMutex::AssertExternallySynchronizedMutex (const shared_ptr<SharedContext>& sharedContext,
115 [[maybe_unused]] AssertExternallySynchronizedMutex&& src) noexcept
116 : AssertExternallySynchronizedMutex{sharedContext}
117 {
118 WriteContext declareWriteContext4Src{src}; // move we must be able to modify source
119 }
120 inline AssertExternallySynchronizedMutex::AssertExternallySynchronizedMutex ([[maybe_unused]] AssertExternallySynchronizedMutex&& src) noexcept
121 : AssertExternallySynchronizedMutex{}
122 {
123 WriteContext writeLockRHS{src}; // move we must be able to modify source
124 }
125#endif
126 inline AssertExternallySynchronizedMutex& AssertExternallySynchronizedMutex::operator= ([[maybe_unused]] const AssertExternallySynchronizedMutex& rhs) noexcept
127 {
128 ReadContext readLockRHS{rhs}; // we must be able to read RHS
129 WriteContext declareWriteContext4This{*this}; // we must be able modify this
130 return *this;
131 }
133 {
134 WriteContext writeLockRHS{rhs}; // move we must be able to modify rhs to move it
135 WriteContext writeLockThis{*this}; // we must be able modify this
136 return *this;
137 }
138#if qStroika_Foundation_Debug_AssertExternallySynchronizedMutex_Enabled
139 inline auto AssertExternallySynchronizedMutex::GetSharedContext () const -> shared_ptr<SharedContext>
140 {
141 return fSharedContext_;
142 }
143 inline void AssertExternallySynchronizedMutex::SetAssertExternallySynchronizedMutexContext (const shared_ptr<SharedContext>& sharedContext)
144 {
145 Require (sharedContext != nullptr);
146 fSharedContext_ = sharedContext;
147 }
148#endif
150 {
151#if qStroika_Foundation_Debug_AssertExternallySynchronizedMutex_Enabled
152 lock_ ();
153#endif
154 }
156 {
157#if qStroika_Foundation_Debug_AssertExternallySynchronizedMutex_Enabled
158 unlock_ ();
159#endif
160 }
162 {
163#if qStroika_Foundation_Debug_AssertExternallySynchronizedMutex_Enabled
164 lock_shared_ ();
165#endif
166 }
168 {
169#if qStroika_Foundation_Debug_AssertExternallySynchronizedMutex_Enabled
170 unlock_shared_ ();
171#endif
172 }
173
174}
#define RequireNotReached()
Definition Assertions.h:385
NOT a real mutex - just a debugging infrastructure support tool so in debug builds can be assured thr...
nonvirtual AssertExternallySynchronizedMutex & operator=(AssertExternallySynchronizedMutex &&rhs) noexcept
unique_lock< AssertExternallySynchronizedMutex > WriteContext
Instantiate AssertExternallySynchronizedMutex::WriteContext to designate an area of code where protec...