1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : /*
8 : * NaCl Server Runtime logging code.
9 : */
10 : #include "native_client/src/include/nacl_compiler_annotations.h"
11 : #include "native_client/src/include/portability.h"
12 : #include "native_client/src/include/portability_io.h"
13 : #include "native_client/src/include/portability_process.h"
14 : #include "native_client/src/include/portability_string.h"
15 :
16 : #include <stdio.h>
17 : #include <stdlib.h>
18 : #include <stdarg.h>
19 : #include <string.h>
20 : #include <limits.h>
21 : #include <sys/stat.h>
22 : #include <fcntl.h>
23 : #include <errno.h>
24 :
25 : #include "native_client/src/shared/platform/nacl_log.h"
26 : #include "native_client/src/shared/platform/nacl_log_intern.h"
27 :
28 : #define THREAD_SAFE_DETAIL_CHECK 0
29 : /*
30 : * If set, check detail_level without grabbing a mutex. This makes
31 : * logging much cheaper, but implies that the verbosity level should
32 : * only be changed prior to going multithreaded.
33 : */
34 :
35 : #include "native_client/src/shared/gio/gio.h"
36 : #include "native_client/src/shared/platform/nacl_exit.h"
37 : #include "native_client/src/shared/platform/nacl_sync.h"
38 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
39 : #include "native_client/src/shared/platform/nacl_threads.h"
40 : #include "native_client/src/shared/platform/nacl_timestamp.h"
41 :
42 : static int g_initialized = 0;
43 :
44 : /*
45 : * Three implementation strategies for module-specific logging:
46 : *
47 : * If Thread Local Storage is available, NaClLogSetModule sets a TLS
48 : * variable to the current module name and NaClLogDoLogAndUnsetModule
49 : * will use that variable to determine whether to log or not, without
50 : * taking a lock.
51 : *
52 : * If Thread-Specific Data is available (pthread.h), then
53 : * NaClLogModuleInit allocates a pthread_[sg]etspecific key, and
54 : * NaClLogSetModule / NaClLogDoLogAndUnsetModule uses the TSD variable
55 : * in much the same way that a TLS variable would be used.
56 : *
57 : * If neither TLS nor TSD is available, then a global variable is used
58 : * to hold the module name, and a NaClMutex lock is used to prevent
59 : * another thread from changing it until the detail level vs verbosity
60 : * level check has fired.
61 : */
62 : #if NACL_PLATFORM_HAS_TLS
63 : THREAD char const *gTls_ModuleName;
64 : #elif NACL_PLATFORM_HAS_TSD
65 : # include <pthread.h>
66 : pthread_key_t gModuleNameKey;
67 : #else
68 : static char const *nacl_log_module_name = NULL;
69 : #endif
70 :
71 : /*
72 : * All logging output is protected by this mutex, so that the logging
73 : * code may output using multiple calls to the gio functions and not
74 : * have logging output from multiple threads get intermixed.
75 : */
76 : static struct NaClMutex log_mu;
77 : static int tag_output = 0;
78 : static int g_abort_count = 0;
79 : /*
80 : * g_abort_count is incremented prior to calling
81 : * gNaClLogAbortBehavior, so that the abort hook can invoke other
82 : * functions that might need to log, without those log entries
83 : * deadlocking or polluting the crash log output.
84 : */
85 : static int g_abort_behavior_active = 0;
86 :
87 : #define NACL_VERBOSITY_UNSET INT_MAX
88 :
89 : static int verbosity = NACL_VERBOSITY_UNSET;
90 : static struct Gio *log_stream = NULL;
91 : static struct GioFile log_file_stream;
92 : static int timestamp_enabled = 1;
93 :
94 : /* global, but explicitly not exposed in non-test header file */
95 : void (*gNaClLogAbortBehavior)(void) = NaClAbort;
96 :
97 : /*
98 : * For now, we use a simple linked list. New entries are pushed to
99 : * the front; search starts at front. So last entry for a particular
100 : * module wins, and we don't bother to eliminate duplicates. The
101 : * expected number of modules is small, so we don't do anything
102 : * fancier. TODO(bsy): measure performance loss and consider
103 : * alternatives.
104 : */
105 :
106 : struct NaClLogModuleVerbosity {
107 : struct NaClLogModuleVerbosity *next;
108 : char const *module_name; /* strdup'd */
109 : int verbosity;
110 : };
111 :
112 : static struct NaClLogModuleVerbosity *gNaClLogModuleVerbosity = NULL;
113 :
114 1 : static FILE *NaClLogFileIoBufferFromFile(char const *log_file) {
115 1 : int log_desc;
116 1 : FILE *log_iob;
117 :
118 1 : log_desc = open(log_file, O_WRONLY | O_APPEND | O_CREAT, 0777);
119 1 : if (-1 == log_desc) {
120 0 : perror("NaClLogSetFile");
121 0 : fprintf(stderr, "Could not create log file\n");
122 0 : NaClAbort();
123 0 : }
124 :
125 1 : log_iob = FDOPEN(log_desc, "a");
126 1 : if (NULL == log_iob) {
127 0 : perror("NaClLogSetFile");
128 0 : fprintf(stderr, "Could not fdopen log stream\n");
129 0 : NaClAbort();
130 0 : }
131 1 : return log_iob;
132 : }
133 :
134 : /*
135 : * Setting the log stream buffering to fully buffered, so that the
136 : * write of the tag string will be less likely to be separated
137 : * from the write of the actual log message.
138 : */
139 361 : static FILE *NaClLogDupFileIo(FILE *orig) {
140 361 : int d;
141 361 : FILE *copy;
142 :
143 : /*
144 : * On windows (at least on a win7 machine which i tested on),
145 : * fileno(stderr) is -2. I/O to the stderr stream appears to
146 : * succeed -- though who knows, maybe fclose(stderr) would actually
147 : * report an error? -- but DUP of -2 fails. We don't try to detect
148 : * -2 (or other windows magic values) as a special case here, since
149 : * in the future other FILE* might be used here. Instead, we just
150 : * check for DUP failure and trundle on as best as we could.
151 : */
152 361 : if (-1 == (d = DUP(fileno(orig)))) {
153 0 : copy = orig;
154 : /* this means that setvbuf later will affect the shared stream */
155 361 : } else if (NULL == (copy = FDOPEN(d, "a"))) {
156 0 : copy = orig;
157 : /* ditto */
158 0 : }
159 361 : (void) setvbuf(copy, (char *) NULL, _IOFBF, 1024);
160 361 : return copy;
161 : }
162 :
163 362 : static struct Gio *NaClLogGioFromFileIoBuffer(FILE *log_iob) {
164 362 : struct GioFile *log_gio;
165 :
166 362 : log_gio = malloc(sizeof *log_gio);
167 362 : if (NULL == log_gio) {
168 0 : perror("NaClLogSetFile");
169 0 : fprintf(stderr, "No memory for log buffers\n");
170 0 : NaClAbort();
171 0 : }
172 362 : if (!GioFileRefCtor(log_gio, log_iob)) {
173 0 : fprintf(stderr, "NaClLog module internal error: GioFileRefCtor failed\n");
174 0 : NaClAbort();
175 0 : }
176 362 : return (struct Gio *) log_gio;
177 : }
178 :
179 0 : void NaClLogSetFile(char const *log_file) {
180 0 : NaClLogSetGio(NaClLogGioFromFileIoBuffer(
181 0 : NaClLogFileIoBufferFromFile(log_file)));
182 0 : }
183 :
184 : int NaClLogDefaultLogVerbosity(void) {
185 362 : char *env_verbosity;
186 :
187 362 : if (NULL != (env_verbosity = getenv("NACLVERBOSITY"))) {
188 5 : int v = strtol(env_verbosity, (char **) 0, 0);
189 :
190 5 : if (v >= 0) {
191 5 : return v;
192 : }
193 0 : }
194 357 : return 0;
195 362 : }
196 :
197 : struct Gio *NaClLogDefaultLogGio(void) {
198 362 : char *log_file;
199 362 : FILE *log_iob;
200 :
201 362 : log_file = getenv("NACLLOG");
202 :
203 362 : if (NULL == log_file) {
204 361 : log_iob = NaClLogDupFileIo(stderr);
205 361 : } else {
206 1 : log_iob = NaClLogFileIoBufferFromFile(log_file);
207 : }
208 362 : return NaClLogGioFromFileIoBuffer(log_iob);
209 : }
210 :
211 1302 : void NaClLogParseAndSetModuleVerbosityMap(char const *module_verbosity_map) {
212 1302 : char entry_buf[256];
213 1302 : size_t entry_len;
214 1302 : char const *sep;
215 1302 : char const *next;
216 1302 : char *assign;
217 1302 : int seen_global = 0;
218 1302 : char *module_name;
219 1302 : int module_verbosity;
220 :
221 1302 : if (NULL == module_verbosity_map) {
222 1297 : return;
223 : }
224 :
225 15 : while (*module_verbosity_map != '\0') {
226 5 : sep = strpbrk(module_verbosity_map, ",:");
227 5 : if (NULL == sep) {
228 5 : sep = module_verbosity_map + strlen(module_verbosity_map);
229 5 : next = sep;
230 5 : } else {
231 0 : next = sep + 1;
232 : }
233 : /* post: sep points to comma or termination NUL */
234 5 : entry_len = sep - module_verbosity_map;
235 5 : if (entry_len > sizeof entry_buf - 1) {
236 0 : NaClLog(LOG_ERROR,
237 : "NaClLog: entry too long in module verbosity map \"%.*s\".\n",
238 : (int) entry_len,
239 : module_verbosity_map);
240 0 : entry_len = sizeof entry_buf - 1;
241 0 : }
242 5 : strncpy(entry_buf, module_verbosity_map, entry_len);
243 5 : entry_buf[entry_len] = '\0';
244 5 : assign = strchr(entry_buf, '=');
245 10 : if (NULL == assign && !seen_global) {
246 5 : verbosity = strtol(entry_buf, (char **) 0, 0);
247 5 : seen_global = 1;
248 5 : } else {
249 0 : *assign = '\0';
250 :
251 0 : module_verbosity = strtol(assign+1, (char **) 0, 0);
252 :
253 0 : while (entry_buf < assign && (' ' == assign[-1] || '\t' == assign[-1])) {
254 0 : *--assign = '\0';
255 0 : }
256 0 : if (entry_buf == assign) {
257 0 : NaClLog(LOG_FATAL,
258 : "NaClLog: Bad module name in \"%s\".\n",
259 : module_verbosity_map);
260 0 : }
261 :
262 0 : for (module_name = entry_buf;
263 : ' ' == *module_name || '\t' == *module_name;
264 0 : ++module_name) {
265 : ;
266 0 : }
267 0 : NaClLogSetModuleVerbosity(module_name, module_verbosity);
268 : }
269 5 : module_verbosity_map = next;
270 5 : }
271 1302 : }
272 :
273 1302 : void NaClLogModuleInitExtended2(int default_verbosity,
274 1302 : char const *module_verbosity_map,
275 1302 : struct Gio *log_gio) {
276 1302 : if (!g_initialized) {
277 : #if !THREAD_SAFE_DETAIL_CHECK && !NACL_PLATFORM_HAS_TLS && NACL_PLATFORM_HAS_TSD
278 1301 : int errnum;
279 :
280 1301 : if (0 != (errnum = pthread_key_create(&gModuleNameKey, NULL))) {
281 0 : fprintf(stderr, "NaClLogModuleInitExtended2: "
282 : "pthread_key_create failed\n");
283 0 : abort();
284 : }
285 : #endif
286 1301 : NaClXMutexCtor(&log_mu);
287 1301 : g_initialized = 1;
288 1301 : }
289 1302 : NaClLogSetVerbosity(default_verbosity);
290 1302 : NaClLogParseAndSetModuleVerbosityMap(module_verbosity_map);
291 1302 : NaClLogSetGio(log_gio);
292 1302 : }
293 :
294 1302 : void NaClLogModuleInitExtended(int initial_verbosity,
295 1302 : struct Gio *log_gio) {
296 :
297 2604 : NaClLogModuleInitExtended2(initial_verbosity,
298 1302 : getenv("NACLVERBOSITY"),
299 : log_gio);
300 1302 : }
301 :
302 : void NaClLogModuleInit(void) {
303 724 : NaClLogModuleInitExtended(NaClLogDefaultLogVerbosity(),
304 362 : NaClLogDefaultLogGio());
305 362 : }
306 :
307 : void NaClLogModuleFini(void) {
308 1014 : struct NaClLogModuleVerbosity *entry;
309 1014 : struct NaClLogModuleVerbosity *next;
310 :
311 1014 : entry = gNaClLogModuleVerbosity;
312 2028 : while (entry != NULL) {
313 0 : next = entry->next;
314 0 : free(entry);
315 0 : entry = next;
316 0 : }
317 1014 : gNaClLogModuleVerbosity = NULL;
318 1014 : NaClMutexDtor(&log_mu);
319 1014 : g_initialized = 0;
320 1014 : }
321 :
322 : void NaClLogTagNext_mu(void) {
323 80407 : tag_output = 1;
324 80407 : }
325 :
326 : void NaClLogLock(void) {
327 80407 : NaClXMutexLock(&log_mu);
328 80407 : NaClLogTagNext_mu();
329 80407 : }
330 :
331 : void NaClLogUnlock(void) {
332 160814 : int run_abort_behavior = 0;
333 80407 : switch (g_abort_count) {
334 : case 0:
335 80397 : NaClXMutexUnlock(&log_mu);
336 80397 : break;
337 : case 1:
338 : /*
339 : * include an easy-to-recognize output for the fuzzer to recognize
340 : */
341 10 : if (!g_abort_behavior_active) {
342 10 : NaClLog_mu(LOG_ERROR, "LOG_FATAL abort exit\n");
343 10 : g_abort_behavior_active = 1;
344 10 : run_abort_behavior = 1;
345 : /*
346 : * run abort behavior only on edge transition when
347 : * g_abort_behavior_active is first set.
348 : */
349 10 : }
350 10 : NaClXMutexUnlock(&log_mu);
351 10 : if (run_abort_behavior) {
352 : #ifdef __COVERITY__
353 : NaClAbort(); /* help coverity figure out that this is the default */
354 : #else
355 10 : (*gNaClLogAbortBehavior)();
356 : #endif
357 10 : NaClAbort();
358 10 : }
359 0 : break;
360 : default:
361 : /*
362 : * Abort handling code in turn aborted. Eeep!
363 : */
364 0 : NaClAbort();
365 0 : break;
366 : }
367 80397 : }
368 :
369 : static INLINE struct Gio *NaClLogGetGio_mu(void) {
370 23241 : if (NULL == log_stream) {
371 0 : (void) GioFileRefCtor(&log_file_stream, NaClLogDupFileIo(stderr));
372 0 : log_stream = (struct Gio *) &log_file_stream;
373 0 : }
374 23241 : return log_stream;
375 : }
376 :
377 1303 : static void NaClLogSetVerbosity_mu(int verb) {
378 1303 : verbosity = verb;
379 1303 : }
380 :
381 0 : void NaClLogPreInitSetVerbosity(int verb) {
382 : /*
383 : * The lock used by NaClLogLock has not been initialized and cannot
384 : * be used; however, prior to initialization we are not going to be
385 : * invoked from multiple threads, since the caller is responsible
386 : * for not invoking NaClLog module functions (except for the PreInit
387 : * ones, obviously) at all, let alone from multiple threads. Ergo,
388 : * it is safe to manipulate the module globals without locking.
389 : */
390 0 : NaClLogSetVerbosity_mu(verb);
391 0 : }
392 :
393 1303 : void NaClLogSetVerbosity(int verb) {
394 1303 : NaClLogLock();
395 1303 : NaClLogSetVerbosity_mu(verb);
396 1303 : NaClLogUnlock();
397 1303 : }
398 :
399 : void NaClLogIncrVerbosity(void) {
400 17 : NaClLogLock();
401 17 : if (NACL_VERBOSITY_UNSET == verbosity) {
402 0 : verbosity = 0;
403 0 : }
404 17 : ++verbosity;
405 17 : NaClLogUnlock();
406 17 : }
407 :
408 : int NaClLogGetVerbosity(void) {
409 54278 : int v;
410 :
411 54278 : NaClLogLock();
412 54278 : if (NACL_VERBOSITY_UNSET == verbosity) {
413 0 : verbosity = 0;
414 0 : }
415 54278 : v = verbosity;
416 54278 : NaClLogUnlock();
417 :
418 54278 : return v;
419 : }
420 :
421 1568 : static void NaClLogSetGio_mu(struct Gio *stream) {
422 1568 : if (NULL != log_stream) {
423 288 : (void) (*log_stream->vtbl->Flush)(log_stream);
424 288 : }
425 1568 : log_stream = stream;
426 1568 : }
427 :
428 0 : void NaClLogPreInitSetGio(struct Gio *out_stream) {
429 : /*
430 : * See thread safety comment in NaClLogPreInitSetVerbosity.
431 : */
432 0 : NaClLogSetGio_mu(out_stream);
433 0 : }
434 :
435 1568 : void NaClLogSetGio(struct Gio *stream) {
436 1568 : NaClLogLock();
437 1568 : NaClLogSetGio_mu(stream);
438 1568 : NaClLogUnlock();
439 1568 : }
440 :
441 : struct Gio *NaClLogGetGio(void) {
442 10729 : struct Gio *s;
443 :
444 10729 : NaClLogLock();
445 10729 : s = NaClLogGetGio_mu();
446 10729 : NaClLogUnlock();
447 :
448 10729 : return s;
449 : }
450 :
451 : void NaClLogEnableTimestamp(void) {
452 0 : timestamp_enabled = 1;
453 0 : }
454 :
455 : void NaClLogDisableTimestamp(void) {
456 569 : timestamp_enabled = 0;
457 569 : }
458 :
459 12512 : static void NaClLogOutputTag_mu(struct Gio *s) {
460 12512 : char timestamp[128];
461 12512 : int pid;
462 :
463 24454 : if (timestamp_enabled && tag_output) {
464 11942 : pid = GETPID();
465 23884 : gprintf(s, "[%d,%u:%s] ",
466 : pid,
467 11942 : NaClThreadId(),
468 11942 : NaClTimeStampString(timestamp, sizeof timestamp));
469 11942 : tag_output = 0;
470 11942 : }
471 12512 : }
472 :
473 : /*
474 : * Output a printf-style formatted message if the log verbosity level
475 : * is set higher than the log output's detail level. Note that since
476 : * this is not a macro, log message arguments that have side effects
477 : * will have their side effects regardless of whether the
478 : * corresponding log message is printed or not. This is good from a
479 : * consistency point of view, but it means that should a logging
480 : * argument be expensive to compute, the log statement needs to be
481 : * surrounded by something like
482 : *
483 : * if (detail_level <= NaClLogGetVerbosity()) {
484 : * NaClLog(detail_level, "format string", expensive_arg(), ...);
485 : * }
486 : *
487 : * The log message, if written, is prepended by a microsecond
488 : * resolution timestamp on linux and a millisecond resolution
489 : * timestamp on windows. This means that if the NaCl app can read its
490 : * own logs, it can distinguish which host OS it is running on.
491 : */
492 12522 : void NaClLogDoLogV_mu(int detail_level,
493 12522 : char const *fmt,
494 12522 : va_list ap) {
495 12522 : struct Gio *s;
496 :
497 12522 : if (0 == g_abort_count) {
498 12512 : s = NaClLogGetGio_mu();
499 :
500 12512 : NaClLogOutputTag_mu(s);
501 12512 : (void) gvprintf(s, fmt, ap);
502 12512 : (void) (*s->vtbl->Flush)(s);
503 12512 : } else {
504 10 : (void) fprintf(stderr, "POST-ABORT: ");
505 10 : (void) vfprintf(stderr, fmt, ap);
506 10 : (void) fflush(stderr);
507 : }
508 :
509 12522 : if (LOG_FATAL == detail_level) {
510 10 : ++g_abort_count;
511 10 : }
512 12522 : }
513 :
514 12176 : void NaClLogV_mu(int detail_level,
515 12176 : char const *fmt,
516 12176 : va_list ap) {
517 12176 : if (NACL_VERBOSITY_UNSET == verbosity) {
518 0 : verbosity = NaClLogDefaultLogVerbosity();
519 0 : }
520 :
521 12176 : if (detail_level <= verbosity) {
522 12176 : NaClLogDoLogV_mu(detail_level, fmt, ap);
523 12176 : }
524 12176 : }
525 :
526 0 : void NaClLogV(int detail_level,
527 0 : char const *fmt,
528 0 : va_list ap) {
529 : #if !THREAD_SAFE_DETAIL_CHECK
530 0 : if (detail_level > verbosity) {
531 0 : return;
532 : }
533 : #endif
534 0 : NaClLogLock();
535 0 : NaClLogV_mu(detail_level, fmt, ap);
536 0 : NaClLogUnlock();
537 0 : }
538 :
539 0 : void NaClLogSetModuleVerbosity_mu(char const *module_name,
540 0 : int verbosity) {
541 0 : struct NaClLogModuleVerbosity *entry;
542 :
543 0 : entry = (struct NaClLogModuleVerbosity *) malloc(sizeof *entry);
544 0 : if (NULL == entry) {
545 0 : NaClLog_mu(LOG_FATAL,
546 : ("NaClLogSetModuleVerbosity_mu: Out of memory while setting"
547 : " module record for module: %s, verbosity: %d\n"),
548 : module_name, verbosity);
549 0 : }
550 0 : entry->module_name = STRDUP(module_name);
551 0 : if (NULL == entry->module_name) {
552 0 : NaClLog_mu(LOG_FATAL,
553 : ("NaClLogSetModuleVerbosity_mu: Out of memory while duplicating"
554 : " module name: %s, verbosity: %d\n"),
555 : module_name, verbosity);
556 0 : }
557 0 : entry->verbosity = verbosity;
558 0 : entry->next = gNaClLogModuleVerbosity;
559 0 : gNaClLogModuleVerbosity = entry;
560 0 : }
561 :
562 0 : void NaClLogSetModuleVerbosity(char const *module_name,
563 0 : int verbosity) {
564 0 : NaClLogLock();
565 0 : NaClLogSetModuleVerbosity_mu(module_name, verbosity);
566 0 : NaClLogUnlock();
567 0 : }
568 :
569 : /*
570 : * After initialization, gNaClLogModuleVerbosity is read-only, so can
571 : * be examined sans locking.
572 : */
573 31095 : int NaClLogGetModuleVerbosity_mu(char const *module_name) {
574 31095 : struct NaClLogModuleVerbosity *p;
575 :
576 31095 : if (NULL != module_name) {
577 62190 : for (p = gNaClLogModuleVerbosity; NULL != p; p = p->next) {
578 0 : if (!strcmp(p->module_name, module_name)) {
579 0 : return p->verbosity;
580 : }
581 0 : }
582 31095 : }
583 31095 : return verbosity;
584 31095 : }
585 :
586 0 : int NaClLogGetModuleVerbosity(char const *module_name) {
587 0 : int rv;
588 0 : NaClLogLock();
589 0 : rv = NaClLogGetModuleVerbosity_mu(module_name);
590 0 : NaClLogUnlock();
591 0 : return rv;
592 : }
593 :
594 : #if NACL_PLATFORM_HAS_TLS
595 : int NaClLogSetModule(char const *module_name) {
596 : gTls_ModuleName = module_name;
597 : return 0;
598 : }
599 :
600 : static void NaClLogDoLogAndUnsetModuleV(int detail_level,
601 : const char *fmt,
602 : va_list ap) {
603 : int module_verbosity;
604 :
605 : module_verbosity = NaClLogGetModuleVerbosity_mu(gTls_ModuleName);
606 : if (detail_level <= module_verbosity) {
607 : NaClLogLock();
608 : NaClLogDoLogV_mu(detail_level, fmt, ap);
609 : NaClLogUnlock();
610 : }
611 : gTls_ModuleName = (char const *) NULL;
612 : }
613 :
614 : #elif NACL_PLATFORM_HAS_TSD
615 31095 : int NaClLogSetModule(char const *module_name) {
616 31095 : (void) pthread_setspecific(gModuleNameKey, (void const *) module_name);
617 31095 : return 0;
618 : }
619 :
620 31095 : static void NaClLogDoLogAndUnsetModuleV(int detail_level,
621 31095 : const char *fmt,
622 31095 : va_list ap) {
623 31095 : char const *module_name = (char const *) pthread_getspecific(gModuleNameKey);
624 31095 : int module_verbosity;
625 :
626 31095 : module_verbosity = NaClLogGetModuleVerbosity_mu(module_name);
627 31095 : if (detail_level <= module_verbosity) {
628 346 : NaClLogLock();
629 346 : NaClLogDoLogV_mu(detail_level, fmt, ap);
630 346 : NaClLogUnlock();
631 346 : }
632 31095 : (void) pthread_setspecific(gModuleNameKey, (void const *) NULL);
633 31095 : }
634 :
635 : #else
636 : /* !NACL_PLATFORM_HAS_TLS && !NACL_PLATFORM_HAS_TSD */
637 :
638 : int NaClLogSetModule(char const *module_name) {
639 : NaClLogLock();
640 : nacl_log_module_name = module_name;
641 : return 0;
642 : }
643 :
644 : static void NaClLogDoLogAndUnsetModuleV(int detail_level,
645 : char const *fmt,
646 : va_list ap) {
647 : int module_verbosity;
648 :
649 : module_verbosity = NaClLogGetModuleVerbosity_mu(nacl_log_module_name);
650 : if (detail_level <= module_verbosity) {
651 : NaClLogDoLogV_mu(detail_level, fmt, ap);
652 : }
653 : nacl_log_module_name = NULL;
654 : NaClLogUnlock();
655 : }
656 : #endif
657 :
658 31003 : void NaClLogDoLogAndUnsetModule(int detail_level,
659 31003 : char const *fmt,
660 : ...) {
661 31003 : va_list ap;
662 :
663 31003 : va_start(ap, fmt);
664 31003 : NaClLogDoLogAndUnsetModuleV(detail_level, fmt, ap);
665 31003 : va_end(ap);
666 31003 : }
667 :
668 27829440 : void NaClLog(int detail_level,
669 27829440 : char const *fmt,
670 : ...) {
671 27829440 : va_list ap;
672 :
673 : #if !THREAD_SAFE_DETAIL_CHECK
674 27829440 : if (NACL_LIKELY(detail_level > verbosity)) {
675 27817199 : return;
676 : }
677 : #endif
678 :
679 12166 : NaClLogLock();
680 12166 : va_start(ap, fmt);
681 12166 : NaClLogV_mu(detail_level, fmt, ap);
682 12166 : va_end(ap);
683 12166 : NaClLogUnlock();
684 27841515 : }
685 :
686 10 : void NaClLog_mu(int detail_level,
687 10 : char const *fmt,
688 : ...) {
689 10 : va_list ap;
690 :
691 : #if THREAD_SAFE_DETAIL_CHECK
692 : if (detail_level > verbosity) {
693 : return;
694 : }
695 : #endif
696 :
697 10 : va_start(ap, fmt);
698 10 : NaClLogV_mu(detail_level, fmt, ap);
699 10 : va_end(ap);
700 10 : }
701 :
702 92 : void NaClLog2(char const *module_name,
703 92 : int detail_level,
704 92 : char const *fmt,
705 : ...) {
706 92 : va_list ap;
707 :
708 92 : NaClLogSetModule(module_name);
709 92 : va_start(ap, fmt);
710 92 : NaClLogDoLogAndUnsetModuleV(detail_level, fmt, ap);
711 92 : va_end(ap);
712 92 : }
713 :
714 266 : void NaClLogSetAbortBehavior(void (*fn)(void)) {
715 266 : NaClXMutexLock(&log_mu);
716 266 : gNaClLogAbortBehavior = fn;
717 266 : NaClXMutexUnlock(&log_mu);
718 266 : }
|