/* -*- C++ -*- This file declares debugging aids for multithreaded applications. SPDX-FileCopyrightText: 2004-2013 Mirko Boehm SPDX-License-Identifier: LGPL-2.0-or-later $Id: DebuggingAids.h 30 2005-08-16 16:16:04Z mirko $ */ // krazy:excludeall=inline #ifndef DEBUGGINGAIDS_H #define DEBUGGINGAIDS_H #include extern "C" { #include #ifndef Q_OS_WIN #include #endif #include #include #include } #include "threadweaver_export.h" #include #include namespace ThreadWeaver { extern THREADWEAVER_EXPORT bool Debug; extern THREADWEAVER_EXPORT int DebugLevel; extern THREADWEAVER_EXPORT QMutex GlobalMutex; /*! Set the debug log level. * \sa debug */ extern inline void setDebugLevel(bool TWDEBUG, int level); /*! This method prints a text message on the screen, if debugging is * enabled. Otherwise, it does nothing. The message is thread safe, * therefore providing that the messages appear in the order they where * issued by the different threads. * All messages are suppressed when Debug is false. All messages with a * lower importance (higher number) than DebugLevel will be suppressed, * too. Debug level 0 messages will always be printed as long as * Debug is true. * We use our own debugging method, since debugging threads is a more * complicated experience than debugging single threaded * contexts. This might change in future in the way that debug * prints its messages to another logging facility provided by * the platform. * Use setDebugLevel () to integrate adapt debug () to your platform. */ inline void TWDEBUG(int severity, const char *cformat, ...) #ifdef __GNUC__ __attribute__((format(printf, 2, 3))) #endif ; /*! Prints the message to the console if condition is true. */ inline void TWDEBUG(bool condition, int severity, const char *cformat, ...) #ifdef __GNUC__ __attribute__((format(printf, 3, 4))) #endif ; /* PROTECT executes x with GlobalMutex locked. * Mostly used for debugging, as in P_ASSERT. */ #ifdef PROTECT #undef PROTECT #endif /* clang-format off */ #define PROTECT(x) \ do { \ QMutexLocker l(&ThreadWeaver::GlobalMutex); \ (x); \ } while (0) /* clang-format on */ /*! P_ASSERT ensures that error messages occur in the correct order. */ #ifdef P_ASSERT #undef P_ASSERT #endif /* clang-format off */ #define P_ASSERT(x) \ do { \ QMutexLocker l(&ThreadWeaver::GlobalMutex); \ Q_ASSERT(x); \ } while (0) /* clang-format on */ /*! */ inline void setDebugLevel(bool debug, int level) { Debug = debug; DebugLevel = level; } #ifndef QT_NO_DEBUG #define TWDEBUG(...) ThreadWeaver::threadweaver_debug(__VA_ARGS__) /*! */ inline void threadweaver_debug(int severity, const char *cformat, ...) { if (Debug == true && (severity <= DebugLevel || severity == 0)) { QString text; va_list ap; va_start(ap, cformat); PROTECT(vprintf(cformat, ap)); va_end(ap); } } /*! */ inline void threadweaver_debug(bool condition, int severity, const char *cformat, ...) { if (condition && Debug == true && (severity <= DebugLevel || severity == 0)) { QString text; va_list ap; va_start(ap, cformat); PROTECT(vprintf(cformat, ap)); va_end(ap); } } #else #define TWDEBUG(...) #endif // Macros to ensure that mutexes are locked or unlocked: /*! */ void THREADWEAVER_EXPORT mutexAssertUnlocked(QMutex *mutex, const char *where); /*! */ void THREADWEAVER_EXPORT mutexAssertLocked(QMutex *mutex, const char *where); #ifndef QT_NO_DEBUG #define MUTEX_ASSERT_UNLOCKED(x) mutexAssertUnlocked(x, Q_FUNC_INFO) #define MUTEX_ASSERT_LOCKED(x) mutexAssertLocked(x, Q_FUNC_INFO) #else #define MUTEX_ASSERT_UNLOCKED(x) #define MUTEX_ASSERT_LOCKED(x) #endif /*! */ inline bool invariant() { return true; } #define INVARIANT Q_ASSERT_X(invariant(), __FILE__, "class invariant failed"); /* clang-format off */ #define REQUIRE(x) \ INVARIANT \ Q_ASSERT_X(x, Q_FUNC_INFO, "unfulfilled requirement " #x); #define ENSURE(x) \ INVARIANT \ Q_ASSERT_X(x, Q_FUNC_INFO, "broken guarantee " #x); /* clang-format on */ #ifdef QT_NO_DEBUG #define DEBUGONLY(x) #else #define DEBUGONLY(x) x #endif } #endif // DEBUGGINGAIDS_H