File indexing completed on 2024-05-12 12:02:32
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