root/src/libsir/src/sirinternal.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _sir_makeinit
  2. _sir_init
  3. _sir_cleanup
  4. _sir_isinitialized
  5. _sir_sanity
  6. _sir_init_sanity
  7. _sir_reset_tls
  8. _sir_updatelevels
  9. _sir_updateopts
  10. _sir_stdoutlevels
  11. _sir_stdoutopts
  12. _sir_stderrlevels
  13. _sir_stderropts
  14. _sir_sysloglevels
  15. _sir_syslogopts
  16. _sir_syslogid
  17. _sir_syslogcat
  18. _sir_writeinit
  19. _sir_locksection
  20. _sir_unlocksection
  21. _sir_mapmutexid
  22. _sir_init_static_once
  23. _sir_init_static_once
  24. _sir_init_common_static
  25. _sir_once
  26. PRINTF_FORMAT_ATTR
  27. _sir_dispatch
  28. _sir_format
  29. _sir_syslog_init
  30. _sir_syslog_open
  31. _sir_syslog_write
  32. _sir_syslog_updated
  33. _sir_syslog_close
  34. _sir_syslog_reset
  35. _sir_formattedlevelstr
  36. _sir_clock_gettime
  37. _sir_msec_since
  38. _sir_getpid
  39. _sir_gettid
  40. _sir_getthreadname
  41. _sir_setthreadname
  42. _sir_gethostname
  43. __sir_nprocs

   1 /*
   2  * sirinternal.c
   3  *
   4  * Version: 2.2.5
   5  *
   6  * -----------------------------------------------------------------------------
   7  *
   8  * SPDX-License-Identifier: MIT
   9  *
  10  * Copyright (c) 2018-2024 Ryan M. Lederman <lederman@gmail.com>
  11  * Copyright (c) 2018-2024 Jeffrey H. Johnson <trnsz@pobox.com>
  12  *
  13  * Permission is hereby granted, free of charge, to any person obtaining a copy of
  14  * this software and associated documentation files (the "Software"), to deal in
  15  * the Software without restriction, including without limitation the rights to
  16  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  17  * the Software, and to permit persons to whom the Software is furnished to do so,
  18  * subject to the following conditions:
  19  *
  20  * The above copyright notice and this permission notice shall be included in all
  21  * copies or substantial portions of the Software.
  22  *
  23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  24  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  25  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  26  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  27  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  28  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  29  *
  30  * -----------------------------------------------------------------------------
  31  */
  32 
  33 #include "sir/internal.h"
  34 #include "sir/console.h"
  35 #include "sir/defaults.h"
  36 #include "sir/filecache.h"
  37 #include "sir/plugins.h"
  38 #include "sir/textstyle.h"
  39 #include "sir/filesystem.h"
  40 #include "sir/mutex.h"
  41 
  42 #if defined(__WIN__)
  43 # if defined(SIR_EVENTLOG_ENABLED)
  44 #  include "sir/wineventlog.h"
  45 #  pragma comment(lib, "advapi32.lib")
  46 # endif
  47 # if defined(__EMBARCADEROC__) && defined(_WIN64)
  48 #  pragma comment(lib, "ws2_32.a")
  49 # else
  50 #  pragma comment(lib, "ws2_32.lib")
  51 # endif
  52 #endif
  53 
  54 static sirconfig _sir_cfg      = {0};
  55 static sirfcache _sir_fc       = {0};
  56 static sir_plugincache _sir_pc = {0};
  57 
  58 #if !defined(__IMPORTC__)
  59 static sir_mutex cfg_mutex  = SIR_MUTEX_INIT;
  60 static sir_mutex fc_mutex   = SIR_MUTEX_INIT;
  61 static sir_mutex pc_mutex   = SIR_MUTEX_INIT;
  62 # if !defined(SIR_NO_TEXT_STYLING)
  63 static sir_mutex ts_mutex   = SIR_MUTEX_INIT;
  64 # endif
  65 #else
  66 static sir_mutex cfg_mutex  = {0};
  67 static sir_mutex fc_mutex   = {0};
  68 static sir_mutex pc_mutex   = {0};
  69 # if !defined(SIR_NO_TEXT_STYLING)
  70 static sir_mutex ts_mutex   = {0};
  71 # endif
  72 #endif
  73 static sir_once static_once = SIR_ONCE_INIT;
  74 
  75 #if defined(__WIN__)
  76 static LARGE_INTEGER _sir_perfcntr_freq = {0};
  77 #endif
  78 
  79 #if defined(__HAVE_ATOMIC_H__)
  80 static atomic_uint_fast32_t _sir_magic;
  81 #else
  82 static volatile uint32_t _sir_magic = 0U;
  83 #endif
  84 
  85 static _sir_thread_local char _sir_tid[SIR_MAXPID]   = {0};
  86 static _sir_thread_local sir_time _sir_last_thrd_chk = {0};
  87 static _sir_thread_local time_t _sir_last_timestamp  = 0;
  88 
  89 bool _sir_makeinit(sirinit* si) {
     /* [previous][next][first][last][top][bottom][index][help] */
  90     bool retval = _sir_validptr(si);
  91 
  92     if (retval) {
  93         (void)memset(si, 0, sizeof(sirinit));
  94 
  95         si->d_stdout.opts   = SIRO_DEFAULT;
  96         si->d_stdout.levels = SIRL_DEFAULT;
  97 
  98         si->d_stderr.opts   = SIRO_DEFAULT;
  99         si->d_stderr.levels = SIRL_DEFAULT;
 100 
 101 #if !defined(SIR_NO_SYSTEM_LOGGERS)
 102         si->d_syslog.opts   = SIRO_DEFAULT;
 103         si->d_syslog.levels = SIRL_DEFAULT;
 104 #else
 105         si->d_syslog.opts   = SIRO_MSGONLY;
 106         si->d_syslog.levels = SIRL_NONE;
 107 #endif
 108     }
 109 
 110     return retval;
 111 }
 112 
 113 bool _sir_init(sirinit* si) {
     /* [previous][next][first][last][top][bottom][index][help] */
 114     (void)_sir_seterror(_SIR_E_NOERROR);
 115 
 116     /* can only fail on Windows. */
 117     bool once_init = _sir_once(&static_once, _sir_init_static_once);
 118 #if !defined(__WIN__)
 119     SIR_UNUSED(once_init);
 120 #else
 121     if (!once_init) {
 122         _sir_selflog("error: static data initialization routine failed!");
 123         return false;
 124     }
 125 #endif
 126 
 127     if (!_sir_validptr(si))
 128         return false;
 129 
 130 #if defined(__HAVE_ATOMIC_H__)
 131     if (_SIR_MAGIC == atomic_load(&_sir_magic))
 132 #else
 133     if (_SIR_MAGIC == _sir_magic)
 134 #endif
 135         return _sir_seterror(_SIR_E_ALREADY);
 136 
 137     _sir_defaultlevels(&si->d_stdout.levels, sir_stdout_def_lvls);
 138     _sir_defaultopts(&si->d_stdout.opts, sir_stdout_def_opts);
 139 
 140     _sir_defaultlevels(&si->d_stderr.levels, sir_stderr_def_lvls);
 141     _sir_defaultopts(&si->d_stderr.opts, sir_stderr_def_opts);
 142 
 143 #if !defined(SIR_NO_SYSTEM_LOGGERS)
 144     _sir_defaultlevels(&si->d_syslog.levels, sir_syslog_def_lvls);
 145     _sir_defaultopts(&si->d_syslog.opts, sir_syslog_def_opts);
 146 #endif
 147 
 148     if (!_sir_init_sanity(si))
 149         return false;
 150 
 151     _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
 152 
 153     bool init = true;
 154 
 155 #if defined(__HAVE_ATOMIC_H__)
 156     atomic_store(&_sir_magic, _SIR_MAGIC);
 157 #else
 158     _sir_magic = _SIR_MAGIC;
 159 #endif
 160 
 161     _sir_reset_tls();
 162 
 163 #if defined(__WIN__)
 164     _sir_initialize_stdio();
 165 #else
 166     tzset();
 167 #endif
 168 
 169 #if !defined(SIR_NO_TEXT_STYLING)
 170     if (!_sir_setcolormode(SIRCM_16)) {
 171         init = false;
 172         _sir_selflog("error: failed to set color mode!");
 173     }
 174 
 175     if (!_sir_resettextstyles()) {
 176         init = false;
 177         _sir_selflog("error: failed to reset text styles!");
 178     }
 179 #endif
 180 
 181     (void)memset(&_cfg->state, 0, sizeof(_cfg->state));
 182     (void)memcpy(&_cfg->si, si, sizeof(sirinit));
 183 
 184     /* forcibly null-terminate the process name. */
 185     _cfg->si.name[SIR_MAXNAME - 1] = '\0';
 186 
 187     /* store PID. */
 188     _cfg->state.pid = _sir_getpid();
 189 
 190     (void)snprintf(_cfg->state.pidbuf, SIR_MAXPID, SIR_PIDFORMAT,
 191         PID_CAST _cfg->state.pid);
 192 
 193 #if !defined(SIR_NO_SYSTEM_LOGGERS)
 194     /* initialize system logger. */
 195     _sir_syslog_reset(&_cfg->si.d_syslog);
 196 
 197     if (_cfg->si.d_syslog.levels != SIRL_NONE &&
 198         !_sir_syslog_init(_cfg->si.name, &_cfg->si.d_syslog)) {
 199         init = false;
 200         _sir_selflog("failed to initialize system logger!");
 201     }
 202 #endif
 203 
 204     _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
 205 
 206     _sir_selflog("initialized %s", (init ? "successfully" : "with errors")); //-V547
 207 
 208     SIR_ASSERT(init);
 209     return init;
 210 }
 211 
 212 bool _sir_cleanup(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 213     if (!_sir_sanity())
 214         return false;
 215 
 216     _SIR_LOCK_SECTION(sirfcache, sfc, SIRMI_FILECACHE, false);
 217     bool cleanup   = true;
 218     bool destroyfc = _sir_fcache_destroy(sfc);
 219     SIR_ASSERT(destroyfc);
 220 
 221     _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
 222     _sir_eqland(cleanup, destroyfc);
 223 
 224 #if !defined(SIR_NO_PLUGINS)
 225     _SIR_LOCK_SECTION(sir_plugincache, spc, SIRMI_PLUGINCACHE, false);
 226     bool destroypc = _sir_plugin_cache_destroy(spc);
 227     SIR_ASSERT(destroypc);
 228     _SIR_UNLOCK_SECTION(SIRMI_PLUGINCACHE);
 229     _sir_eqland(cleanup, destroypc);
 230 #endif
 231 
 232     _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
 233 
 234 #if !defined(SIR_NO_SYSTEM_LOGGERS)
 235     if (!_sir_syslog_close(&_cfg->si.d_syslog)) {
 236         cleanup = false;
 237         _sir_selflog("error: failed to close system logger!");
 238     }
 239 
 240     _sir_syslog_reset(&_cfg->si.d_syslog);
 241 #endif
 242 
 243 #if !defined(SIR_NO_TEXT_STYLING)
 244     if (!_sir_resettextstyles()) {
 245         cleanup = false;
 246         _sir_selflog("error: failed to reset text styles!");
 247     }
 248 #endif
 249 
 250 #if defined(__HAVE_ATOMIC_H__)
 251     atomic_store(&_sir_magic, 0);
 252 #else
 253     _sir_magic = 0U;
 254 #endif
 255 
 256     _sir_reset_tls();
 257 
 258     (void)memset(_cfg, 0, sizeof(sirconfig));
 259     _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
 260 
 261     _sir_selflog("cleaned up %s", (cleanup ? "successfully" : "with errors"));
 262 
 263     SIR_ASSERT(cleanup);
 264     return cleanup;
 265 }
 266 
 267 bool _sir_isinitialized(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 268 #if defined(__HAVE_ATOMIC_H__)
 269     if (_SIR_MAGIC == atomic_load(&_sir_magic))
 270         return true;
 271 #else
 272     if (_SIR_MAGIC == _sir_magic)
 273         return true;
 274 #endif
 275     return false;
 276 }
 277 
 278 bool _sir_sanity(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 279     if (_sir_isinitialized())
 280         return true;
 281     return _sir_seterror(_SIR_E_NOTREADY);
 282 }
 283 
 284 bool _sir_init_sanity(const sirinit* si) {
     /* [previous][next][first][last][top][bottom][index][help] */
 285     if (!_sir_validptr(si))
 286         return false;
 287 
 288     bool levelcheck = true;
 289     _sir_eqland(levelcheck, _sir_validlevels(si->d_stdout.levels));
 290     _sir_eqland(levelcheck, _sir_validlevels(si->d_stderr.levels));
 291 
 292     bool regcheck = true;
 293     _sir_eqland(regcheck, SIRL_NONE == si->d_stdout.levels);
 294     _sir_eqland(regcheck, SIRL_NONE == si->d_stderr.levels);
 295 
 296 #if !defined(SIR_NO_SYSTEM_LOGGERS)
 297     _sir_eqland(levelcheck, _sir_validlevels(si->d_syslog.levels));
 298     _sir_eqland(regcheck, SIRL_NONE == si->d_syslog.levels);
 299 #endif
 300 
 301     if (regcheck)
 302         _sir_selflog("warning: no level registrations set!");
 303 
 304     bool optscheck = true;
 305     _sir_eqland(optscheck, _sir_validopts(si->d_stdout.opts));
 306     _sir_eqland(optscheck, _sir_validopts(si->d_stderr.opts));
 307 
 308 #if !defined(SIR_NO_SYSTEM_LOGGERS)
 309     _sir_eqland(optscheck, _sir_validopts(si->d_syslog.opts));
 310 #endif
 311 
 312     return levelcheck && optscheck;
 313 }
 314 
 315 void _sir_reset_tls(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 316     _sir_resetstr(_sir_tid);
 317     (void)memset(&_sir_last_thrd_chk, 0, sizeof(sir_time));
 318     _sir_last_timestamp = 0;
 319     _sir_reset_tls_error();
 320 }
 321 
 322 static
 323 bool _sir_updatelevels(const char* name, sir_levels* old, const sir_levels* new) {
     /* [previous][next][first][last][top][bottom][index][help] */
 324     bool retval = _sir_validstr(name) && _sir_validptr(old) && _sir_validptr(new);
 325     if (retval) {
 326         if (*old != *new) {
 327             _sir_selflog("updating %s levels from %04"PRIx16" to %04"PRIx16, name, *old, *new);
 328             *old = *new;
 329         } else {
 330             _sir_selflog("skipped superfluous update of %s levels: %04"PRIx16, name, *old);
 331         }
 332     }
 333     return retval;
 334 }
 335 
 336 static
 337 bool _sir_updateopts(const char* name, sir_options* old, const sir_options* new) {
     /* [previous][next][first][last][top][bottom][index][help] */
 338     bool retval = _sir_validstr(name) && _sir_validptr(old) && _sir_validptr(new);
 339     if (retval) {
 340         if (*old != *new) {
 341             _sir_selflog("updating %s options from %08"PRIx32" to %08"PRIx32, name, *old, *new);
 342             *old = *new;
 343         } else {
 344             _sir_selflog("skipped superfluous update of %s options: %08"PRIx32, name, *old);
 345         }
 346     }
 347     return retval;
 348 }
 349 
 350 bool _sir_stdoutlevels(sirinit* si, const sir_update_config_data* data) {
     /* [previous][next][first][last][top][bottom][index][help] */
 351     return _sir_updatelevels(SIR_DESTNAME_STDOUT, &si->d_stdout.levels, data->levels);
 352 }
 353 
 354 bool _sir_stdoutopts(sirinit* si, const sir_update_config_data* data) {
     /* [previous][next][first][last][top][bottom][index][help] */
 355     return _sir_updateopts(SIR_DESTNAME_STDOUT, &si->d_stdout.opts, data->opts);
 356 }
 357 
 358 bool _sir_stderrlevels(sirinit* si, const sir_update_config_data* data) {
     /* [previous][next][first][last][top][bottom][index][help] */
 359     return _sir_updatelevels(SIR_DESTNAME_STDERR, &si->d_stderr.levels, data->levels);
 360 }
 361 
 362 bool _sir_stderropts(sirinit* si, const sir_update_config_data* data) {
     /* [previous][next][first][last][top][bottom][index][help] */
 363     return _sir_updateopts(SIR_DESTNAME_STDERR, &si->d_stderr.opts, data->opts);
 364 }
 365 
 366 bool _sir_sysloglevels(sirinit* si, const sir_update_config_data* data) {
     /* [previous][next][first][last][top][bottom][index][help] */
 367     bool updated = _sir_updatelevels(SIR_DESTNAME_SYSLOG, &si->d_syslog.levels, data->levels);
 368     if (updated) {
 369         _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_LEVELS);
 370         updated = _sir_syslog_updated(si, data);
 371         _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_LEVELS);
 372     }
 373     return updated;
 374 }
 375 
 376 bool _sir_syslogopts(sirinit* si, const sir_update_config_data* data) {
     /* [previous][next][first][last][top][bottom][index][help] */
 377     bool updated = _sir_updateopts(SIR_DESTNAME_SYSLOG, &si->d_syslog.opts, data->opts);
 378     if (updated) {
 379         _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_OPTIONS);
 380         updated = _sir_syslog_updated(si, data);
 381         _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_OPTIONS);
 382     }
 383     return updated;
 384 }
 385 
 386 bool _sir_syslogid(sirinit* si, const sir_update_config_data* data) {
     /* [previous][next][first][last][top][bottom][index][help] */
 387     bool retval = _sir_validptr(si) && _sir_validptr(data);
 388 
 389     if (retval) {
 390         bool cur_ok = _sir_validstrnofail(si->d_syslog.identity);
 391         if (!cur_ok || 0 != strncmp(si->d_syslog.identity, data->sl_identity, SIR_MAX_SYSLOG_ID)) {
 392             _sir_selflog("updating %s identity from '%s' to '%s'", SIR_DESTNAME_SYSLOG,
 393                 si->d_syslog.identity, data->sl_identity);
 394             (void)_sir_strncpy(si->d_syslog.identity, SIR_MAX_SYSLOG_ID, data->sl_identity,
 395                 strnlen(data->sl_identity, SIR_MAX_SYSLOG_ID));
 396             _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_IDENTITY);
 397             retval = _sir_syslog_updated(si, data);
 398             _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_IDENTITY);
 399         } else {
 400             _sir_selflog("skipped superfluous update of %s identity: '%s'", SIR_DESTNAME_SYSLOG,
 401                 si->d_syslog.identity);
 402         }
 403     }
 404 
 405     return retval;
 406 }
 407 
 408 bool _sir_syslogcat(sirinit* si, const sir_update_config_data* data) {
     /* [previous][next][first][last][top][bottom][index][help] */
 409     bool retval = _sir_validptr(si) && _sir_validptr(data);
 410 
 411     if (retval) {
 412         bool cur_ok = _sir_validstrnofail(si->d_syslog.category);
 413         if (!cur_ok || 0 != strncmp(si->d_syslog.category, data->sl_category, SIR_MAX_SYSLOG_CAT)) {
 414             _sir_selflog("updating %s category from '%s' to '%s'", SIR_DESTNAME_SYSLOG,
 415                 si->d_syslog.category, data->sl_category);
 416             (void)_sir_strncpy(si->d_syslog.category, SIR_MAX_SYSLOG_CAT, data->sl_category,
 417                 strnlen(data->sl_category, SIR_MAX_SYSLOG_CAT));
 418             _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_CATEGORY);
 419             retval = _sir_syslog_updated(si, data);
 420             _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_CATEGORY);
 421         } else {
 422             _sir_selflog("skipped superfluous update of %s category: '%s'", SIR_DESTNAME_SYSLOG,
 423                 si->d_syslog.identity);
 424         }
 425     }
 426 
 427     return retval;
 428 }
 429 
 430 bool _sir_writeinit(const sir_update_config_data* data, sirinit_update update) {
     /* [previous][next][first][last][top][bottom][index][help] */
 431     (void)_sir_seterror(_SIR_E_NOERROR);
 432 
 433     if (!_sir_sanity() || !_sir_validupdatedata(data) || !_sir_validfnptr(update))
 434         return false;
 435 
 436     _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
 437 
 438     bool updated = update(&_cfg->si, data);
 439     if (!updated)
 440         _sir_selflog("error: update routine failed!");
 441 
 442     _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
 443     return updated;
 444 }
 445 
 446 void* _sir_locksection(sir_mutex_id mid) {
     /* [previous][next][first][last][top][bottom][index][help] */
 447     sir_mutex* m = NULL;
 448     void* sec    = NULL;
 449 
 450     bool enter = _sir_mapmutexid(mid, &m, &sec) && _sir_mutexlock(m);
 451     SIR_ASSERT(enter);
 452 
 453     return enter ? sec : NULL;
 454 }
 455 
 456 void _sir_unlocksection(sir_mutex_id mid) {
     /* [previous][next][first][last][top][bottom][index][help] */
 457     sir_mutex* m = NULL;
 458     void* sec    = NULL;
 459 
 460     bool leave = _sir_mapmutexid(mid, &m, &sec) && _sir_mutexunlock(m);
 461     SIR_ASSERT_UNUSED(leave, leave);
 462 }
 463 
 464 bool _sir_mapmutexid(sir_mutex_id mid, sir_mutex** m, void** section) {
     /* [previous][next][first][last][top][bottom][index][help] */
 465     sir_mutex* tmpm;
 466     void* tmpsec;
 467 
 468     switch (mid) {
 469         case SIRMI_CONFIG:
 470             tmpm   = &cfg_mutex;
 471             tmpsec = &_sir_cfg;
 472             break;
 473         case SIRMI_FILECACHE:
 474             tmpm   = &fc_mutex;
 475             tmpsec = &_sir_fc;
 476             break;
 477         case SIRMI_PLUGINCACHE:
 478             tmpm   = &pc_mutex;
 479             tmpsec = &_sir_pc;
 480             break;
 481 #if !defined(SIR_NO_TEXT_STYLING)
 482         case SIRMI_TEXTSTYLE:
 483             tmpm   = &ts_mutex;
 484             tmpsec = &sir_text_style_section;
 485             break;
 486 #endif
 487         default: // GCOVR_EXCL_START
 488 #if !defined(SIR_NO_TEXT_STYLING)
 489             SIR_ASSERT(false);
 490 #endif
 491             tmpm   = NULL;
 492             tmpsec = NULL;
 493             break;
 494     } // GCOVR_EXCL_STOP
 495 
 496     *m = tmpm;
 497 
 498     if (section)
 499         *section = tmpsec;
 500 
 501     return *m != NULL && (!section || *section != NULL);
 502 }
 503 
 504 #if !defined(__WIN__)
 505 void _sir_init_static_once(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 506     (void)_sir_init_common_static();
 507 }
 508 #else /* __WIN__ */
 509 BOOL CALLBACK _sir_init_static_once(PINIT_ONCE ponce, PVOID param, PVOID* ctx) {
     /* [previous][next][first][last][top][bottom][index][help] */
 510     SIR_UNUSED(ponce);
 511     SIR_UNUSED(param);
 512     SIR_UNUSED(ctx);
 513     return _sir_init_common_static() ? TRUE : FALSE;
 514 }
 515 #endif
 516 
 517 bool _sir_init_common_static(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 518 #if defined(__HAVE_ATOMIC_H__)
 519     atomic_init(&_sir_magic, 0);
 520 #endif
 521 
 522 #if defined(__WIN__)
 523     (void)QueryPerformanceFrequency(&_sir_perfcntr_freq);
 524 #endif
 525 
 526     bool created = _sir_mutexcreate(&cfg_mutex);
 527     SIR_ASSERT(created);
 528 
 529     _sir_eqland(created, _sir_mutexcreate(&fc_mutex));
 530     SIR_ASSERT(created);
 531 
 532     _sir_eqland(created, _sir_mutexcreate(&pc_mutex));
 533     SIR_ASSERT(created);
 534 
 535 #if !defined(SIR_NO_TEXT_STYLING)
 536     _sir_eqland(created, _sir_mutexcreate(&ts_mutex));
 537     SIR_ASSERT(created);
 538 #endif
 539 
 540     return created;
 541 }
 542 
 543 bool _sir_once(sir_once* once, sir_once_fn func) {
     /* [previous][next][first][last][top][bottom][index][help] */
 544 #if !defined(__WIN__)
 545     int ret = pthread_once(once, func);
 546     return 0 == ret ? true : _sir_handleerr(ret);
 547 #else /* __WIN__ */
 548     return (FALSE != InitOnceExecuteOnce(once, func, NULL, NULL)) ? true
 549         : _sir_handlewin32err(GetLastError());
 550 #endif
 551 }
 552 
 553 PRINTF_FORMAT_ATTR(2, 0)
     /* [previous][next][first][last][top][bottom][index][help] */
 554 bool _sir_logv(sir_level level, PRINTF_FORMAT const char* format, va_list args) {
 555     if (!_sir_sanity() || !_sir_validlevel(level) || !_sir_validstr(format))
 556         return false;
 557 
 558     (void)_sir_seterror(_SIR_E_NOERROR);
 559 
 560     _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
 561 
 562     sirbuf buf = {0};
 563 
 564     /* from time to time, update the host name in the config, just in case. */
 565     time_t now_sec = -1;
 566     if (-1 != time(&now_sec) &&
 567         (now_sec - _cfg->state.last_hname_chk) > SIR_HNAME_CHK_INTERVAL) {
 568         _sir_selflog("updating hostname...");
 569         if (!_sir_gethostname(_cfg->state.hostname)) {
 570             _sir_selflog("error: failed to get hostname!");
 571         } else {
 572             _cfg->state.last_hname_chk = now_sec;
 573             _sir_selflog("hostname: '%s'", _cfg->state.hostname);
 574         }
 575     }
 576 
 577     /* format timestamp (h/m/s only if the integer time has changed). */
 578     long now_msec = 0L;
 579     bool gettime = _sir_clock_gettime(SIR_WALLCLOCK, &now_sec, &now_msec);
 580     SIR_ASSERT_UNUSED(gettime, gettime);
 581 
 582     /* milliseconds. */
 583     _sir_snprintf_trunc(buf.msec, SIR_MAXMSEC, SIR_MSECFORMAT, now_msec);
 584 
 585     /* hours/minutes/seconds. */
 586     if (now_sec > _sir_last_timestamp || !*_cfg->state.timestamp) {
 587         _sir_last_timestamp = now_sec;
 588         bool fmt = _sir_formattime(now_sec, _cfg->state.timestamp, SIR_TIMEFORMAT);
 589         SIR_ASSERT_UNUSED(fmt, fmt);
 590     }
 591 
 592     /* check elapsed time since updating thread identifier/name. */
 593     sir_time thrd_chk;
 594     double msec_since_thrd_chk = _sir_msec_since(&_sir_last_thrd_chk, &thrd_chk);
 595 
 596     /* update the thread identifier/name if enough time has elapsed. */
 597     if (msec_since_thrd_chk > SIR_THRD_CHK_INTERVAL) {
 598         _sir_last_thrd_chk = thrd_chk;
 599 
 600         pid_t tid         = _sir_gettid();
 601         bool resolved_tid = false;
 602 
 603         /* prefer thread names. */
 604         resolved_tid = _sir_getthreadname(_sir_tid);
 605 
 606         /* if tid is identical to pid... */
 607         if (!resolved_tid && tid == _cfg->state.pid) {
 608             /* don't use anything to identify the thread. */
 609             _sir_resetstr(_sir_tid);
 610             resolved_tid = true;
 611         }
 612 
 613         /* fall back on tid. */
 614         if (!resolved_tid)
 615             _sir_snprintf_trunc(_sir_tid, SIR_MAXPID, SIR_TIDFORMAT,
 616                 PID_CAST tid);
 617     }
 618 
 619     sirconfig cfg;
 620     (void)memcpy(&cfg, _cfg, sizeof(sirconfig));
 621     _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
 622 
 623     buf.timestamp = cfg.state.timestamp;
 624     buf.hostname  = cfg.state.hostname;
 625     buf.pid       = cfg.state.pidbuf;
 626     buf.name      = cfg.si.name;
 627 
 628 #if !defined(SIR_NO_TEXT_STYLING)
 629     const char* style_str = _sir_gettextstyle(level);
 630 
 631     SIR_ASSERT(NULL != style_str);
 632     if (NULL != style_str)
 633         (void)_sir_strncpy(buf.style, SIR_MAXSTYLE, style_str,
 634             strnlen(style_str, SIR_MAXSTYLE));
 635 #endif
 636 
 637     buf.level = _sir_formattedlevelstr(level);
 638 
 639     if (_sir_validstrnofail(_sir_tid))
 640         (void)_sir_strncpy(buf.tid, SIR_MAXPID, _sir_tid,
 641             strnlen(_sir_tid, SIR_MAXPID));
 642 
 643     (void)vsnprintf(buf.message, SIR_MAXMESSAGE, format, args);
 644 
 645     if (!_sir_validstrnofail(buf.message))
 646         return _sir_seterror(_SIR_E_INTERNAL);
 647 
 648     bool match             = false;
 649     bool exit_early        = false;
 650     bool update_last_props = true;
 651     uint64_t hash          = 0ULL;
 652 
 653     if (cfg.state.last.level == level &&
 654         cfg.state.last.prefix[0] == buf.message[0]  &&
 655         cfg.state.last.prefix[1] == buf.message[1]) {
 656         hash  = FNV64_1a(buf.message);
 657         match = cfg.state.last.hash == hash;
 658     }
 659 
 660     if (match) {
 661         cfg.state.last.counter++;
 662 
 663         if (cfg.state.last.counter >= cfg.state.last.threshold - 2) {
 664             size_t old_threshold = cfg.state.last.threshold;
 665 
 666             update_last_props = false;
 667             cfg.state.last.threshold *= SIR_SQUELCH_BACKOFF_FACTOR;
 668             cfg.state.last.squelch = true;
 669 
 670             _sir_selflog("hit squelch threshold of %zu; setting new threshold"
 671                          " to %zu (factor: %d)", old_threshold,
 672                          cfg.state.last.threshold, SIR_SQUELCH_BACKOFF_FACTOR);
 673 
 674             (void)snprintf(buf.message, SIR_MAXMESSAGE, SIR_SQUELCH_MSG_FORMAT, old_threshold);
 675         } else if (cfg.state.last.squelch) {
 676             exit_early = true;
 677         }
 678     } else {
 679         cfg.state.last.squelch   = false;
 680         cfg.state.last.counter   = 0;
 681         cfg.state.last.threshold = SIR_SQUELCH_THRESHOLD;
 682         /* _sir_selflog("message '%s' does not match last; resetting", buf.message); */
 683     }
 684 
 685     _cfg = _sir_locksection(SIRMI_CONFIG);
 686     if (!_cfg)
 687         return _sir_seterror(_SIR_E_INTERNAL);
 688 
 689     _cfg->state.last.squelch = cfg.state.last.squelch;
 690 
 691     if (update_last_props) {
 692         _cfg->state.last.level     = level;
 693         _cfg->state.last.hash      = hash;
 694         _cfg->state.last.prefix[0] = buf.message[0];
 695         _cfg->state.last.prefix[1] = buf.message[1];
 696     }
 697 
 698     _cfg->state.last.counter   = cfg.state.last.counter;
 699     _cfg->state.last.threshold = cfg.state.last.threshold;
 700 
 701     _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
 702 
 703     if (exit_early)
 704         return false;
 705 
 706     bool dispatched = _sir_dispatch(&cfg.si, level, &buf);
 707     return update_last_props ? dispatched : false;
 708 }
 709 
 710 bool _sir_dispatch(const sirinit* si, sir_level level, sirbuf* buf) {
     /* [previous][next][first][last][top][bottom][index][help] */
 711     bool retval       = true;
 712     size_t dispatched = 0;
 713     size_t wanted     = 0;
 714 
 715 #if !defined(SIR_NO_TEXT_STYLING)
 716     static const bool styling = true;
 717 #else
 718     static const bool styling = false;
 719 #endif
 720 
 721     if (_sir_bittest(si->d_stdout.levels, level)) {
 722         const char* writef = _sir_format(styling, si->d_stdout.opts, buf);
 723         bool wrote         = _sir_validstrnofail(writef) &&
 724             _sir_write_stdout(writef, buf->output_len);
 725         _sir_eqland(retval, wrote);
 726 
 727         if (wrote)
 728             dispatched++;
 729         wanted++;
 730     }
 731 
 732     if (_sir_bittest(si->d_stderr.levels, level)) {
 733         const char* writef = _sir_format(styling, si->d_stderr.opts, buf);
 734         bool wrote         = _sir_validstrnofail(writef) &&
 735             _sir_write_stderr(writef, buf->output_len);
 736         _sir_eqland(retval, wrote);
 737 
 738         if (wrote)
 739             dispatched++;
 740         wanted++;
 741     }
 742 
 743 #if !defined(SIR_NO_SYSTEM_LOGGERS)
 744     if (_sir_bittest(si->d_syslog.levels, level)) {
 745         if (_sir_syslog_write(level, buf, &si->d_syslog))
 746             dispatched++;
 747         wanted++;
 748     }
 749 #endif
 750 
 751     _SIR_LOCK_SECTION(const sirfcache, sfc, SIRMI_FILECACHE, false);
 752     size_t fdispatched = 0;
 753     size_t fwanted     = 0;
 754     _sir_eqland(retval, _sir_fcache_dispatch(sfc, level, buf, &fdispatched, &fwanted));
 755     _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
 756 
 757     dispatched += fdispatched;
 758     wanted += fwanted;
 759 
 760 #if !defined(SIR_NO_PLUGINS)
 761     _SIR_LOCK_SECTION(const sir_plugincache, spc, SIRMI_PLUGINCACHE, false);
 762     size_t pdispatched = 0;
 763     size_t pwanted     = 0;
 764     _sir_eqland(retval, _sir_plugin_cache_dispatch(spc, level, buf, &pdispatched, &pwanted));
 765     _SIR_UNLOCK_SECTION(SIRMI_PLUGINCACHE);
 766 
 767     dispatched += pdispatched;
 768     wanted += pwanted;
 769 #endif
 770 
 771     if (0 == wanted) {
 772         _sir_selflog("error: no destinations registered for level %04"PRIx16, level);
 773         return _sir_seterror(_SIR_E_NODEST);
 774     }
 775 
 776     return retval && (dispatched == wanted);
 777 }
 778 
 779 const char* _sir_format(bool styling, sir_options opts, sirbuf* buf) {
     /* [previous][next][first][last][top][bottom][index][help] */
 780     if (_sir_validptr(buf)) {
 781         bool first = true;
 782 
 783         _sir_resetstr(buf->output);
 784 
 785         if (styling)
 786             (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->style, SIR_MAXSTYLE);
 787 
 788         if (!_sir_bittest(opts, SIRO_NOTIME)) {
 789             (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->timestamp, SIR_MAXTIME);
 790             first = false;
 791 
 792 #if defined(SIR_MSEC_TIMER)
 793             if (!_sir_bittest(opts, SIRO_NOMSEC))
 794                 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->msec, SIR_MAXMSEC);
 795 #endif
 796         }
 797 
 798         if (!_sir_bittest(opts, SIRO_NOHOST) && _sir_validstrnofail(buf->hostname)) {
 799             if (!first)
 800                 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
 801             (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->hostname, SIR_MAXHOST);
 802             first = false;
 803         }
 804 
 805         if (!_sir_bittest(opts, SIRO_NOLEVEL)) {
 806             if (!first)
 807                 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
 808             (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->level, SIR_MAXLEVEL);
 809             first = false;
 810         }
 811 
 812         bool name = false;
 813         if (!_sir_bittest(opts, SIRO_NONAME) && _sir_validstrnofail(buf->name)) {
 814             if (!first)
 815                 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
 816             (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->name, SIR_MAXNAME);
 817             first = false;
 818             name  = true;
 819         }
 820 
 821         bool wantpid = !_sir_bittest(opts, SIRO_NOPID) && _sir_validstrnofail(buf->pid);
 822         bool wanttid = !_sir_bittest(opts, SIRO_NOTID) && _sir_validstrnofail(buf->tid);
 823 
 824         if (wantpid || wanttid) {
 825             if (name)
 826                 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDPREFIX, 1);
 827             else if (!first)
 828                 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
 829 
 830             if (wantpid)
 831                 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->pid, SIR_MAXPID);
 832 
 833             if (wanttid) {
 834                 if (wantpid)
 835                     (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDSEPARATOR, 1);
 836                 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->tid, SIR_MAXPID);
 837             }
 838 
 839             if (name)
 840                 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDSUFFIX, 1);
 841 
 842             first = false;
 843         }
 844 
 845         if (!first)
 846             (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, ": ", 2);
 847 
 848         (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->message, SIR_MAXMESSAGE);
 849 
 850         if (styling)
 851             (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_ESC_RST, SIR_MAXSTYLE);
 852 
 853 #if defined(SIR_USE_EOL_CRLF)
 854         (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_EOL, 2);
 855 #else
 856         (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_EOL, 1);
 857 #endif
 858 
 859         buf->output_len = strnlen(buf->output, SIR_MAXOUTPUT);
 860 
 861         return buf->output;
 862     }
 863 
 864     return NULL;
 865 }
 866 
 867 bool _sir_syslog_init(const char* name, sir_syslog_dest* ctx) {
     /* [previous][next][first][last][top][bottom][index][help] */
 868 #if !defined(SIR_NO_SYSTEM_LOGGERS)
 869     if (!_sir_validptr(name) || !_sir_validptr(ctx))
 870         return false;
 871 
 872     /* begin resolve identity. */
 873     if (!_sir_validstrnofail(ctx->identity)) {
 874         _sir_selflog("ctx->identity is no good; trying name");
 875         if (_sir_validstrnofail(name)) {
 876             _sir_selflog("using name");
 877             (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, name, strnlen(name, SIR_MAX_SYSLOG_ID));
 878         } else {
 879             _sir_selflog("name is no good; trying filename");
 880             char* appbasename = _sir_getappbasename();
 881             if (_sir_validstrnofail(appbasename)) {
 882                 _sir_selflog("filename is good: %s", appbasename);
 883                 (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, appbasename,
 884                     strnlen(appbasename, SIR_MAX_SYSLOG_ID));
 885             } else {
 886                 _sir_selflog("filename no good; using fallback");
 887                 (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, SIR_FALLBACK_SYSLOG_ID,
 888                     strnlen(SIR_FALLBACK_SYSLOG_ID, SIR_MAX_SYSLOG_ID));
 889             }
 890             _sir_safefree(&appbasename);
 891         }
 892     } else {
 893         _sir_selflog("already have identity");
 894     }
 895 
 896     /* category */
 897     if (!_sir_validstrnofail(ctx->category)) {
 898         _sir_selflog("category not set; using fallback");
 899         (void)_sir_strncpy(ctx->category, SIR_MAX_SYSLOG_CAT, SIR_FALLBACK_SYSLOG_CAT,
 900             strnlen(SIR_FALLBACK_SYSLOG_CAT, SIR_MAX_SYSLOG_CAT));
 901     } else {
 902         _sir_selflog("already have category");
 903     }
 904 
 905     _sir_setbitshigh(&ctx->_state.mask, SIRSL_IS_INIT);
 906     _sir_selflog("resolved (identity: '%s', category: '%s')", ctx->identity, ctx->category);
 907 
 908     return _sir_syslog_open(ctx);
 909 #else
 910     SIR_UNUSED(name);
 911     SIR_UNUSED(ctx);
 912     return false;
 913 #endif
 914 }
 915 
 916 bool _sir_syslog_open(sir_syslog_dest* ctx) {
     /* [previous][next][first][last][top][bottom][index][help] */
 917 #if !defined(SIR_NO_SYSTEM_LOGGERS)
 918     if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_INIT)) {
 919         _sir_selflog("not initialized; ignoring");
 920         return _sir_seterror(_SIR_E_INVALID);
 921     }
 922 
 923     if (_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
 924         _sir_selflog("log already open; ignoring");
 925         return true;
 926     }
 927 
 928     _sir_selflog("opening log (levels: %04"PRIx16", options: %08"PRIx32")", ctx->levels,
 929         ctx->opts);
 930 
 931 # if defined(SIR_OS_LOG_ENABLED)
 932     ctx->_state.logger = (void*)os_log_create(ctx->identity, ctx->category);
 933     _sir_selflog("opened os_log ('%s', '%s')", ctx->identity, ctx->category);
 934 # elif defined(SIR_SYSLOG_ENABLED)
 935     int logopt   = LOG_NDELAY | (_sir_bittest(ctx->opts, SIRO_NOPID) ? 0 : LOG_PID);
 936     int facility = LOG_USER;
 937 
 938     openlog(ctx->identity, logopt, facility);
 939     _sir_selflog("opened syslog('%s', %x, %x)", ctx->identity, logopt, facility);
 940 # elif defined(SIR_EVENTLOG_ENABLED)
 941     DWORD reg = EventRegister(&SIR_EVENTLOG_GUID, NULL, NULL,
 942         (PREGHANDLE)&ctx->_state.logger);
 943     if (ERROR_SUCCESS == reg) {
 944         _sir_selflog("opened eventlog('%s')", ctx->identity);
 945     } else {
 946         /* not fatal; logging calls will just silently fail. */
 947         _sir_selflog("failed to open eventlog! error: %lu", reg);
 948         (void)_sir_handlewin32err(reg);
 949     }
 950 # endif
 951 
 952     _sir_setbitshigh(&ctx->_state.mask, SIRSL_IS_OPEN);
 953     return true;
 954 #else
 955     SIR_UNUSED(ctx);
 956     return false;
 957 #endif
 958 }
 959 
 960 bool _sir_syslog_write(sir_level level, const sirbuf* buf, const sir_syslog_dest* ctx) {
     /* [previous][next][first][last][top][bottom][index][help] */
 961 #if !defined(SIR_NO_SYSTEM_LOGGERS)
 962     if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_INIT)) {
 963         _sir_selflog("not initialized; ignoring");
 964         return _sir_seterror(_SIR_E_INVALID);
 965     }
 966 
 967     if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
 968         _sir_selflog("log not open; ignoring");
 969         return _sir_seterror(_SIR_E_INVALID);
 970     }
 971 
 972 # if defined(SIR_OS_LOG_ENABLED)
 973     if (SIRL_DEBUG == level)
 974         os_log_debug((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
 975     else if (SIRL_INFO == level || SIRL_NOTICE == level)
 976         os_log_info((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
 977     else if (SIRL_WARN == level || SIRL_ERROR == level)
 978         os_log_error((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
 979     else if (SIRL_CRIT == level || SIRL_ALERT == level || SIRL_EMERG == level)
 980         os_log_fault((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
 981 
 982     return true;
 983 # elif defined(SIR_SYSLOG_ENABLED)
 984     int syslog_level;
 985     switch (level) {
 986         case SIRL_DEBUG:  syslog_level = LOG_DEBUG; break;
 987         case SIRL_INFO:   syslog_level = LOG_INFO; break;
 988         case SIRL_NOTICE: syslog_level = LOG_NOTICE; break;
 989         case SIRL_WARN:   syslog_level = LOG_WARNING; break;
 990         case SIRL_ERROR:  syslog_level = LOG_ERR; break;
 991         case SIRL_CRIT:   syslog_level = LOG_CRIT; break;
 992         case SIRL_ALERT:  syslog_level = LOG_ALERT; break;
 993         case SIRL_EMERG:  syslog_level = LOG_EMERG; break;
 994         // GCOVR_EXCL_START
 995         default: /* this should never happen. */
 996             SIR_ASSERT(false);
 997             syslog_level = LOG_DEBUG;
 998         // GCOVR_EXCL_STOP
 999     }
1000 
1001     syslog(syslog_level, "%s", buf->message);
1002     return true;
1003 # elif defined(SIR_EVENTLOG_ENABLED)
1004     const EVENT_DESCRIPTOR* edesc = NULL;
1005     if (SIRL_DEBUG == level)
1006         edesc = &SIR_EVT_DEBUG;
1007     else if (SIRL_INFO == level || SIRL_NOTICE == level)
1008         edesc = &SIR_EVT_INFO;
1009     else if (SIRL_WARN == level)
1010         edesc = &SIR_EVT_WARNING;
1011     else if (SIRL_ERROR == level)
1012         edesc = &SIR_EVT_ERROR;
1013     else if (SIRL_CRIT == level || SIRL_ALERT == level || SIRL_EMERG == level)
1014         edesc = &SIR_EVT_CRITICAL;
1015 
1016     SIR_ASSERT(NULL != edesc);
1017     if (NULL == edesc)
1018         return _sir_seterror(_SIR_E_INTERNAL);
1019 
1020 #  if defined(__HAVE_STDC_SECURE_OR_EXT1__)
1021     size_t msg_len = strnlen_s(buf->message, SIR_MAXMESSAGE) + 1;
1022 #  else
1023     size_t msg_len = strnlen(buf->message, SIR_MAXMESSAGE) + 1;
1024 #  endif
1025     int wlen = MultiByteToWideChar(CP_UTF8, 0UL, buf->message, (int)msg_len, NULL, 0);
1026     if (wlen <= 0)
1027         return _sir_handlewin32err(GetLastError());
1028 
1029     DWORD write = 1UL;
1030     wchar_t* wmsg = calloc(wlen, sizeof(wchar_t));
1031     if (NULL != wmsg) {
1032         int conv = MultiByteToWideChar(CP_UTF8, 0UL, buf->message, (int)msg_len, wmsg, wlen);
1033         if (conv > 0) {
1034             EVENT_DATA_DESCRIPTOR eddesc = {0};
1035             EventDataDescCreate(&eddesc, wmsg, (ULONG)(wlen * sizeof(wchar_t)));
1036 
1037             write = EventWrite((REGHANDLE)ctx->_state.logger, edesc, 1UL, &eddesc);
1038             if (ERROR_SUCCESS != write) {
1039                 _sir_selflog("failed to write eventlog! error: %lu", write);
1040                 (void)_sir_handlewin32err(write);
1041             }
1042         }
1043         _sir_safefree(&wmsg);
1044     }
1045 
1046     return ERROR_SUCCESS == write;
1047 # else
1048     SIR_UNUSED(level);
1049     SIR_UNUSED(buf);
1050     SIR_UNUSED(ctx);
1051     return false;
1052 # endif
1053 #else
1054     SIR_UNUSED(level);
1055     SIR_UNUSED(buf);
1056     SIR_UNUSED(ctx);
1057     return false;
1058 #endif
1059 }
1060 
1061 bool _sir_syslog_updated(sirinit* si, const sir_update_config_data* data) {
     /* [previous][next][first][last][top][bottom][index][help] */
1062 #if !defined(SIR_NO_SYSTEM_LOGGERS)
1063     if (!_sir_validptr(si) || !_sir_validptr(data))
1064         return false;
1065 
1066     if (_sir_bittest(si->d_syslog._state.mask, SIRSL_UPDATED)) {
1067         bool levels   = _sir_bittest(si->d_syslog._state.mask, SIRSL_LEVELS);
1068         bool options  = _sir_bittest(si->d_syslog._state.mask, SIRSL_OPTIONS);
1069         bool category = _sir_bittest(si->d_syslog._state.mask, SIRSL_CATEGORY);
1070         bool identity = _sir_bittest(si->d_syslog._state.mask, SIRSL_IDENTITY);
1071         bool is_init  = _sir_bittest(si->d_syslog._state.mask, SIRSL_IS_INIT);
1072         bool is_open  = _sir_bittest(si->d_syslog._state.mask, SIRSL_IS_OPEN);
1073 
1074         _sir_selflog("config update: (levels: %u, options: %u, category: %u,"
1075                      " identity: %u, is_init: %u, is_open: %u)",
1076                      levels, options, category, identity, is_init, is_open);
1077 
1078         bool must_init = false;
1079 # if defined(SIR_OS_LOG_ENABLED)
1080         /* for os_log, if initialized and open already, only need to reconfigure
1081          * if identity or category changed. */
1082         must_init = (!is_init || !is_open) || (identity || category);
1083 # elif defined(SIR_SYSLOG_ENABLED)
1084         /* for syslog, if initialized and open already, only need to reconfigure
1085          * if identity or options changed. */
1086         must_init = (!is_init || !is_open) || (identity || options);
1087 # elif defined(SIR_EVENTLOG_ENABLED)
1088         /* for event log, if initialized and open already, only need to reconfigure
1089          * if identity changed. */
1090         must_init = (!is_init || !is_open) || identity;
1091 # endif
1092         bool init = true;
1093         if (must_init) {
1094             if (is_open) /* close first; open will fail otherwise. */
1095                 init = _sir_syslog_close(&si->d_syslog);
1096 
1097             _sir_selflog("re-init...");
1098             _sir_eqland(init, _sir_syslog_init(si->name, &si->d_syslog));
1099             _sir_selflog("re-init %s", init ? "succeeded" : "failed");
1100         } else {
1101             _sir_selflog("no re-init necessary");
1102         }
1103 
1104         return init;
1105     }
1106 
1107     return false;
1108 #else
1109     SIR_UNUSED(si);
1110     SIR_UNUSED(data);
1111     return false;
1112 #endif
1113 }
1114 
1115 bool _sir_syslog_close(sir_syslog_dest* ctx) {
     /* [previous][next][first][last][top][bottom][index][help] */
1116 #if !defined(SIR_NO_SYSTEM_LOGGERS)
1117     if (!_sir_validptr(ctx))
1118         return false;
1119 
1120     if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
1121         _sir_selflog("log not open; ignoring");
1122         return true;
1123     }
1124 
1125 # if defined(SIR_OS_LOG_ENABLED)
1126     /* Evidently, you don't need to close the handle returned from os_log_create(), and
1127      * if you make that call again, you'll get the same cached value. so let's keep the
1128      * value we've got in the global context. */
1129     _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
1130     _sir_selflog("log closure not necessary");
1131     return true;
1132 # elif defined(SIR_SYSLOG_ENABLED)
1133     closelog();
1134     _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
1135     _sir_selflog("closed log");
1136     return true;
1137 # elif defined(SIR_EVENTLOG_ENABLED)
1138     ULONG unreg = EventUnregister((REGHANDLE)ctx->_state.logger);
1139     _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
1140     if (ERROR_SUCCESS == unreg)
1141         _sir_selflog("closed log");
1142     else
1143         _sir_selflog("error: failed to close log");
1144 
1145     return ERROR_SUCCESS == unreg;
1146 # else
1147     SIR_UNUSED(ctx);
1148     return false;
1149 # endif
1150 #else
1151     SIR_UNUSED(ctx);
1152     return false;
1153 #endif
1154 }
1155 
1156 void _sir_syslog_reset(sir_syslog_dest* ctx) {
     /* [previous][next][first][last][top][bottom][index][help] */
1157 #if !defined(SIR_NO_SYSTEM_LOGGERS)
1158     if (_sir_validptr(ctx)) {
1159         uint32_t old       = ctx->_state.mask;
1160         ctx->_state.mask   = 0U;
1161         ctx->_state.logger = NULL;
1162         _sir_selflog("state reset; mask was %08"PRIx32, old);
1163     }
1164 #else
1165     SIR_UNUSED(ctx);
1166 #endif
1167 }
1168 
1169 const char* _sir_formattedlevelstr(sir_level level) {
     /* [previous][next][first][last][top][bottom][index][help] */
1170     static const size_t low  = 0;
1171     static const size_t high = SIR_NUMLEVELS - 1;
1172 
1173     const char* retval = SIR_UNKNOWN;
1174 
1175     _SIR_DECLARE_BIN_SEARCH(low, high);
1176     _SIR_BEGIN_BIN_SEARCH()
1177 
1178     if (sir_level_to_str_map[_mid].level == level) {
1179         retval = sir_level_to_str_map[_mid].fmt;
1180         break;
1181     }
1182 
1183     _SIR_ITERATE_BIN_SEARCH((sir_level_to_str_map[_mid].level < level ? 1 : -1));
1184     _SIR_END_BIN_SEARCH();
1185 
1186     return retval;
1187 }
1188 
1189 bool _sir_clock_gettime(int clock, time_t* tbuf, long* msecbuf) {
     /* [previous][next][first][last][top][bottom][index][help] */
1190     if (tbuf) {
1191 #if defined(SIR_MSEC_POSIX)
1192         struct timespec ts = {0};
1193         int ret            = clock_gettime(clock, &ts);
1194         SIR_ASSERT(0 == ret);
1195 
1196         if (0 == ret) {
1197             *tbuf = ts.tv_sec;
1198             if (msecbuf)
1199                 *msecbuf = ts.tv_nsec / 1000000L;
1200         } else {
1201             if (msecbuf)
1202                 *msecbuf = 0L;
1203             return _sir_handleerr(errno);
1204         }
1205 #elif defined(SIR_MSEC_WIN32)
1206         SIR_UNUSED(clock);
1207         static const ULONGLONG uepoch = (ULONGLONG)116444736e9;
1208 
1209         FILETIME ftutc = {0};
1210         GetSystemTimePreciseAsFileTime(&ftutc);
1211 
1212         ULARGE_INTEGER ftnow = {0};
1213         ftnow.HighPart = ftutc.dwHighDateTime;
1214         ftnow.LowPart  = ftutc.dwLowDateTime;
1215         ftnow.QuadPart = (ULONGLONG)((ftnow.QuadPart - uepoch) / 10000000ULL);
1216 
1217         *tbuf = (time_t)ftnow.QuadPart;
1218 
1219         SYSTEMTIME st = {0};
1220         if (FileTimeToSystemTime(&ftutc, &st)) {
1221             if (msecbuf)
1222                 *msecbuf = (long)st.wMilliseconds;
1223         } else {
1224             if (msecbuf)
1225                 *msecbuf = 0L;
1226             return _sir_handlewin32err(GetLastError());
1227         }
1228 #else
1229         SIR_UNUSED(clock);
1230         (void)time(tbuf);
1231         if (msecbuf)
1232             *msecbuf = 0L;
1233 #endif
1234         return true;
1235     }
1236     return false;
1237 }
1238 
1239 double _sir_msec_since(const sir_time* when, sir_time* out) {
     /* [previous][next][first][last][top][bottom][index][help] */
1240     if (!_sir_validptr(out))
1241         return 0.0;
1242 #if !defined(__WIN__)
1243     out->sec = 0;
1244     out->msec = 0L;
1245 
1246     bool gettime = _sir_clock_gettime(SIR_INTERVALCLOCK, &out->sec, &out->msec);
1247     SIR_ASSERT(gettime);
1248 
1249     if (!_sir_validptrnofail(when) || !gettime || (out->sec < when->sec ||
1250         (out->sec == when->sec && out->msec < when->msec)))
1251         return 0.0;
1252 
1253     return ((((double)out->sec) * 1e3) + (double)out->msec) -
1254            ((((double)when->sec) * 1e3) + (double)when->msec);
1255 #else /* __WIN__ */
1256     SIR_ASSERT(_sir_perfcntr_freq.QuadPart > 0LL);
1257 
1258     if (_sir_perfcntr_freq.QuadPart <= 0LL)
1259         (void)QueryPerformanceFrequency(&_sir_perfcntr_freq);
1260 
1261     (void)QueryPerformanceCounter(&out->counter);
1262 
1263     if (!_sir_validptrnofail(when) || out->counter.QuadPart <= when->counter.QuadPart)
1264         return 0.0;
1265 
1266     double msec_ratio = ((double)_sir_perfcntr_freq.QuadPart) / 1e3;
1267     return ((double)(out->counter.QuadPart - when->counter.QuadPart)) / msec_ratio;
1268 #endif
1269 }
1270 
1271 pid_t _sir_getpid(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
1272 #if !defined(__WIN__)
1273     return getpid();
1274 #else /* __WIN__ */
1275     return (pid_t)GetCurrentProcessId();
1276 #endif
1277 }
1278 
1279 pid_t _sir_gettid(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
1280     pid_t tid = 0;
1281 #if defined(__MACOS__)
1282     uint64_t tid64 = 0ULL;
1283     int gettid     = pthread_threadid_np(NULL, &tid64);
1284     if (0 != gettid)
1285         (void)_sir_handleerr(gettid);
1286     tid = (pid_t)tid64;
1287 #elif (defined(__BSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)) || \
1288       defined(__DragonFly_getthreadid__)
1289     tid = (pid_t)pthread_getthreadid_np();
1290 #elif defined(__OpenBSD__)
1291     tid = (pid_t)getthrid();
1292 #elif defined(__SOLARIS__) || defined(__NetBSD__) || defined(__HURD__) || \
1293       defined(__DragonFly__) || defined(__CYGWIN__) || defined(_AIX) || \
1294       defined(__EMSCRIPTEN__)
1295 # if defined(__CYGWIN__)
1296     tid = (pid_t)(uintptr_t)pthread_self();
1297 # else
1298     tid = (pid_t)pthread_self();
1299 # endif
1300 #elif defined(__HAIKU__)
1301     tid = get_pthread_thread_id(pthread_self());
1302 #elif defined(__linux__) || defined(__serenity__)
1303 # if (defined(__GLIBC__) && GLIBC_VERSION >= 23000) || defined(__serenity__)
1304     tid = gettid();
1305 # else
1306     tid = syscall(SYS_gettid);
1307 # endif
1308 #elif defined(__WIN__)
1309     tid = (pid_t)GetCurrentThreadId();
1310 #else
1311 # error "unable to determine how to get a thread identifier"
1312 #endif
1313     return tid;
1314 }
1315 
1316 bool _sir_getthreadname(char name[SIR_MAXPID]) {
     /* [previous][next][first][last][top][bottom][index][help] */
1317     _sir_resetstr(name);
1318 #if defined(__MACOS__) || (defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_12_2__)) || \
1319     (defined(__linux__) && defined(__UCLIBC__) && defined(_GNU_SOURCE)) || \
1320     (defined(__GLIBC__) && GLIBC_VERSION >= 21200 && defined(_GNU_SOURCE)) || \
1321     (defined(__ANDROID__) &&  __ANDROID_API__ >= 26) || defined(SIR_PTHREAD_GETNAME_NP) || \
1322     defined(__serenity__) || (defined(__linux__) && !defined(__GLIBC__) && \
1323     defined(_GNU_SOURCE) && defined(__NEED_pthread_t))
1324     int ret = pthread_getname_np(pthread_self(), name, SIR_MAXPID);
1325     if (0 != ret)
1326         return _sir_handleerr(ret);
1327 # if defined(__HAIKU__)
1328     if (!(strncmp(name, "pthread func", SIR_MAXPID)))
1329         (void)snprintf(name, SIR_MAXPID, "%ld", (long)get_pthread_thread_id(pthread_self()));
1330 # endif
1331     return _sir_validstrnofail(name);
1332 #elif defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_11_3__)
1333     pthread_get_name_np(pthread_self(), name, SIR_MAXPID);
1334     return _sir_validstrnofail(name);
1335 #elif defined(__WIN__)
1336     wchar_t* wname = NULL;
1337     HRESULT hr     = GetThreadDescription(GetCurrentThread(), &wname);
1338     if (FAILED(hr))
1339         return _sir_handlewin32err(GetLastError());
1340     bool success = true;
1341 # if defined(__HAVE_STDC_SECURE_OR_EXT1__)
1342     size_t wlen = wcsnlen_s(wname, SIR_MAXPID);
1343 # elif defined(__EMBARCADEROC__) && (__clang_major__ < 15)
1344     size_t wlen = wcslen(wname);
1345 # else
1346     size_t wlen = wcsnlen(wname, SIR_MAXPID);
1347 # endif
1348     if (wlen > 0) {
1349         if (!WideCharToMultiByte(CP_UTF8, 0UL, wname, (int)wlen, name,
1350             SIR_MAXPID, NULL, NULL)) {
1351             success = false;
1352             (void)_sir_handlewin32err(GetLastError());
1353         }
1354     }
1355     (void)LocalFree(wname);
1356     return success && _sir_validstrnofail(name);
1357 #else
1358 # if !defined(SUNLINT) && !defined(_AIX) && !defined(__HURD__)
1359 #  pragma message("unable to determine how to get a thread name")
1360 # endif
1361     SIR_UNUSED(name);
1362     return false;
1363 #endif
1364 }
1365 
1366 bool _sir_setthreadname(const char* name) {
     /* [previous][next][first][last][top][bottom][index][help] */
1367     if (!_sir_validptr(name))
1368         return false;
1369 #if defined(__MACOS__)
1370     int ret = pthread_setname_np(name);
1371     return (0 != ret) ? _sir_handleerr(ret) : true;
1372 #elif defined(__HAIKU__)
1373     status_t ret = rename_thread(find_thread(NULL), name);
1374     return (B_OK != ret) ? _sir_handleerr((int)ret) : true;
1375 #elif defined(__NetBSD__)
1376     int ret = pthread_setname_np(pthread_self(), "%s", name);
1377     return (0 != ret) ? _sir_handleerr(ret) : true;
1378 #elif (defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_12_2__)) || \
1379       (defined(__linux__) && defined(__UCLIBC__) && defined(_GNU_SOURCE)) || \
1380       (defined(__GLIBC__) && GLIBC_VERSION >= 21200 && defined(_GNU_SOURCE)) || \
1381        defined(__QNXNTO__) || defined(__SOLARIS__) || defined(SIR_PTHREAD_GETNAME_NP) || \
1382        defined(__ANDROID__) && !defined(__OpenBSD__) || defined(__serenity__) || \
1383       (defined(__linux__) && !defined(__GLIBC__) && \
1384        defined(_GNU_SOURCE) && defined(__NEED_pthread_t))
1385     int ret = pthread_setname_np(pthread_self(), name);
1386     return (0 != ret) ? _sir_handleerr(ret) : true;
1387 #elif defined(__OpenBSD__) || defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_11_3__)
1388     pthread_set_name_np(pthread_self(), name);
1389     return true;
1390 #elif defined(__WIN__)
1391 # if defined(__HAVE_STDC_SECURE_OR_EXT1__)
1392     size_t name_len = strnlen_s(name, SIR_MAXPID);
1393 # else
1394     size_t name_len = strnlen(name, SIR_MAXPID);
1395 # endif
1396     if (0 == name_len)
1397         name_len = 1;
1398 
1399     wchar_t buf[SIR_MAXPID] = {0};
1400     if (!MultiByteToWideChar(CP_UTF8, 0UL, name, (int)name_len, buf, SIR_MAXPID))
1401         return _sir_handlewin32err(GetLastError());
1402 
1403     HRESULT hr = SetThreadDescription(GetCurrentThread(), buf);
1404     return FAILED(hr) ? _sir_handlewin32err(hr) : true;
1405 #else
1406 # if !defined(SUNLINT) && !defined(_AIX)
1407 #  pragma message("unable to determine how to set a thread name")
1408 # endif
1409     SIR_UNUSED(name);
1410     return false;
1411 #endif
1412 }
1413 
1414 bool _sir_gethostname(char name[SIR_MAXHOST]) {
     /* [previous][next][first][last][top][bottom][index][help] */
1415 #if !defined(__WIN__)
1416     int ret = gethostname(name, SIR_MAXHOST - 1);
1417     return 0 == ret ? true : _sir_handleerr(errno);
1418 #else
1419     WSADATA wsad = {0};
1420     int ret      = WSAStartup(MAKEWORD(2, 2), &wsad);
1421     if (0 != ret)
1422         return _sir_handlewin32err(ret);
1423 
1424     if (SOCKET_ERROR == gethostname(name, SIR_MAXHOST)) {
1425         int err = WSAGetLastError();
1426         WSACleanup();
1427         return _sir_handlewin32err(err);
1428     }
1429 
1430     WSACleanup();
1431     return true;
1432 #endif /* !__WIN__ */
1433 }
1434 
1435 long __sir_nprocs(bool test_mode) {
     /* [previous][next][first][last][top][bottom][index][help] */
1436     long nprocs = 0;
1437 
1438 #if defined(_AIX)
1439     nprocs = (long)_system_configuration.ncpus;
1440     _sir_selflog("AIX _system_configuration.ncpus reports %ld processor(s)", nprocs);
1441 #endif
1442 
1443 #if defined(__WIN__)
1444     SYSTEM_INFO system_info;
1445     ZeroMemory(&system_info, sizeof(system_info));
1446     GetSystemInfo(&system_info);
1447     nprocs = (long)system_info.dwNumberOfProcessors;
1448     _sir_selflog("Windows GetSystemInfo() reports %ld processor(s)", nprocs);
1449 #endif
1450 
1451 #if defined(__HAIKU__)
1452     system_info hinfo;
1453     get_system_info(&hinfo);
1454     nprocs = (long)hinfo.cpu_count;
1455     _sir_selflog("Haiku get_system_info() reports %ld processor(s)", nprocs);
1456 #endif
1457 
1458 #if defined(SC_NPROCESSORS_ONLN)
1459 # define SIR_SC_NPROCESSORS SC_NPROCESSORS_ONLN
1460 #elif defined(_SC_NPROCESSORS_ONLN)
1461 # define SIR_SC_NPROCESSORS _SC_NPROCESSORS_ONLN
1462 #endif
1463 #if defined(SIR_SC_NPROCESSORS)
1464     long tprocs = sysconf(SIR_SC_NPROCESSORS);
1465     _sir_selflog("sysconf() reports %ld processor(s)", tprocs);
1466     if (tprocs > nprocs)
1467         nprocs = tprocs;
1468 #endif
1469 
1470 #if defined(__linux__) && defined(CPU_COUNT) && !defined(__ANDROID__) && !defined(__UCLIBC__)
1471     long ctprocs;
1472     cpu_set_t p_aff;
1473     memset(&p_aff, 0, sizeof(p_aff));
1474     if (sched_getaffinity(0, sizeof(p_aff), &p_aff)) {
1475         ctprocs = 0;
1476     } else {
1477         ctprocs = CPU_COUNT(&p_aff);
1478         _sir_selflog("sched_getaffinity() reports %ld processor(s)", ctprocs);
1479     }
1480     if (ctprocs > nprocs)
1481         nprocs = ctprocs;
1482 #endif
1483 
1484 #if defined(CTL_HW) && defined(HW_AVAILCPU)
1485     int ntprocs = 0;
1486     size_t sntprocs = sizeof(ntprocs);
1487     if (sysctl ((int[2]) {CTL_HW, HW_AVAILCPU}, 2, &ntprocs, &sntprocs, NULL, 0)) {
1488         ntprocs = 0;
1489     } else {
1490         _sir_selflog("sysctl(CTL_HW, HW_AVAILCPU) reports %d processor(s)", ntprocs);
1491         if (ntprocs > nprocs)
1492             nprocs = (long)ntprocs;
1493     }
1494 #elif defined(CTL_HW) && defined(HW_NCPU)
1495     int ntprocs = 0;
1496     size_t sntprocs = sizeof(ntprocs);
1497     if (sysctl ((int[2]) {CTL_HW, HW_NCPU}, 2, &ntprocs, &sntprocs, NULL, 0)) {
1498         ntprocs = 0;
1499     } else {
1500         _sir_selflog("sysctl(CTL_HW, HW_NCPU) reports %d processor(s)", ntprocs);
1501         if (ntprocs > nprocs)
1502             nprocs = (long)ntprocs;
1503     }
1504 #elif defined(CTL_HW) && defined(HW_NCPUFOUND)
1505     int ntprocs = 0;
1506     size_t sntprocs = sizeof(ntprocs);
1507     if (sysctl ((int[2]) {CTL_HW, HW_NCPUFOUND}, 2, &ntprocs, &sntprocs, NULL, 0)) {
1508         ntprocs = 0;
1509     } else {
1510         _sir_selflog("sysctl(CTL_HW, HW_NCPUFOUND) reports %d processor(s)", ntprocs);
1511         if (ntprocs > nprocs)
1512             nprocs = (long)ntprocs;
1513     }
1514 #endif
1515 
1516 #if defined(__MACOS__)
1517     int antprocs = 0;
1518     size_t asntprocs = sizeof(antprocs);
1519     if (sysctlbyname("hw.ncpu", &antprocs, &asntprocs, NULL, 0)) {
1520         antprocs = 0;
1521     } else {
1522         _sir_selflog("sysctlbyname(hw.ncpu) reports %d processor(s)", antprocs);
1523         if (antprocs > nprocs)
1524             nprocs = (long)antprocs;
1525     }
1526 #endif
1527 
1528 #if defined(__QNX__) || defined(__QNXNTO__)
1529     long qtprocs = (long)_syspage_ptr->num_cpu;
1530     _sir_selflog("QNX _syspage_ptr->num_cpu reports %ld processor(s)", qtprocs);
1531     if (qtprocs > nprocs)
1532         nprocs = qtprocs;
1533 #endif
1534 
1535 #if defined(__VXWORKS__)
1536 # if defined(_WRS_CONFIG_SMP)
1537     long vtprocs = 0;
1538     cpuset_t vset = vxCpuEnabledGet();
1539     for (int count = 0; count < 512 && !CPUSET_ISZERO(vset); ++count) {
1540         if (CPUSET_ISSET(vset, count)) {
1541             CPUSET_CLR(vset, count);
1542             vtprocs++;
1543         }
1544     }
1545     _sir_selflog("VxWorks vxCpuEnabledGet() reports %ld processor(s)", vtprocs);
1546 # else
1547     long vtprocs = 1;
1548     _sir_selflog("Uniprocessor system or VxWorks SMP is not enabled");
1549 # endif
1550     if (vtprocs > nprocs)
1551         nprocs = vtprocs;
1552 #endif
1553 
1554     if (nprocs < 1) {
1555         _sir_selflog(SIR_BRED("Failed to determine processor count!"));
1556         if (!test_mode)
1557             nprocs = 1;
1558     }
1559 
1560     _sir_selflog("Detected %ld processor(s)", nprocs);
1561     return nprocs;
1562 }

/* [previous][next][first][last][top][bottom][index][help] */