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