LCOV - code coverage report
Current view: directory - src/shared/platform - nacl_log.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 255 142 55.7 %
Date: 2012-02-16 Functions: 0 0 -

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

Generated by: LCOV version 1.7