• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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