File indexing completed on 2024-04-28 04:01:22

0001 /* -*- C++ -*-
0002     This file declares debugging aids for multithreaded applications.
0003 
0004     SPDX-FileCopyrightText: 2004-2013 Mirko Boehm <mirko@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 
0008     $Id: DebuggingAids.h 30 2005-08-16 16:16:04Z mirko $
0009 */
0010 
0011 // krazy:excludeall=inline
0012 
0013 #ifndef DEBUGGINGAIDS_H
0014 #define DEBUGGINGAIDS_H
0015 
0016 #include <QtGlobal>
0017 
0018 extern "C" {
0019 #include <stdarg.h>
0020 #ifndef Q_OS_WIN
0021 #include <unistd.h>
0022 #endif
0023 #include <assert.h>
0024 #include <stdio.h>
0025 #include <stdlib.h>
0026 }
0027 
0028 #include "threadweaver_export.h"
0029 #include <QMutex>
0030 #include <QString>
0031 
0032 namespace ThreadWeaver
0033 {
0034 extern THREADWEAVER_EXPORT bool Debug;
0035 extern THREADWEAVER_EXPORT int DebugLevel;
0036 extern THREADWEAVER_EXPORT QMutex GlobalMutex;
0037 
0038 /** Set the debug log level.
0039 @see debug
0040 */
0041 extern inline void setDebugLevel(bool TWDEBUG, int level);
0042 
0043 /** This method prints a text message on the screen, if debugging is
0044 enabled. Otherwise, it does nothing. The message is thread safe,
0045 therefore providing that the messages appear in the order they where
0046 issued by the different threads.
0047 All messages are suppressed when Debug is false. All messages with a
0048 lower importance (higher number) than DebugLevel will be suppressed,
0049 too. Debug level 0 messages will always be printed as long as
0050 Debug is true.
0051     We use our own debugging method, since debugging threads is a more
0052     complicated experience than debugging single threaded
0053     contexts. This might change in future in the way that debug
0054     prints its messages to another logging facility provided by
0055     the platform.
0056 Use setDebugLevel () to integrate adapt debug () to your platform.
0057 */
0058 inline void TWDEBUG(int severity, const char *cformat, ...)
0059 #ifdef __GNUC__
0060     __attribute__((format(printf, 2, 3)))
0061 #endif
0062     ;
0063 
0064 /** Prints the message to the console if condition is true. */
0065 inline void TWDEBUG(bool condition, int severity, const char *cformat, ...)
0066 #ifdef __GNUC__
0067     __attribute__((format(printf, 3, 4)))
0068 #endif
0069     ;
0070 
0071 /** PROTECT executes x with GlobalMutex locked.
0072     Mostly used for debugging, as in P_ASSERT. */
0073 #ifdef PROTECT
0074 #undef PROTECT
0075 #endif
0076 
0077 /* clang-format off */
0078 #define PROTECT(x) \
0079     do { \
0080         QMutexLocker l(&ThreadWeaver::GlobalMutex); \
0081         (x); \
0082     } while (0)
0083 /* clang-format on */
0084 
0085 /** P_ASSERT ensures that error messages occur in the correct order. */
0086 #ifdef P_ASSERT
0087 #undef P_ASSERT
0088 #endif
0089 
0090 /* clang-format off */
0091 #define P_ASSERT(x) \
0092     do { \
0093         QMutexLocker l(&ThreadWeaver::GlobalMutex); \
0094         Q_ASSERT(x); \
0095     } while (0)
0096 /* clang-format on */
0097 
0098 inline void setDebugLevel(bool debug, int level)
0099 {
0100     Debug = debug;
0101     DebugLevel = level;
0102 }
0103 
0104 #ifndef QT_NO_DEBUG
0105 
0106 #define TWDEBUG(...) ThreadWeaver::threadweaver_debug(__VA_ARGS__)
0107 inline void threadweaver_debug(int severity, const char *cformat, ...)
0108 {
0109     if (Debug == true && (severity <= DebugLevel || severity == 0)) {
0110         QString text;
0111 
0112         va_list ap;
0113         va_start(ap, cformat);
0114         PROTECT(vprintf(cformat, ap));
0115         va_end(ap);
0116     }
0117 }
0118 
0119 inline void threadweaver_debug(bool condition, int severity, const char *cformat, ...)
0120 {
0121     if (condition && Debug == true && (severity <= DebugLevel || severity == 0)) {
0122         QString text;
0123 
0124         va_list ap;
0125         va_start(ap, cformat);
0126         PROTECT(vprintf(cformat, ap));
0127         va_end(ap);
0128     }
0129 }
0130 #else
0131 #define TWDEBUG(...)
0132 #endif
0133 
0134 // Macros to ensure that mutexes are locked or unlocked:
0135 void THREADWEAVER_EXPORT mutexAssertUnlocked(QMutex *mutex, const char *where);
0136 void THREADWEAVER_EXPORT mutexAssertLocked(QMutex *mutex, const char *where);
0137 
0138 #ifndef QT_NO_DEBUG
0139 #define MUTEX_ASSERT_UNLOCKED(x) mutexAssertUnlocked(x, Q_FUNC_INFO)
0140 #define MUTEX_ASSERT_LOCKED(x) mutexAssertLocked(x, Q_FUNC_INFO)
0141 #else
0142 #define MUTEX_ASSERT_UNLOCKED(x)
0143 #define MUTEX_ASSERT_LOCKED(x)
0144 #endif
0145 
0146 inline bool invariant()
0147 {
0148     return true;
0149 }
0150 
0151 #define INVARIANT Q_ASSERT_X(invariant(), __FILE__, "class invariant failed");
0152 
0153 /* clang-format off */
0154 #define REQUIRE(x) \
0155     INVARIANT \
0156     Q_ASSERT_X(x, Q_FUNC_INFO, "unfulfilled requirement " #x);
0157 
0158 #define ENSURE(x) \
0159     INVARIANT \
0160     Q_ASSERT_X(x, Q_FUNC_INFO, "broken guarantee " #x);
0161 /* clang-format on */
0162 
0163 #ifdef QT_NO_DEBUG
0164 #define DEBUGONLY(x)
0165 #else
0166 #define DEBUGONLY(x) x
0167 #endif
0168 
0169 }
0170 
0171 #endif // DEBUGGINGAIDS_H