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