LCOV - code coverage report
Current view: directory - src/shared/platform - nacl_log.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 294 135 45.9 %
Date: 2014-09-25 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               0 : static FILE *NaClLogFileIoBufferFromFile(char const *log_file) {
     115                 :   int   log_desc;
     116                 :   FILE  *log_iob;
     117                 : 
     118               0 :   log_desc = open(log_file, O_WRONLY | O_APPEND | O_CREAT, 0777);
     119               0 :   if (-1 == log_desc) {
     120               0 :     perror("NaClLogSetFile");
     121               0 :     fprintf(stderr, "Could not create log file\n");
     122               0 :     NaClAbort();
     123                 :   }
     124                 : 
     125               0 :   log_iob = FDOPEN(log_desc, "a");
     126               0 :   if (NULL == log_iob) {
     127               0 :     perror("NaClLogSetFile");
     128               0 :     fprintf(stderr, "Could not fdopen log stream\n");
     129               0 :     NaClAbort();
     130                 :   }
     131               0 :   return log_iob;
     132               0 : }
     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              25 : static FILE *NaClLogDupFileIo(FILE *orig) {
     140                 :   int  d;
     141                 :   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              25 :   if (-1 == (d = DUP(fileno(orig)))) {
     153               0 :     copy = orig;
     154                 :     /* this means that setvbuf later will affect the shared stream */
     155              25 :   } else if (NULL == (copy = FDOPEN(d, "a"))) {
     156               0 :     copy = orig;
     157                 :     /* ditto */
     158                 :   }
     159              25 :   (void) setvbuf(copy, (char *) NULL, _IOFBF, 1024);
     160              25 :   return copy;
     161              25 : }
     162                 : 
     163              25 : static struct Gio *NaClLogGioFromFileIoBuffer(FILE *log_iob) {
     164                 :   struct GioFile *log_gio;
     165                 : 
     166              25 :   log_gio = malloc(sizeof *log_gio);
     167              25 :   if (NULL == log_gio) {
     168               0 :     perror("NaClLogSetFile");
     169               0 :     fprintf(stderr, "No memory for log buffers\n");
     170               0 :     NaClAbort();
     171                 :   }
     172              25 :   if (!GioFileRefCtor(log_gio, log_iob)) {
     173               0 :     fprintf(stderr, "NaClLog module internal error: GioFileRefCtor failed\n");
     174               0 :     NaClAbort();
     175                 :   }
     176              25 :   return (struct Gio *) log_gio;
     177              25 : }
     178                 : 
     179               0 : void NaClLogSetFile(char const *log_file) {
     180                 :   NaClLogSetGio(NaClLogGioFromFileIoBuffer(
     181               0 :       NaClLogFileIoBufferFromFile(log_file)));
     182               0 : }
     183                 : 
     184              25 : int NaClLogDefaultLogVerbosity(void) {
     185                 :   char *env_verbosity;
     186                 : 
     187              25 :   if (NULL != (env_verbosity = getenv("NACLVERBOSITY"))) {
     188               0 :     int v = strtol(env_verbosity, (char **) 0, 0);
     189                 : 
     190               0 :     if (v >= 0) {
     191               0 :       return v;
     192                 :     }
     193                 :   }
     194              25 :   return 0;
     195              25 : }
     196                 : 
     197              25 : struct Gio *NaClLogDefaultLogGio(void) {
     198                 :   char            *log_file;
     199                 :   FILE            *log_iob;
     200                 : 
     201              25 :   log_file = getenv("NACLLOG");
     202                 : 
     203              25 :   if (NULL == log_file) {
     204              25 :     log_iob = NaClLogDupFileIo(stderr);
     205              25 :   } else {
     206               0 :     log_iob = NaClLogFileIoBufferFromFile(log_file);
     207                 :   }
     208              25 :   return NaClLogGioFromFileIoBuffer(log_iob);
     209              25 : }
     210                 : 
     211              27 : void NaClLogParseAndSetModuleVerbosityMap(char const *module_verbosity_map) {
     212                 :   char        entry_buf[256];
     213                 :   size_t      entry_len;
     214                 :   char const  *sep;
     215                 :   char const  *next;
     216                 :   char        *assign;
     217              27 :   int         seen_global = 0;
     218                 :   char        *module_name;
     219                 :   int         module_verbosity;
     220                 : 
     221              27 :   if (NULL == module_verbosity_map) {
     222              27 :     return;
     223                 :   }
     224                 : 
     225               0 :   while (*module_verbosity_map != '\0') {
     226               0 :     sep = strpbrk(module_verbosity_map, ",:");
     227               0 :     if (NULL == sep) {
     228               0 :       sep = module_verbosity_map + strlen(module_verbosity_map);
     229               0 :       next = sep;
     230               0 :     } else {
     231               0 :       next = sep + 1;
     232                 :     }
     233                 :     /* post: sep points to comma or termination NUL */
     234               0 :     entry_len = sep - module_verbosity_map;
     235               0 :     if (entry_len > sizeof entry_buf - 1) {
     236                 :       NaClLog(LOG_ERROR,
     237                 :               "NaClLog: entry too long in module verbosity map \"%.*s\".\n",
     238                 :               (int) entry_len,
     239               0 :               module_verbosity_map);
     240               0 :       entry_len = sizeof entry_buf - 1;
     241                 :     }
     242               0 :     strncpy(entry_buf, module_verbosity_map, entry_len);
     243               0 :     entry_buf[entry_len] = '\0';
     244               0 :     assign = strchr(entry_buf, '=');
     245               0 :     if (NULL == assign && !seen_global) {
     246               0 :       verbosity = strtol(entry_buf, (char **) 0, 0);
     247               0 :       seen_global = 1;
     248               0 :     } 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                 :         NaClLog(LOG_FATAL,
     258                 :                 "NaClLog: Bad module name in \"%s\".\n",
     259               0 :                 module_verbosity_map);
     260                 :       }
     261                 : 
     262                 :       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               0 :     module_verbosity_map = next;
     270               0 :   }
     271              27 : }
     272                 : 
     273                 : void NaClLogModuleInitExtended2(int         default_verbosity,
     274                 :                                 char const  *module_verbosity_map,
     275              27 :                                 struct Gio  *log_gio) {
     276              27 :   if (!g_initialized) {
     277                 : #if !THREAD_SAFE_DETAIL_CHECK && !NACL_PLATFORM_HAS_TLS && NACL_PLATFORM_HAS_TSD
     278                 :     int errnum;
     279                 : 
     280                 :     if (0 != (errnum = pthread_key_create(&gModuleNameKey, NULL))) {
     281                 :       fprintf(stderr, "NaClLogModuleInitExtended2: "
     282                 :               "pthread_key_create failed\n");
     283                 :       abort();
     284                 :     }
     285                 : #endif
     286              27 :     NaClXMutexCtor(&log_mu);
     287              27 :     g_initialized = 1;
     288                 :   }
     289              27 :   NaClLogSetVerbosity(default_verbosity);
     290              27 :   NaClLogParseAndSetModuleVerbosityMap(module_verbosity_map);
     291              27 :   NaClLogSetGio(log_gio);
     292              27 : }
     293                 : 
     294                 : void NaClLogModuleInitExtended(int        initial_verbosity,
     295              27 :                                struct Gio *log_gio) {
     296                 : 
     297                 :   NaClLogModuleInitExtended2(initial_verbosity,
     298                 :                              getenv("NACLVERBOSITY"),
     299              27 :                              log_gio);
     300              27 : }
     301                 : 
     302              25 : void NaClLogModuleInit(void) {
     303                 :   NaClLogModuleInitExtended(NaClLogDefaultLogVerbosity(),
     304              25 :                             NaClLogDefaultLogGio());
     305              25 : }
     306                 : 
     307              18 : void NaClLogModuleFini(void) {
     308                 :   struct NaClLogModuleVerbosity *entry;
     309                 :   struct NaClLogModuleVerbosity *next;
     310                 : 
     311              18 :   entry = gNaClLogModuleVerbosity;
     312              18 :   while (entry != NULL) {
     313               0 :     next = entry->next;
     314               0 :     free(entry);
     315               0 :     entry = next;
     316               0 :   }
     317              18 :   gNaClLogModuleVerbosity = NULL;
     318              18 :   NaClMutexDtor(&log_mu);
     319              18 :   g_initialized = 0;
     320              18 : }
     321                 : 
     322              27 : void NaClLogTagNext_mu(void) {
     323              27 :   tag_output = 1;
     324              27 : }
     325                 : 
     326              27 : void NaClLogLock(void) {
     327              27 :   NaClXMutexLock(&log_mu);
     328              27 :   NaClLogTagNext_mu();
     329              27 : }
     330                 : 
     331              27 : void NaClLogUnlock(void) {
     332              27 :   int run_abort_behavior = 0;
     333              27 :   switch (g_abort_count) {
     334                 :     case 0:
     335              27 :       NaClXMutexUnlock(&log_mu);
     336              27 :       break;
     337                 :     case 1:
     338                 :       /*
     339                 :        * include an easy-to-recognize output for the fuzzer to recognize
     340                 :        */
     341               1 :       if (!g_abort_behavior_active) {
     342               1 :         NaClLog_mu(LOG_ERROR, "LOG_FATAL abort exit\n");
     343               1 :         g_abort_behavior_active = 1;
     344               1 :         run_abort_behavior = 1;
     345                 :         /*
     346                 :          * run abort behavior only on edge transition when
     347                 :          * g_abort_behavior_active is first set.
     348                 :          */
     349                 :       }
     350               1 :       NaClXMutexUnlock(&log_mu);
     351               1 :       if (run_abort_behavior) {
     352                 : #ifdef __COVERITY__
     353                 :         NaClAbort();  /* help coverity figure out that this is the default */
     354                 : #else
     355               1 :         (*gNaClLogAbortBehavior)();
     356                 : #endif
     357               0 :         NaClAbort();
     358                 :       }
     359               0 :       break;
     360                 :     default:
     361                 :       /*
     362                 :        * Abort handling code in turn aborted.  Eeep!
     363                 :        */
     364               0 :       NaClAbort();
     365                 :       break;
     366                 :   }
     367              27 : }
     368                 : 
     369               9 : static INLINE struct Gio *NaClLogGetGio_mu(void) {
     370               9 :   if (NULL == log_stream) {
     371               0 :     (void) GioFileRefCtor(&log_file_stream, NaClLogDupFileIo(stderr));
     372               0 :     log_stream = (struct Gio *) &log_file_stream;
     373                 :   }
     374               9 :   return log_stream;
     375               9 : }
     376                 : 
     377              27 : static void NaClLogSetVerbosity_mu(int verb) {
     378              27 :   verbosity = verb;
     379              27 : }
     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              27 : void  NaClLogSetVerbosity(int verb) {
     394              27 :   NaClLogLock();
     395              27 :   NaClLogSetVerbosity_mu(verb);
     396              27 :   NaClLogUnlock();
     397              27 : }
     398                 : 
     399               0 : void  NaClLogIncrVerbosity(void) {
     400               0 :   NaClLogLock();
     401               0 :   if (NACL_VERBOSITY_UNSET == verbosity) {
     402               0 :     verbosity = 0;
     403                 :   }
     404               0 :   ++verbosity;
     405               0 :   NaClLogUnlock();
     406               0 : }
     407                 : 
     408               0 : int NaClLogGetVerbosity(void) {
     409                 :   int v;
     410                 : 
     411               0 :   NaClLogLock();
     412               0 :   if (NACL_VERBOSITY_UNSET == verbosity) {
     413               0 :     verbosity = 0;
     414                 :   }
     415               0 :   v = verbosity;
     416               0 :   NaClLogUnlock();
     417                 : 
     418               0 :   return v;
     419               0 : }
     420                 : 
     421              27 : static void NaClLogSetGio_mu(struct Gio *stream) {
     422              27 :   if (NULL != log_stream) {
     423               2 :     (void) (*log_stream->vtbl->Flush)(log_stream);
     424                 :   }
     425              27 :   log_stream = stream;
     426              27 : }
     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              27 : void NaClLogSetGio(struct Gio *stream) {
     436              27 :   NaClLogLock();
     437              27 :   NaClLogSetGio_mu(stream);
     438              27 :   NaClLogUnlock();
     439              27 : }
     440                 : 
     441               2 : struct Gio  *NaClLogGetGio(void) {
     442                 :   struct Gio  *s;
     443                 : 
     444               2 :   NaClLogLock();
     445               2 :   s = NaClLogGetGio_mu();
     446               2 :   NaClLogUnlock();
     447                 : 
     448               2 :   return s;
     449               2 : }
     450                 : 
     451               0 : void NaClLogEnableTimestamp(void) {
     452               0 :   timestamp_enabled = 1;
     453               0 : }
     454                 : 
     455               0 : void NaClLogDisableTimestamp(void) {
     456               0 :   timestamp_enabled = 0;
     457               0 : }
     458                 : 
     459               7 : static void NaClLogOutputTag_mu(struct Gio *s) {
     460                 :   char timestamp[128];
     461                 :   int  pid;
     462                 : 
     463               7 :   if (timestamp_enabled && tag_output) {
     464               7 :     pid = GETPID();
     465                 :     gprintf(s, "[%d,%u:%s] ",
     466                 :             pid,
     467                 :             NaClThreadId(),
     468               7 :             NaClTimeStampString(timestamp, sizeof timestamp));
     469               7 :     tag_output = 0;
     470                 :   }
     471               7 : }
     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                 : void NaClLogDoLogV_mu(int         detail_level,
     493                 :                       char const  *fmt,
     494               7 :                       va_list     ap) {
     495                 :   struct Gio  *s;
     496                 : 
     497               7 :   if (0 == g_abort_count) {
     498               7 :     s = NaClLogGetGio_mu();
     499                 : 
     500               7 :     NaClLogOutputTag_mu(s);
     501               7 :     (void) gvprintf(s, fmt, ap);
     502               7 :     (void) (*s->vtbl->Flush)(s);
     503               7 :   } else {
     504               1 :     (void) fprintf(stderr, "POST-ABORT: ");
     505               1 :     (void) vfprintf(stderr, fmt, ap);
     506               1 :     (void) fflush(stderr);
     507                 :   }
     508                 : 
     509               7 :   if (LOG_FATAL == detail_level) {
     510               1 :     ++g_abort_count;
     511                 :   }
     512               7 : }
     513                 : 
     514                 : void NaClLogV_mu(int        detail_level,
     515                 :                  char const *fmt,
     516               7 :                  va_list    ap) {
     517               7 :   if (NACL_VERBOSITY_UNSET == verbosity) {
     518               0 :     verbosity = NaClLogDefaultLogVerbosity();
     519                 :   }
     520                 : 
     521               7 :   if (detail_level <= verbosity) {
     522               7 :     NaClLogDoLogV_mu(detail_level, fmt, ap);
     523                 :   }
     524               7 : }
     525                 : 
     526                 : void NaClLogV(int         detail_level,
     527                 :               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                 : void NaClLogSetModuleVerbosity_mu(char const  *module_name,
     540               0 :                                   int         verbosity) {
     541                 :   struct NaClLogModuleVerbosity *entry;
     542                 : 
     543               0 :   entry = (struct NaClLogModuleVerbosity *) malloc(sizeof *entry);
     544               0 :   if (NULL == entry) {
     545                 :     NaClLog_mu(LOG_FATAL,
     546                 :                ("NaClLogSetModuleVerbosity_mu: Out of memory while setting"
     547                 :                 " module record for module: %s, verbosity: %d\n"),
     548               0 :                module_name, verbosity);
     549                 :   }
     550               0 :   entry->module_name = STRDUP(module_name);
     551               0 :   if (NULL == entry->module_name) {
     552                 :     NaClLog_mu(LOG_FATAL,
     553                 :                ("NaClLogSetModuleVerbosity_mu: Out of memory while duplicating"
     554                 :                 " module name: %s, verbosity: %d\n"),
     555               0 :                module_name, verbosity);
     556                 :   }
     557               0 :   entry->verbosity = verbosity;
     558               0 :   entry->next = gNaClLogModuleVerbosity;
     559               0 :   gNaClLogModuleVerbosity = entry;
     560               0 : }
     561                 : 
     562                 : 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               0 : int NaClLogGetModuleVerbosity_mu(char const *module_name) {
     574                 :   struct NaClLogModuleVerbosity *p;
     575                 : 
     576               0 :   if (NULL != module_name) {
     577               0 :     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                 :   }
     583               0 :   return verbosity;
     584               0 : }
     585                 : 
     586               0 : int NaClLogGetModuleVerbosity(char const *module_name) {
     587                 :   int rv;
     588               0 :   NaClLogLock();
     589               0 :   rv = NaClLogGetModuleVerbosity_mu(module_name);
     590               0 :   NaClLogUnlock();
     591               0 :   return rv;
     592               0 : }
     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                 : int NaClLogSetModule(char const *module_name) {
     616                 :   (void) pthread_setspecific(gModuleNameKey, (void const *) module_name);
     617                 :   return 0;
     618                 : }
     619                 : 
     620                 : static void NaClLogDoLogAndUnsetModuleV(int        detail_level,
     621                 :                                         const char *fmt,
     622                 :                                         va_list    ap) {
     623                 :   char const  *module_name = (char const *) pthread_getspecific(gModuleNameKey);
     624                 :   int         module_verbosity;
     625                 : 
     626                 :   module_verbosity = NaClLogGetModuleVerbosity_mu(module_name);
     627                 :   if (detail_level <= module_verbosity) {
     628                 :     NaClLogLock();
     629                 :     NaClLogDoLogV_mu(detail_level, fmt, ap);
     630                 :     NaClLogUnlock();
     631                 :   }
     632                 :   (void) pthread_setspecific(gModuleNameKey, (void const *) NULL);
     633                 : }
     634                 : 
     635                 : #else
     636                 : /* !NACL_PLATFORM_HAS_TLS && !NACL_PLATFORM_HAS_TSD */
     637                 : 
     638               0 : int NaClLogSetModule(char const *module_name) {
     639               0 :   NaClLogLock();
     640               0 :   nacl_log_module_name = module_name;
     641               0 :   return 0;
     642               0 : }
     643                 : 
     644                 : static void NaClLogDoLogAndUnsetModuleV(int         detail_level,
     645                 :                                         char const  *fmt,
     646               0 :                                         va_list     ap) {
     647                 :   int module_verbosity;
     648                 : 
     649               0 :   module_verbosity = NaClLogGetModuleVerbosity_mu(nacl_log_module_name);
     650               0 :   if (detail_level <= module_verbosity) {
     651               0 :     NaClLogDoLogV_mu(detail_level, fmt, ap);
     652                 :   }
     653               0 :   nacl_log_module_name = NULL;
     654               0 :   NaClLogUnlock();
     655               0 : }
     656                 : #endif
     657                 : 
     658                 : void NaClLogDoLogAndUnsetModule(int        detail_level,
     659                 :                                 char const *fmt,
     660               0 :                                 ...) {
     661                 :   va_list ap;
     662                 : 
     663               0 :   va_start(ap, fmt);
     664               0 :   NaClLogDoLogAndUnsetModuleV(detail_level, fmt, ap);
     665               0 :   va_end(ap);
     666               0 : }
     667                 : 
     668                 : void NaClLog(int         detail_level,
     669                 :              char const  *fmt,
     670              19 :              ...) {
     671                 :   va_list ap;
     672                 : 
     673                 : #if !THREAD_SAFE_DETAIL_CHECK
     674              19 :   if (NACL_LIKELY(detail_level > verbosity)) {
     675              18 :     return;
     676                 :   }
     677                 : #endif
     678                 : 
     679               7 :   NaClLogLock();
     680               7 :   va_start(ap, fmt);
     681               7 :   NaClLogV_mu(detail_level, fmt, ap);
     682               7 :   va_end(ap);
     683               7 :   NaClLogUnlock();
     684              18 : }
     685                 : 
     686                 : void NaClLog_mu(int         detail_level,
     687                 :                 char const  *fmt,
     688               1 :                 ...) {
     689                 :   va_list ap;
     690                 : 
     691                 : #if THREAD_SAFE_DETAIL_CHECK
     692                 :   if (detail_level > verbosity) {
     693                 :     return;
     694                 :   }
     695                 : #endif
     696                 : 
     697               1 :   va_start(ap, fmt);
     698               1 :   NaClLogV_mu(detail_level, fmt, ap);
     699               1 :   va_end(ap);
     700               1 : }
     701                 : 
     702                 : void NaClLog2(char const *module_name,
     703                 :               int        detail_level,
     704                 :               char const *fmt,
     705               0 :               ...) {
     706                 :   va_list ap;
     707                 : 
     708               0 :   NaClLogSetModule(module_name);
     709               0 :   va_start(ap, fmt);
     710               0 :   NaClLogDoLogAndUnsetModuleV(detail_level, fmt, ap);
     711               0 :   va_end(ap);
     712               0 : }
     713                 : 
     714               0 : void NaClLogSetAbortBehavior(void (*fn)(void)) {
     715               0 :   NaClXMutexLock(&log_mu);
     716               0 :   gNaClLogAbortBehavior = fn;
     717               0 :   NaClXMutexUnlock(&log_mu);
     718               0 : }

Generated by: LCOV version 1.7