LCOV - code coverage report
Current view: top level - util/log - fd_log.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 662 873 75.8 %
Date: 2025-11-07 04:31:33 Functions: 61 69 88.4 %

          Line data    Source code
       1             : #ifndef FD_LOG_STYLE
       2             : #if FD_HAS_HOSTED
       3             : #define FD_LOG_STYLE 0
       4             : #else
       5             : #error "Define FD_LOG_STYLE for this platform"
       6             : #endif
       7             : #endif
       8             : 
       9             : #if FD_LOG_STYLE==0 /* POSIX style */
      10             : 
      11             : #ifndef FD_HAS_BACKTRACE
      12             : #if __has_include( <execinfo.h> )
      13             : #define FD_HAS_BACKTRACE 1
      14             : #else
      15             : #define FD_HAS_BACKTRACE 0
      16             : #endif
      17             : #endif
      18             : 
      19             : /* FIXME: SANITIZE VARIOUS USER SET STRINGS */
      20             : 
      21             : #define _GNU_SOURCE
      22             : 
      23             : #include "fd_log.h"
      24             : #include "fd_backtrace.h"
      25             : 
      26             : #include <stdio.h>
      27             : #include <stdlib.h>
      28             : #include <stdarg.h>
      29             : #include <ctype.h>
      30             : #include <errno.h>
      31             : #include <fcntl.h>
      32             : #include <unistd.h>
      33             : #include <signal.h>
      34             : #include <sched.h>
      35             : #include <time.h>
      36             : #if defined(__linux__)
      37             : #include <syscall.h>
      38             : #endif
      39             : #include <sys/mman.h>
      40             : 
      41             : #if FD_HAS_BACKTRACE
      42             : #include <execinfo.h>
      43             : #endif
      44             : 
      45             : #if defined(__FreeBSD__)
      46             : #include <sys/stat.h> /* S_IRUSR */
      47             : #endif /* defined(__FreeBSD__) */
      48             : 
      49             : #include "../tile/fd_tile_private.h"
      50             : 
      51             : #ifdef __has_include
      52             : #if __has_include("../../app/fdctl/version.h")
      53             : #include "../../app/fdctl/version.h"
      54             : #endif
      55             : #endif
      56             : 
      57             : #ifndef FDCTL_MAJOR_VERSION
      58             : #define FDCTL_MAJOR_VERSION 0
      59             : #endif
      60             : #ifndef FDCTL_MINOR_VERSION
      61             : #define FDCTL_MINOR_VERSION 0
      62             : #endif
      63             : #ifndef FDCTL_PATCH_VERSION
      64             : #define FDCTL_PATCH_VERSION 0
      65             : #endif
      66             : 
      67             : #ifdef FD_BUILD_INFO
      68             : FD_IMPORT_CSTR( fd_log_build_info, FD_BUILD_INFO );
      69             : #else
      70             : char const  fd_log_build_info[1] __attribute__((aligned(1))) = { '\0' };
      71             : ulong const fd_log_build_info_sz                             = 1UL;
      72             : #endif
      73             : 
      74             : /* TEXT_* are quick-and-dirty color terminal hacks.  Probably should
      75             :    do something more robust longer term. */
      76             : 
      77       80592 : #define TEXT_NORMAL    "\033[0m"
      78             : #define TEXT_BOLD      "\033[1m"
      79             : #define TEXT_UNDERLINE "\033[4m"
      80             : #define TEXT_BLINK     "\033[5m"
      81             : 
      82       10074 : #define TEXT_BLUE      "\033[34m"
      83       10074 : #define TEXT_GREEN     "\033[32m"
      84       10074 : #define TEXT_YELLOW    "\033[93m"
      85       40296 : #define TEXT_RED       "\033[31m"
      86             : 
      87             : /* APPLICATION LOGICAL ID APIS ****************************************/
      88             : 
      89             : /* App id */
      90             : 
      91             : static ulong fd_log_private_app_id; /* 0 outside boot/halt, init on boot */
      92             : 
      93        2491 : void fd_log_private_app_id_set( ulong app_id ) { fd_log_private_app_id = app_id; }
      94             : 
      95    18005054 : ulong fd_log_app_id( void ) { return fd_log_private_app_id; }
      96             : 
      97             : /* App */
      98             : 
      99             : static char fd_log_private_app[ FD_LOG_NAME_MAX ]; /* "" outside boot/halt, init on boot */
     100             : 
     101             : void
     102        2491 : fd_log_private_app_set( char const * app ) {
     103        2491 :   if( FD_UNLIKELY( !app ) ) app = "[app]";
     104        2491 :   if( FD_LIKELY( app!=fd_log_private_app ) )
     105        2491 :     fd_cstr_fini( fd_cstr_append_cstr_safe( fd_cstr_init( fd_log_private_app ), app, FD_LOG_NAME_MAX-1UL ) );
     106        2491 : }
     107             : 
     108     2394300 : char const * fd_log_app( void ) { return fd_log_private_app; }
     109             : 
     110             : /* Thread ID */
     111             : 
     112             : #if FD_HAS_THREADS
     113             : static ulong fd_log_private_thread_id_ctr; /* 0 outside boot/halt, init on boot */
     114             : 
     115             : static ulong
     116        2527 : fd_log_private_thread_id_next( void ) {
     117        2527 :   return FD_ATOMIC_FETCH_AND_ADD( &fd_log_private_thread_id_ctr, 1UL );
     118        2527 : }
     119             : #endif
     120             : 
     121             : static FD_TL ulong fd_log_private_thread_id;      /* 0 at thread start */
     122             : static FD_TL int   fd_log_private_thread_id_init; /* 0 at thread start */
     123             : 
     124             : void
     125        2527 : fd_log_private_thread_id_set( ulong thread_id ) {
     126        2527 :   fd_log_private_thread_id      = thread_id;
     127        2527 :   fd_log_private_thread_id_init = 1;
     128        2527 : }
     129             : 
     130             : ulong
     131    36007608 : fd_log_thread_id( void ) {
     132    36007608 : # if FD_HAS_THREADS
     133    36007608 :   if( FD_UNLIKELY( !fd_log_private_thread_id_init ) ) fd_log_private_thread_id_set( fd_log_private_thread_id_next() );
     134             : # else
     135             :   FD_COMPILER_MFENCE(); /* Work around FD_FN_CONST */
     136             : # endif
     137    36007608 :   return fd_log_private_thread_id;
     138    36007608 : }
     139             : 
     140             : /* Thread */
     141             : 
     142             : /* Initialize name to a reasonable default thread description (FIXME:
     143             :    WEEN THIS OFF STDLIB) */
     144             : 
     145             : static void
     146        2536 : fd_log_private_thread_default( char * name ) { /* FD_LOG_NAME_MAX bytes */
     147        2536 :   sprintf( name, "%lu", fd_log_thread_id() );
     148        2536 : }
     149             : 
     150             : static FD_TL char fd_log_private_thread[ FD_LOG_NAME_MAX ]; /* "" at thread start */
     151             : static FD_TL int  fd_log_private_thread_init;               /* 0 at thread start */
     152             : 
     153             : void
     154        2536 : fd_log_thread_set( char const * thread ) {
     155        2536 :   if( FD_UNLIKELY( !thread ) || FD_UNLIKELY( thread[0]=='\0') ) {
     156        2536 :     fd_log_private_thread_default( fd_log_private_thread );
     157        2536 :     fd_log_private_thread_init = 1;
     158        2536 :   } else if( FD_LIKELY( thread!=fd_log_private_thread ) ) {
     159           0 :     fd_cstr_fini( fd_cstr_append_cstr_safe( fd_cstr_init( fd_log_private_thread ), thread, FD_LOG_NAME_MAX-1UL ) );
     160           0 :     fd_log_private_thread_init = 1;
     161           0 :   }
     162        2536 : }
     163             : 
     164             : char const *
     165     3555426 : fd_log_thread( void ) {
     166     3555426 :   if( FD_UNLIKELY( !fd_log_private_thread_init ) ) fd_log_thread_set( NULL );
     167     3555426 :   return fd_log_private_thread;
     168     3555426 : }
     169             : 
     170             : /* APPLICATION PHYSICAL ID APIS ***************************************/
     171             : 
     172             : /* Host ID */
     173             : 
     174             : static ulong fd_log_private_host_id; /* 0 outside boot/halt, initialized on boot */
     175             : 
     176        2491 : void fd_log_private_host_id_set( ulong host_id ) { fd_log_private_host_id = host_id; }
     177             : 
     178        5018 : ulong fd_log_host_id( void ) { return fd_log_private_host_id; }
     179             : 
     180             : /* Host */
     181             : 
     182             : static char  fd_log_private_host[ FD_LOG_NAME_MAX ]; /* "" outside boot/halt, initialized on boot */
     183             : 
     184     2394299 : char const * fd_log_host( void ) { return fd_log_private_host; }
     185             : 
     186             : void
     187        2491 : fd_log_private_host_set( char const * host ) {
     188        2491 :   if( FD_UNLIKELY( !host ) || FD_UNLIKELY( host[0]=='\0') ) host = "[host]";
     189        2491 :   if( FD_LIKELY( host!=fd_log_private_host ) )
     190        2491 :     fd_cstr_fini( fd_cstr_append_cstr_safe( fd_cstr_init( fd_log_private_host ), host, FD_LOG_NAME_MAX-1UL ) );
     191        2491 : }
     192             : 
     193             : /* CPU ID */
     194             : 
     195             : /* First CPU scheduled to run on or ULONG_MAX on failure */
     196             : 
     197             : ulong
     198        2491 : fd_log_private_cpu_id_default( void ) {
     199        2491 :   FD_CPUSET_DECL( cpu_set );
     200        2491 :   if( FD_UNLIKELY( fd_cpuset_getaffinity( (pid_t)0, cpu_set ) ) ) return ULONG_MAX;
     201        2491 :   ulong idx = fd_cpuset_first( cpu_set );
     202        2491 :         idx = fd_ulong_if( idx<FD_TILE_MAX, idx, ULONG_MAX );
     203        2491 :   return idx;
     204        2491 : }
     205             : 
     206             : static FD_TL ulong fd_log_private_cpu_id;      /* 0 at thread start */
     207             : static FD_TL int   fd_log_private_cpu_id_init; /* 0 at thread start */
     208             : 
     209             : void
     210        2500 : fd_log_private_cpu_id_set( ulong cpu_id ) {
     211        2500 :   fd_log_private_cpu_id      = cpu_id;
     212        2500 :   fd_log_private_cpu_id_init = 1;
     213        2500 : }
     214             : 
     215             : ulong
     216    18002560 : fd_log_cpu_id( void ) {
     217    18002560 :   if( FD_UNLIKELY( !fd_log_private_cpu_id_init ) ) fd_log_private_cpu_id_set( fd_log_private_cpu_id_default() );
     218    18002560 :   return fd_log_private_cpu_id;
     219    18002560 : }
     220             : 
     221             : /* CPU */
     222             : 
     223             : /* Initialize name to a reasonable default CPU description (FIXME: WEEN
     224             :    THIS OFF STDLIB) */
     225             : 
     226             : static void
     227        2536 : fd_log_private_cpu_default( char * name ) { /* FD_LOG_NAME_MAX bytes */
     228        2536 :   FD_CPUSET_DECL( set );
     229             : 
     230        2536 :   int err = fd_cpuset_getaffinity( (pid_t)0, set );
     231        2536 :   if( FD_UNLIKELY( err ) ) { sprintf( name, "e%i", err ); return; }
     232             : 
     233        2536 :   ulong cnt = fd_cpuset_cnt( set );
     234        2536 :   if( FD_UNLIKELY( !((0UL<cnt) & (cnt<=FD_TILE_MAX)) ) ) { sprintf( name, "ec" ); return; }
     235             : 
     236        2536 :   ulong idx = fd_cpuset_first( set );
     237        2536 :   sprintf( name, (cnt>1) ? "f%lu" : "%lu", idx );
     238        2536 : }
     239             : 
     240             : static FD_TL char fd_log_private_cpu[ FD_LOG_NAME_MAX ]; /* "" at thread start */
     241             : static FD_TL int  fd_log_private_cpu_init;               /* 0  at thread start */
     242             : 
     243             : void
     244        2536 : fd_log_cpu_set( char const * cpu ) {
     245        2536 :   if( FD_UNLIKELY( !cpu ) || FD_UNLIKELY( cpu[0]=='\0') ) {
     246        2536 :     fd_log_private_cpu_default( fd_log_private_cpu );
     247        2536 :     fd_log_private_cpu_init = 1;
     248        2536 :   } else if( FD_LIKELY( cpu!=fd_log_private_cpu ) ) {
     249           0 :     fd_cstr_fini( fd_cstr_append_cstr_safe( fd_cstr_init( fd_log_private_cpu ), cpu, FD_LOG_NAME_MAX-1UL ) );
     250           0 :     fd_log_private_cpu_init = 1;
     251           0 :   }
     252        2536 : }
     253             : 
     254             : char const *
     255     3555426 : fd_log_cpu( void ) {
     256     3555426 :   if( FD_UNLIKELY( !fd_log_private_cpu_init ) ) fd_log_cpu_set( NULL );
     257     3555426 :   return fd_log_private_cpu;
     258     3555426 : }
     259             : 
     260             : /* THREAD GROUP ID APIS ***********************************************/
     261             : 
     262             : /* Group id */
     263             : 
     264             : static ulong fd_log_private_group_id; /* 0 outside boot/halt, init on boot */
     265             : 
     266        2491 : void fd_log_private_group_id_set( ulong group_id ) { fd_log_private_group_id = group_id; }
     267             : 
     268   313706214 : ulong fd_log_group_id( void ) { return fd_log_private_group_id; }
     269             : 
     270             : /* Group */
     271             : 
     272             : static char fd_log_private_group[ FD_LOG_NAME_MAX ]; /* "" outside boot/halt, init on boot */
     273             : 
     274     2394298 : char const * fd_log_group( void ) { return fd_log_private_group; }
     275             : 
     276             : void
     277        2491 : fd_log_private_group_set( char const * group ) {
     278        2491 :   if( FD_UNLIKELY( !group ) || FD_UNLIKELY( group[0]=='\0') ) group = "[group]";
     279        2491 :   if( FD_LIKELY( group!=fd_log_private_group ) )
     280        2491 :     fd_cstr_fini( fd_cstr_append_cstr_safe( fd_cstr_init( fd_log_private_group ), group, FD_LOG_NAME_MAX-1UL ) );
     281        2491 : }
     282             : 
     283             : /* System TID or ULONG_MAX on failure */
     284             : 
     285             : ulong
     286        2527 : fd_log_private_tid_default( void ) {
     287        2527 : # if defined(__linux__)
     288        2527 :   long tid = syscall( SYS_gettid );
     289             : # else
     290             :   long tid = getpid();
     291             : # endif
     292        2527 :   return fd_ulong_if( tid>0L, (ulong)tid, ULONG_MAX );
     293        2527 : }
     294             : 
     295             : static FD_TL ulong fd_log_private_tid;      /* 0 at thread start */
     296             : static FD_TL int   fd_log_private_tid_init; /* 0 at thread start */
     297             : 
     298             : void
     299        2527 : fd_log_private_tid_set( ulong tid ) {
     300        2527 :   fd_log_private_tid      = tid;
     301        2527 :   fd_log_private_tid_init = 1;
     302        2527 : }
     303             : 
     304             : ulong
     305     3557881 : fd_log_tid( void ) {
     306     3557881 :   if( FD_UNLIKELY( !fd_log_private_tid_init ) ) fd_log_private_tid_set( fd_log_private_tid_default() );
     307     3557881 :   return fd_log_private_tid;
     308     3557881 : }
     309             : 
     310             : /* User id */
     311             : 
     312             : static ulong
     313        2491 : fd_log_private_user_id_default( void ) {
     314        2491 :   return (ulong)getuid(); /* POSIX spec seems ambiguous as to whether or not this is a signed type */
     315        2491 : }
     316             : 
     317             : static ulong fd_log_private_user_id;      /* 0 outside boot/halt, init on boot */
     318             : static int   fd_log_private_user_id_init;
     319             : 
     320             : void
     321        2491 : fd_log_private_user_id_set( ulong user_id ) {
     322        2491 :   fd_log_private_user_id      = user_id;
     323        2491 :   fd_log_private_user_id_init = 1;
     324        2491 : }
     325             : 
     326             : ulong
     327        2527 : fd_log_user_id( void ) {
     328        2527 :   if( FD_UNLIKELY( !fd_log_private_user_id_init ) ) {
     329           0 :     fd_log_private_user_id      = fd_log_private_user_id_default();
     330           0 :     fd_log_private_user_id_init = 1;
     331           0 :   }
     332        2527 :   return fd_log_private_user_id;
     333        2527 : }
     334             : 
     335             : /* User */
     336             : 
     337             : static char  fd_log_private_user[ FD_LOG_NAME_MAX ]; /* "" outside boot/halt, init on boot */
     338             : 
     339     2394299 : char const * fd_log_user( void ) { return fd_log_private_user; }
     340             : 
     341             : void
     342        2491 : fd_log_private_user_set( char const * user ) {
     343        2491 :   if( FD_UNLIKELY( !user ) || FD_UNLIKELY( user[0]=='\0') ) user = "[user]";
     344        2491 :   if( FD_LIKELY( user!=fd_log_private_user ) )
     345        2491 :     fd_cstr_fini( fd_cstr_append_cstr_safe( fd_cstr_init( fd_log_private_user ), user, FD_LOG_NAME_MAX-1UL ) );
     346        2491 : }
     347             : 
     348             : int
     349           0 : fd_log_group_id_query( ulong group_id ) {
     350           0 :   if( group_id==fd_log_group_id() ) return FD_LOG_GROUP_ID_QUERY_LIVE; /* Avoid O/S call for self queries */
     351           0 :   pid_t pid = (pid_t)group_id;
     352           0 :   if( FD_UNLIKELY( ((group_id!=(ulong)pid) | (pid<=(pid_t)0)) ) ) return FD_LOG_GROUP_ID_QUERY_INVAL;
     353           0 :   if( !kill( (pid_t)group_id, 0 ) ) return FD_LOG_GROUP_ID_QUERY_LIVE;
     354           0 :   if( FD_LIKELY( errno==ESRCH ) ) return FD_LOG_GROUP_ID_QUERY_DEAD;
     355           0 :   if( FD_LIKELY( errno==EPERM ) ) return FD_LOG_GROUP_ID_QUERY_PERM;
     356           0 :   return FD_LOG_GROUP_ID_QUERY_FAIL;
     357           0 : }
     358             : 
     359             : /* WALLCLOCK APIS *****************************************************/
     360             : 
     361             : long
     362   122887973 : fd_log_wallclock_host( void const * _ ) {
     363   122887973 :   (void)_;
     364   122887973 :   struct timespec ts[1];
     365   122887973 :   clock_gettime( CLOCK_REALTIME, ts );
     366   122887973 :   return ((long)1e9)*((long)ts->tv_sec) + (long)ts->tv_nsec;
     367   122887973 : }
     368             : 
     369             : static fd_clock_func_t fd_log_private_clock_func = fd_log_wallclock_host;
     370             : static void const *    fd_log_private_clock_args = NULL;
     371             : 
     372             : long
     373   121667176 : fd_log_wallclock( void ) {
     374   121667176 :   return fd_log_private_clock_func( fd_log_private_clock_args );
     375   121667176 : }
     376             : 
     377             : void
     378             : fd_log_wallclock_set( fd_clock_func_t clock,
     379           0 :                       void const *    args ) {
     380           0 :   fd_log_private_clock_func = clock;
     381           0 :   fd_log_private_clock_args = args;
     382           0 : }
     383             : 
     384             : char *
     385             : fd_log_wallclock_cstr( long   now,
     386     2398756 :                        char * buf ) {
     387     2398756 :   uint  YYYY;
     388     2398756 :   uint  MM;
     389     2398756 :   uint  DD;
     390     2398756 :   uint  hh;
     391     2398756 :   uint  mm;
     392     2398756 :   ulong ns;
     393     2398756 :   int   tz;
     394             : 
     395     2398756 :   static long const ns_per_m = 60000000000L;
     396     2398756 :   static long const ns_per_s =  1000000000L;
     397             : 
     398     2398756 :   static FD_TL long now_ref  = 1262325600000000000L; /* 2010-01-01 00:00:00.000000000 GMT-06 */
     399     2398756 :   static FD_TL uint YYYY_ref = 2010U;                /* Initialized to what now0 corresponds to */
     400     2398756 :   static FD_TL uint MM_ref   = 1U;                   /* " */
     401     2398756 :   static FD_TL uint DD_ref   = 1U;                   /* " */
     402     2398756 :   static FD_TL uint hh_ref   = 0U;                   /* " */
     403     2398756 :   static FD_TL uint mm_ref   = 0U;                   /* " */
     404     2398756 :   static FD_TL int  tz_ref   = -6;                   /* " */
     405             : 
     406     2398756 :   if( FD_LIKELY( (now_ref<=now) & (now<(now_ref+ns_per_m)) ) ) {
     407             : 
     408             :     /* now is near the reference timestamp so we reuse the reference
     409             :        calculation timestamp. */
     410             : 
     411     2396236 :     YYYY = YYYY_ref;
     412     2396236 :     MM   = MM_ref;
     413     2396236 :     DD   = DD_ref;
     414     2396236 :     hh   = hh_ref;
     415     2396236 :     mm   = mm_ref;
     416     2396236 :     ns   = (ulong)(now - now_ref);
     417     2396236 :     tz   = tz_ref;
     418             : 
     419     2396236 :   } else {
     420             : 
     421        2520 :     long _t  = now / ns_per_s;
     422        2520 :     long _ns = now - ns_per_s*_t;
     423        2520 :     if( _ns<0L ) _ns += ns_per_s, _t--;
     424        2520 :     time_t t = (time_t)_t;
     425             : 
     426        2520 :     struct tm tm[1];
     427        2520 :     static FD_TL int localtime_broken = 0;
     428        2520 :     if( FD_UNLIKELY( !localtime_broken && !localtime_r( &t, tm ) ) ) localtime_broken = 1;
     429        2520 :     if( FD_UNLIKELY( localtime_broken ) ) { /* If localtime_r doesn't work, pretty print as a raw UNIX time */
     430             :       /* Note: These can all run in parallel */
     431           0 :       fd_cstr_append_fxp10_as_text( buf,    ' ', fd_char_if( now<0L, '-', '\0' ), 9UL, fd_long_abs( now ), 29UL );
     432           0 :       fd_cstr_append_text         ( buf+29, " s UNIX",                                                      7UL );
     433           0 :       fd_cstr_append_char         ( buf+36, '\0'                                                                );
     434           0 :       return buf;
     435           0 :     }
     436             : 
     437        2520 :     YYYY = (uint)(1900+tm->tm_year);
     438        2520 :     MM   = (uint)(   1+tm->tm_mon );
     439        2520 :     DD   = (uint)tm->tm_mday;
     440        2520 :     hh   = (uint)tm->tm_hour;
     441        2520 :     mm   = (uint)tm->tm_min;
     442        2520 :     ns   = ((ulong)((uint)tm->tm_sec))*((ulong)ns_per_s) + ((ulong)_ns);
     443        2520 : #   if defined(__linux__)
     444        2520 :     tz   = (int)(-timezone/3600L+(long)tm->tm_isdst);
     445             : #   else
     446             :     tz   = 0;
     447             : #   endif
     448             : 
     449        2520 :     now_ref  = now - (long)ns;
     450        2520 :     YYYY_ref = YYYY;
     451        2520 :     MM_ref   = MM;
     452        2520 :     DD_ref   = DD;
     453        2520 :     hh_ref   = hh;
     454        2520 :     mm_ref   = mm;
     455        2520 :     tz_ref   = tz;
     456             : 
     457        2520 :   }
     458             : 
     459             :   /* Note: These can all run in parallel! */
     460     2398756 :   fd_cstr_append_uint_as_text ( buf,    '0', '\0',    YYYY,            4UL );
     461     2398756 :   fd_cstr_append_char         ( buf+ 4, '-'                                );
     462     2398756 :   fd_cstr_append_uint_as_text ( buf+ 5, '0', '\0',      MM,            2UL );
     463     2398756 :   fd_cstr_append_char         ( buf+ 7, '-'                                );
     464     2398756 :   fd_cstr_append_uint_as_text ( buf+ 8, '0', '\0',      DD,            2UL );
     465     2398756 :   fd_cstr_append_char         ( buf+10, ' '                                );
     466     2398756 :   fd_cstr_append_uint_as_text ( buf+11, '0', '\0',      hh,            2UL );
     467     2398756 :   fd_cstr_append_char         ( buf+13, ':'                                );
     468     2398756 :   fd_cstr_append_uint_as_text ( buf+14, '0', '\0',      mm,            2UL );
     469     2398756 :   fd_cstr_append_char         ( buf+16, ':'                                );
     470     2398756 :   fd_cstr_append_fxp10_as_text( buf+17, '0', '\0', 9UL, ns,           12UL );
     471     2398756 :   fd_cstr_append_text         ( buf+29, " GMT",                        4UL );
     472     2398756 :   fd_cstr_append_char         ( buf+33, fd_char_if( tz<0, '-', '+' )       );
     473     2398756 :   fd_cstr_append_uint_as_text ( buf+34, '0', '\0', fd_int_abs( tz ),   2UL );
     474     2398756 :   fd_cstr_append_char         ( buf+36, '\0'                               );
     475     2398756 :   return buf;
     476     2398756 : }
     477             : 
     478             : long
     479         606 : fd_log_sleep( long dt ) {
     480         606 :   if( FD_UNLIKELY( dt < 1L ) ) {
     481           0 :     sched_yield();
     482           0 :     return 0L;
     483           0 :   }
     484             : 
     485             :   /* dt is in [1,LONG_MAX] at this point */
     486         606 :   long ns_dt = fd_long_min( dt, (((long)1e9)<<31)-1L ); /* in [1,2^31*1e9) and <= dt at this point */
     487         606 :   dt -= ns_dt;
     488             : 
     489         606 :   struct timespec req[1];
     490         606 :   struct timespec rem[1];
     491         606 :   req->tv_sec  = (time_t)( ((ulong)ns_dt) / ((ulong)1e9) ); /* in [0,2^31-1] */
     492         606 :   req->tv_nsec = (long)  ( ((ulong)ns_dt) % ((ulong)1e9) ); /* in [0,1e9) */
     493         606 :   int sleep_res;
     494         606 : #if defined(__linux__)
     495             :   /* Always use clock_nanosleep on Linux to be predictable */
     496         606 :   sleep_res = clock_nanosleep( CLOCK_REALTIME, 0, req, rem );
     497             : #else
     498             :   sleep_res = nanosleep( req, rem );
     499             : #endif
     500         606 :   if( FD_UNLIKELY( sleep_res ) && FD_LIKELY( errno==EINTR ) ) dt += ((long)1e9)*((long)rem->tv_sec) + rem->tv_nsec;
     501         606 :   return dt;
     502         606 : }
     503             : 
     504             : long
     505           3 : fd_log_wait_until( long then ) {
     506           3 :   long now;
     507           3 :   for(;;) {
     508           3 :     now = fd_log_wallclock();
     509           3 :     long rem = then - now;
     510           3 :     if( FD_LIKELY( rem<=0L ) ) break; /* we've waited long enough */
     511           0 :     if( FD_UNLIKELY( rem>(long)1e9 ) ) { /* long wait (over ~1 s) ... sleep until medium long */
     512           0 :       fd_log_sleep( rem-(long)0.1e9 );
     513           0 :       continue;
     514           0 :     }
     515           0 :     if( FD_UNLIKELY( rem>(long)0.1e9 ) ) { /* medium long wait (over ~0.1 s) ... yield */
     516           0 :       FD_YIELD();
     517           0 :       continue;
     518           0 :     }
     519           0 :     if( FD_UNLIKELY( rem>(long)1e3 ) ) { /* medium short wait (over ~1 us) ... hyperthreading friendly spin */
     520           0 :       FD_SPIN_PAUSE();
     521           0 :       continue;
     522           0 :     }
     523             :     /* short wait ... spin on fd_log_wallclock */
     524           0 :   }
     525           3 :   return now;
     526           3 : }
     527             : 
     528             : /* LOG APIS ***********************************************************/
     529             : 
     530             : char       fd_log_private_path[ 1024 ]; /* "" outside boot/halt, init at boot */
     531             : static int fd_log_private_fileno = -1;  /* -1 outside boot/halt, init at boot */
     532             : static int fd_log_private_dedup;        /*  0 outside boot/halt, init at boot */
     533             : 
     534             : void
     535        4443 : fd_log_flush( void ) {
     536        4443 :   int log_fileno = FD_VOLATILE_CONST( fd_log_private_fileno );
     537        4443 :   if( FD_LIKELY( log_fileno!=-1 ) ) fsync( log_fileno );
     538        4443 : }
     539             : 
     540             : static int fd_log_private_colorize;      /* 0 outside boot/halt, init at boot */
     541             : static int fd_log_private_level_logfile; /* 0 outside boot/halt, init at boot */
     542             : static int fd_log_private_level_stderr;  /* 0 outside boot/halt, init at boot */
     543             : static int fd_log_private_level_flush;   /* 0 outside boot/halt, init at boot */
     544             : static int fd_log_private_level_core;    /* 0 outside boot/halt, init at boot */
     545             : static int fd_log_private_unclean_exit;
     546             : static int fd_log_private_signal_handler;
     547             : 
     548        2491 : int fd_log_colorize     ( void ) { return FD_VOLATILE_CONST( fd_log_private_colorize      ); }
     549     3689943 : int fd_log_level_logfile( void ) { return FD_VOLATILE_CONST( fd_log_private_level_logfile ); }
     550     3555819 : int fd_log_level_stderr ( void ) { return FD_VOLATILE_CONST( fd_log_private_level_stderr  ); }
     551     2400768 : int fd_log_level_flush  ( void ) { return FD_VOLATILE_CONST( fd_log_private_level_flush   ); }
     552        4741 : int fd_log_level_core   ( void ) { return FD_VOLATILE_CONST( fd_log_private_level_core    ); }
     553             : 
     554        2491 : void fd_log_colorize_set     ( int mode  ) { FD_VOLATILE( fd_log_private_colorize      ) = mode;  }
     555        2500 : void fd_log_level_logfile_set( int level ) { FD_VOLATILE( fd_log_private_level_logfile ) = level; }
     556        2503 : void fd_log_level_stderr_set ( int level ) { FD_VOLATILE( fd_log_private_level_stderr  ) = level; }
     557        2491 : void fd_log_level_flush_set  ( int level ) { FD_VOLATILE( fd_log_private_level_flush   ) = level; }
     558        2503 : void fd_log_level_core_set   ( int level ) { FD_VOLATILE( fd_log_private_level_core    ) = level; }
     559             : 
     560          12 : int fd_log_private_logfile_fd( void ) { return FD_VOLATILE_CONST( fd_log_private_fileno ); }
     561             : 
     562           0 : void fd_log_enable_signal_handler( void ) { fd_log_private_signal_handler = 1; }
     563           0 : void fd_log_enable_unclean_exit( void ) { fd_log_private_unclean_exit = 1; }
     564             : 
     565             : /* Buffer size used for vsnprintf calls (this is also one more than the
     566             :    maximum size that this can passed to fd_io_write) */
     567             : 
     568    12175442 : #define FD_LOG_BUF_SZ (32UL*4096UL)
     569             : 
     570             : /* Lock to used by fd_log_private_fprintf_0 to sequence calls writes
     571             :    between different _processes_ that share the same fd. */
     572             : 
     573             : static int fd_log_private_shared_lock_local[1] __attribute__((aligned(128))); /* location of lock if boot mmap fails */
     574             :        int * fd_log_private_shared_lock  = fd_log_private_shared_lock_local;  /* Local lock outside boot/halt, init at boot */
     575             : 
     576             : /* File descriptor to restore when logging a message that will terminate
     577             :    the application, incase it was redirected to some other consumer in
     578             :    the process which will not be able to process it in time */
     579             : static int fd_log_private_stderr_fileno = STDERR_FILENO;
     580             : int fd_log_private_restore_stderr = STDERR_FILENO;
     581             : 
     582             : void
     583             : fd_log_private_fprintf_0( int          fd,
     584     2407042 :                           char const * fmt, ... ) {
     585             : 
     586             :   /* Note: while this function superficially looks vdprintf-ish, we don't
     587             :      use that as it can do all sorts of unpleasantness under the hood
     588             :      (fflush, mutex / futex on fd, non-AS-safe buffering, ...) that this
     589             :      function deliberately avoids.  Also, the function uses the shared
     590             :      lock to help keep messages generated from processes that share the
     591             :      same log fd sane. */
     592             : 
     593             :   /* TODO:
     594             :      - Consider moving to util/io as fd_io_printf or renaming to
     595             :        fd_log_printf?
     596             :      - Is msg better to have on stack or in thread local storage?
     597             :      - Is msg even necessary given shared lock? (probably still useful to
     598             :        keep the message write to be a single-system-call best effort)
     599             :      - Allow partial write to fd_io_write?  (e.g. src_min=0 such that
     600             :        the fd_io_write below is guaranteed to be a single system call) */
     601             : 
     602     2407042 :   char msg[ FD_LOG_BUF_SZ ];
     603             : 
     604     2407042 :   va_list ap;
     605     2407042 :   va_start( ap, fmt );
     606     2407042 :   int len = vsnprintf( msg, FD_LOG_BUF_SZ, fmt, ap );
     607     2407042 :   if( len<0                        ) len = 0;                        /* cmov */
     608     2407042 :   if( len>(int)(FD_LOG_BUF_SZ-1UL) ) len = (int)(FD_LOG_BUF_SZ-1UL); /* cmov */
     609     2407042 :   msg[ len ] = '\0';
     610     2407042 :   va_end( ap );
     611             : 
     612     2407042 : # if FD_HAS_ATOMIC
     613     2407042 :   FD_COMPILER_MFENCE();
     614     2409262 :   while(( FD_LIKELY( FD_ATOMIC_CAS( fd_log_private_shared_lock, 0, 1 ) ) )) ;
     615     2407042 :   FD_COMPILER_MFENCE();
     616     2407042 : # endif
     617             : 
     618     2407042 :   ulong wsz;
     619     2407042 :   fd_io_write( fd, msg, (ulong)len, (ulong)len, &wsz ); /* Note: we ignore errors because what are we doing to do? log them? */
     620             : 
     621     2407042 : # if FD_HAS_ATOMIC
     622     2407042 :   FD_COMPILER_MFENCE();
     623     2407042 :   FD_VOLATILE( *fd_log_private_shared_lock ) = 0;
     624     2407042 :   FD_COMPILER_MFENCE();
     625     2407042 : # endif
     626             : 
     627     2407042 : }
     628             : 
     629             : /* This is the same as fd_log_private_fprintf_0 except that it does not try to
     630             :    take a lock when writing to the log file.  This should almost never be used
     631             :    except in exceptional cases when logging while the process is shutting down.
     632             : 
     633             :    It exists because if a child process dies while holding the lock, we may
     634             :    want to log some diagnostic messages when tearing down the process tree. */
     635             : void
     636             : fd_log_private_fprintf_nolock_0( int          fd,
     637           0 :                                  char const * fmt, ... ) {
     638             : 
     639             :   /* Note: while this function superficially looks vdprintf-ish, we don't
     640             :      use that as it can do all sorts of unpleasantness under the hood
     641             :      (fflush, mutex / futex on fd, non-AS-safe buffering, ...) that this
     642             :      function deliberately avoids.  Also, the function uses the shared
     643             :      lock to help keep messages generated from processes that share the
     644             :      same log fd sane. */
     645             : 
     646             :   /* TODO:
     647             :      - Consider moving to util/io as fd_io_printf or renaming to
     648             :        fd_log_printf?
     649             :      - Is msg better to have on stack or in thread local storage?
     650             :      - Is msg even necessary given shared lock? (probably still useful to
     651             :        keep the message write to be a single-system-call best effort)
     652             :      - Allow partial write to fd_io_write?  (e.g. src_min=0 such that
     653             :        the fd_io_write below is guaranteed to be a single system call) */
     654             : 
     655           0 :   char msg[ FD_LOG_BUF_SZ ];
     656             : 
     657           0 :   va_list ap;
     658           0 :   va_start( ap, fmt );
     659           0 :   int len = vsnprintf( msg, FD_LOG_BUF_SZ, fmt, ap );
     660           0 :   if( len<0                        ) len = 0;                        /* cmov */
     661           0 :   if( len>(int)(FD_LOG_BUF_SZ-1UL) ) len = (int)(FD_LOG_BUF_SZ-1UL); /* cmov */
     662           0 :   msg[ len ] = '\0';
     663           0 :   va_end( ap );
     664             : 
     665           0 :   ulong wsz;
     666           0 :   fd_io_write( fd, msg, (ulong)len, (ulong)len, &wsz ); /* Note: we ignore errors because what are we doing to do? log them? */
     667           0 : }
     668             : 
     669             : /* Log buffer used by fd_log_private_0 and fd_log_private_hexdump_msg */
     670             : 
     671             : static FD_TL char fd_log_private_log_msg[ FD_LOG_BUF_SZ ];
     672             : 
     673             : char const *
     674     3680679 : fd_log_private_0( char const * fmt, ... ) {
     675     3680679 :   va_list ap;
     676     3680679 :   va_start( ap, fmt );
     677     3680679 :   int len = vsnprintf( fd_log_private_log_msg, FD_LOG_BUF_SZ, fmt, ap );
     678     3680679 :   if( len<0                        ) len = 0;                        /* cmov */
     679     3680679 :   if( len>(int)(FD_LOG_BUF_SZ-1UL) ) len = (int)(FD_LOG_BUF_SZ-1UL); /* cmov */
     680     3680679 :   fd_log_private_log_msg[ len ] = '\0';
     681     3680679 :   va_end( ap );
     682     3680679 :   return fd_log_private_log_msg;
     683     3680679 : }
     684             : 
     685             : char const *
     686             : fd_log_private_hexdump_msg( char const * descr,
     687             :                             void const * mem,
     688        6300 :                             ulong        sz ) {
     689             : 
     690     3159756 : # define FD_LOG_HEXDUMP_BYTES_PER_LINE           (16UL)
     691        6300 : # define FD_LOG_HEXDUMP_BLOB_DESCRIPTION_MAX_LEN (32UL)
     692        6300 : # define FD_LOG_HEXDUMP_MAX_INPUT_BLOB_SZ        (1664UL) /* multiple of 128 >= 1542 */
     693             : 
     694     3560238 : # define FD_LOG_HEXDUMP_ADD_TO_LOG_BUF(...)  do { log_buf_ptr += fd_int_max( sprintf( log_buf_ptr, __VA_ARGS__ ), 0 ); } while(0)
     695        6300 :   char * log_buf_ptr = fd_log_private_log_msg; /* used by FD_LOG_HEXDUMP_ADD_TO_LOG_BUF macro */
     696             : 
     697             :   /* Print the hexdump header */
     698             :   /* FIXME: consider additional sanitization of descr or using compiler
     699             :      tricks to prevent user from passing a non-const-char string (i.e.
     700             :      data they got from somewhere else that might not be sanitized). */
     701             : 
     702        6300 :   if( FD_UNLIKELY( !descr ) ) {
     703             : 
     704           0 :     FD_LOG_HEXDUMP_ADD_TO_LOG_BUF( "HEXDUMP - (%lu bytes at 0x%lx)", sz, (ulong)mem );
     705             : 
     706        6300 :   } else if( FD_UNLIKELY( strlen( descr )>FD_LOG_HEXDUMP_BLOB_DESCRIPTION_MAX_LEN ) ) {
     707             : 
     708           3 :     char tmp[ FD_LOG_HEXDUMP_BLOB_DESCRIPTION_MAX_LEN + 1UL ];
     709           3 :     fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( tmp ), descr, FD_LOG_HEXDUMP_BLOB_DESCRIPTION_MAX_LEN ) );
     710           3 :     FD_LOG_HEXDUMP_ADD_TO_LOG_BUF( "HEXDUMP \"%s\"... (%lu bytes at 0x%lx)", tmp, sz, (ulong)mem );
     711             : 
     712        6297 :   } else {
     713             : 
     714        6297 :     FD_LOG_HEXDUMP_ADD_TO_LOG_BUF( "HEXDUMP \"%s\" (%lu bytes at 0x%lx)", descr, sz, (ulong)mem );
     715             : 
     716        6297 :   }
     717             : 
     718        6300 :   if( FD_UNLIKELY( !sz ) ) return fd_log_private_log_msg;
     719             : 
     720        6300 :   FD_LOG_HEXDUMP_ADD_TO_LOG_BUF( "\n" );
     721             : 
     722        6300 :   if( FD_UNLIKELY( !mem ) ) {
     723           0 :     FD_LOG_HEXDUMP_ADD_TO_LOG_BUF( "\t... snip (unreadable memory) ..." );
     724           0 :     return fd_log_private_log_msg;
     725           0 :   }
     726             : 
     727        6300 :   char         line_buf[ FD_LOG_HEXDUMP_BYTES_PER_LINE+1 ];
     728        6300 :   char const * blob     = (char const *)mem;
     729        6300 :   ulong        blob_off = 0UL;
     730        6300 :   ulong        blob_sz  = fd_ulong_min( sz, FD_LOG_HEXDUMP_MAX_INPUT_BLOB_SZ );
     731             : 
     732     3158370 :   for( ; blob_off<blob_sz; blob_off++ ) {
     733     3152070 :     ulong col_idx = blob_off % FD_LOG_HEXDUMP_BYTES_PER_LINE;
     734             : 
     735             :     /* New line. Print previous line's ASCII representation and then print the offset. */
     736     3152070 :     if( FD_UNLIKELY( !col_idx ) ) {
     737      197091 :       if( FD_LIKELY( blob_off ) ) FD_LOG_HEXDUMP_ADD_TO_LOG_BUF( "  %s\n", line_buf );
     738      197091 :       FD_LOG_HEXDUMP_ADD_TO_LOG_BUF( "\t%04lx: ", blob_off );
     739      197091 :     }
     740             :     /* FIXME: consider extra space between col 7 and 8 to make easier
     741             :        for visual inspection */
     742             : 
     743     3152070 :     char c = blob[blob_off];
     744     3152070 :     FD_LOG_HEXDUMP_ADD_TO_LOG_BUF( " %02x", (uint)(uchar)c );
     745             : 
     746             :     /* If not a printable ASCII character, output a dot. */
     747     3152070 :     line_buf[ col_idx     ] = fd_char_if( fd_isalnum( (int)c ) | fd_ispunct( (int)c ) | (c==' '), c, '.' );
     748     3152070 :     line_buf[ col_idx+1UL ] = '\0';
     749     3152070 :   }
     750             : 
     751             :   /* Print the 2nd column of last blob line */
     752        7686 :   while( blob_off % FD_LOG_HEXDUMP_BYTES_PER_LINE ) {
     753        1386 :     FD_LOG_HEXDUMP_ADD_TO_LOG_BUF( "   " );
     754        1386 :     blob_off++;
     755        1386 :   }
     756        6300 :   FD_LOG_HEXDUMP_ADD_TO_LOG_BUF( "  %s", line_buf );
     757             : 
     758        6300 :   if( FD_UNLIKELY( blob_sz < sz ) )
     759           0 :     FD_LOG_HEXDUMP_ADD_TO_LOG_BUF( "\n\t... snip (printed %lu bytes, omitted %lu bytes) ...", blob_sz, sz-blob_sz );
     760             : 
     761        6300 :   return fd_log_private_log_msg;
     762             : 
     763        6300 : # undef FD_LOG_HEXDUMP_BYTES_PER_LINE
     764        6300 : # undef FD_LOG_HEXDUMP_BLOB_DESCRIPTION_MAX_LEN
     765        6300 : # undef FD_LOG_HEXDUMP_MAX_INPUT_BLOB_SZ
     766        6300 : # undef FD_LOG_HEXDUMP_ADD_TO_LOG_BUF
     767        6300 : }
     768             : 
     769             : void
     770             : fd_log_private_1( int          level,
     771             :                   long         now,
     772             :                   char const * file,
     773             :                   int          line,
     774             :                   char const * func,
     775     3686987 :                   char const * msg ) {
     776             : 
     777     3686987 :   if( level<fd_log_level_logfile() ) return;
     778             : 
     779             :   /* These are thread init so we call them regardless of permanent log
     780             :      enabled to their initialization time is guaranteed independent of
     781             :      whether the permanent log is enabled. */
     782             : 
     783     3552863 :   char const * thread = fd_log_thread();
     784     3552863 :   char const * cpu    = fd_log_cpu();
     785     3552863 :   ulong        tid    = fd_log_tid();
     786             : 
     787     3552863 :   int log_fileno = FD_VOLATILE_CONST( fd_log_private_fileno );
     788     3552863 :   int to_logfile = (log_fileno!=-1);
     789     3552863 :   int to_stderr  = (level>=fd_log_level_stderr());
     790     3552863 :   if( !(to_logfile | to_stderr) ) return;
     791             : 
     792             :   /* Deduplicate the log if requested */
     793             : 
     794     3487610 :   if( fd_log_private_dedup ) {
     795             : 
     796             :     /* Compute if this message appears to be a recent duplicate of
     797             :        a previous log message */
     798             : 
     799     3487608 :     ulong hash = fd_cstr_hash_append( fd_cstr_hash_append( fd_cstr_hash_append( fd_ulong_hash(
     800     3487608 :                    (ulong)(8L*(long)line+(long)level) ), file ), func ), msg );
     801             : 
     802     3487608 :     static long const dedup_interval = 20000000L; /* 1/50 s */
     803             : 
     804     3487608 :     static FD_TL int   init;      /* 0   on thread start */
     805     3487608 :     static FD_TL ulong last_hash; /* 0UL on thread start */
     806     3487608 :     static FD_TL long  then;      /* 0L  on thread start */
     807             : 
     808     3487608 :     int is_dup = init & (hash==last_hash) & ((now-then)<dedup_interval);
     809     3487608 :     init = 1;
     810             : 
     811             :     /* Update how many messages from this thread in row have been
     812             :        duplicates */
     813             : 
     814     3487608 :     static FD_TL ulong dedup_cnt;   /* 0UL on thread start */
     815     3487608 :     static FD_TL int   in_dedup;    /* 0   on thread start */
     816             : 
     817     3487608 :     if( is_dup ) dedup_cnt++;
     818     2397529 :     else {
     819     2397529 :       if( in_dedup ) {
     820             : 
     821             :         /* This message appears to end a long string of duplicates.
     822             :            Log the end of the deduplication. */
     823             : 
     824         284 :         char then_cstr[ FD_LOG_WALLCLOCK_CSTR_BUF_SZ ];
     825         284 :         fd_log_wallclock_cstr( then, then_cstr );
     826             : 
     827         284 :         if( to_logfile )
     828         284 :           fd_log_private_fprintf_0( log_fileno, "SNIP    %s %6lu:%-6lu %s:%s:%-4s %s:%s:%-4s "
     829         284 :                                     "stopped repeating (%lu identical messages)\n",
     830         284 :                                     then_cstr, fd_log_group_id(),tid, fd_log_user(),fd_log_host(),cpu,
     831         284 :                                     fd_log_app(),fd_log_group(),thread, dedup_cnt+1UL );
     832             : 
     833         284 :         if( to_stderr ) {
     834         216 :           char * then_short_cstr = then_cstr+5; then_short_cstr[21] = '\0'; /* Lop off the year, ns resolution and timezone */
     835         216 :           fd_log_private_fprintf_0( fd_log_private_stderr_fileno, "SNIP    %s %-6lu %-4s %-4s stopped repeating (%lu identical messages)\n",
     836         216 :                                     then_short_cstr, tid,cpu,thread, dedup_cnt+1UL );
     837         216 :         }
     838             : 
     839         284 :         in_dedup = 0;
     840         284 :       }
     841             : 
     842     2397529 :       dedup_cnt = 0UL;
     843     2397529 :     }
     844             : 
     845             :     /* dedup_cnt previous messages from this thread appear to be
     846             :        duplicates.  Decide whether to let the raw message print or
     847             :        deduplicate to the log.  FIXME: CONSIDER RANDOMIZING THE
     848             :        THROTTLE. */
     849             : 
     850     3487608 :     static ulong const dedup_thresh   = 3UL;         /* let initial dedup_thresh duplicates go out the door */
     851     3487608 :     static long  const dedup_throttle = 1000000000L; /* ~1s, how often to update status on current duplication */
     852             : 
     853     3487608 :     static FD_TL long dedup_last; /* 0L on thread start */
     854             : 
     855     3487608 :     if( dedup_cnt < dedup_thresh ) dedup_last = now;
     856     1089341 :     else {
     857     1089341 :       if( (now-dedup_last) >= dedup_throttle ) {
     858          36 :         char now_cstr[ FD_LOG_WALLCLOCK_CSTR_BUF_SZ ];
     859          36 :         fd_log_wallclock_cstr( now, now_cstr );
     860          36 :         if( to_logfile )
     861          36 :           fd_log_private_fprintf_0( log_fileno, "SNIP    %s %6lu:%-6lu %s:%s:%-4s %s:%s:%-4s repeating (%lu identical messages)\n",
     862          36 :                                     now_cstr, fd_log_group_id(),tid, fd_log_user(),fd_log_host(),cpu,
     863          36 :                                     fd_log_app(),fd_log_group(),thread, dedup_cnt+1UL );
     864          36 :         if( to_stderr ) {
     865          36 :           char * now_short_cstr = now_cstr+5; now_short_cstr[21] = '\0'; /* Lop off the year, ns resolution and timezone */
     866          36 :           fd_log_private_fprintf_0( fd_log_private_stderr_fileno, "SNIP    %s %-6lu %-4s %-4s repeating (%lu identical messages)\n",
     867          36 :                                     now_short_cstr, tid,cpu,thread, dedup_cnt+1UL );
     868          36 :         }
     869          36 :         dedup_last = now;
     870          36 :       }
     871     1089341 :       in_dedup = 1;
     872     1089341 :     }
     873             : 
     874     3487608 :     last_hash = hash;
     875     3487608 :     then      = now;
     876             : 
     877     3487608 :     if( in_dedup ) return;
     878     3487608 :   }
     879             : 
     880     2398277 :   char now_cstr[ FD_LOG_WALLCLOCK_CSTR_BUF_SZ ];
     881     2398277 :   fd_log_wallclock_cstr( now, now_cstr );
     882             : 
     883     2398277 :   static char const * level_cstr[] = {
     884     2398277 :     /* 0 */ "DEBUG  ",
     885     2398277 :     /* 1 */ "INFO   ",
     886     2398277 :     /* 2 */ "NOTICE ",
     887     2398277 :     /* 3 */ "WARNING",
     888     2398277 :     /* 4 */ "ERR    ",
     889     2398277 :     /* 5 */ "CRIT   ",
     890     2398277 :     /* 6 */ "ALERT  ",
     891     2398277 :     /* 7 */ "EMERG  "
     892     2398277 :   };
     893             : 
     894     2398277 :   if( to_logfile )
     895     2391417 :     fd_log_private_fprintf_0( log_fileno, "%s %s %6lu:%-6lu %s:%s:%-4s %s:%s:%-4s %s(%i)[%s]: %s\n",
     896     2391417 :                               level_cstr[level], now_cstr, fd_log_group_id(),tid, fd_log_user(),fd_log_host(),cpu,
     897     2391417 :                               fd_log_app(),fd_log_group(),thread, file,line,func, msg );
     898             : 
     899     2398277 :   if( to_stderr ) {
     900       10074 :     static char const * color_level_cstr[] = {
     901       10074 :       /* 0 */ TEXT_NORMAL                                  "DEBUG  ",
     902       10074 :       /* 1 */ TEXT_BLUE                                    "INFO   " TEXT_NORMAL,
     903       10074 :       /* 2 */ TEXT_GREEN                                   "NOTICE " TEXT_NORMAL,
     904       10074 :       /* 3 */ TEXT_YELLOW                                  "WARNING" TEXT_NORMAL,
     905       10074 :       /* 4 */ TEXT_RED                                     "ERR    " TEXT_NORMAL,
     906       10074 :       /* 5 */ TEXT_RED TEXT_BOLD                           "CRIT   " TEXT_NORMAL,
     907       10074 :       /* 6 */ TEXT_RED TEXT_BOLD TEXT_UNDERLINE            "ALERT  " TEXT_NORMAL,
     908       10074 :       /* 7 */ TEXT_RED TEXT_BOLD TEXT_UNDERLINE TEXT_BLINK "EMERG  " TEXT_NORMAL
     909       10074 :     };
     910       10074 :     char * now_short_cstr = now_cstr+5; now_short_cstr[21] = '\0'; /* Lop off the year, ns resolution and timezone */
     911       10074 :     fd_log_private_fprintf_0( fd_log_private_stderr_fileno, "%s %s %-6lu %-4s %-4s %s(%i): %s\n",
     912       10074 :                               fd_log_private_colorize ? color_level_cstr[level] : level_cstr[level],
     913       10074 :                               now_short_cstr, tid,cpu,thread, file, line, msg );
     914       10074 :   }
     915             : 
     916     2398277 :   if( level<fd_log_level_flush() ) return;
     917             : 
     918        4410 :   fd_log_flush();
     919        4410 : }
     920             : 
     921             : void
     922             : fd_log_private_2( int          level,
     923             :                   long         now,
     924             :                   char const * file,
     925             :                   int          line,
     926             :                   char const * func,
     927        1125 :                   char const * msg ) {
     928        1125 :   if( level<fd_log_level_core() && fd_log_private_restore_stderr!=-1 ) {
     929             :     /* Restore stderr to original fd in case it was redirected to
     930             :        something that won't be able to process the fatal message */
     931             : 
     932        1125 :     fd_log_private_stderr_fileno = fd_log_private_restore_stderr;
     933        1125 :     fd_log_private_restore_stderr = -1;
     934             : 
     935        1125 :   }
     936             : 
     937        1125 :   fd_log_private_1( level, now, file, line, func, msg );
     938             : 
     939        1125 :   if( level<fd_log_level_core() ) {
     940        1125 : #   if defined(__linux__)
     941        1125 :     if( fd_log_private_unclean_exit ) {
     942           0 :       syscall( SYS_exit_group, 1 );
     943           0 :     }
     944        1125 : #   endif /* defined(__linux__) */
     945        1125 :     exit(1); /* atexit will call fd_log_private_cleanup implicitly */
     946        1125 :   }
     947             : 
     948           0 :   abort();
     949        1125 : }
     950             : 
     951             : void
     952             : fd_log_private_raw_2( char const * file,
     953             :                       int          line,
     954             :                       char const * func,
     955           0 :                       char const * msg ) {
     956           0 :   fd_log_private_fprintf_nolock_0( fd_log_private_stderr_fileno, "%s(%i)[%s]: %s\n", file, line, func, msg );
     957           0 : # if defined(__linux__)
     958           0 :   syscall( SYS_exit_group, 1 );
     959             : # else
     960             :   exit(1);
     961             : # endif
     962           0 :   abort();
     963           0 : }
     964             : 
     965             : /* BOOT/HALT APIS *****************************************************/
     966             : 
     967             : static void
     968        3830 : fd_log_private_cleanup( void ) {
     969             : 
     970             :   /* The atexit below means that all calls to "exit();" implicitly
     971             :      become "fd_log_private_cleanup(); exit();".  It also implies that
     972             :      programs that terminate via a top level return from main implicitly
     973             :      call fd_log_private_cleanup().
     974             : 
     975             :      As such it is possible that a thread other than the booter will
     976             :      trigger cleanup either by triggering this directly (e.g. calling
     977             :      exit) or indirectly (e.g. by logging a message with an exit
     978             :      triggering priority) and that the booter itself might call this
     979             :      more than once sequentially (e.g. fd_halt() calling cleanup
     980             :      explicitly followed by return from main triggering it again.
     981             : 
     982             :      Accordingly we protect this with a ONCE block so it only will
     983             :      execute once per program.  Further, if cleanup gets triggered by
     984             :      multiple threads concurrently, the ONCE block will prevent them
     985             :      from progressing until the first thread that hits the once block
     986             :      has completed cleanup. */
     987             : 
     988       12642 :   FD_ONCE_BEGIN {
     989        2491 :     int log_fileno = FD_VOLATILE_CONST( fd_log_private_fileno );
     990        2491 :     if(      log_fileno==-1                      ) fd_log_private_fprintf_0( STDERR_FILENO, "No log\n" );
     991         667 :     else if( !strcmp( fd_log_private_path, "-" ) ) fd_log_private_fprintf_0( STDERR_FILENO, "Log to stdout\n" );
     992         655 :     else {
     993         655 : #     if FD_HAS_THREADS
     994         655 :       if( fd_log_private_thread_id_ctr>1UL ) { /* There are potentially other log users running */
     995             :         /* Just closing the permanent log file is not multithreading
     996             :            safe in the case where other threads are still running
     997             :            normally and thus potentially logging to the permanent log.
     998             :            Such should not happen in a correctly written and functioning
     999             :            application but logging exists in large part to help
    1000             :            understand when applications misbehave.  So we try to be as
    1001             :            robust and informative as we can here.  FIXME: THE SECOND
    1002             :            USLEEP IS AN UGLY HACK TO REDUCE (BUT NOT FULLY ELIMINATE)
    1003             :            THE RISK OF USE AFTER CLOSE BY THOSE OTHER THREADS.  IT IS
    1004             :            POSSIBLE WITH A MORE INVASIVE CHANGES TO FULLY ELIMINATE THIS
    1005             :            RISK. */
    1006           0 :         usleep( (useconds_t)40000 ); /* Give potentially concurrent users a chance to get their dying messages out */
    1007           0 :         FD_COMPILER_MFENCE();
    1008           0 :         FD_VOLATILE( fd_log_private_fileno ) = -1; /* Turn off the permanent log for concurrent users */
    1009           0 :         FD_COMPILER_MFENCE();
    1010           0 :         usleep( (useconds_t)40000 ); /* Give any concurrent log operations progress at turn off a chance to wrap */
    1011           0 :       }
    1012             : #     else
    1013             :       FD_VOLATILE( fd_log_private_fileno ) = -1;
    1014             : #     endif
    1015             : 
    1016         655 :       fsync( log_fileno );
    1017         655 :       sync();
    1018         655 :       fd_log_private_fprintf_0( STDERR_FILENO, "Log at \"%s\"\n", fd_log_private_path );
    1019         655 :     }
    1020        2491 :   } FD_ONCE_END;
    1021        3830 : }
    1022             : 
    1023             : static void
    1024             : fd_log_private_sig_abort( int         sig,
    1025             :                           siginfo_t * info,
    1026           0 :                           void *      context ) {
    1027           0 :   (void)sig; (void)info; (void)context;
    1028             : 
    1029             :   /* Thread could have caught signal while holding a lock.
    1030             :      Hack around this re-entrancy problem by pointing the log lock to
    1031             :      a dummy buffer. */
    1032           0 :   int lock = 0;
    1033           0 :   fd_log_private_shared_lock = &lock;
    1034             : 
    1035           0 : #define FD_LOG_ERR_NOEXIT(a) do { long _fd_log_msg_now = fd_log_wallclock(); fd_log_private_1( 4, _fd_log_msg_now, __FILE__, __LINE__, __func__, fd_log_private_0 a ); } while(0)
    1036           0 :   FD_LOG_ERR_NOEXIT(( "Received signal %s", fd_io_strsignal( sig ) ));
    1037           0 : #undef FD_LOG_ERR_NOEXIT
    1038             : 
    1039           0 : # if FD_HAS_BACKTRACE
    1040             : 
    1041           0 :   void * btrace[ 128UL ];
    1042           0 :   int btrace_cnt = backtrace( btrace, 128 );
    1043             : 
    1044           0 :   fd_backtrace_log( btrace, (ulong)btrace_cnt );
    1045             : 
    1046           0 : # endif
    1047             : 
    1048             :   /* Returning is going to cause SIGSYS since it's probably not allowed
    1049             :      in the sandbox, which is OK.  The parent process will terminate
    1050             :      everything anyway.  If we allow rt_sigreturn to be called in the
    1051             :      sandbox, then we will get a correct signal. */
    1052           0 :   return;
    1053           0 : }
    1054             : 
    1055             : static void
    1056       44568 : fd_log_private_sig_trap( int sig ) {
    1057       44568 :   struct sigaction act[1];
    1058             :   /* FIXME: CONSIDER NOT OVERRIDING IF THE SIGNAL HANDLER HAS ALREADY
    1059             :      BEEN SET BY THE USER. */
    1060       44568 :   act->sa_sigaction = fd_log_private_sig_abort;
    1061       44568 :   if( sigemptyset( &act->sa_mask ) ) FD_LOG_ERR(( "sigempty set failed" ));
    1062       44568 :   act->sa_flags = (int)(SA_SIGINFO | SA_RESETHAND);
    1063       44568 :   if( sigaction( sig, act, NULL ) ) FD_LOG_ERR(( "unable to override signal %i", sig ));
    1064       44568 : }
    1065             : 
    1066             : static int
    1067             : fd_log_private_open_path( int          cmdline,
    1068        2491 :                           char const * log_path ) {
    1069        2491 :   ulong        log_path_sz = log_path ? (strlen( log_path )+1UL) : 0UL;
    1070             : 
    1071        2491 :   if( !log_path_sz ) { /* Use default log path */
    1072           0 :     char tag[ FD_LOG_WALLCLOCK_CSTR_BUF_SZ ];
    1073           0 :     fd_log_wallclock_cstr( fd_log_wallclock(), tag );
    1074           0 :     for( ulong b=0UL; tag[b]; b++ ) if( tag[b]==' ' || tag[b]=='-' || tag[b]=='.' || tag[b]==':' ) tag[b] = '_';
    1075           0 :     ulong len; fd_cstr_printf( fd_log_private_path, 1024UL, &len, "/tmp/fd-%i.%i.%i_%lu_%s_%s_%s",
    1076           0 :                               FDCTL_MAJOR_VERSION, FDCTL_MINOR_VERSION, FDCTL_PATCH_VERSION,
    1077           0 :                               fd_log_group_id(), fd_log_user(), fd_log_host(), tag );
    1078           0 :     if( len==1023UL ) { fd_log_private_fprintf_0( STDERR_FILENO, "default log path too long; unable to boot\n" ); exit(1); }
    1079           0 :   }
    1080        2491 :   else if( log_path_sz==1UL    ) fd_log_private_path[0] = '\0'; /* User disabled */
    1081         667 :   else if( log_path_sz<=1024UL ) fd_memcpy( fd_log_private_path, log_path, log_path_sz ); /* User specified */
    1082           0 :   else                          { fd_log_private_fprintf_0( STDERR_FILENO, "log path too long; unable to boot\n" ); exit(1); } /* Invalid */
    1083             : 
    1084        2491 :   int log_fileno;
    1085        2491 :   if( fd_log_private_path[0]=='\0' ) {
    1086        1824 :     if( cmdline ) fd_log_private_fprintf_0( STDERR_FILENO, "--log-path \"\"\nNo log\n" );
    1087           0 :     else          fd_log_private_fprintf_0( STDERR_FILENO, "No log\n" );
    1088        1824 :     log_fileno = -1;
    1089        1824 :   } else if( !strcmp( fd_log_private_path, "-" ) ) {
    1090          12 :     if( cmdline ) fd_log_private_fprintf_0( STDERR_FILENO, "--log-path \"-\"\nLog to stdout\n" );
    1091           0 :     else          fd_log_private_fprintf_0( STDERR_FILENO, "Log to stdout\n" );
    1092          12 :     log_fileno = STDOUT_FILENO;
    1093         655 :   } else {
    1094         655 :     if( cmdline && !log_path_sz ) fd_log_private_fprintf_0( STDERR_FILENO, "--log-path not specified; using autogenerated path\n" );
    1095         655 :     log_fileno = open( fd_log_private_path, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
    1096         655 :     if( log_fileno==-1 ) {
    1097           0 :       fd_log_private_fprintf_0( STDERR_FILENO, "open failed (--log-path \"%s\"); unable to boot (%d-%s)\n", fd_log_private_path, errno, fd_io_strerror( errno ) );
    1098           0 :       exit(1);
    1099           0 :     }
    1100         655 :     fd_log_private_fprintf_0( STDERR_FILENO, "Log at \"%s\"\n", fd_log_private_path );
    1101         655 :   }
    1102        2491 :   return log_fileno;
    1103        2491 : }
    1104             : 
    1105             : void
    1106             : fd_log_private_boot( int  *   pargc,
    1107        2491 :                      char *** pargv ) {
    1108             : //FD_LOG_INFO(( "fd_log: booting" )); /* Log not online yet */
    1109             : 
    1110        2491 :   char buf[ FD_LOG_NAME_MAX ];
    1111             : 
    1112        2491 :   fd_log_private_shared_lock  = fd_log_private_shared_lock_local;
    1113             : 
    1114             :   /* Init our our application logical ids */
    1115             :   /* FIXME: CONSIDER EXPLICIT SPECIFICATION OF RANGE OF THREADS
    1116             :      INSTEAD OF ATOMIC COUNTER FROM BASE */
    1117             : 
    1118        2491 :   fd_log_private_app_id_set( fd_env_strip_cmdline_ulong( pargc, pargv, "--log-app-id", "FD_LOG_APP_ID", 0UL ) );
    1119             : 
    1120        2491 :   fd_log_private_app_set( fd_env_strip_cmdline_cstr( pargc, pargv, "--log-app", "FD_LOG_APP", NULL ) );
    1121             : 
    1122        2491 : # if FD_HAS_THREADS
    1123        2491 :   fd_log_private_thread_id_ctr = fd_env_strip_cmdline_ulong( pargc, pargv, "--log-thread-id", "FD_LOG_THREAD_ID", 0UL );
    1124        2491 :   ulong thread_id = fd_log_private_thread_id_next();
    1125             : # else
    1126             :   ulong thread_id = fd_env_strip_cmdline_ulong( pargc, pargv, "--log-thread-id", "FD_LOG_THREAD_ID", 0UL );
    1127             : # endif
    1128        2491 :   fd_log_private_thread_id_set( thread_id );
    1129             : 
    1130        2491 :   fd_log_thread_set( fd_env_strip_cmdline_cstr( pargc, pargv, "--log-thread", "FD_LOG_THREAD", NULL ) );
    1131             : 
    1132             :   /* Init our application physical ids */
    1133             :   /* We ignore any user specified cpu-id in favor of the actual core
    1134             :      assigned by the host OS.  We strip it from the command line so
    1135             :      downstream command line handling is identical from user's point of
    1136             :      view. */
    1137             : 
    1138        2491 :   fd_log_private_host_id_set( fd_env_strip_cmdline_ulong( pargc, pargv, "--log-host-id", "FD_LOG_HOST_ID", 0UL ) );
    1139             : 
    1140        2491 :   char const * host = fd_env_strip_cmdline_cstr( pargc, pargv, "--log-host", "FD_LOG_HOST", NULL );
    1141        2491 :   if( !host ) { if( !gethostname( buf, FD_LOG_NAME_MAX ) ) buf[ FD_LOG_NAME_MAX-1UL ] = '\0', host = buf; }
    1142        2491 :   fd_msan_unpoison( (void *)host, FD_LOG_NAME_MAX );
    1143        2491 :   fd_log_private_host_set( host );
    1144             : 
    1145        2491 :   fd_env_strip_cmdline_ulong( pargc, pargv, "--log-cpu-id", "FD_LOG_CPU_ID", 0UL ); /* FIXME: LOG IGNORING? */
    1146        2491 :   fd_log_private_cpu_id_set( fd_log_private_cpu_id_default() );
    1147             : 
    1148        2491 :   fd_log_cpu_set( fd_env_strip_cmdline_cstr( pargc, pargv, "--log-cpu", "FD_LOG_CPU", NULL ) );
    1149             : 
    1150             :   /* Init our thread group ids */
    1151             :   /* We ignore any user specified group id and tid in favor of the actual
    1152             :      group id and tid assigned by the host OS.  We strip it from the
    1153             :      command line so downstream command line handling is identical from
    1154             :      user's point of view. */
    1155             : 
    1156        2491 :   fd_env_strip_cmdline_ulong( pargc, pargv, "--log-group-id", "FD_LOG_GROUP_ID", 0UL ); /* FIXME: LOG IGNORING? */
    1157        2491 :   pid_t pid = getpid();
    1158        2491 :   fd_log_private_group_id_set( fd_ulong_if( pid>(pid_t)0, (ulong)pid, ULONG_MAX ) );
    1159             : 
    1160        2491 :   char const * group = fd_env_strip_cmdline_cstr( pargc, pargv, "--log-group", "FD_LOG_GROUP", NULL );
    1161        2491 : # if defined(__linux__)
    1162        2491 :   if( !group ) group = program_invocation_short_name;
    1163             : # elif defined(__FreeBSD__)
    1164             :   if( !group ) group = getprogname();
    1165             : # endif
    1166        2491 :   if( !group ) group = (pargc && pargv && (*pargc)>0) ? (*pargv)[0] : NULL;
    1167        2491 :   fd_log_private_group_set( group );
    1168             : 
    1169        2491 :   fd_env_strip_cmdline_ulong( pargc, pargv, "--log-tid", "FD_LOG_TID", 0UL ); /* FIXME: LOG IGNORING? */
    1170        2491 :   fd_log_private_tid_set( fd_log_private_tid_default() );
    1171             : 
    1172        2491 :   fd_env_strip_cmdline_ulong( pargc, pargv, "--log-user-id", "FD_LOG_USER_ID", 0UL ); /* FIXME: LOG IGNORING? */
    1173        2491 :   fd_log_private_user_id_set( fd_log_private_user_id_default() );
    1174             : 
    1175        2491 :   char const * user = fd_env_strip_cmdline_cstr( pargc, pargv, "--log-user", "FD_LOG_USER", NULL );
    1176        2491 :   if( !user )  user = getenv( "LOGNAME" );
    1177        2491 :   if( !user )  user = getlogin();
    1178        2491 :   fd_log_private_user_set( user );
    1179             : 
    1180             :   /* Configure the log */
    1181             : 
    1182        2491 :   fd_log_private_dedup = fd_env_strip_cmdline_int( pargc, pargv, "--log-dedup", "FD_LOG_DEDUP", 1 );
    1183             : 
    1184        2491 :   int colorize = 0;
    1185        2491 :   do {
    1186        2491 :     char const * cstr = fd_env_strip_cmdline_cstr( pargc, pargv, "--log-colorize", "FD_LOG_COLORIZE", NULL );
    1187        2491 :     if( cstr ) { colorize = fd_cstr_to_int( cstr ); break; }
    1188             : 
    1189        2491 :     cstr = fd_env_strip_cmdline_cstr( NULL, NULL, NULL, "COLORTERM", NULL );
    1190        2491 :     if( cstr && !strcmp( cstr, "truecolor" ) ) { colorize = 1; break; }
    1191             : 
    1192        2491 :     cstr = fd_env_strip_cmdline_cstr( NULL, NULL, NULL, "TERM", NULL );
    1193        2491 :     if( cstr && strstr( cstr, "256color" ) ) { colorize = 1; break; }
    1194             : 
    1195        2491 :   } while(0);
    1196           0 :   fd_log_colorize_set( colorize );
    1197             : 
    1198        2491 :   fd_log_level_logfile_set( fd_env_strip_cmdline_int( pargc, pargv, "--log-level-logfile", "FD_LOG_LEVEL_LOGFILE", 1 ) );
    1199        2491 :   fd_log_level_stderr_set ( fd_env_strip_cmdline_int( pargc, pargv, "--log-level-stderr",  "FD_LOG_LEVEL_STDERR",  2 ) );
    1200        2491 :   fd_log_level_flush_set  ( fd_env_strip_cmdline_int( pargc, pargv, "--log-level-flush",   "FD_LOG_LEVEL_FLUSH",   3 ) );
    1201        2491 :   fd_log_level_core_set   ( fd_env_strip_cmdline_int( pargc, pargv, "--log-level-core",    "FD_LOG_LEVEL_CORE",    5 ) );
    1202             : 
    1203             :   /* Hook up signal handlers */
    1204             : 
    1205        2491 :   int log_backtrace = fd_env_strip_cmdline_int( pargc, pargv, "--log-backtrace", "FD_LOG_BACKTRACE", 1 );
    1206        2491 :   if( log_backtrace || fd_log_private_signal_handler ) {
    1207             : 
    1208        2476 : #   if FD_HAS_BACKTRACE
    1209             :     /* If libgcc isn't already linked into the program when a trapped
    1210             :        signal is received by an application, calls to backtrace and
    1211             :        backtrace_symbols_fd within the signal handler can silently
    1212             :        invoke the dynamic linker, which in turn can do silent async
    1213             :        signal unsafe behavior behind our back.  We do dummy calls to
    1214             :        backtrace and backtrace_symbols_fd here to avoid dynamic linking
    1215             :        surprises in the signal handler.  (Hat tip to runtimeverification
    1216             :        for finding this.) */
    1217             : 
    1218        2476 :     void * btrace[128];
    1219        2476 :     (void)backtrace( btrace, 128 );
    1220        2476 : #   endif /* FD_HAS_BACKTRACE */
    1221             : 
    1222             :     /* This is all overridable POSIX sigs whose default behavior is to
    1223             :        abort the program.  It will backtrace and then fallback to the
    1224             :        default behavior. */
    1225        2476 :     fd_log_private_sig_trap( SIGABRT   );
    1226        2476 :     fd_log_private_sig_trap( SIGALRM   );
    1227        2476 :     fd_log_private_sig_trap( SIGFPE    );
    1228        2476 :     fd_log_private_sig_trap( SIGHUP    );
    1229        2476 :     fd_log_private_sig_trap( SIGILL    );
    1230        2476 :     fd_log_private_sig_trap( SIGQUIT   );
    1231        2476 :     fd_log_private_sig_trap( SIGPIPE   );
    1232        2476 :     fd_log_private_sig_trap( SIGSEGV   );
    1233        2476 :     fd_log_private_sig_trap( SIGUSR1   );
    1234        2476 :     fd_log_private_sig_trap( SIGUSR2   );
    1235        2476 :     fd_log_private_sig_trap( SIGBUS    );
    1236        2476 :     fd_log_private_sig_trap( SIGPOLL   );
    1237        2476 :     fd_log_private_sig_trap( SIGPROF   );
    1238        2476 :     fd_log_private_sig_trap( SIGSYS    );
    1239        2476 :     fd_log_private_sig_trap( SIGTRAP   );
    1240        2476 :     fd_log_private_sig_trap( SIGVTALRM );
    1241        2476 :     fd_log_private_sig_trap( SIGXCPU   );
    1242        2476 :     fd_log_private_sig_trap( SIGXFSZ   );
    1243        2476 :   }
    1244             : 
    1245             :   /* Hook up the permanent log */
    1246        2491 :   char const * log_path = fd_env_strip_cmdline_cstr( pargc, pargv, "--log-path", "FD_LOG_PATH", NULL );
    1247        2491 :   FD_VOLATILE( fd_log_private_fileno ) = fd_log_private_open_path( 1, log_path );
    1248             : 
    1249        2491 :   if( !fd_log_private_unclean_exit ) {
    1250        2491 :     if( atexit( fd_log_private_cleanup ) ) { fd_log_private_fprintf_0( STDERR_FILENO, "atexit failed; unable to boot\n" ); exit(1); }
    1251        2491 :   }
    1252             : 
    1253             :   /* At this point, logging online */
    1254        2491 :   if( fd_log_build_info_sz>1UL ) FD_LOG_INFO(( "fd_log: build info:\n%s", fd_log_build_info ));
    1255           0 :   else                           FD_LOG_INFO(( "fd_log: build info not available"           ));
    1256        2491 :   FD_LOG_INFO(( "fd_log: --log-path          %s",  fd_log_private_path    ));
    1257        2491 :   FD_LOG_INFO(( "fd_log: --log-dedup         %i",  fd_log_private_dedup   ));
    1258        2491 :   FD_LOG_INFO(( "fd_log: --log-colorize      %i",  fd_log_colorize()      ));
    1259        2491 :   FD_LOG_INFO(( "fd_log: --log-level-logfile %i",  fd_log_level_logfile() ));
    1260        2491 :   FD_LOG_INFO(( "fd_log: --log-level-stderr  %i",  fd_log_level_stderr()  ));
    1261        2491 :   FD_LOG_INFO(( "fd_log: --log-level-flush   %i",  fd_log_level_flush()   ));
    1262        2491 :   FD_LOG_INFO(( "fd_log: --log-level-core    %i",  fd_log_level_core()    ));
    1263        2491 :   FD_LOG_INFO(( "fd_log: --log-app-id        %lu", fd_log_app_id()        ));
    1264        2491 :   FD_LOG_INFO(( "fd_log: --log-app           %s",  fd_log_app()           ));
    1265        2491 :   FD_LOG_INFO(( "fd_log: --log-thread-id     %lu", fd_log_thread_id()     ));
    1266        2491 :   FD_LOG_INFO(( "fd_log: --log-thread        %s",  fd_log_thread()        ));
    1267        2491 :   FD_LOG_INFO(( "fd_log: --log-host-id       %lu", fd_log_host_id()       ));
    1268        2491 :   FD_LOG_INFO(( "fd_log: --log-host          %s",  fd_log_host()          ));
    1269        2491 :   FD_LOG_INFO(( "fd_log: --log-cpu-id        %lu", fd_log_cpu_id()        ));
    1270        2491 :   FD_LOG_INFO(( "fd_log: --log-cpu           %s",  fd_log_cpu()           ));
    1271        2491 :   FD_LOG_INFO(( "fd_log: --log-group-id      %lu", fd_log_group_id()      ));
    1272        2491 :   FD_LOG_INFO(( "fd_log: --log-group         %s",  fd_log_group()         ));
    1273        2491 :   FD_LOG_INFO(( "fd_log: --log-tid           %lu", fd_log_tid()           ));
    1274        2491 :   FD_LOG_INFO(( "fd_log: --log-user-id       %lu", fd_log_user_id()       ));
    1275        2491 :   FD_LOG_INFO(( "fd_log: --log-user          %s",  fd_log_user()          ));
    1276             : 
    1277        2491 :   FD_LOG_INFO(( "fd_log: boot success" ));
    1278        2491 : }
    1279             : 
    1280             : void
    1281             : fd_log_private_boot_custom( int *        lock,
    1282             :                             ulong        app_id,
    1283             :                             char const * app,
    1284             :                             ulong        thread_id,
    1285             :                             char const * thread,
    1286             :                             ulong        host_id,
    1287             :                             char const * host,
    1288             :                             ulong        cpu_id,
    1289             :                             char const * cpu,
    1290             :                             ulong        group_id,
    1291             :                             char const * group,
    1292             :                             ulong        tid,
    1293             :                             ulong        user_id,
    1294             :                             char const * user,
    1295             :                             int          dedup,
    1296             :                             int          colorize,
    1297             :                             int          level_logfile,
    1298             :                             int          level_stderr,
    1299             :                             int          level_flush,
    1300             :                             int          level_core,
    1301             :                             int          log_fd,
    1302           0 :                             char const * log_path ) {
    1303           0 :   fd_log_private_shared_lock  = lock;
    1304             : 
    1305           0 :   fd_log_private_app_id_set( app_id );
    1306           0 :   fd_log_private_app_set( app );
    1307           0 :   fd_log_private_thread_id_set( thread_id );
    1308           0 :   fd_log_thread_set( thread );
    1309           0 :   fd_log_private_host_id_set( host_id );
    1310           0 :   fd_log_private_host_set( host );
    1311           0 :   fd_log_private_cpu_id_set( cpu_id );
    1312           0 :   fd_log_cpu_set( cpu );
    1313           0 :   fd_log_private_group_id_set( group_id );
    1314           0 :   fd_log_private_group_set( group );
    1315           0 :   fd_log_private_tid_set( tid );
    1316           0 :   fd_log_private_user_id_set( user_id );
    1317           0 :   fd_log_private_user_set( user );
    1318             : 
    1319           0 :   fd_log_private_dedup = dedup;
    1320           0 :   fd_log_colorize_set( colorize );
    1321             : 
    1322           0 :   fd_log_level_logfile_set( level_logfile );
    1323           0 :   fd_log_level_stderr_set ( level_stderr );
    1324           0 :   fd_log_level_flush_set  ( level_flush );
    1325           0 :   fd_log_level_core_set   ( level_core );
    1326             : 
    1327             :   /* Hook up the permanent log */
    1328           0 :   if( -1!=log_fd ) {
    1329             :     /* Log file descriptor was set up before boot, user wishes to log there directly. */
    1330           0 :     fd_log_private_path[0] = '\0';
    1331           0 :     FD_VOLATILE( fd_log_private_fileno ) = log_fd;
    1332           0 :   } else {
    1333           0 :     FD_VOLATILE( fd_log_private_fileno ) = fd_log_private_open_path( 0, log_path );
    1334           0 :   }
    1335             : 
    1336           0 :   if( FD_UNLIKELY( fd_log_private_signal_handler ) ) {
    1337             :     /* See note above about needing to prime backtrace */
    1338           0 :     void * btrace[128];
    1339           0 :     (void)backtrace( btrace, 128 );
    1340             : 
    1341             :     /* This is all overridable POSIX sigs whose default behavior is to
    1342             :        abort the program.  It will backtrace and then fallback to the
    1343             :        default behavior. */
    1344           0 :     fd_log_private_sig_trap( SIGABRT   );
    1345           0 :     fd_log_private_sig_trap( SIGALRM   );
    1346           0 :     fd_log_private_sig_trap( SIGFPE    );
    1347           0 :     fd_log_private_sig_trap( SIGHUP    );
    1348           0 :     fd_log_private_sig_trap( SIGILL    );
    1349           0 :     fd_log_private_sig_trap( SIGQUIT   );
    1350           0 :     fd_log_private_sig_trap( SIGPIPE   );
    1351           0 :     fd_log_private_sig_trap( SIGSEGV   );
    1352           0 :     fd_log_private_sig_trap( SIGUSR1   );
    1353           0 :     fd_log_private_sig_trap( SIGUSR2   );
    1354           0 :     fd_log_private_sig_trap( SIGBUS    );
    1355           0 :     fd_log_private_sig_trap( SIGPOLL   );
    1356           0 :     fd_log_private_sig_trap( SIGPROF   );
    1357           0 :     fd_log_private_sig_trap( SIGSYS    );
    1358           0 :     fd_log_private_sig_trap( SIGTRAP   );
    1359           0 :     fd_log_private_sig_trap( SIGVTALRM );
    1360           0 :     fd_log_private_sig_trap( SIGXCPU   );
    1361           0 :     fd_log_private_sig_trap( SIGXFSZ   );
    1362           0 :   }
    1363             : 
    1364             :   /* At this point, logging online */
    1365           0 :   if( fd_log_build_info_sz>1UL ) FD_LOG_INFO(( "fd_log: build info:\n%s", fd_log_build_info ));
    1366           0 :   else                           FD_LOG_INFO(( "fd_log: build info not available"           ));
    1367           0 :   FD_LOG_INFO(( "fd_log: --log-path          %s",  fd_log_private_path    ));
    1368           0 :   FD_LOG_INFO(( "fd_log: --log-dedup         %i",  fd_log_private_dedup   ));
    1369           0 :   FD_LOG_INFO(( "fd_log: --log-colorize      %i",  fd_log_colorize()      ));
    1370           0 :   FD_LOG_INFO(( "fd_log: --log-level-logfile %i",  fd_log_level_logfile() ));
    1371           0 :   FD_LOG_INFO(( "fd_log: --log-level-logfile %i",  fd_log_level_logfile() ));
    1372           0 :   FD_LOG_INFO(( "fd_log: --log-level-stderr  %i",  fd_log_level_stderr()  ));
    1373           0 :   FD_LOG_INFO(( "fd_log: --log-level-flush   %i",  fd_log_level_flush()   ));
    1374           0 :   FD_LOG_INFO(( "fd_log: --log-level-core    %i",  fd_log_level_core()    ));
    1375           0 :   FD_LOG_INFO(( "fd_log: --log-app-id        %lu", fd_log_app_id()        ));
    1376           0 :   FD_LOG_INFO(( "fd_log: --log-app           %s",  fd_log_app()           ));
    1377           0 :   FD_LOG_INFO(( "fd_log: --log-thread-id     %lu", fd_log_thread_id()     ));
    1378           0 :   FD_LOG_INFO(( "fd_log: --log-thread        %s",  fd_log_thread()        ));
    1379           0 :   FD_LOG_INFO(( "fd_log: --log-host-id       %lu", fd_log_host_id()       ));
    1380           0 :   FD_LOG_INFO(( "fd_log: --log-host          %s",  fd_log_host()          ));
    1381           0 :   FD_LOG_INFO(( "fd_log: --log-cpu-id        %lu", fd_log_cpu_id()        ));
    1382           0 :   FD_LOG_INFO(( "fd_log: --log-cpu           %s",  fd_log_cpu()           ));
    1383           0 :   FD_LOG_INFO(( "fd_log: --log-group-id      %lu", fd_log_group_id()      ));
    1384           0 :   FD_LOG_INFO(( "fd_log: --log-group         %s",  fd_log_group()         ));
    1385           0 :   FD_LOG_INFO(( "fd_log: --log-tid           %lu", fd_log_tid()           ));
    1386           0 :   FD_LOG_INFO(( "fd_log: --log-user-id       %lu", fd_log_user_id()       ));
    1387           0 :   FD_LOG_INFO(( "fd_log: --log-user          %s",  fd_log_user()          ));
    1388             : 
    1389           0 :   FD_LOG_INFO(( "fd_log: boot success" ));
    1390           0 : }
    1391             : 
    1392             : void
    1393        1339 : fd_log_private_halt( void ) {
    1394        1339 :   FD_LOG_INFO(( "fd_log: halting" ));
    1395             : 
    1396        1339 :   fd_log_private_cleanup();
    1397             : 
    1398             :   /* At this point, log is offline */
    1399             : 
    1400        1339 :   fd_log_private_path[0]        = '\0';
    1401             : //fd_log_private_fileno         = -1;   /* Already handled by cleanup */
    1402        1339 :   fd_log_private_dedup          = 0;
    1403             : 
    1404        1339 :   fd_log_private_level_core     = 0;
    1405        1339 :   fd_log_private_level_flush    = 0;
    1406        1339 :   fd_log_private_level_stderr   = 0;
    1407        1339 :   fd_log_private_level_logfile  = 0;
    1408        1339 :   fd_log_private_colorize       = 0;
    1409             : 
    1410        1339 :   fd_log_private_clock_func     = fd_log_wallclock_host;
    1411        1339 :   fd_log_private_clock_args     = NULL;
    1412             : 
    1413        1339 :   fd_log_private_user[0]        = '\0';
    1414        1339 :   fd_log_private_user_id_init   = 0;
    1415        1339 :   fd_log_private_user_id        = 0UL;
    1416        1339 :   fd_log_private_tid_init       = 0;
    1417        1339 :   fd_log_private_tid            = 0UL;
    1418        1339 :   fd_log_private_group[0]       = '\0';
    1419        1339 :   fd_log_private_group_id       = 0UL;
    1420             : 
    1421        1339 :   fd_log_private_cpu_init       = 0;
    1422        1339 :   fd_log_private_cpu[0]         = '\0';
    1423        1339 :   fd_log_private_cpu_id_init    = 0;
    1424        1339 :   fd_log_private_cpu_id         = 0UL;
    1425        1339 :   fd_log_private_host[0]        = '\0';
    1426        1339 :   fd_log_private_host_id        = 0UL;
    1427             : 
    1428        1339 :   fd_log_private_thread_init    = 0;
    1429        1339 :   fd_log_private_thread[0]      = '\0';
    1430        1339 :   fd_log_private_thread_id_init = 0;
    1431        1339 :   fd_log_private_thread_id      = 0UL;
    1432        1339 : # if FD_HAS_THREADS
    1433        1339 :   fd_log_private_thread_id_ctr  = 0UL;
    1434        1339 : # endif
    1435        1339 :   fd_log_private_app[0]         = '\0';
    1436        1339 :   fd_log_private_app_id         = 0UL;
    1437             : 
    1438        1339 :   if( FD_LIKELY( fd_log_private_shared_lock!=fd_log_private_shared_lock_local ) ) {
    1439             :     /* Note: the below will not unmap this in any clones that also
    1440             :        inherited this mapping unless they were cloned with CLONE_VM.  In
    1441             :        cases like this, the caller is expected to handle the cleanup
    1442             :        semantics sanely (e.g. only have the parent do boot/halt and then
    1443             :        children only use log while parent has log booted). */
    1444           0 :     if( FD_UNLIKELY( munmap( fd_log_private_shared_lock, sizeof(int) ) ) )
    1445           0 :       fd_log_private_fprintf_0( STDERR_FILENO,
    1446           0 :                                 "munmap( fd_log_private_shared_lock, sizeof(int) ) failed (%i-%s); attempting to continue",
    1447           0 :                                 errno, fd_io_strerror( errno ) );
    1448           0 :   }
    1449        1339 :   fd_log_private_shared_lock = NULL;
    1450             : 
    1451             : //FD_LOG_INFO(( "fd_log: halt success" )); /* Log not online anymore */
    1452        1339 : }
    1453             : 
    1454             : #include <sys/resource.h>
    1455             : 
    1456             : ulong
    1457        2491 : fd_log_private_main_stack_sz( void ) {
    1458             : 
    1459             :   /* We are extra paranoid about what rlimit returns and we don't trust
    1460             :      environments that claim an unlimited stack size (because it just
    1461             :      isn't unlimited ... even if rlimit says otherwise ... which it will
    1462             :      if a user tries to be clever with a "ulimit -s unlimited" ... e.g.
    1463             :      tile0's stack highest address is at 128 TiB-4KiB typically on
    1464             :      modern Linux and grows down while the text / data / heap grow up
    1465             :      from 0B ... so stack size is practically always going to be << 128
    1466             :      TiB irrespective of any getrlimit claim).  TODO: It looks like
    1467             :      pthead_attr_getstack might be getrlimit based under the hood, so
    1468             :      maybe just use pthread_attr_getstack here too? */
    1469             : 
    1470        2491 :   struct rlimit rlim[1];
    1471        2491 :   int err = getrlimit( RLIMIT_STACK, rlim );
    1472        2491 :   if( FD_UNLIKELY( err ) ) {
    1473           0 :     FD_LOG_WARNING(( "fd_log: getrlimit failed (%i-%s)", errno, fd_io_strerror( errno ) ));
    1474           0 :     return 0UL;
    1475           0 :   }
    1476             : 
    1477        2491 :   ulong stack_sz = (ulong)rlim->rlim_cur;
    1478        2491 :   if( FD_UNLIKELY( (rlim->rlim_cur>rlim->rlim_max) | (rlim->rlim_max>RLIM_INFINITY    ) |
    1479        2491 :                    (rlim->rlim_cur==RLIM_INFINITY) | (rlim->rlim_cur!=(rlim_t)stack_sz) ) ) {
    1480           0 :     FD_LOG_WARNING(( "fd_log: unexpected stack limits (rlim_cur %lu, rlim_max %lu)",
    1481           0 :                      (ulong)rlim->rlim_cur, (ulong)rlim->rlim_max ));
    1482           0 :     return 0UL;
    1483           0 :   }
    1484             : 
    1485        2491 :   return stack_sz;
    1486        2491 : }
    1487             : 
    1488             : /* When pthread_setstack is not used to explicitly set the memory region
    1489             :    for a new thread's stack, pthread_create will create a memory region
    1490             :    (using either the requested size or a default size).  And, while
    1491             :    pthread allows us to set and get the size of the stack region it
    1492             :    creates and we can get a pointer into a thread's stack by just
    1493             :    declaring a stack variable in that thread and we obviously know where
    1494             :    a thread's stack is when we explicitly specify it to pthread create,
    1495             :    pthreads does not seem to provide a simple way to get the extents of
    1496             :    the stacks it creates.
    1497             : 
    1498             :    But the relationship between a pointer in the stack and the stack
    1499             :    extents is non-trival because pthreads will use some of the stack for
    1500             :    things like thread local storage (and it will not tell us how much
    1501             :    stack was used by that and this is practically only known after
    1502             :    linking is complete and then it is not simply exposed to the
    1503             :    application).
    1504             : 
    1505             :    Similar uncertainty applies to the first thread's stack.  We can
    1506             :    learn how large the stack is and get a pointer into the stack via a
    1507             :    stack variable but we have no simple way to get the extents.  And, in
    1508             :    this case on recent Linux, things like command line strings and
    1509             :    environment strings are typically allowed to consume up to 1/4 of
    1510             :    main's thread stack ... these are only known at application load
    1511             :    time.  (There is the additional caveat that the main stack might be
    1512             :    dynamically allocated such that the address space reserved for it
    1513             :    might not be backed by memory yet.)
    1514             : 
    1515             :    But, if we want to do useful run-time stack diagnostics (e.g. alloca
    1516             :    bounds checking / stack overflow prevention / etc), having explicit
    1517             :    knowledge of a thread's stack extents is very useful.  Hence the
    1518             :    below.  It would be nice if there was portable and non-horrific way
    1519             :    to do this (an even more horrific way is trigger seg faults by
    1520             :    scanning for the guard pages and then recover from the seg fault via
    1521             :    a longjmp ... shivers). */
    1522             : 
    1523             : void
    1524             : fd_log_private_stack_discover( ulong   stack_sz,
    1525             :                                ulong * _stack0,
    1526        2491 :                                ulong * _stack1 ) {
    1527             : 
    1528        2491 :   if( FD_UNLIKELY( !stack_sz ) ) {
    1529           0 :     *_stack0 = 0UL;
    1530           0 :     *_stack1 = 0UL;
    1531           0 :     return;
    1532           0 :   }
    1533             : 
    1534        2491 :   ulong stack0 = 0UL;
    1535        2491 :   ulong stack1 = 0UL;
    1536             : 
    1537             :   /* Create a variable on the caller's stack and scan the thread group's
    1538             :      memory map for the memory region holding the variable.  That should
    1539             :      be the caller's stack. */
    1540             : 
    1541        2491 :   uchar stack_mem[1];
    1542        2491 :   FD_VOLATILE( stack_mem[0] ) = (uchar)1; /* Paranoia to make sure compiler puts this in stack */
    1543        2491 :   ulong stack_addr = (ulong)stack_mem;
    1544             : 
    1545        2491 :   int filefd;
    1546        2491 :   if( FD_UNLIKELY( ( filefd = open( "/proc/self/maps", O_RDONLY ) ) < 0 ) ) {
    1547           0 :     FD_LOG_WARNING(( "open( \"/proc/self/maps\" ) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
    1548           0 :     *_stack0 = 0UL;
    1549           0 :     *_stack1 = 0UL;
    1550           0 :     return;
    1551           0 :   }
    1552             : 
    1553        2491 :   char filebuf[1<<12];
    1554        2491 :   ulong filelen = 0;
    1555        2491 :   char * p = filebuf;
    1556        2491 :   int found = 0;
    1557       95079 :   while( !found ) {
    1558             : 
    1559             :     /* Scan a line */
    1560             : 
    1561       95079 :     int full_line = 0;
    1562       95079 :     char * nextp;
    1563     9784765 :     for( nextp = p; nextp < filebuf + filelen; ) {
    1564     9782264 :       if( *(nextp++) == '\n' ) {
    1565       92578 :         full_line = 1;
    1566       92578 :         break;
    1567       92578 :       }
    1568     9782264 :     }
    1569       95079 :     if( !full_line ) {
    1570             :       /* We need to read more data. First shift the old data down. */
    1571        2501 :       filelen = (ulong)((filebuf + filelen) - p);
    1572        2501 :       if( filelen )
    1573           0 :         memmove( filebuf, p, filelen );
    1574        2501 :       p = filebuf;
    1575             :       /* Now read data */
    1576        2501 :       ssize_t tlen;
    1577        2501 :       if( FD_UNLIKELY( ( tlen = read( filefd, filebuf + filelen, sizeof(filebuf)-1U-filelen ) ) < 0 ) ) {
    1578           0 :         FD_LOG_WARNING(( "read( \"/proc/self/maps\" ) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
    1579           0 :         break;
    1580           0 :       }
    1581        2501 :       if( tlen == 0 ) break; /* End of file */
    1582        2501 :       filelen += (ulong)tlen;
    1583        2501 :       filebuf[filelen] = '\0'; /* For sscanf */
    1584        2501 :       continue;
    1585        2501 :     }
    1586             : 
    1587       92578 :     ulong m0;
    1588       92578 :     ulong m1;
    1589       92578 :     int r = sscanf( p, "%lx-%lx", &m0, &m1 );
    1590       92578 :     p = nextp;
    1591       92578 :     if( FD_UNLIKELY( r !=2 ) ) continue;
    1592             : 
    1593             :     /* Test if the stack allocation is in the discovered region */
    1594             : 
    1595       92578 :     if( FD_UNLIKELY( (m0<=stack_addr) & (stack_addr<m1) ) ) {
    1596        2491 :       found = 1;
    1597        2491 :       ulong msz = m1 - m0;
    1598        2491 :       if( msz==stack_sz ) { /* Memory region matches expectations */
    1599           0 :         stack0 = m0;
    1600           0 :         stack1 = m1;
    1601        2491 :       } else if( ((fd_log_group_id()==fd_log_tid()) & (msz<stack_sz)) ) {
    1602             :         /* This is the main thread, which, on recent Linux, seems to
    1603             :            just reserve address space for main's stack at program
    1604             :            start up to the application stack size limits then uses
    1605             :            page faults to dynamically back the stack with DRAM as the
    1606             :            stack grows (which is awful for performance, jitter and
    1607             :            reliability ... sigh).  This assumes stack grows down such
    1608             :            that m1 is the fixed value in this process. */
    1609        2491 :         stack0 = m1 - stack_sz;
    1610        2491 :         stack1 = m1;
    1611        2491 :       } else {
    1612           0 :         FD_LOG_WARNING(( "unexpected caller stack memory region size (got %lu bytes, expected %lu bytes)", msz, stack_sz ));
    1613             :         /* don't trust the discovered region */
    1614           0 :       }
    1615        2491 :       break;
    1616        2491 :     }
    1617             : 
    1618       92578 :   }
    1619        2491 :   if( !found )
    1620           0 :     FD_LOG_WARNING(( "unable to find stack size around address 0x%lx", stack_addr ));
    1621             : 
    1622        2491 :   close(filefd);
    1623             : 
    1624        2491 :   *_stack0 = stack0;
    1625        2491 :   *_stack1 = stack1;
    1626        2491 : }
    1627             : 
    1628             : #else
    1629             : #error "Unknown FD_LOG_STYLE"
    1630             : #endif

Generated by: LCOV version 1.14