1/* -*- C++ -*-
2 This file declares debugging aids for multithreaded applications.
3
4 SPDX-FileCopyrightText: 2004-2013 Mirko Boehm <mirko@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7
8 $Id: DebuggingAids.h 30 2005-08-16 16:16:04Z mirko $
9*/
10
11// krazy:excludeall=inline
12
13#ifndef DEBUGGINGAIDS_H
14#define DEBUGGINGAIDS_H
15
16#include <QtGlobal>
17
18extern "C" {
19#include <stdarg.h>
20#ifndef Q_OS_WIN
21#include <unistd.h>
22#endif
23#include <assert.h>
24#include <stdio.h>
25#include <stdlib.h>
26}
27
28#include "threadweaver_export.h"
29#include <QMutex>
30#include <QString>
31
32namespace ThreadWeaver
33{
34extern THREADWEAVER_EXPORT bool Debug;
35extern THREADWEAVER_EXPORT int DebugLevel;
36extern THREADWEAVER_EXPORT QMutex GlobalMutex;
37
38/*! Set the debug log level.
39 * \sa debug
40 */
41extern inline void setDebugLevel(bool TWDEBUG, int level);
42
43/*! This method prints a text message on the screen, if debugging is
44 * enabled. Otherwise, it does nothing. The message is thread safe,
45 * therefore providing that the messages appear in the order they where
46 * issued by the different threads.
47 * All messages are suppressed when Debug is false. All messages with a
48 * lower importance (higher number) than DebugLevel will be suppressed,
49 * too. Debug level 0 messages will always be printed as long as
50 * Debug is true.
51 * We use our own debugging method, since debugging threads is a more
52 * complicated experience than debugging single threaded
53 * contexts. This might change in future in the way that debug
54 * prints its messages to another logging facility provided by
55 * the platform.
56 * Use setDebugLevel () to integrate adapt debug () to your platform.
57 */
58inline void TWDEBUG(int severity, const char *cformat, ...)
59#ifdef __GNUC__
60 __attribute__((format(printf, 2, 3)))
61#endif
62 ;
63
64/*! Prints the message to the console if condition is true. */
65inline void TWDEBUG(bool condition, int severity, const char *cformat, ...)
66#ifdef __GNUC__
67 __attribute__((format(printf, 3, 4)))
68#endif
69 ;
70
71/* PROTECT executes x with GlobalMutex locked.
72 * Mostly used for debugging, as in P_ASSERT. */
73#ifdef PROTECT
74#undef PROTECT
75#endif
76
77/* clang-format off */
78#define PROTECT(x) \
79 do { \
80 QMutexLocker l(&ThreadWeaver::GlobalMutex); \
81 (x); \
82 } while (0)
83/* clang-format on */
84
85/*! P_ASSERT ensures that error messages occur in the correct order. */
86#ifdef P_ASSERT
87#undef P_ASSERT
88#endif
89
90/* clang-format off */
91#define P_ASSERT(x) \
92 do { \
93 QMutexLocker l(&ThreadWeaver::GlobalMutex); \
94 Q_ASSERT(x); \
95 } while (0)
96/* clang-format on */
97
98/*!
99 */
100inline void setDebugLevel(bool debug, int level)
101{
102 Debug = debug;
103 DebugLevel = level;
104}
105
106#ifndef QT_NO_DEBUG
107
108#define TWDEBUG(...) ThreadWeaver::threadweaver_debug(__VA_ARGS__)
109/*!
110 */
111inline void threadweaver_debug(int severity, const char *cformat, ...)
112{
113 if (Debug == true && (severity <= DebugLevel || severity == 0)) {
114 QString text;
115
116 va_list ap;
117 va_start(ap, cformat);
118 PROTECT(vprintf(cformat, ap));
119 va_end(ap);
120 }
121}
122
123/*!
124 */
125inline void threadweaver_debug(bool condition, int severity, const char *cformat, ...)
126{
127 if (condition && Debug == true && (severity <= DebugLevel || severity == 0)) {
128 QString text;
129
130 va_list ap;
131 va_start(ap, cformat);
132 PROTECT(vprintf(cformat, ap));
133 va_end(ap);
134 }
135}
136#else
137#define TWDEBUG(...)
138#endif
139
140// Macros to ensure that mutexes are locked or unlocked:
141/*!
142 */
143void THREADWEAVER_EXPORT mutexAssertUnlocked(QMutex *mutex, const char *where);
144/*!
145 */
146void THREADWEAVER_EXPORT mutexAssertLocked(QMutex *mutex, const char *where);
147
148#ifndef QT_NO_DEBUG
149#define MUTEX_ASSERT_UNLOCKED(x) mutexAssertUnlocked(x, Q_FUNC_INFO)
150#define MUTEX_ASSERT_LOCKED(x) mutexAssertLocked(x, Q_FUNC_INFO)
151#else
152#define MUTEX_ASSERT_UNLOCKED(x)
153#define MUTEX_ASSERT_LOCKED(x)
154#endif
155
156/*!
157 */
158inline bool invariant()
159{
160 return true;
161}
162
163#define INVARIANT Q_ASSERT_X(invariant(), __FILE__, "class invariant failed");
164
165/* clang-format off */
166#define REQUIRE(x) \
167 INVARIANT \
168 Q_ASSERT_X(x, Q_FUNC_INFO, "unfulfilled requirement " #x);
169
170#define ENSURE(x) \
171 INVARIANT \
172 Q_ASSERT_X(x, Q_FUNC_INFO, "broken guarantee " #x);
173/* clang-format on */
174
175#ifdef QT_NO_DEBUG
176#define DEBUGONLY(x)
177#else
178#define DEBUGONLY(x) x
179#endif
180
181}
182
183#endif // DEBUGGINGAIDS_H
184

source code of threadweaver/src/debuggingaids.h