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

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