1*061da546Spatrick //===-- DNBLog.cpp ----------------------------------------------*- C++ -*-===// 2*061da546Spatrick // 3*061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*061da546Spatrick // See https://llvm.org/LICENSE.txt for license information. 5*061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*061da546Spatrick // 7*061da546Spatrick //===----------------------------------------------------------------------===// 8*061da546Spatrick // 9*061da546Spatrick // Created by Greg Clayton on 6/18/07. 10*061da546Spatrick // 11*061da546Spatrick //===----------------------------------------------------------------------===// 12*061da546Spatrick 13*061da546Spatrick #include "DNBLog.h" 14*061da546Spatrick 15*061da546Spatrick static int g_debug = 0; 16*061da546Spatrick static int g_verbose = 0; 17*061da546Spatrick 18*061da546Spatrick #if defined(DNBLOG_ENABLED) 19*061da546Spatrick 20*061da546Spatrick #include "PThreadMutex.h" 21*061da546Spatrick #include <mach/mach.h> 22*061da546Spatrick #include <pthread.h> 23*061da546Spatrick #include <stdarg.h> 24*061da546Spatrick #include <stdio.h> 25*061da546Spatrick #include <stdlib.h> 26*061da546Spatrick #include <sys/time.h> 27*061da546Spatrick #include <unistd.h> 28*061da546Spatrick 29*061da546Spatrick uint32_t g_log_bits = 0; 30*061da546Spatrick static DNBCallbackLog g_log_callback = NULL; 31*061da546Spatrick static void *g_log_baton = NULL; 32*061da546Spatrick 33*061da546Spatrick int DNBLogGetDebug() { return g_debug; } 34*061da546Spatrick 35*061da546Spatrick void DNBLogSetDebug(int g) { g_debug = g; } 36*061da546Spatrick 37*061da546Spatrick int DNBLogGetVerbose() { return g_verbose; } 38*061da546Spatrick 39*061da546Spatrick void DNBLogSetVerbose(int v) { g_verbose = v; } 40*061da546Spatrick 41*061da546Spatrick bool DNBLogCheckLogBit(uint32_t bit) { return (g_log_bits & bit) != 0; } 42*061da546Spatrick 43*061da546Spatrick uint32_t DNBLogSetLogMask(uint32_t mask) { 44*061da546Spatrick uint32_t old = g_log_bits; 45*061da546Spatrick g_log_bits = mask; 46*061da546Spatrick return old; 47*061da546Spatrick } 48*061da546Spatrick 49*061da546Spatrick uint32_t DNBLogGetLogMask() { return g_log_bits; } 50*061da546Spatrick 51*061da546Spatrick void DNBLogSetLogCallback(DNBCallbackLog callback, void *baton) { 52*061da546Spatrick g_log_callback = callback; 53*061da546Spatrick g_log_baton = baton; 54*061da546Spatrick } 55*061da546Spatrick 56*061da546Spatrick DNBCallbackLog DNBLogGetLogCallback() { return g_log_callback; } 57*061da546Spatrick 58*061da546Spatrick bool DNBLogEnabled() { return g_log_callback != NULL; } 59*061da546Spatrick 60*061da546Spatrick bool DNBLogEnabledForAny(uint32_t mask) { 61*061da546Spatrick if (g_log_callback) 62*061da546Spatrick return (g_log_bits & mask) != 0; 63*061da546Spatrick return false; 64*061da546Spatrick } 65*061da546Spatrick static inline void _DNBLogVAPrintf(uint32_t flags, const char *format, 66*061da546Spatrick va_list args) { 67*061da546Spatrick static PThreadMutex g_LogThreadedMutex(PTHREAD_MUTEX_RECURSIVE); 68*061da546Spatrick PTHREAD_MUTEX_LOCKER(locker, g_LogThreadedMutex); 69*061da546Spatrick 70*061da546Spatrick if (g_log_callback) 71*061da546Spatrick g_log_callback(g_log_baton, flags, format, args); 72*061da546Spatrick } 73*061da546Spatrick 74*061da546Spatrick void _DNBLog(uint32_t flags, const char *format, ...) { 75*061da546Spatrick va_list args; 76*061da546Spatrick va_start(args, format); 77*061da546Spatrick _DNBLogVAPrintf(flags, format, args); 78*061da546Spatrick va_end(args); 79*061da546Spatrick } 80*061da546Spatrick 81*061da546Spatrick // Print debug strings if and only if the global g_debug is set to 82*061da546Spatrick // a non-zero value. 83*061da546Spatrick void _DNBLogDebug(const char *format, ...) { 84*061da546Spatrick if (DNBLogEnabled() && g_debug) { 85*061da546Spatrick va_list args; 86*061da546Spatrick va_start(args, format); 87*061da546Spatrick _DNBLogVAPrintf(DNBLOG_FLAG_DEBUG, format, args); 88*061da546Spatrick va_end(args); 89*061da546Spatrick } 90*061da546Spatrick } 91*061da546Spatrick 92*061da546Spatrick // Print debug strings if and only if the global g_debug is set to 93*061da546Spatrick // a non-zero value. 94*061da546Spatrick void _DNBLogDebugVerbose(const char *format, ...) { 95*061da546Spatrick if (DNBLogEnabled() && g_debug && g_verbose) { 96*061da546Spatrick va_list args; 97*061da546Spatrick va_start(args, format); 98*061da546Spatrick _DNBLogVAPrintf(DNBLOG_FLAG_DEBUG | DNBLOG_FLAG_VERBOSE, format, args); 99*061da546Spatrick va_end(args); 100*061da546Spatrick } 101*061da546Spatrick } 102*061da546Spatrick 103*061da546Spatrick static uint32_t g_message_id = 0; 104*061da546Spatrick 105*061da546Spatrick // Prefix the formatted log string with process and thread IDs and 106*061da546Spatrick // suffix it with a newline. 107*061da546Spatrick void _DNBLogThreaded(const char *format, ...) { 108*061da546Spatrick if (DNBLogEnabled()) { 109*061da546Spatrick // PTHREAD_MUTEX_LOCKER(locker, GetLogThreadedMutex()); 110*061da546Spatrick 111*061da546Spatrick char *arg_msg = NULL; 112*061da546Spatrick va_list args; 113*061da546Spatrick va_start(args, format); 114*061da546Spatrick ::vasprintf(&arg_msg, format, args); 115*061da546Spatrick va_end(args); 116*061da546Spatrick 117*061da546Spatrick if (arg_msg != NULL) { 118*061da546Spatrick static struct timeval g_timeval = {0, 0}; 119*061da546Spatrick static struct timeval tv; 120*061da546Spatrick static struct timeval delta; 121*061da546Spatrick gettimeofday(&tv, NULL); 122*061da546Spatrick if (g_timeval.tv_sec == 0) { 123*061da546Spatrick delta.tv_sec = 0; 124*061da546Spatrick delta.tv_usec = 0; 125*061da546Spatrick } else { 126*061da546Spatrick timersub(&tv, &g_timeval, &delta); 127*061da546Spatrick } 128*061da546Spatrick g_timeval = tv; 129*061da546Spatrick 130*061da546Spatrick // Calling "mach_port_deallocate()" bumps the reference count on the 131*061da546Spatrick // thread 132*061da546Spatrick // port, so we need to deallocate it. mach_task_self() doesn't bump the 133*061da546Spatrick // ref 134*061da546Spatrick // count. 135*061da546Spatrick thread_port_t thread_self = mach_thread_self(); 136*061da546Spatrick 137*061da546Spatrick _DNBLog(DNBLOG_FLAG_THREADED, "%u +%lu.%06u sec [%4.4x/%4.4x]: %s", 138*061da546Spatrick ++g_message_id, delta.tv_sec, delta.tv_usec, getpid(), 139*061da546Spatrick thread_self, arg_msg); 140*061da546Spatrick 141*061da546Spatrick mach_port_deallocate(mach_task_self(), thread_self); 142*061da546Spatrick free(arg_msg); 143*061da546Spatrick } 144*061da546Spatrick } 145*061da546Spatrick } 146*061da546Spatrick 147*061da546Spatrick // Prefix the formatted log string with process and thread IDs and 148*061da546Spatrick // suffix it with a newline. 149*061da546Spatrick void _DNBLogThreadedIf(uint32_t log_bit, const char *format, ...) { 150*061da546Spatrick if (DNBLogEnabled() && (log_bit & g_log_bits) == log_bit) { 151*061da546Spatrick // PTHREAD_MUTEX_LOCKER(locker, GetLogThreadedMutex()); 152*061da546Spatrick 153*061da546Spatrick char *arg_msg = NULL; 154*061da546Spatrick va_list args; 155*061da546Spatrick va_start(args, format); 156*061da546Spatrick ::vasprintf(&arg_msg, format, args); 157*061da546Spatrick va_end(args); 158*061da546Spatrick 159*061da546Spatrick if (arg_msg != NULL) { 160*061da546Spatrick static struct timeval g_timeval = {0, 0}; 161*061da546Spatrick static struct timeval tv; 162*061da546Spatrick static struct timeval delta; 163*061da546Spatrick gettimeofday(&tv, NULL); 164*061da546Spatrick if (g_timeval.tv_sec == 0) { 165*061da546Spatrick delta.tv_sec = 0; 166*061da546Spatrick delta.tv_usec = 0; 167*061da546Spatrick } else { 168*061da546Spatrick timersub(&tv, &g_timeval, &delta); 169*061da546Spatrick } 170*061da546Spatrick g_timeval = tv; 171*061da546Spatrick 172*061da546Spatrick // Calling "mach_port_deallocate()" bumps the reference count on the 173*061da546Spatrick // thread 174*061da546Spatrick // port, so we need to deallocate it. mach_task_self() doesn't bump the 175*061da546Spatrick // ref 176*061da546Spatrick // count. 177*061da546Spatrick thread_port_t thread_self = mach_thread_self(); 178*061da546Spatrick 179*061da546Spatrick _DNBLog(DNBLOG_FLAG_THREADED, "%u +%lu.%06u sec [%4.4x/%4.4x]: %s", 180*061da546Spatrick ++g_message_id, delta.tv_sec, delta.tv_usec, getpid(), 181*061da546Spatrick thread_self, arg_msg); 182*061da546Spatrick 183*061da546Spatrick mach_port_deallocate(mach_task_self(), thread_self); 184*061da546Spatrick 185*061da546Spatrick free(arg_msg); 186*061da546Spatrick } 187*061da546Spatrick } 188*061da546Spatrick } 189*061da546Spatrick 190*061da546Spatrick // Printing of errors that are not fatal. 191*061da546Spatrick void _DNBLogError(const char *format, ...) { 192*061da546Spatrick if (DNBLogEnabled()) { 193*061da546Spatrick char *arg_msg = NULL; 194*061da546Spatrick va_list args; 195*061da546Spatrick va_start(args, format); 196*061da546Spatrick ::vasprintf(&arg_msg, format, args); 197*061da546Spatrick va_end(args); 198*061da546Spatrick 199*061da546Spatrick if (arg_msg != NULL) { 200*061da546Spatrick _DNBLog(DNBLOG_FLAG_ERROR, "error: %s", arg_msg); 201*061da546Spatrick free(arg_msg); 202*061da546Spatrick } 203*061da546Spatrick } 204*061da546Spatrick } 205*061da546Spatrick 206*061da546Spatrick // Printing of errors that ARE fatal. Exit with ERR exit code 207*061da546Spatrick // immediately. 208*061da546Spatrick void _DNBLogFatalError(int err, const char *format, ...) { 209*061da546Spatrick if (DNBLogEnabled()) { 210*061da546Spatrick char *arg_msg = NULL; 211*061da546Spatrick va_list args; 212*061da546Spatrick va_start(args, format); 213*061da546Spatrick ::vasprintf(&arg_msg, format, args); 214*061da546Spatrick va_end(args); 215*061da546Spatrick 216*061da546Spatrick if (arg_msg != NULL) { 217*061da546Spatrick _DNBLog(DNBLOG_FLAG_ERROR | DNBLOG_FLAG_FATAL, "error: %s", arg_msg); 218*061da546Spatrick free(arg_msg); 219*061da546Spatrick } 220*061da546Spatrick ::exit(err); 221*061da546Spatrick } 222*061da546Spatrick } 223*061da546Spatrick 224*061da546Spatrick // Printing of warnings that are not fatal only if verbose mode is 225*061da546Spatrick // enabled. 226*061da546Spatrick void _DNBLogVerbose(const char *format, ...) { 227*061da546Spatrick if (DNBLogEnabled() && g_verbose) { 228*061da546Spatrick va_list args; 229*061da546Spatrick va_start(args, format); 230*061da546Spatrick _DNBLogVAPrintf(DNBLOG_FLAG_VERBOSE, format, args); 231*061da546Spatrick va_end(args); 232*061da546Spatrick } 233*061da546Spatrick } 234*061da546Spatrick 235*061da546Spatrick // Printing of warnings that are not fatal only if verbose mode is 236*061da546Spatrick // enabled. 237*061da546Spatrick void _DNBLogWarningVerbose(const char *format, ...) { 238*061da546Spatrick if (DNBLogEnabled() && g_verbose) { 239*061da546Spatrick char *arg_msg = NULL; 240*061da546Spatrick va_list args; 241*061da546Spatrick va_start(args, format); 242*061da546Spatrick ::vasprintf(&arg_msg, format, args); 243*061da546Spatrick va_end(args); 244*061da546Spatrick 245*061da546Spatrick if (arg_msg != NULL) { 246*061da546Spatrick _DNBLog(DNBLOG_FLAG_WARNING | DNBLOG_FLAG_VERBOSE, "warning: %s", 247*061da546Spatrick arg_msg); 248*061da546Spatrick free(arg_msg); 249*061da546Spatrick } 250*061da546Spatrick } 251*061da546Spatrick } 252*061da546Spatrick // Printing of warnings that are not fatal. 253*061da546Spatrick void _DNBLogWarning(const char *format, ...) { 254*061da546Spatrick if (DNBLogEnabled()) { 255*061da546Spatrick char *arg_msg = NULL; 256*061da546Spatrick va_list args; 257*061da546Spatrick va_start(args, format); 258*061da546Spatrick ::vasprintf(&arg_msg, format, args); 259*061da546Spatrick va_end(args); 260*061da546Spatrick 261*061da546Spatrick if (arg_msg != NULL) { 262*061da546Spatrick _DNBLog(DNBLOG_FLAG_WARNING, "warning: %s", arg_msg); 263*061da546Spatrick free(arg_msg); 264*061da546Spatrick } 265*061da546Spatrick } 266*061da546Spatrick } 267*061da546Spatrick 268*061da546Spatrick #endif 269