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