LCOV - code coverage report
Current view: directory - src/shared/platform - nacl_log.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 355 251 70.7 %
Date: 2014-06-18 Functions: 0 0 -

       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 : }

Generated by: LCOV version 1.7