Stroika Library 3.0d23
 
Loading...
Searching...
No Matches
AssertExternallySynchronizedMutex.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#include "Stroika/Foundation/StroikaPreComp.h"
5
8
9#include "Sanitizer.h"
10#include "Trace.h"
11
13
14using namespace Stroika::Foundation;
16using namespace Stroika::Foundation::Debug;
17
18#if qStroika_Foundation_Debug_AssertExternallySynchronizedMutex_Enabled
19/*
20 ********************************************************************************
21 ****************** Debug::AssertExternallySynchronizedMutex ********************
22 ********************************************************************************
23 */
24void AssertExternallySynchronizedMutex::lock_ () noexcept
25{
26 try {
27 SharedContext* sharedContext = fSharedContext_.get ();
28 if (sharedContext->fFullLocks_++ == 0) {
29 // If first time in, save thread-id
30 sharedContext->fThreadWithFullLock_ = this_thread::get_id ();
31 if (not sharedContext->GetSharedLockEmpty_ ()) {
32 // If first already shared locks - OK - so long as same thread
33 Require (sharedContext->CountOfIInSharedLockThreads_ (sharedContext->fThreadWithFullLock_) ==
34 sharedContext->GetSharedLockThreadsCount_ ());
35 }
36 }
37 else {
38 // If first already locked - OK - so long as same thread
39 if (sharedContext->fThreadWithFullLock_ != this_thread::get_id ()) {
40 // Duplicate the Require() below, but with more debug information, because this is a COMMON and IMPORANT case;
41 // If this happens, this means one thread has (the object containing this) is using this object (fake locked)
42 // while we are trying to use it (again doing fake write lock) - so we want to PRINT INFO about that thread!!!
43#if !qCompilerAndStdLib_FormatThreadId_Buggy
44 DbgTrace ("ATTEMPT TO modify (lock for write) an object which is already in use (debuglocked) in another thread (thisthread={})"_f,
45 this_thread::get_id ());
46 DbgTrace ("Original thread holding lock: threadID={}, and DbgTraceThreadName={}"_f,
47 Execution::Thread::FormatThreadID (sharedContext->fThreadWithFullLock_),
48 Characters::ToString (Debug::GetDbgTraceThreadName_A (sharedContext->fThreadWithFullLock_)));
49#endif
50 }
51 Require (sharedContext->fThreadWithFullLock_ == this_thread::get_id ());
52 }
53 }
54 catch (...) {
56 }
57}
58
59bool AssertExternallySynchronizedMutex::try_lock_ () noexcept
60{
61 // Note - not critical if there are races in this, as its just a diagnostic for debugging, and false-negatives OK
62 bool lockedSuccessfully = true;
63 try {
64 SharedContext* sharedContext = fSharedContext_.get ();
65 if (sharedContext->fFullLocks_++ == 0) {
66 // If first time in, save thread-id
67 sharedContext->fThreadWithFullLock_ = this_thread::get_id ();
68 if (not sharedContext->GetSharedLockEmpty_ ()) {
69 // If first already shared locks - OK - so long as same thread
70 lockedSuccessfully = sharedContext->CountOfIInSharedLockThreads_ (sharedContext->fThreadWithFullLock_) ==
71 sharedContext->GetSharedLockThreadsCount_ ();
72 }
73 }
74 else {
75 // If first already locked - OK - so long as same thread
76 lockedSuccessfully = (sharedContext->fThreadWithFullLock_ == this_thread::get_id ());
77 }
78 if (not lockedSuccessfully) {
79 unlock_ ();
80 }
81 }
82 catch (...) {
84 lockedSuccessfully = false;
85 }
86 return lockedSuccessfully;
87}
88
89void AssertExternallySynchronizedMutex::unlock_ () noexcept
90{
91 SharedContext* sharedContext = fSharedContext_.get ();
92 Require (sharedContext->fThreadWithFullLock_ == this_thread::get_id ());
93 Require (sharedContext->fFullLocks_ > 0); // else unbalanced
94 --sharedContext->fFullLocks_;
95 // Note at this point - it would make some sense to CLEAR fThreadWithFullLock_, but that could be a race, cuz someone
96 // else could lock just as we are unlocking...
97}
98
99void AssertExternallySynchronizedMutex::lock_shared_ () const noexcept
100{
101 try {
102 SharedContext* sharedContext = fSharedContext_.get ();
103 // OK to shared lock from various threads
104 // But if already locked, NOT OK (would have blocked in real impl) - if you try to shared lock from another thread while locked
105 if (sharedContext->fFullLocks_ != 0) {
106 // If first already locks - OK - so long as same thread
107 if (sharedContext->fThreadWithFullLock_ != this_thread::get_id ()) {
108 // Duplicate the Require() below, but with more debug information, because this is a COMMON and IMPORANT case;
109 // If this happens, this means one thread has (the object containing this) is using this object (fake locked)
110 // while we are trying to use it (again doing fake write lock) - so we want to PRINT INFO about that thread!!!
111 DbgTrace ("ATTEMPT TO shared_lock (lock for READ) an object which is already in use (debuglocked for WRITE) in another thread"_f);
112 DbgTrace ("Original thread holding (write) lock: threadID={}, and DbgTraceThreadName={}"_f,
113 Characters::ToString (Execution::Thread::FormatThreadID_A (sharedContext->fThreadWithFullLock_)),
114 Characters::ToString (Debug::GetDbgTraceThreadName_A (sharedContext->fThreadWithFullLock_)));
115 }
116 Require (sharedContext->fThreadWithFullLock_ == this_thread::get_id ());
117 }
118 sharedContext->AddSharedLock_ (this_thread::get_id ());
119 }
120 catch (...) {
122 }
123}
124
125void AssertExternallySynchronizedMutex::unlock_shared_ () const noexcept
126{
127 try {
128 SharedContext* sharedContext = fSharedContext_.get ();
129 sharedContext->RemoveSharedLock_ (this_thread::get_id ());
130 }
131 catch (...) {
133 }
134}
135
136mutex& AssertExternallySynchronizedMutex::GetSharedLockMutexThreads_ ()
137{
138 static mutex sMutex_; // must be out-of-line so we can have just one mutex object. Could use static member, but then trouble using
139 // AssertExternallySynchronizedMutex before main
140 return sMutex_;
141}
142#endif
#define AssertNotReached()
Definition Assertions.h:356
#define DbgTrace
Definition Trace.h:317
String ToString(T &&t, ARGS... args)
Return a debug-friendly, display version of the argument: not guaranteed parsable or usable except fo...
Definition ToString.inl:465
wstring FormatThreadID(Thread::IDType threadID, const FormatThreadInfo &formatInfo={})
Definition Thread.cpp:1058