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
DNBLogGetDebug()33 int DNBLogGetDebug() { return g_debug; }
34
DNBLogSetDebug(int g)35 void DNBLogSetDebug(int g) { g_debug = g; }
36
DNBLogGetVerbose()37 int DNBLogGetVerbose() { return g_verbose; }
38
DNBLogSetVerbose(int v)39 void DNBLogSetVerbose(int v) { g_verbose = v; }
40
DNBLogCheckLogBit(uint32_t bit)41 bool DNBLogCheckLogBit(uint32_t bit) { return (g_log_bits & bit) != 0; }
42
DNBLogSetLogMask(uint32_t mask)43 uint32_t DNBLogSetLogMask(uint32_t mask) {
44 uint32_t old = g_log_bits;
45 g_log_bits = mask;
46 return old;
47 }
48
DNBLogGetLogMask()49 uint32_t DNBLogGetLogMask() { return g_log_bits; }
50
DNBLogSetLogCallback(DNBCallbackLog callback,void * baton)51 void DNBLogSetLogCallback(DNBCallbackLog callback, void *baton) {
52 g_log_callback = callback;
53 g_log_baton = baton;
54 }
55
DNBLogGetLogCallback()56 DNBCallbackLog DNBLogGetLogCallback() { return g_log_callback; }
57
DNBLogEnabled()58 bool DNBLogEnabled() { return g_log_callback != NULL; }
59
DNBLogEnabledForAny(uint32_t mask)60 bool DNBLogEnabledForAny(uint32_t mask) {
61 if (g_log_callback)
62 return (g_log_bits & mask) != 0;
63 return false;
64 }
_DNBLogVAPrintf(uint32_t flags,const char * format,va_list args)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
_DNBLog(uint32_t flags,const char * format,...)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 // Print debug strings if and only if the global g_debug is set to
82 // a non-zero value.
_DNBLogDebug(const char * format,...)83 void _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 to
93 // a non-zero value.
_DNBLogDebugVerbose(const char * format,...)94 void _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
103 static uint32_t g_message_id = 0;
104
105 // Prefix the formatted log string with process and thread IDs and
106 // suffix it with a newline.
_DNBLogThreaded(const char * format,...)107 void _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 the
131 // thread
132 // port, so we need to deallocate it. mach_task_self() doesn't bump the
133 // ref
134 // 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 and
148 // suffix it with a newline.
_DNBLogThreadedIf(uint32_t log_bit,const char * format,...)149 void _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 the
173 // thread
174 // port, so we need to deallocate it. mach_task_self() doesn't bump the
175 // ref
176 // 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.
_DNBLogError(const char * format,...)191 void _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 code
207 // immediately.
_DNBLogFatalError(int err,const char * format,...)208 void _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 is
225 // enabled.
_DNBLogVerbose(const char * format,...)226 void _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 is
236 // enabled.
_DNBLogWarningVerbose(const char * format,...)237 void _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.
_DNBLogWarning(const char * format,...)253 void _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 #endif
269