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 <stdio.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <sys/time.h>
25 #include <unistd.h>
26 #include <mach/mach.h>
27 #include <pthread.h>
28 #include "PThreadMutex.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 
35 int
36 DNBLogGetDebug ()
37 {
38     return g_debug;
39 }
40 
41 
42 void
43 DNBLogSetDebug (int g)
44 {
45     g_debug = g;
46 }
47 
48 int
49 DNBLogGetVerbose ()
50 {
51     return g_verbose;
52 }
53 
54 void
55 DNBLogSetVerbose (int v)
56 {
57     g_verbose = v;
58 }
59 
60 bool
61 DNBLogCheckLogBit (uint32_t bit)
62 {
63     return (g_log_bits & bit) != 0;
64 }
65 
66 uint32_t
67 DNBLogSetLogMask (uint32_t mask)
68 {
69     uint32_t old = g_log_bits;
70     g_log_bits = mask;
71     return old;
72 }
73 
74 uint32_t
75 DNBLogGetLogMask ()
76 {
77     return g_log_bits;
78 }
79 
80 void
81 DNBLogSetLogCallback (DNBCallbackLog callback, void *baton)
82 {
83     g_log_callback = callback;
84     g_log_baton = baton;
85 }
86 
87 bool
88 DNBLogEnabled ()
89 {
90     return g_log_callback != NULL;
91 }
92 
93 bool
94 DNBLogEnabledForAny (uint32_t mask)
95 {
96     if (g_log_callback)
97         return (g_log_bits & mask) != 0;
98     return false;
99 }
100 static inline void
101 _DNBLogVAPrintf(uint32_t flags, const char *format, va_list args)
102 {
103     static PThreadMutex g_LogThreadedMutex(PTHREAD_MUTEX_RECURSIVE);
104     PTHREAD_MUTEX_LOCKER(locker, g_LogThreadedMutex);
105 
106     if (g_log_callback)
107       g_log_callback(g_log_baton, flags, format, args);
108 }
109 
110 void
111 _DNBLog(uint32_t flags, const char *format, ...)
112 {
113     va_list args;
114     va_start (args, format);
115     _DNBLogVAPrintf(flags, format, args);
116     va_end (args);
117 }
118 
119 //----------------------------------------------------------------------
120 // Print debug strings if and only if the global g_debug is set to
121 // a non-zero value.
122 //----------------------------------------------------------------------
123 void
124 _DNBLogDebug (const char *format, ...)
125 {
126     if (DNBLogEnabled () && g_debug)
127     {
128         va_list args;
129         va_start (args, format);
130         _DNBLogVAPrintf(DNBLOG_FLAG_DEBUG, format, args);
131         va_end (args);
132     }
133 }
134 
135 
136 //----------------------------------------------------------------------
137 // Print debug strings if and only if the global g_debug is set to
138 // a non-zero value.
139 //----------------------------------------------------------------------
140 void
141 _DNBLogDebugVerbose (const char *format, ...)
142 {
143     if (DNBLogEnabled () && g_debug && g_verbose)
144     {
145         va_list args;
146         va_start (args, format);
147         _DNBLogVAPrintf(DNBLOG_FLAG_DEBUG | DNBLOG_FLAG_VERBOSE, format, args);
148         va_end (args);
149     }
150 }
151 
152 
153 static uint32_t g_message_id = 0;
154 
155 //----------------------------------------------------------------------
156 // Prefix the formatted log string with process and thread IDs and
157 // suffix it with a newline.
158 //----------------------------------------------------------------------
159 void
160 _DNBLogThreaded (const char *format, ...)
161 {
162     if (DNBLogEnabled ())
163     {
164         //PTHREAD_MUTEX_LOCKER(locker, GetLogThreadedMutex());
165 
166         char *arg_msg = NULL;
167         va_list args;
168         va_start (args, format);
169         ::vasprintf (&arg_msg, format, args);
170         va_end (args);
171 
172         if (arg_msg != NULL)
173         {
174             static struct timeval g_timeval = { 0 , 0 };
175             static struct timeval tv;
176             static struct timeval delta;
177             gettimeofday(&tv, NULL);
178             if (g_timeval.tv_sec == 0)
179             {
180                 delta.tv_sec = 0;
181                 delta.tv_usec = 0;
182             }
183             else
184             {
185                 timersub (&tv, &g_timeval, &delta);
186             }
187             g_timeval = tv;
188 
189             // Calling "mach_port_deallocate()" bumps the reference count on the thread
190             // port, so we need to deallocate it. mach_task_self() doesn't bump the ref
191             // count.
192             thread_port_t thread_self = mach_thread_self();
193 
194             _DNBLog (DNBLOG_FLAG_THREADED, "%u +%lu.%06u sec [%4.4x/%4.4x]: %s",
195                      ++g_message_id,
196                      delta.tv_sec,
197                      delta.tv_usec,
198                      getpid(),
199                      thread_self,
200                      arg_msg);
201 
202             mach_port_deallocate(mach_task_self(), thread_self);
203             free (arg_msg);
204         }
205     }
206 }
207 
208 //----------------------------------------------------------------------
209 // Prefix the formatted log string with process and thread IDs and
210 // suffix it with a newline.
211 //----------------------------------------------------------------------
212 void
213 _DNBLogThreadedIf (uint32_t log_bit, const char *format, ...)
214 {
215     if (DNBLogEnabled () && (log_bit & g_log_bits) == log_bit)
216     {
217         //PTHREAD_MUTEX_LOCKER(locker, GetLogThreadedMutex());
218 
219         char *arg_msg = NULL;
220         va_list args;
221         va_start (args, format);
222         ::vasprintf (&arg_msg, format, args);
223         va_end (args);
224 
225         if (arg_msg != NULL)
226         {
227             static struct timeval g_timeval = { 0 , 0 };
228             static struct timeval tv;
229             static struct timeval delta;
230             gettimeofday(&tv, NULL);
231             if (g_timeval.tv_sec == 0)
232             {
233                 delta.tv_sec = 0;
234                 delta.tv_usec = 0;
235             }
236             else
237             {
238                 timersub (&tv, &g_timeval, &delta);
239             }
240             g_timeval = tv;
241 
242             // Calling "mach_port_deallocate()" bumps the reference count on the thread
243             // port, so we need to deallocate it. mach_task_self() doesn't bump the ref
244             // count.
245             thread_port_t thread_self = mach_thread_self();
246 
247             _DNBLog (DNBLOG_FLAG_THREADED, "%u +%lu.%06u sec [%4.4x/%4.4x]: %s",
248                      ++g_message_id,
249                      delta.tv_sec,
250                      delta.tv_usec,
251                      getpid(),
252                      thread_self,
253                      arg_msg);
254 
255             mach_port_deallocate(mach_task_self(), thread_self);
256 
257             free (arg_msg);
258         }
259     }
260 }
261 
262 
263 
264 //----------------------------------------------------------------------
265 // Printing of errors that are not fatal.
266 //----------------------------------------------------------------------
267 void
268 _DNBLogError (const char *format, ...)
269 {
270     if (DNBLogEnabled ())
271     {
272         char *arg_msg = NULL;
273         va_list args;
274         va_start (args, format);
275         ::vasprintf (&arg_msg, format, args);
276         va_end (args);
277 
278         if (arg_msg != NULL)
279         {
280             _DNBLog (DNBLOG_FLAG_ERROR, "error: %s", arg_msg);
281             free (arg_msg);
282         }
283     }
284 }
285 
286 //----------------------------------------------------------------------
287 // Printing of errors that ARE fatal. Exit with ERR exit code
288 // immediately.
289 //----------------------------------------------------------------------
290 void
291 _DNBLogFatalError (int err, const char *format, ...)
292 {
293     if (DNBLogEnabled ())
294     {
295         char *arg_msg = NULL;
296         va_list args;
297         va_start (args, format);
298         ::vasprintf (&arg_msg, format, args);
299         va_end (args);
300 
301         if (arg_msg != NULL)
302         {
303             _DNBLog (DNBLOG_FLAG_ERROR | DNBLOG_FLAG_FATAL, "error: %s", arg_msg);
304             free (arg_msg);
305         }
306         ::exit (err);
307     }
308 }
309 
310 
311 //----------------------------------------------------------------------
312 // Printing of warnings that are not fatal only if verbose mode is
313 // enabled.
314 //----------------------------------------------------------------------
315 void
316 _DNBLogVerbose (const char *format, ...)
317 {
318     if (DNBLogEnabled () && g_verbose)
319     {
320         va_list args;
321         va_start (args, format);
322         _DNBLogVAPrintf(DNBLOG_FLAG_VERBOSE, format, args);
323         va_end (args);
324     }
325 }
326 
327 //----------------------------------------------------------------------
328 // Printing of warnings that are not fatal only if verbose mode is
329 // enabled.
330 //----------------------------------------------------------------------
331 void
332 _DNBLogWarningVerbose (const char *format, ...)
333 {
334     if (DNBLogEnabled () && g_verbose)
335     {
336         char *arg_msg = NULL;
337         va_list args;
338         va_start (args, format);
339         ::vasprintf (&arg_msg, format, args);
340         va_end (args);
341 
342         if (arg_msg != NULL)
343         {
344             _DNBLog (DNBLOG_FLAG_WARNING | DNBLOG_FLAG_VERBOSE, "warning: %s", arg_msg);
345             free (arg_msg);
346         }
347     }
348 }
349 //----------------------------------------------------------------------
350 // Printing of warnings that are not fatal.
351 //----------------------------------------------------------------------
352 void
353 _DNBLogWarning (const char *format, ...)
354 {
355     if (DNBLogEnabled ())
356     {
357         char *arg_msg = NULL;
358         va_list args;
359         va_start (args, format);
360         ::vasprintf (&arg_msg, format, args);
361         va_end (args);
362 
363         if (arg_msg != NULL)
364         {
365             _DNBLog (DNBLOG_FLAG_WARNING, "warning: %s", arg_msg);
366             free (arg_msg);
367         }
368     }
369 }
370 
371 #endif
372