Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
AssertExternallySynchronizedMutex.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. 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
59void AssertExternallySynchronizedMutex::unlock_ () noexcept
60{
61 SharedContext* sharedContext = fSharedContext_.get ();
62 Require (sharedContext->fThreadWithFullLock_ == this_thread::get_id ());
63 Require (sharedContext->fFullLocks_ > 0); // else unbalanced
64 --sharedContext->fFullLocks_;
65 // Note at this point - it would make some sense to CLEAR fThreadWithFullLock_, but that could be a race, cuz someone
66 // else could lock just as we are unlocking...
67}
68
69void AssertExternallySynchronizedMutex::lock_shared_ () const noexcept
70{
71 try {
72 SharedContext* sharedContext = fSharedContext_.get ();
73 // OK to shared lock from various threads
74 // But if already locked, NOT OK (would have blocked in real impl) - if you try to shared lock from another thread while locked
75 if (sharedContext->fFullLocks_ != 0) {
76 // If first already locks - OK - so long as same thread
77 if (sharedContext->fThreadWithFullLock_ != this_thread::get_id ()) {
78 // Duplicate the Require() below, but with more debug information, because this is a COMMON and IMPORANT case;
79 // If this happens, this means one thread has (the object containing this) is using this object (fake locked)
80 // while we are trying to use it (again doing fake write lock) - so we want to PRINT INFO about that thread!!!
81 DbgTrace ("ATTEMPT TO shared_lock (lock for READ) an object which is already in use (debuglocked for WRITE) in another thread"_f);
82 DbgTrace ("Original thread holding (write) lock: threadID={}, and DbgTraceThreadName={}"_f,
83 Characters::ToString (Execution::Thread::FormatThreadID_A (sharedContext->fThreadWithFullLock_)),
84 Characters::ToString (Debug::GetDbgTraceThreadName_A (sharedContext->fThreadWithFullLock_)));
85 }
86 Require (sharedContext->fThreadWithFullLock_ == this_thread::get_id ());
87 }
88 sharedContext->AddSharedLock_ (this_thread::get_id ());
89 }
90 catch (...) {
92 }
93}
94
95void AssertExternallySynchronizedMutex::unlock_shared_ () const noexcept
96{
97 try {
98 SharedContext* sharedContext = fSharedContext_.get ();
99 sharedContext->RemoveSharedLock_ (this_thread::get_id ());
100 }
101 catch (...) {
103 }
104}
105
106mutex& AssertExternallySynchronizedMutex::GetSharedLockMutexThreads_ ()
107{
108 static mutex sMutex_; // must be out-of-line so we can have just one mutex object. Could use static member, but then trouble using
109 // AssertExternallySynchronizedMutex before main
110 return sMutex_;
111}
112#endif
#define AssertNotReached()
Definition Assertions.h:355
#define DbgTrace
Definition Trace.h:309
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:1052