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