ALib C++ Library
Library Version: 2510 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
dbgasserters.inl
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header-file is part of module \alib_threads of the \aliblong.
4///
5/// \emoji :copyright: 2013-2025 A-Worx GmbH, Germany.
6/// Published under \ref mainpage_license "Boost Software License".
7//==================================================================================================
8#if !ALIB_SINGLE_THREADED && ALIB_DEBUG
9
10ALIB_EXPORT namespace alib::threads {
11
12//==================================================================================================
13/// This type is used for debugging and asserting \alib lock (mutex) types.
14/// With debug compilations the non-shared lock types hold one member of this struct, which
15/// aggregates all debug information.
16//==================================================================================================
18{
19 /// The name of this Lock.
20 /// Set to <em> "<unnamed>"</em> by default.
21 /// Used for debug-output.
22 /// For automatic pruning of changes to this name, macro \ref ALIB_DBG should be used.
23 const char* Name ="<unnamed>";
24 CallerInfo AcqCI ; ///< Source location of the most recent acquirement.
25 CallerInfo RelCI ; ///< Source location of the most recent release.
26 int16_t CntAcquirements= 0; ///< The number of nested acquirements.
27
28 /// The format string used to write exceptions to the console.
29 /// This string can be changed if the source information is not "clickable" in a user's
30 /// development environment.<br>
31 ///
32 /// The default string is optimized for
33 /// \https{JetBrains CLion,www.jetbrains.com/clion} and is defined as:
34 /** \verbatim
35Multi-Threadding {} in Lock \"{}\"
36 Message: {}
37 In (Member-)Function: {}
38 Is Owned: {} ({})
39
40 Called By: {}::{}
41 At: {}:{}
42 Thread: {}
43
44 Latest Acquisition By: {}::{}
45 At: {}:{}
46 Thread: {}
47 Latest Release By: {}:{}
48 At: {}:{}
49 Thread: {}
50 \endverbatim
51 <p>
52 The placeholder fields that this format string refers to are set as follows:
53 - \c 0: String "Assertion" or "Warning"
54 - \c 1: Debug-name of the lock.
55 - \c 2: Headline.
56 - \c 3: Function name.
57 - \c 4: Is acquired (true/false).
58 - \c 5: number of acquirements.
59 - \c 6-10: \b %CallerInfo of caller.
60 - \c 11-15: \b %CallerInfo of the latest acquisition.
61 - \c 16-20: \b %CallerInfo of the latest release.
62*/
64 static const char* ASSERTION_FORMAT;
65
66
67 /// This is a threshold that causes non-timed Acquire() methods to raise a \alib warning in
68 /// debug-builds in case a thread is blocked longer than the given duration.
69 ///
70 /// To disable warnings in cases that high block times are suitable, set this value to \c 0.
71 /// The default value is two seconds.
72 Ticks::Duration WaitTimeLimit = Ticks::Duration::FromAbsoluteSeconds(2);
73
74 /// Limit of recursions. If the limit is reached or a multiple of it, an
75 /// \alib warning is raised.
76 /// Defaults is \c 10. To disable, set to \c 0.<p>
77 /// Available only in debug versions of \alib.
79
80 /// Destructor.
81 virtual ~DbgLockAsserter() {}
82
83 /// Returns a pointer the owning thread.<p>
84 /// Available only in debug-builds.
85 /// @return Pointer to the owning thread, or \c nullptr if not owned.
87 Thread* GetOwner() const;
88
89 /// Returns \c true if the current owner is the current thread.<p>
90 /// Available only in debug-builds.
91 /// @return \c true, if the lock is owned by this thread, \c false if it is owned by
92 /// another thread or not owned.
94 { return CntAcquirements > 0 && AcqCI.ThreadID == std::this_thread::get_id(); }
95
96 /// Returns \c true if this is a non-recursive lock or a recursive instance which is acquired
97 /// exactly once.<br>
98 /// Available only in debug-builds.
99 ///
100 /// \note
101 /// This method is not (and cannot) be synchronized. Consequently, a reliable result
102 /// is only guaranteed in case #IsOwnedByCurrentThread returns \c true before this method
103 /// is invoked.
104 ///
105 /// @return \c true if the next release will free this lock, \c false otherwise.
106 bool WillRelease() const noexcept { return CntAcquirements == 1; }
107
108 /// Collects assertion info and \ref alib_mod_assert "raises a warning or error".
109 /// @see
110 /// Field #ASSERTION_FORMAT which allows changing the output format to achieve 'clickable'
111 /// assertion messages.
112 /// @param type 0= assertion, 1= warning.
113 /// @param assertCI Location where the assertion is placed.
114 /// @param ci Location of the call to the method that asserted.
115 /// @param headline The message.
117 virtual
118 void DoAssert (int type, const CallerInfo& assertCI, const CallerInfo& ci,
119 const char* headline );
120
121 /// Asserts that #CntAcquirements is not \c 0
122 /// @param assertCI Location where the assertion is placed.
123 /// @param ci Location of the call to the method that asserted.
124 /// @param headline The message.
125 void AssertOwned (const CallerInfo& assertCI, const CallerInfo& ci, const char* headline )
126 {
127 if( CntAcquirements == 0 )
128 DoAssert( 0, assertCI, ci, headline );
129 }
130
131 /// Asserts that #CntAcquirements is \c 0
132 /// @param assertCI Location where the assertion is placed.
133 /// @param ci Location of the call to the method that asserted.
134 /// @param headline The message.
135 void AssertNotOwned (const CallerInfo& assertCI, const CallerInfo& ci, const char* headline )
136 {
137 if( CntAcquirements > 0 )
138 DoAssert( 0, assertCI, ci, headline );
139 }
140
141 /// Asserts that either #CntAcquirements is \c 0 or the lock is owned by calling thread.
142 /// @param assertCI Location where the assertion is placed.
143 /// @param ci Location of the call to the method that asserted.
144 /// @param headline The message.
145 void AssertNotOwnedOrMe (const CallerInfo& assertCI, const CallerInfo& ci, const char* headline )
146 {
147 if( CntAcquirements > 0 && ci.ThreadID != AcqCI.ThreadID )
148 DoAssert( 0, assertCI, ci, headline );
149 }
150
151 /// Asserts that this lock is owned by the thread in \p{ci}.
152 /// @param assertCI Location where the assertion is placed.
153 /// @param ci Location of the call to the method that asserted.
154 /// @param headline The message.
155 void AssertOwning (const CallerInfo& assertCI, const CallerInfo& ci, const char* headline )
156 {
157 if( CntAcquirements == 0 || ci.ThreadID != AcqCI.ThreadID )
158 DoAssert( 0, assertCI, ci, headline);
159 }
160
161 /// Asserts that this lock is not owned by the thread in \p{ci}.
162 /// @param assertCI Location where the assertion is placed.
163 /// @param ci Location of the call to the method that asserted.
164 /// @param headline The message.
165 void AssertNotOwning(const CallerInfo& assertCI, const CallerInfo& ci, const char* headline )
166 {
167 if( CntAcquirements > 0 && ci.ThreadID == AcqCI.ThreadID )
168 DoAssert( 0, assertCI, ci, headline);
169 }
170}; // struct DbgLockAsserter
171
172//==================================================================================================
173/// This type is used for debugging and asserting \alib lock (mutex) types.
174/// With debug compilations the shared lock types hold one member of this struct, which
175/// aggregates all debug information.
176//==================================================================================================
178{
179 CallerInfo SAcqCI; ///< Source location of the most recent shared acquirement.
180 CallerInfo SRelCI; ///< Source location of the most recent shared release.
181 std::atomic<int> CntSharedAcquirements{0}; ///< The number of shared acquirements.
182
183 /// The format string used to write exceptions to the console.
184 /// This string can be changed if the source information is not "clickable" in a user's
185 /// development environment.<br>
186 ///
187 /// The default string is optimized for
188 /// \https{JetBrains CLion,www.jetbrains.com/clion} and is defined as:
189 /** \verbatim
190Multi-Threadding {} in Shared-Lock \"{}\"
191 Message: {}
192 In (Member-)Function: {}
193 Is Owned: {} ({})
194 Is Shared Owned: {} ({})
195
196 Called By: {}::{}
197 At: {}:{}
198 Thread: {}
199
200 Latest Acquisition By: {}::{}
201 At: {}:{}
202 Thread: {}
203 Latest Release By: {}::{}
204 At: {}:{}
205 Thread: {}
206
207 Latest Shared Acquisition By: {}::{}
208 At: {}:{}
209 Thread: {}
210 Latest SharedRelease By: {}::{}
211 At: {}:{}
212 Thread: {}
213 \endverbatim
214 <p>
215 The placeholder fields that this format string refers to are set as follows:
216
217 - \c 0: String "Assertion" or "Warning"
218 - \c 1: Debug-name of the lock.
219 - \c 2: Headline.
220 - \c 3: Function name.
221 - \c 4: Is acquired (true/false).
222 - \c 5: number of acquirements.
223 - \c 6: Is shared acquired (true/false).
224 - \c 7: number of shared-acquirements.
225 - \c 8-12: \b %CallerInfo of caller.
226 - \c 13-17: \b %CallerInfo of the latest acquisition.
227 - \c 18-22: \b %CallerInfo of the latest release.
228 - \c 23-27: \b %CallerInfo of the latest shared-acquisition.
229 - \c 32-36: \b %CallerInfo of the latest shared-release.
230 */
232 static const char* ASSERTION_FORMAT_SHARED;
233
234
235 /// Destructor.
236 virtual ~DbgSharedLockAsserter() override {}
237
238 /// Assembles assertion info and \ref alib_mod_assert "raises a warning or an error".
239 /// @see
240 /// Field #ASSERTION_FORMAT which allows changing the output format to achieve 'clickable'
241 /// assertion messages.
242 /// @param type 0= assertion, 1= warning.
243 /// @param assertCI Location where the assertion is placed.
244 /// @param ci Location of the call to the method that asserted.
245 /// @param headline The message.
247 void DoAssert (int type, const CallerInfo& assertCI, const CallerInfo& ci,
248 const char* headline ) override;
249
250 /// Returns \c true if currently a reader is registered. This method is used to
251 /// create assertions. of course, to detect assertions, it would be more efficient to check
252 /// if shared ownership is with the current thread, but a check on this would cost
253 /// a lot of overhead to realize. This way, at least assertions can be raised when no other
254 /// thread acquired this lock in shared mode.<p>
255 /// Available only in debug-builds.
256 /// @return \c true, if the lock is owned by this thread, \c false if it is owned by
257 /// another thread or not owned.
258 bool IsSharedOwnedByAnyThread() const{ return CntSharedAcquirements.load() > 0; }
259
260 /// Asserts that #CntAcquirements is \c 0
261 /// @param assertCI Location where the assertion is placed.
262 /// @param ci Location of the call to the method that asserted.
263 /// @param headline The message.
264 void AssertNotOwned (const CallerInfo& assertCI, const CallerInfo& ci, const char* headline )
265 {
266 if( CntAcquirements > 0 || CntSharedAcquirements.load() > 0 )
267 DoAssert( 0, assertCI, ci, headline );
268 }
269}; // struct DbgSharedLockAsserter
270
271
272//==================================================================================================
273/// This type is used for debugging and asserting types \alib{threads;TCondition}.
274/// With debug compilations that class holds one member of this struct, which aggregates all
275/// debug information.
276//==================================================================================================
278{
279 const character* Name; ///< The name of this instance.
280 Thread* Owner{nullptr}; ///< Tracks the current owner.
281 CallerInfo AcqCI ; ///< Source location of the most recent acquirement.
282 CallerInfo RelCI ; ///< Source location of the most recent release.
283 CallerInfo WaitCI; ///< The most recent call to \b WaitForNotification.
284 CallerInfo NotifyCI; ///< The most recent call to \b ReleaseAndNotify or
285 std::atomic<int> CntWaiters{0}; ///< The number of currently waiting threads.
286 std::thread::id AssertExclusiveWaiter; ///< If set from outside, methods \b WaitForNotification
287 ///< will raise an assertion in the case they are called
288 ///< from a different thread.
289 /// The format string used to write exceptions to the console.
290 /// This string can be changed if the source information is not "clickable" in a user's
291 /// development environment.<br>
292 ///
293 /// The default string is optimized for
294 /// \https{JetBrains CLion,www.jetbrains.com/clion} and is defined as:
295 /** \verbatim
296Assertion failed in method TCondition::{}
297 Message: {}
298 Instance: {}
299
300 Called By: {}::{}
301 At: {}:{}
302 Thread: {}
303
304 Current Owner: {}
305 #Of Waiters: {}
306 Exclusive Waiter: {}
307
308 Latest Acquisition By: {}::{}
309 At: {}:{}
310 Thread: {}
311 Latest Release By: {}::{}
312 At: {}:{}
313 Thread: {}
314
315 Latest Wait By: {}::{}
316 At: {}:{}
317 Thread: {}
318 Latest Notify By: {}::{}
319 At: {}:{}
320 Thread: {}
321 \endverbatim
322*/
324 static const char* ASSERTION_FORMAT;
325
326 /// Writes assertion info and calls \ref ALIB_ASSERT.
327 /// @see
328 /// Field #ASSERTION_FORMAT which allows changing the output format to achieve 'clickable'
329 /// assertion messages.
330 /// @param cond The condition that is to be met.
331 /// @param assertCI Location where the assertion is placed.
332 /// @param ci Location of the call to the method that asserted.
333 /// @param headline The message.
335 void Assert( bool cond, const CallerInfo& assertCI, const CallerInfo& ci,
336 const char* headline );
337
338 /// Returns \c true if the current owner is the current thread.<p>
339 /// Available only in debug-builds.
340 /// @return \c true, if the lock is owned by this thread, \c false if it is owned by
341 /// another thread or not owned.
343 { return Owner != nullptr && Owner == Thread::GetCurrent() ; }
344
345}; // struct DbgConditionAsserter
346
347} // namespace [alib::threads]
348
349#endif // !ALIB_SINGLE_THREADED && ALIB_DEBUG
static Thread * GetCurrent()
Definition thread.inl:300
#define ALIB_DLL
Definition alib.inl:496
#define ALIB_EXPORT
Definition alib.inl:488
lang::CallerInfo CallerInfo
Type alias in namespace alib.
characters::character character
Type alias in namespace alib.
std::thread::id ThreadID
The ID of the calling thread.
ALIB_DLL void Assert(bool cond, const CallerInfo &assertCI, const CallerInfo &ci, const char *headline)
CallerInfo NotifyCI
The most recent call to ReleaseAndNotify or.
const character * Name
The name of this instance.
static ALIB_DLL const char * ASSERTION_FORMAT
CallerInfo RelCI
Source location of the most recent release.
Thread * Owner
Tracks the current owner.
std::atomic< int > CntWaiters
The number of currently waiting threads.
CallerInfo AcqCI
Source location of the most recent acquirement.
CallerInfo WaitCI
The most recent call to WaitForNotification.
static ALIB_DLL const char * ASSERTION_FORMAT
CallerInfo RelCI
Source location of the most recent release.
int16_t CntAcquirements
The number of nested acquirements.
virtual ALIB_DLL void DoAssert(int type, const CallerInfo &assertCI, const CallerInfo &ci, const char *headline)
void AssertOwned(const CallerInfo &assertCI, const CallerInfo &ci, const char *headline)
ALIB_DLL Thread * GetOwner() const
void AssertNotOwning(const CallerInfo &assertCI, const CallerInfo &ci, const char *headline)
void AssertNotOwnedOrMe(const CallerInfo &assertCI, const CallerInfo &ci, const char *headline)
bool WillRelease() const noexcept
void AssertOwning(const CallerInfo &assertCI, const CallerInfo &ci, const char *headline)
CallerInfo AcqCI
Source location of the most recent acquirement.
virtual ~DbgLockAsserter()
Destructor.
void AssertNotOwned(const CallerInfo &assertCI, const CallerInfo &ci, const char *headline)
CallerInfo SAcqCI
Source location of the most recent shared acquirement.
virtual ~DbgSharedLockAsserter() override
Destructor.
ALIB_DLL void DoAssert(int type, const CallerInfo &assertCI, const CallerInfo &ci, const char *headline) override
static ALIB_DLL const char * ASSERTION_FORMAT_SHARED
void AssertNotOwned(const CallerInfo &assertCI, const CallerInfo &ci, const char *headline)
std::atomic< int > CntSharedAcquirements
The number of shared acquirements.
CallerInfo SRelCI
Source location of the most recent shared release.