• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aremmell / libsir / 1413

23 Dec 2023 09:45PM UTC coverage: 95.431% (-0.05%) from 95.477%
1413

Pull #365

gitlab-ci

web-flow
Merge branch 'master' into merge_pio
Pull Request #365: Add experimental support for PlatformIO, just to see if we can get it to work on an ESP32 or similar.

14 of 16 new or added lines in 1 file covered. (87.5%)

1 existing line in 1 file now uncovered.

3864 of 4049 relevant lines covered (95.43%)

473034.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.75
/src/sirinternal.c
1
/*
2
 * sirinternal.c
3
 *
4
 * Version: 2.2.4
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
static sir_mutex cfg_mutex  = SIR_MUTEX_INIT;
59
static sir_mutex fc_mutex   = SIR_MUTEX_INIT;
60
static sir_mutex pc_mutex   = SIR_MUTEX_INIT;
61
#if !defined(SIR_NO_TEXT_STYLING)
62
static sir_mutex ts_mutex   = SIR_MUTEX_INIT;
63
#endif
64
static sir_once static_once = SIR_ONCE_INIT;
65

66
#if defined(__WIN__)
67
static LARGE_INTEGER _sir_perfcntr_freq = {0};
68
#endif
69

70
#if defined(__HAVE_ATOMIC_H__)
71
static atomic_uint_fast32_t _sir_magic;
72
#else
73
static volatile uint32_t _sir_magic = 0U;
74
#endif
75

76
static _sir_thread_local char _sir_tid[SIR_MAXPID]   = {0};
77
static _sir_thread_local sir_time _sir_last_thrd_chk = {0};
78
static _sir_thread_local time_t _sir_last_timestamp  = 0;
79

80
bool _sir_makeinit(sirinit* si) {
72✔
81
    bool retval = _sir_validptr(si);
72✔
82

83
    if (retval) {
72✔
84
        (void)memset(si, 0, sizeof(sirinit));
65✔
85

86
        si->d_stdout.opts   = SIRO_DEFAULT;
72✔
87
        si->d_stdout.levels = SIRL_DEFAULT;
72✔
88

89
        si->d_stderr.opts   = SIRO_DEFAULT;
72✔
90
        si->d_stderr.levels = SIRL_DEFAULT;
72✔
91

92
#if !defined(SIR_NO_SYSTEM_LOGGERS)
93
        si->d_syslog.opts   = SIRO_DEFAULT;
59✔
94
        si->d_syslog.levels = SIRL_DEFAULT;
59✔
95
#else
96
        si->d_syslog.opts   = SIRO_MSGONLY;
13✔
97
        si->d_syslog.levels = SIRL_NONE;
13✔
98
#endif
99
    }
100

101
    return retval;
72✔
102
}
103

104
bool _sir_init(sirinit* si) {
976✔
105
    (void)_sir_seterror(_SIR_E_NOERROR);
976✔
106

107
    /* can only fail on Windows. */
108
    bool once_init = _sir_once(&static_once, _sir_init_static_once);
976✔
109
#if !defined(__WIN__)
110
    SIR_UNUSED(once_init);
111
#else
112
    if (!once_init) {
113
        _sir_selflog("error: static data initialization routine failed!");
114
        return false;
115
    }
116
#endif
117

118
    if (!_sir_validptr(si))
976✔
119
        return false;
20✔
120

121
#if defined(__HAVE_ATOMIC_H__)
122
    if (_SIR_MAGIC == atomic_load(&_sir_magic))
953✔
123
#else
124
    if (_SIR_MAGIC == _sir_magic)
125
#endif
126
        return _sir_seterror(_SIR_E_ALREADY);
26✔
127

128
    _sir_defaultlevels(&si->d_stdout.levels, sir_stdout_def_lvls);
927✔
129
    _sir_defaultopts(&si->d_stdout.opts, sir_stdout_def_opts);
927✔
130

131
    _sir_defaultlevels(&si->d_stderr.levels, sir_stderr_def_lvls);
927✔
132
    _sir_defaultopts(&si->d_stderr.opts, sir_stderr_def_opts);
927✔
133

134
#if !defined(SIR_NO_SYSTEM_LOGGERS)
135
    _sir_defaultlevels(&si->d_syslog.levels, sir_syslog_def_lvls);
700✔
136
    _sir_defaultopts(&si->d_syslog.opts, sir_syslog_def_opts);
700✔
137
#endif
138

139
    if (!_sir_init_sanity(si))
927✔
140
        return false;
20✔
141

142
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
904✔
143

144
    bool init = true;
786✔
145

146
#if defined(__HAVE_ATOMIC_H__)
147
    atomic_store(&_sir_magic, _SIR_MAGIC);
904✔
148
#else
149
    _sir_magic = _SIR_MAGIC;
150
#endif
151

152
    _sir_reset_tls();
904✔
153

154
#if defined(__WIN__)
155
    _sir_initialize_stdio();
156
#else
157
    tzset();
904✔
158
#endif
159

160
#if !defined(SIR_NO_TEXT_STYLING)
161
    if (!_sir_setcolormode(SIRCM_16)) {
904✔
162
        init = false;
×
163
        _sir_selflog("error: failed to set color mode!");
×
164
    }
165

166
    if (!_sir_resettextstyles()) {
904✔
167
        init = false;
×
168
        _sir_selflog("error: failed to reset text styles!");
×
169
    }
170
#endif
171

172
    (void)memset(&_cfg->state, 0, sizeof(_cfg->state));
904✔
173
    (void)memcpy(&_cfg->si, si, sizeof(sirinit));
904✔
174

175
    /* forcibly null-terminate the process name. */
176
    _cfg->si.name[SIR_MAXNAME - 1] = '\0';
904✔
177

178
    /* store PID. */
179
    _cfg->state.pid = _sir_getpid();
904✔
180

181
    if (_cfg->state.pid != -1 && _cfg->state.pid != 0) {
904✔
182
        (void)snprintf(_cfg->state.pidbuf, SIR_MAXPID, SIR_PIDFORMAT,
904✔
183
            PID_CAST _cfg->state.pid);
184
    } else {
NEW
185
        _sir_resetstr(_cfg->state.pidbuf);
×
186
    }
187

188
#if !defined(SIR_NO_SYSTEM_LOGGERS)
189
    /* initialize system logger. */
190
    _sir_syslog_reset(&_cfg->si.d_syslog);
683✔
191

192
    if (_cfg->si.d_syslog.levels != SIRL_NONE &&
701✔
193
        !_sir_syslog_init(_cfg->si.name, &_cfg->si.d_syslog)) {
114✔
194
        init = false;
×
195
        _sir_selflog("failed to initialize system logger!");
×
196
    }
197
#endif
198

199
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
904✔
200

201
    _sir_selflog("initialized %s", (init ? "successfully" : "with errors")); //-V547
865✔
202

203
    SIR_ASSERT(init);
865✔
204
    return init;
825✔
205
}
206

207
bool _sir_cleanup(void) {
927✔
208
    if (!_sir_sanity())
927✔
209
        return false;
22✔
210

211
    _SIR_LOCK_SECTION(sirfcache, sfc, SIRMI_FILECACHE, false);
902✔
212
    bool cleanup   = true;
784✔
213
    bool destroyfc = _sir_fcache_destroy(sfc);
902✔
214
    SIR_ASSERT(destroyfc);
863✔
215

216
    _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
902✔
217
    _sir_eqland(cleanup, destroyfc);
784✔
218

219
#if !defined(SIR_NO_PLUGINS)
220
    _SIR_LOCK_SECTION(sir_plugincache, spc, SIRMI_PLUGINCACHE, false);
843✔
221
    bool destroypc = _sir_plugin_cache_destroy(spc);
843✔
222
    SIR_ASSERT(destroypc);
804✔
223
    _SIR_UNLOCK_SECTION(SIRMI_PLUGINCACHE);
843✔
224
    _sir_eqland(cleanup, destroypc);
843✔
225
#endif
226

227
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
902✔
228

229
#if !defined(SIR_NO_SYSTEM_LOGGERS)
230
    if (!_sir_syslog_close(&_cfg->si.d_syslog)) {
681✔
231
        cleanup = false;
×
232
        _sir_selflog("error: failed to close system logger!");
×
233
    }
234

235
    _sir_syslog_reset(&_cfg->si.d_syslog);
681✔
236
#endif
237

238
#if !defined(SIR_NO_TEXT_STYLING)
239
    if (!_sir_resettextstyles()) {
902✔
240
        cleanup = false;
×
241
        _sir_selflog("error: failed to reset text styles!");
×
242
    }
243
#endif
244

245
#if defined(__HAVE_ATOMIC_H__)
246
    atomic_store(&_sir_magic, 0);
902✔
247
#else
248
    _sir_magic = 0U;
249
#endif
250

251
    _sir_reset_tls();
902✔
252

253
    (void)memset(_cfg, 0, sizeof(sirconfig));
784✔
254
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
902✔
255

256
    _sir_selflog("cleaned up %s", (cleanup ? "successfully" : "with errors"));
863✔
257

258
    SIR_ASSERT(cleanup);
863✔
259
    return cleanup;
823✔
260
}
261

262
bool _sir_isinitialized(void) {
2,278,614✔
263
#if defined(__HAVE_ATOMIC_H__)
264
    if (_SIR_MAGIC == atomic_load(&_sir_magic))
2,278,614✔
265
        return true;
2,278,510✔
266
#else
267
    if (_SIR_MAGIC == _sir_magic)
268
        return true;
269
#endif
270
    return false;
89✔
271
}
272

273
bool _sir_sanity(void) {
2,278,532✔
274
    if (_sir_isinitialized())
2,278,532✔
275
        return true;
2,237,340✔
276
    return _sir_seterror(_SIR_E_NOTREADY);
71✔
277
}
278

279
bool _sir_init_sanity(const sirinit* si) {
927✔
280
    if (!_sir_validptr(si))
927✔
281
        return false;
×
282

283
    bool levelcheck = true;
806✔
284
    _sir_eqland(levelcheck, _sir_validlevels(si->d_stdout.levels));
927✔
285
    _sir_eqland(levelcheck, _sir_validlevels(si->d_stderr.levels));
927✔
286

287
    bool regcheck = true;
806✔
288
    _sir_eqland(regcheck, SIRL_NONE == si->d_stdout.levels);
887✔
289
    _sir_eqland(regcheck, SIRL_NONE == si->d_stderr.levels);
887✔
290

291
#if !defined(SIR_NO_SYSTEM_LOGGERS)
292
    _sir_eqland(levelcheck, _sir_validlevels(si->d_syslog.levels));
700✔
293
    _sir_eqland(regcheck, SIRL_NONE == si->d_syslog.levels);
660✔
294
#endif
295

296
    if (regcheck)
806✔
297
        _sir_selflog("warning: no level registrations set!");
61✔
298

299
    bool optscheck = true;
806✔
300
    _sir_eqland(optscheck, _sir_validopts(si->d_stdout.opts));
927✔
301
    _sir_eqland(optscheck, _sir_validopts(si->d_stderr.opts));
927✔
302

303
#if !defined(SIR_NO_SYSTEM_LOGGERS)
304
    _sir_eqland(optscheck, _sir_validopts(si->d_syslog.opts));
700✔
305
#endif
306

307
    return levelcheck && optscheck;
927✔
308
}
309

310
void _sir_reset_tls(void) {
1,806✔
311
    _sir_resetstr(_sir_tid);
1,806✔
312
    (void)memset(&_sir_last_thrd_chk, 0, sizeof(sir_time));
1,570✔
313
    _sir_last_timestamp = 0;
1,806✔
314
    _sir_reset_tls_error();
1,806✔
315
}
1,806✔
316

317
static
318
bool _sir_updatelevels(const char* name, sir_levels* old, const sir_levels* new) {
918✔
319
    if (*old != *new) {
918✔
320
        _sir_selflog("updating %s levels from %04"PRIx16" to %04"PRIx16, name, *old, *new);
832✔
321
        *old = *new;
878✔
322
    } else {
323
        _sir_selflog("skipped superfluous update of %s levels: %04"PRIx16, name, *old);
38✔
324
    }
325
    return true;
918✔
326
}
327

328
static
329
bool _sir_updateopts(const char* name, sir_options* old, const sir_options* new) {
31,272✔
330
    if (*old != *new) {
31,272✔
331
        _sir_selflog("updating %s options from %08"PRIx32" to %08"PRIx32, name, *old, *new);
15,037✔
332
        *old = *new;
15,871✔
333
    } else {
334
        _sir_selflog("skipped superfluous update of %s options: %08"PRIx32, name, *old);
14,589✔
335
    }
336
    return true;
31,272✔
337
}
338

339
bool _sir_stdoutlevels(sirinit* si, const sir_update_config_data* data) {
447✔
340
    return _sir_updatelevels(SIR_DESTNAME_STDOUT, &si->d_stdout.levels, data->levels);
447✔
341
}
342

343
bool _sir_stdoutopts(sirinit* si, const sir_update_config_data* data) {
30,801✔
344
    return _sir_updateopts(SIR_DESTNAME_STDOUT, &si->d_stdout.opts, data->opts);
30,801✔
345
}
346

347
bool _sir_stderrlevels(sirinit* si, const sir_update_config_data* data) {
401✔
348
    return _sir_updatelevels(SIR_DESTNAME_STDERR, &si->d_stderr.levels, data->levels);
401✔
349
}
350

351
bool _sir_stderropts(sirinit* si, const sir_update_config_data* data) {
401✔
352
    return _sir_updateopts(SIR_DESTNAME_STDERR, &si->d_stderr.opts, data->opts);
401✔
353
}
354

355
bool _sir_sysloglevels(sirinit* si, const sir_update_config_data* data) {
70✔
356
    bool updated = _sir_updatelevels(SIR_DESTNAME_SYSLOG, &si->d_syslog.levels, data->levels);
70✔
357
    if (updated) {
70✔
358
        _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_LEVELS);
70✔
359
        updated = _sir_syslog_updated(si, data);
70✔
360
        _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_LEVELS);
70✔
361
    }
362
    return updated;
70✔
363
}
364

365
bool _sir_syslogopts(sirinit* si, const sir_update_config_data* data) {
70✔
366
    bool updated = _sir_updateopts(SIR_DESTNAME_SYSLOG, &si->d_syslog.opts, data->opts);
70✔
367
    if (updated) {
70✔
368
        _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_OPTIONS);
70✔
369
        updated = _sir_syslog_updated(si, data);
70✔
370
        _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_OPTIONS);
70✔
371
    }
372
    return updated;
70✔
373
}
374

375
bool _sir_syslogid(sirinit* si, const sir_update_config_data* data) {
122✔
376
    bool cur_valid = _sir_validstrnofail(si->d_syslog.identity);
122✔
377
    if (!cur_valid || 0 != strncmp(si->d_syslog.identity, data->sl_identity, SIR_MAX_SYSLOG_ID)) {
122✔
378
        _sir_selflog("updating %s identity from '%s' to '%s'", SIR_DESTNAME_SYSLOG,
74✔
379
            si->d_syslog.identity, data->sl_identity);
380
        (void)_sir_strncpy(si->d_syslog.identity, SIR_MAX_SYSLOG_ID, data->sl_identity,
74✔
381
            strnlen(data->sl_identity, SIR_MAX_SYSLOG_ID));
70✔
382
    } else {
383
        _sir_selflog("skipped superfluous update of %s identity: '%s'", SIR_DESTNAME_SYSLOG,
45✔
384
            si->d_syslog.identity);
385
        return true;
45✔
386
    }
387

388
    _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_IDENTITY);
74✔
389
    bool updated = _sir_syslog_updated(si, data);
74✔
390
    _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_IDENTITY);
74✔
391

392
    return updated;
74✔
393
}
394

395
bool _sir_syslogcat(sirinit* si, const sir_update_config_data* data) {
84✔
396
    bool cur_valid = _sir_validstrnofail(si->d_syslog.category);
84✔
397
    if (!cur_valid || 0 != strncmp(si->d_syslog.category, data->sl_category, SIR_MAX_SYSLOG_CAT)) {
84✔
398
        _sir_selflog("updating %s category from '%s' to '%s'", SIR_DESTNAME_SYSLOG,
42✔
399
            si->d_syslog.category, data->sl_category);
400
        (void)_sir_strncpy(si->d_syslog.category, SIR_MAX_SYSLOG_CAT, data->sl_category,
42✔
401
            strnlen(data->sl_category, SIR_MAX_SYSLOG_CAT));
40✔
402
    } else {
403
        _sir_selflog("skipped superfluous update of %s category: '%s'", SIR_DESTNAME_SYSLOG,
40✔
404
            si->d_syslog.identity);
405
        return true;
40✔
406
    }
407

408
    _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_CATEGORY);
42✔
409
    bool updated = _sir_syslog_updated(si, data);
42✔
410
    _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_CATEGORY);
42✔
411

412
    return updated;
42✔
413
}
414

415
bool _sir_writeinit(const sir_update_config_data* data, sirinit_update update) {
32,396✔
416
    (void)_sir_seterror(_SIR_E_NOERROR);
32,396✔
417

418
    if (!_sir_sanity() || !_sir_validupdatedata(data) || !_sir_validfnptr(update))
32,396✔
419
        return false;
×
420

421
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
32,396✔
422

423
    bool updated = update(&_cfg->si, data);
32,396✔
424
    if (!updated)
30,691✔
425
        _sir_selflog("error: update routine failed!");
×
426

427
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
32,396✔
428
    return updated;
32,396✔
429
}
430

431
void* _sir_locksection(sir_mutex_id mid) {
8,703,300✔
432
    sir_mutex* m = NULL;
8,703,300✔
433
    void* sec    = NULL;
8,703,300✔
434

435
    bool enter = _sir_mapmutexid(mid, &m, &sec) && _sir_mutexlock(m);
8,703,300✔
436
    SIR_ASSERT(enter);
8,670,579✔
437

438
    return enter ? sec : NULL;
8,704,307✔
439
}
440

441
void _sir_unlocksection(sir_mutex_id mid) {
8,704,062✔
442
    sir_mutex* m = NULL;
8,704,062✔
443
    void* sec    = NULL;
8,704,062✔
444

445
    bool leave = _sir_mapmutexid(mid, &m, &sec) && _sir_mutexunlock(m);
8,704,062✔
446
    SIR_ASSERT_UNUSED(leave, leave);
8,670,727✔
447
}
8,704,496✔
448

449
bool _sir_mapmutexid(sir_mutex_id mid, sir_mutex** m, void** section) {
17,405,653✔
450
    sir_mutex* tmpm;
451
    void* tmpsec;
452

453
    switch (mid) {
17,405,653✔
454
        case SIRMI_CONFIG:
8,481,028✔
455
            tmpm   = &cfg_mutex;
8,481,028✔
456
            tmpsec = &_sir_cfg;
8,481,028✔
457
            break;
8,481,028✔
458
        case SIRMI_FILECACHE:
4,277,597✔
459
            tmpm   = &fc_mutex;
4,236,863✔
460
            tmpsec = &_sir_fc;
4,236,863✔
461
            break;
4,277,597✔
462
        case SIRMI_PLUGINCACHE:
174,147✔
463
            tmpm   = &pc_mutex;
148,161✔
464
            tmpsec = &_sir_pc;
148,161✔
465
            break;
174,147✔
466
        case SIRMI_TEXTSTYLE:
4,397,148✔
467
#if !defined(SIR_NO_TEXT_STYLING)
468
            tmpm   = &ts_mutex;
4,339,897✔
469
            tmpsec = &sir_text_style_section;
4,339,897✔
470
#else
471
            tmpm   = NULL;
472
            tmpsec = NULL;
473
#endif
474
            break;
4,397,148✔
475
        // GCOVR_EXCL_START
476
        default: /* this should never happen. */
477
            SIR_ASSERT(false);
478
            tmpm   = NULL;
479
            tmpsec = NULL;
480
            break;
481
        // GCOVR_EXCL_STOP
482
    }
483

484
    *m = tmpm;
17,408,919✔
485

486
    if (section)
17,408,919✔
487
        *section = tmpsec;
17,405,683✔
488

489
    return *m != NULL && (!section || *section != NULL);
17,408,919✔
490
}
491

492
#if !defined(__WIN__)
493
void _sir_init_static_once(void) {
62✔
494
    (void)_sir_init_common_static();
62✔
495
}
62✔
496
#else /* __WIN__ */
497
BOOL CALLBACK _sir_init_static_once(PINIT_ONCE ponce, PVOID param, PVOID* ctx) {
498
    SIR_UNUSED(ponce);
499
    SIR_UNUSED(param);
500
    SIR_UNUSED(ctx);
501
    return _sir_init_common_static() ? TRUE : FALSE;
502
}
503
#endif
504

505
bool _sir_init_common_static(void) {
62✔
506
#if defined(__HAVE_ATOMIC_H__)
507
    atomic_init(&_sir_magic, 0);
62✔
508
#endif
509

510
#if defined(__WIN__)
511
    (void)QueryPerformanceFrequency(&_sir_perfcntr_freq);
512
#endif
513

514
    bool created = _sir_mutexcreate(&cfg_mutex);
62✔
515
    SIR_ASSERT(created);
60✔
516

517
    _sir_eqland(created, _sir_mutexcreate(&fc_mutex));
62✔
518
    SIR_ASSERT(created);
60✔
519

520
    _sir_eqland(created, _sir_mutexcreate(&pc_mutex));
62✔
521
    SIR_ASSERT(created);
60✔
522

523
#if !defined(SIR_NO_TEXT_STYLING)
524
    _sir_eqland(created, _sir_mutexcreate(&ts_mutex));
62✔
525
    SIR_ASSERT(created);
60✔
526
#endif
527

528
    return created;
62✔
529
}
530

531
bool _sir_once(sir_once* once, sir_once_fn func) {
976✔
532
#if !defined(__WIN__)
533
    int ret = pthread_once(once, func);
976✔
534
    return 0 == ret ? true : _sir_handleerr(ret);
976✔
535
#else /* __WIN__ */
536
    return (FALSE != InitOnceExecuteOnce(once, func, NULL, NULL)) ? true
537
        : _sir_handlewin32err(GetLastError());
538
#endif
539
}
540

541
PRINTF_FORMAT_ATTR(2, 0)
542
bool _sir_logv(sir_level level, PRINTF_FORMAT const char* format, va_list args) {
2,122,989✔
543
    if (!_sir_sanity() || !_sir_validlevel(level) || !_sir_validstr(format))
2,122,989✔
544
        return false;
46✔
545

546
    (void)_sir_seterror(_SIR_E_NOERROR);
2,122,935✔
547

548
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
2,122,936✔
549

550
    sirbuf buf = {0};
2,122,945✔
551

552
    /* from time to time, update the host name in the config, just in case. */
553
    time_t now_sec = -1;
2,122,945✔
554
    if (-1 != time(&now_sec)) {
2,122,945✔
555
#if !defined(SIR_EMBEDDED)
556
        if (now_sec - _cfg->state.last_hname_chk > SIR_HNAME_CHK_INTERVAL) {
2,117,250✔
557
            _sir_selflog("updating hostname...");
6,139✔
558
            if (!_sir_gethostname(_cfg->state.hostname)) {
6,163✔
559
                _sir_selflog("error: failed to get hostname!");
5,689✔
560
            } else {
561
                _cfg->state.last_hname_chk = now_sec;
474✔
562
                _sir_selflog("hostname: '%s'", _cfg->state.hostname);
450✔
563
            }
564
        }
565
#endif
566
    }
567

568
    /* format timestamp (h/m/s only if the integer time has changed). */
569
    long now_msec = 0L;
2,122,945✔
570
    bool gettime = _sir_clock_gettime(SIR_WALLCLOCK, &now_sec, &now_msec);
2,122,945✔
571
    SIR_ASSERT_UNUSED(gettime, gettime);
2,117,256✔
572

573
    /* milliseconds. */
574
    _sir_snprintf_trunc(buf.msec, SIR_MAXMSEC, SIR_MSECFORMAT, now_msec);
2,122,945✔
575

576
    /* hours/minutes/seconds. */
577
    if (now_sec > _sir_last_timestamp || !*_cfg->state.timestamp) {
2,122,945✔
578
        _sir_last_timestamp = now_sec;
6,501✔
579
        bool fmt = _sir_formattime(now_sec, _cfg->state.timestamp, SIR_TIMEFORMAT);
6,501✔
580
        SIR_ASSERT_UNUSED(fmt, fmt);
6,464✔
581
    }
582

583
    /* check elapsed time since updating thread identifier/name. */
584
    sir_time thrd_chk;
585
    double msec_since_thrd_chk = _sir_msec_since(&_sir_last_thrd_chk, &thrd_chk);
2,122,945✔
586

587
    /* update the thread identifier/name if enough time has elapsed. */
588
    if (msec_since_thrd_chk > SIR_THRD_CHK_INTERVAL) {
2,122,945✔
589
        _sir_last_thrd_chk = thrd_chk;
837✔
590

591
        pid_t tid         = _sir_gettid();
837✔
592
        bool resolved_tid = false;
718✔
593
        bool valid_tid    = tid != -1 && tid != 0;
837✔
594

595
#if !defined(SIR_NO_PREFER_THREAD_NAMES)
596
        /* prefer thread names. */
597
        resolved_tid = _sir_getthreadname(_sir_tid);
837✔
598
#else
599
        /* only use thread names if tid is invalid. */
600
        if (!valid_tid)
601
            resolved_tid = _sir_getthreadname(_sir_tid);
602
#endif
603

604
        /* if unresolved and tid is invalid or identical to pid... */
605
        if (!resolved_tid && (!valid_tid || tid == _cfg->state.pid)) {
837✔
606
            /* don't use anything to identify the thread. */
607
            _sir_resetstr(_sir_tid);
172✔
608
            resolved_tid = true;
145✔
609
        }
610

611
        /* fall back on tid. */
612
        if (!resolved_tid)
718✔
NEW
613
            _sir_snprintf_trunc(_sir_tid, SIR_MAXPID, SIR_TIDFORMAT, PID_CAST tid);
×
614
    }
615

616
    sirconfig cfg;
617
    (void)memcpy(&cfg, _cfg, sizeof(sirconfig));
2,105,857✔
618
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
2,122,945✔
619

620
    buf.timestamp = cfg.state.timestamp;
2,122,945✔
621
    buf.hostname  = cfg.state.hostname;
2,122,945✔
622
    buf.pid       = cfg.state.pidbuf;
2,122,945✔
623
    buf.name      = cfg.si.name;
2,122,945✔
624

625
#if !defined(SIR_NO_TEXT_STYLING)
626
    const char* style_str = _sir_gettextstyle(level);
2,122,945✔
627

628
    SIR_ASSERT(NULL != style_str);
2,117,256✔
629
    if (NULL != style_str)
2,111,546✔
630
        (void)_sir_strncpy(buf.style, SIR_MAXSTYLE, style_str,
2,122,945✔
631
            strnlen(style_str, SIR_MAXSTYLE));
632
#endif
633

634
    buf.level = _sir_formattedlevelstr(level);
2,122,944✔
635

636
    if (_sir_validstrnofail(_sir_tid))
2,122,944✔
637
        (void)_sir_strncpy(buf.tid, SIR_MAXPID, _sir_tid,
2,048,300✔
638
            strnlen(_sir_tid, SIR_MAXPID));
639

640
    (void)vsnprintf(buf.message, SIR_MAXMESSAGE, format, args);
2,105,857✔
641

642
    if (!_sir_validstrnofail(buf.message))
2,122,944✔
643
        return _sir_seterror(_SIR_E_INTERNAL);
22✔
644

645
    bool match             = false;
2,105,838✔
646
    bool exit_early        = false;
2,105,838✔
647
    bool update_last_props = true;
2,105,838✔
648
    uint64_t hash          = 0ULL;
2,105,838✔
649

650
    if (cfg.state.last.level == level &&
2,122,922✔
651
        cfg.state.last.prefix[0] == buf.message[0]  &&
2,089,902✔
652
        cfg.state.last.prefix[1] == buf.message[1]) {
2,046,552✔
653
        hash  = FNV64_1a(buf.message);
2,052,839✔
654
        match = cfg.state.last.hash == hash;
2,052,838✔
655
    }
656

657
    if (match) {
2,113,236✔
658
        cfg.state.last.counter++;
34,035✔
659

660
        /* _sir_selflog("message '%s' matches last; incremented counter to %zu", buf.message,
661
            cfg.state.last.counter); */
662

663
        if (cfg.state.last.counter >= cfg.state.last.threshold - 2) {
34,035✔
664
            size_t old_threshold = cfg.state.last.threshold;
960✔
665

666
            update_last_props = false;
960✔
667
            cfg.state.last.threshold *= SIR_SQUELCH_BACKOFF_FACTOR;
1,104✔
668
            cfg.state.last.squelch = true;
1,104✔
669

670
            _sir_selflog("hit squelch threshold of %zu; setting new threshold"
1,056✔
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);
960✔
675
        } else if (cfg.state.last.squelch) {
32,931✔
676
            exit_early = true;
28,140✔
677
        }
678
    } else {
679
        cfg.state.last.squelch   = false;
2,088,886✔
680
        cfg.state.last.counter   = 0;
2,088,886✔
681
        cfg.state.last.threshold = SIR_SQUELCH_THRESHOLD;
2,088,886✔
682
        /* _sir_selflog("message '%s' does not match last; resetting", buf.message); */
683
    }
684

685
    _cfg = _sir_locksection(SIRMI_CONFIG);
2,122,921✔
686
    if (!_cfg)
2,122,922✔
687
        return _sir_seterror(_SIR_E_INTERNAL);
×
688

689
    _cfg->state.last.squelch = cfg.state.last.squelch;
2,122,922✔
690

691
    if (update_last_props) {
2,122,922✔
692
        _cfg->state.last.level     = level;
2,121,818✔
693
        _cfg->state.last.hash      = hash;
2,121,818✔
694
        _cfg->state.last.prefix[0] = buf.message[0];
2,121,818✔
695
        _cfg->state.last.prefix[1] = buf.message[1];
2,121,818✔
696
    }
697

698
    _cfg->state.last.counter   = cfg.state.last.counter;
2,122,922✔
699
    _cfg->state.last.threshold = cfg.state.last.threshold;
2,122,922✔
700

701
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
2,122,922✔
702

703
    if (exit_early)
2,122,921✔
704
        return false;
28,140✔
705

706
    bool dispatched = _sir_dispatch(&cfg.si, level, &buf);
2,090,560✔
707
    return update_last_props ? dispatched : false;
2,090,561✔
708
}
709

710
bool _sir_dispatch(const sirinit* si, sir_level level, sirbuf* buf) {
2,090,560✔
711
    bool retval       = true;
2,077,696✔
712
    size_t dispatched = 0;
2,077,696✔
713
    size_t wanted     = 0;
2,077,696✔
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)) {
2,090,560✔
722
        const char* write = _sir_format(styling, si->d_stdout.opts, buf);
1,085,509✔
723
        bool wrote        = _sir_validstrnofail(write) &&
2,171,019✔
724
            _sir_write_stdout(write, buf->output_len);
1,085,510✔
725
        _sir_eqland(retval, wrote);
1,073,465✔
726

727
        if (wrote)
1,073,465✔
728
            dispatched++;
1,069,539✔
729
        wanted++;
1,073,465✔
730
    }
731

732
    if (_sir_bittest(si->d_stderr.levels, level)) {
2,090,560✔
733
        const char* write = _sir_format(styling, si->d_stderr.opts, buf);
1,329✔
734
        bool wrote        = _sir_validstrnofail(write) &&
2,658✔
735
            _sir_write_stderr(write, buf->output_len);
1,329✔
736
        _sir_eqland(retval, wrote);
1,329✔
737

738
        if (wrote)
1,329✔
739
            dispatched++;
1,320✔
740
        wanted++;
1,329✔
741
    }
742

743
#if !defined(SIR_NO_SYSTEM_LOGGERS)
744
    if (_sir_bittest(si->d_syslog.levels, level)) {
2,067,158✔
745
        if (_sir_syslog_write(level, buf, &si->d_syslog))
718✔
746
            dispatched++;
718✔
747
        wanted++;
718✔
748
    }
749
#endif
750

751
    _SIR_LOCK_SECTION(sirfcache, sfc, SIRMI_FILECACHE, false);
2,090,560✔
752
    size_t fdispatched = 0;
2,090,561✔
753
    size_t fwanted     = 0;
2,090,561✔
754
    _sir_eqland(retval, _sir_fcache_dispatch(sfc, level, buf, &fdispatched, &fwanted));
2,090,561✔
755
    _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
2,090,561✔
756

757
    dispatched += fdispatched;
2,090,560✔
758
    wanted += fwanted;
2,090,560✔
759

760
#if !defined(SIR_NO_PLUGINS)
761
    _SIR_LOCK_SECTION(sir_plugincache, spc, SIRMI_PLUGINCACHE, false);
86,137✔
762
    size_t pdispatched = 0;
86,138✔
763
    size_t pwanted     = 0;
86,138✔
764
    _sir_eqland(retval, _sir_plugin_cache_dispatch(spc, level, buf, &pdispatched, &pwanted));
86,138✔
765
    _SIR_UNLOCK_SECTION(SIRMI_PLUGINCACHE);
86,138✔
766

767
    dispatched += pdispatched;
86,138✔
768
    wanted += pwanted;
86,138✔
769
#endif
770

771
    if (0 == wanted) {
2,090,561✔
772
        _sir_selflog("error: no destinations registered for level %04"PRIx16, level);
792✔
773
        return _sir_seterror(_SIR_E_NODEST);
828✔
774
    }
775

776
    return retval && (dispatched == wanted);
2,089,733✔
777
}
778

779
const char* _sir_format(bool styling, sir_options opts, sirbuf* buf) {
2,158,145✔
780
    if (_sir_validptr(buf)) {
2,158,145✔
781
        bool first = true;
2,134,810✔
782

783
        _sir_resetstr(buf->output);
2,158,143✔
784

785
        if (styling)
2,158,149✔
786
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->style, SIR_MAXSTYLE);
1,086,838✔
787

788
        if (!_sir_bittest(opts, SIRO_NOTIME)) {
2,158,148✔
789
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->timestamp, SIR_MAXTIME);
2,051,485✔
790
            first = false;
2,043,463✔
791

792
#if defined(SIR_MSEC_TIMER)
793
            if (!_sir_bittest(opts, SIRO_NOMSEC))
2,051,484✔
794
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->msec, SIR_MAXMSEC);
36,240✔
795
#endif
796
        }
797

798
        if (!_sir_bittest(opts, SIRO_NOHOST) && _sir_validstrnofail(buf->hostname)) {
2,158,149✔
799
            if (!first)
1,015,421✔
800
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,001,625✔
801
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->hostname, SIR_MAXHOST);
1,015,421✔
802
            first = false;
1,012,674✔
803
        }
804

805
        if (!_sir_bittest(opts, SIRO_NOLEVEL)) {
2,158,133✔
806
            if (!first)
2,106,783✔
807
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
2,051,613✔
808
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->level, SIR_MAXLEVEL);
2,106,783✔
809
            first = false;
2,091,506✔
810
        }
811

812
        bool name = false;
2,134,795✔
813
        if (!_sir_bittest(opts, SIRO_NONAME) && _sir_validstrnofail(buf->name)) {
2,158,137✔
814
            if (!first)
1,051,261✔
815
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,049,645✔
816
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->name, SIR_MAXNAME);
1,051,260✔
817
            first = false;
1,043,176✔
818
            name  = true;
1,043,176✔
819
        }
820

821
        bool wantpid = !_sir_bittest(opts, SIRO_NOPID) && _sir_validstrnofail(buf->pid);
2,158,147✔
822
        bool wanttid = !_sir_bittest(opts, SIRO_NOTID) && _sir_validstrnofail(buf->tid);
2,158,163✔
823

824
        if (wantpid || wanttid) {
2,158,152✔
825
            if (name)
2,066,399✔
826
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDPREFIX, 1);
1,047,729✔
827
            else if (!first)
1,018,670✔
828
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,018,667✔
829

830
            if (wantpid)
2,066,397✔
831
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->pid, SIR_MAXPID);
2,035,165✔
832

833
            if (wanttid) {
2,066,397✔
834
                if (wantpid)
2,063,292✔
835
                    (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDSEPARATOR, 1);
2,032,079✔
836
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->tid, SIR_MAXPID);
2,063,292✔
837
            }
838

839
            if (name)
2,066,398✔
840
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDSUFFIX, 1);
1,047,716✔
841

842
            first = false;
2,055,713✔
843
        }
844

845
        if (!first)
2,147,466✔
846
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, ": ", 2);
2,122,047✔
847

848
        (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->message, SIR_MAXMESSAGE);
2,158,133✔
849

850
        if (styling)
2,158,124✔
851
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_ESC_RST, SIR_MAXSTYLE);
1,086,831✔
852

853
        (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, "\n", 1);
2,158,126✔
854

855
        buf->output_len = strnlen(buf->output, SIR_MAXOUTPUT);
2,158,134✔
856

857
        return buf->output;
2,158,134✔
858
    }
859

860
    return NULL;
×
861
}
862

863
bool _sir_syslog_init(const char* name, sir_syslog_dest* ctx) {
258✔
864
#if !defined(SIR_NO_SYSTEM_LOGGERS)
865
    if (!_sir_validptr(name) || !_sir_validptr(ctx))
258✔
866
        return false;
×
867

868
    /* begin resolve identity. */
869
    if (!_sir_validstrnofail(ctx->identity)) {
258✔
870
        _sir_selflog("ctx->identity is no good; trying name");
63✔
871
        if (_sir_validstrnofail(name)) {
66✔
872
            _sir_selflog("using name");
22✔
873
            (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, name, strnlen(name, SIR_MAX_SYSLOG_ID));
24✔
874
        } else {
875
            _sir_selflog("name is no good; trying filename");
41✔
876
            char* appbasename = _sir_getappbasename();
42✔
877
            if (_sir_validstrnofail(appbasename)) {
42✔
878
                _sir_selflog("filename is good: %s", appbasename);
39✔
879
                (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, appbasename,
39✔
880
                    strnlen(appbasename, SIR_MAX_SYSLOG_ID));
881
            } else {
882
                _sir_selflog("filename no good; using fallback");
3✔
883
                (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, SIR_FALLBACK_SYSLOG_ID,
3✔
884
                    strnlen(SIR_FALLBACK_SYSLOG_ID, SIR_MAX_SYSLOG_ID));
885
            }
886
            _sir_safefree(&appbasename);
42✔
887
        }
888
    } else {
889
        _sir_selflog("already have identity");
181✔
890
    }
891

892
    /* category */
893
    if (!_sir_validstrnofail(ctx->category)) {
258✔
894
        _sir_selflog("category not set; using fallback");
93✔
895
        (void)_sir_strncpy(ctx->category, SIR_MAX_SYSLOG_CAT, SIR_FALLBACK_SYSLOG_CAT,
98✔
896
            strnlen(SIR_FALLBACK_SYSLOG_CAT, SIR_MAX_SYSLOG_CAT));
897
    } else {
898
        _sir_selflog("already have category");
151✔
899
    }
900

901
    _sir_setbitshigh(&ctx->_state.mask, SIRSL_IS_INIT);
258✔
902
    _sir_selflog("resolved (identity: '%s', category: '%s')", ctx->identity, ctx->category);
244✔
903

904
    return _sir_syslog_open(ctx);
258✔
905
#else
906
    SIR_UNUSED(name);
907
    SIR_UNUSED(ctx);
908
    return false;
×
909
#endif
910
}
911

912
bool _sir_syslog_open(sir_syslog_dest* ctx) {
258✔
913
#if !defined(SIR_NO_SYSTEM_LOGGERS)
914
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_INIT)) {
258✔
915
        _sir_selflog("not initialized; ignoring");
×
916
        return _sir_seterror(_SIR_E_INVALID);
×
917
    }
918

919
    if (_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
258✔
920
        _sir_selflog("log already open; ignoring");
×
921
        return true;
×
922
    }
923

924
    _sir_selflog("opening log (levels: %04"PRIx16", options: %08"PRIx32")", ctx->levels,
258✔
925
        ctx->opts);
926

927
# if defined(SIR_OS_LOG_ENABLED)
928
    ctx->_state.logger = (void*)os_log_create(ctx->identity, ctx->category);
929
    _sir_selflog("opened os_log ('%s', '%s')", ctx->identity, ctx->category);
930
# elif defined(SIR_SYSLOG_ENABLED)
931
    int logopt   = LOG_NDELAY | (_sir_bittest(ctx->opts, SIRO_NOPID) ? 0 : LOG_PID);
258✔
932
    int facility = LOG_USER;
216✔
933

934
    openlog(ctx->identity, logopt, facility);
258✔
935
    _sir_selflog("opened syslog('%s', %x, %x)", ctx->identity, logopt, facility);
244✔
936
# elif defined(SIR_EVENTLOG_ENABLED)
937
    DWORD reg = EventRegister(&SIR_EVENTLOG_GUID, NULL, NULL,
938
        (PREGHANDLE)&ctx->_state.logger);
939
    if (ERROR_SUCCESS == reg) {
940
        _sir_selflog("opened eventlog('%s')", ctx->identity);
941
    } else {
942
        /* not fatal; logging calls will just silently fail. */
943
        _sir_selflog("failed to open eventlog! error: %lu", reg);
944
        (void)_sir_handlewin32err(reg);
945
    }
946
# endif
947

948
    _sir_setbitshigh(&ctx->_state.mask, SIRSL_IS_OPEN);
258✔
949
    return true;
258✔
950
#else
951
    SIR_UNUSED(ctx);
952
    return false;
×
953
#endif
954
}
955

956
bool _sir_syslog_write(sir_level level, const sirbuf* buf, const sir_syslog_dest* ctx) {
718✔
957
#if !defined(SIR_NO_SYSTEM_LOGGERS)
958
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_INIT)) {
718✔
959
        _sir_selflog("not initialized; ignoring");
×
960
        return _sir_seterror(_SIR_E_INVALID);
×
961
    }
962

963
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
718✔
964
        _sir_selflog("log not open; ignoring");
×
965
        return _sir_seterror(_SIR_E_INVALID);
×
966
    }
967

968
# if defined(SIR_OS_LOG_ENABLED)
969
    if (SIRL_DEBUG == level)
970
        os_log_debug((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
971
    else if (SIRL_INFO == level || SIRL_NOTICE == level)
972
        os_log_info((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
973
    else if (SIRL_WARN == level || SIRL_ERROR == level)
974
        os_log_error((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
975
    else if (SIRL_CRIT == level || SIRL_ALERT == level || SIRL_EMERG == level)
976
        os_log_fault((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
977

978
    return true;
979
# elif defined(SIR_SYSLOG_ENABLED)
980
    int syslog_level;
981
    switch (level) {
718✔
982
        case SIRL_DEBUG:  syslog_level = LOG_DEBUG; break;
35✔
983
        case SIRL_INFO:   syslog_level = LOG_INFO; break;
38✔
984
        case SIRL_NOTICE: syslog_level = LOG_NOTICE; break;
92✔
985
        case SIRL_WARN:   syslog_level = LOG_WARNING; break;
92✔
986
        case SIRL_ERROR:  syslog_level = LOG_ERR; break;
92✔
987
        case SIRL_CRIT:   syslog_level = LOG_CRIT; break;
118✔
988
        case SIRL_ALERT:  syslog_level = LOG_ALERT; break;
118✔
989
        case SIRL_EMERG:  syslog_level = LOG_EMERG; break;
118✔
990
        // GCOVR_EXCL_START
991
        default: /* this should never happen. */
992
            SIR_ASSERT(false);
993
            syslog_level = LOG_DEBUG;
994
        // GCOVR_EXCL_STOP
995
    }
996

997
    syslog(syslog_level, "%s", buf->message);
718✔
998
    return true;
718✔
999
# elif defined(SIR_EVENTLOG_ENABLED)
1000
    const EVENT_DESCRIPTOR* edesc = NULL;
1001
    if (SIRL_DEBUG == level)
1002
        edesc = &SIR_EVT_DEBUG;
1003
    else if (SIRL_INFO == level || SIRL_NOTICE == level)
1004
        edesc = &SIR_EVT_INFO;
1005
    else if (SIRL_WARN == level)
1006
        edesc = &SIR_EVT_WARNING;
1007
    else if (SIRL_ERROR == level)
1008
        edesc = &SIR_EVT_ERROR;
1009
    else if (SIRL_CRIT == level || SIRL_ALERT == level || SIRL_EMERG == level)
1010
        edesc = &SIR_EVT_CRITICAL;
1011

1012
    SIR_ASSERT(NULL != edesc);
1013
    if (NULL == edesc)
1014
        return _sir_seterror(_SIR_E_INTERNAL);
1015

1016
#  if defined(__HAVE_STDC_SECURE_OR_EXT1__)
1017
    size_t msg_len = strnlen_s(buf->message, SIR_MAXMESSAGE) + 1;
1018
#  else
1019
    size_t msg_len = strnlen(buf->message, SIR_MAXMESSAGE) + 1;
1020
#  endif
1021
    int wlen = MultiByteToWideChar(CP_UTF8, 0UL, buf->message, (int)msg_len, NULL, 0);
1022
    if (wlen <= 0)
1023
        return _sir_handlewin32err(GetLastError());
1024

1025
    DWORD write = 1UL;
1026
    wchar_t* wmsg = calloc(sizeof(wchar_t), wlen);
1027
    if (NULL != wmsg) {
1028
        int conv = MultiByteToWideChar(CP_UTF8, 0UL, buf->message, (int)msg_len, wmsg, wlen);
1029
        if (conv > 0) {
1030
            EVENT_DATA_DESCRIPTOR eddesc = {0};
1031
            EventDataDescCreate(&eddesc, wmsg, (ULONG)(wlen * sizeof(wchar_t)));
1032

1033
            write = EventWrite((REGHANDLE)ctx->_state.logger, edesc, 1UL, &eddesc);
1034
            if (ERROR_SUCCESS != write) {
1035
                _sir_selflog("failed to write eventlog! error: %lu", write);
1036
                (void)_sir_handlewin32err(write);
1037
            }
1038
        }
1039
        _sir_safefree(&wmsg);
1040
    }
1041

1042
    return ERROR_SUCCESS == write;
1043
# else
1044
    SIR_UNUSED(level);
1045
    SIR_UNUSED(buf);
1046
    SIR_UNUSED(ctx);
1047
    return false;
1048
# endif
1049
#else
1050
    SIR_UNUSED(level);
1051
    SIR_UNUSED(buf);
1052
    SIR_UNUSED(ctx);
1053
    return false;
×
1054
#endif
1055
}
1056

1057
bool _sir_syslog_updated(sirinit* si, const sir_update_config_data* data) {
256✔
1058
#if !defined(SIR_NO_SYSTEM_LOGGERS)
1059
    if (!_sir_validptr(si) || !_sir_validptr(data))
256✔
1060
        return false;
×
1061

1062
    if (_sir_bittest(si->d_syslog._state.mask, SIRSL_UPDATED)) {
256✔
1063
        bool levels   = _sir_bittest(si->d_syslog._state.mask, SIRSL_LEVELS);
242✔
1064
        bool options  = _sir_bittest(si->d_syslog._state.mask, SIRSL_OPTIONS);
256✔
1065
        bool category = _sir_bittest(si->d_syslog._state.mask, SIRSL_CATEGORY);
242✔
1066
        bool identity = _sir_bittest(si->d_syslog._state.mask, SIRSL_IDENTITY);
256✔
1067
        bool is_init  = _sir_bittest(si->d_syslog._state.mask, SIRSL_IS_INIT);
256✔
1068
        bool is_open  = _sir_bittest(si->d_syslog._state.mask, SIRSL_IS_OPEN);
256✔
1069

1070
        _sir_selflog("config update: (levels: %u, options: %u, category: %u,"
242✔
1071
                     " identity: %u, is_init: %u, is_open: %u)",
1072
                     levels, options, category, identity, is_init, is_open);
1073

1074
        bool must_init = false;
213✔
1075
# if defined(SIR_OS_LOG_ENABLED)
1076
        /* for os_log, if initialized and open already, only need to reconfigure
1077
         * if identity or category changed. */
1078
        must_init = (!is_init || !is_open) || (identity || category);
1079
# elif defined(SIR_SYSLOG_ENABLED)
1080
        /* for syslog, if initialized and open already, only need to reconfigure
1081
         * if identity or options changed. */
1082
        must_init = (!is_init || !is_open) || (identity || options);
256✔
1083
# elif defined(SIR_EVENTLOG_ENABLED)
1084
        /* for event log, if initialized and open already, only need to reconfigure
1085
         * if identity changed. */
1086
        must_init = (!is_init || !is_open) || identity;
1087
# endif
1088
        bool init = true;
213✔
1089
        if (must_init) {
213✔
1090
            if (is_open) /* close first; open will fail otherwise. */
144✔
1091
                init = _sir_syslog_close(&si->d_syslog);
118✔
1092

1093
            _sir_selflog("re-init...");
136✔
1094
            _sir_eqland(init, _sir_syslog_init(si->name, &si->d_syslog));
144✔
1095
            _sir_selflog("re-init %s", init ? "succeeded" : "failed");
136✔
1096
        } else {
1097
            _sir_selflog("no re-init necessary");
106✔
1098
        }
1099

1100
        return init;
256✔
1101
    }
1102

1103
    return false;
×
1104
#else
1105
    SIR_UNUSED(si);
1106
    SIR_UNUSED(data);
1107
    return false;
×
1108
#endif
1109
}
1110

1111
bool _sir_syslog_close(sir_syslog_dest* ctx) {
799✔
1112
#if !defined(SIR_NO_SYSTEM_LOGGERS)
1113
    if (!_sir_validptr(ctx))
799✔
1114
        return false;
×
1115

1116
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
799✔
1117
        _sir_selflog("log not open; ignoring");
509✔
1118
        return true;
509✔
1119
    }
1120

1121
# if defined(SIR_OS_LOG_ENABLED)
1122
    /* Evidently, you don't need to close the handle returned from os_log_create(), and
1123
     * if you make that call again, you'll get the same cached value. so let's keep the
1124
     * value we've got in the global context. */
1125
    _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
1126
    _sir_selflog("log closure not necessary");
1127
    return true;
1128
# elif defined(SIR_SYSLOG_ENABLED)
1129
    closelog();
258✔
1130
    _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
258✔
1131
    _sir_selflog("closed log");
244✔
1132
    return true;
258✔
1133
# elif defined(SIR_EVENTLOG_ENABLED)
1134
    ULONG unreg = EventUnregister((REGHANDLE)ctx->_state.logger);
1135
    _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
1136
    if (ERROR_SUCCESS == unreg)
1137
        _sir_selflog("closed log");
1138
    else
1139
        _sir_selflog("error: failed to close log");
1140

1141
    return ERROR_SUCCESS == unreg;
1142
# else
1143
    SIR_UNUSED(ctx);
1144
    return false;
1145
# endif
1146
#else
1147
    SIR_UNUSED(ctx);
1148
    return false;
×
1149
#endif
1150
}
1151

1152
void _sir_syslog_reset(sir_syslog_dest* ctx) {
1,364✔
1153
#if !defined(SIR_NO_SYSTEM_LOGGERS)
1154
    if (_sir_validptr(ctx)) {
1,364✔
1155
        uint32_t old       = ctx->_state.mask;
1,286✔
1156
        ctx->_state.mask   = 0U;
1,364✔
1157
        ctx->_state.logger = NULL;
1,364✔
1158
        _sir_selflog("state reset; mask was %08"PRIx32, old);
1,286✔
1159
    }
1160
#else
1161
    SIR_UNUSED(ctx);
1162
#endif
1163
}
1,364✔
1164

1165
const char* _sir_formattedlevelstr(sir_level level) {
2,122,944✔
1166
    static const size_t low  = 0;
1167
    static const size_t high = SIR_NUMLEVELS - 1;
1168

1169
    const char* retval = SIR_UNKNOWN;
2,105,856✔
1170

1171
    _SIR_DECLARE_BIN_SEARCH(low, high);
2,105,856✔
1172
    _SIR_BEGIN_BIN_SEARCH()
1173

1174
    if (sir_level_to_str_map[_mid].level == level) {
8,467,432✔
1175
        retval = sir_level_to_str_map[_mid].fmt;
2,122,945✔
1176
        break;
2,122,945✔
1177
    }
1178

1179
    _SIR_ITERATE_BIN_SEARCH((sir_level_to_str_map[_mid].level < level ? 1 : -1));
6,344,487✔
1180
    _SIR_END_BIN_SEARCH();
1181

1182
    return retval;
2,122,944✔
1183
}
1184

1185
bool _sir_clock_gettime(int clock, time_t* tbuf, long* msecbuf) {
6,245,973✔
1186
    if (tbuf) {
6,245,973✔
1187
#if defined(SIR_MSEC_POSIX)
1188
        struct timespec ts = {0};
6,245,973✔
1189
        int ret            = clock_gettime(clock, &ts);
6,245,973✔
1190
        SIR_ASSERT(0 == ret);
6,234,592✔
1191

1192
        if (0 == ret) {
6,223,169✔
1193
            *tbuf = ts.tv_sec;
6,234,656✔
1194
            if (msecbuf)
6,234,656✔
1195
                *msecbuf = ts.tv_nsec / 1000000L;
6,234,656✔
1196
        } else {
1197
            if (msecbuf)
11,317✔
1198
                *msecbuf = 0L;
11,317✔
1199
            return _sir_handleerr(errno);
11,317✔
1200
        }
1201
#elif defined(SIR_MSEC_WIN32)
1202
        SIR_UNUSED(clock);
1203
        static const ULONGLONG uepoch = (ULONGLONG)116444736e9;
1204

1205
        FILETIME ftutc = {0};
1206
        GetSystemTimePreciseAsFileTime(&ftutc);
1207

1208
        ULARGE_INTEGER ftnow = {0};
1209
        ftnow.HighPart = ftutc.dwHighDateTime;
1210
        ftnow.LowPart  = ftutc.dwLowDateTime;
1211
        ftnow.QuadPart = (ULONGLONG)((ftnow.QuadPart - uepoch) / 10000000ULL);
1212

1213
        *tbuf = (time_t)ftnow.QuadPart;
1214

1215
        SYSTEMTIME st = {0};
1216
        if (FileTimeToSystemTime(&ftutc, &st)) {
1217
            if (msecbuf)
1218
                *msecbuf = (long)st.wMilliseconds;
1219
        } else {
1220
            if (msecbuf)
1221
                *msecbuf = 0L;
1222
            return _sir_handlewin32err(GetLastError());
1223
        }
1224
#else
1225
        SIR_UNUSED(clock);
1226
        (void)time(tbuf);
1227
        if (msecbuf)
1228
            *msecbuf = 0L;
1229
#endif
1230
        return true;
6,234,656✔
1231
    }
1232
    return false;
×
1233
}
1234

1235
double _sir_msec_since(const sir_time* when, sir_time* out) {
4,123,028✔
1236
    if (!_sir_validptr(out))
4,123,028✔
1237
        return 0.0;
×
1238
#if !defined(__WIN__)
1239
    out->sec = 0;
4,123,028✔
1240
    out->msec = 0L;
4,123,028✔
1241

1242
    bool gettime = _sir_clock_gettime(SIR_INTERVALCLOCK, &out->sec, &out->msec);
4,123,028✔
1243
    SIR_ASSERT(gettime);
4,117,336✔
1244

1245
    if (!_sir_validptrnofail(when) || !gettime || (out->sec < when->sec ||
4,123,028✔
1246
        (out->sec == when->sec && out->msec < when->msec)))
4,116,015✔
1247
        return 0.0;
5,705✔
1248

1249
    return ((((double)out->sec) * 1e3) + (double)out->msec) -
4,117,317✔
1250
           ((((double)when->sec) * 1e3) + (double)when->msec);
4,117,317✔
1251
#else /* __WIN__ */
1252
    SIR_ASSERT(_sir_perfcntr_freq.QuadPart > 0LL);
1253

1254
    if (_sir_perfcntr_freq.QuadPart <= 0LL)
1255
        (void)QueryPerformanceFrequency(&_sir_perfcntr_freq);
1256

1257
    (void)QueryPerformanceCounter(&out->counter);
1258

1259
    if (!_sir_validptrnofail(when) || out->counter.QuadPart <= when->counter.QuadPart)
1260
        return 0.0;
1261

1262
    double msec_ratio = ((double)_sir_perfcntr_freq.QuadPart) / 1e3;
1263
    return ((double)(out->counter.QuadPart - when->counter.QuadPart)) / msec_ratio;
1264
#endif
1265
}
1266

1267
pid_t _sir_getpid(void) {
921✔
1268
#if !defined(__WIN__)
1269
    return getpid();
921✔
1270
#else /* __WIN__ */
1271
    return (pid_t)GetCurrentProcessId();
1272
#endif
1273
}
1274

1275
pid_t _sir_gettid(void) {
978✔
1276
    pid_t tid = 0;
838✔
1277
#if defined(__MACOS__)
1278
    uint64_t tid64 = 0ULL;
1279
    int gettid     = pthread_threadid_np(NULL, &tid64);
1280
    if (0 != gettid)
1281
        (void)_sir_handleerr(gettid);
1282
    tid = (pid_t)tid64;
1283
#elif (defined(__BSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)) || \
1284
      defined(__DragonFly_getthreadid__)
1285
    tid = (pid_t)pthread_getthreadid_np();
1286
#elif defined(__OpenBSD__)
1287
    tid = (pid_t)getthrid();
1288
#elif defined(__SOLARIS__) || defined(__NetBSD__) || defined(__HURD__) || \
1289
      defined(__DragonFly__) || defined(__CYGWIN__) || defined(_AIX) || \
1290
      defined(__EMSCRIPTEN__)
1291
# if defined(__CYGWIN__)
1292
    tid = (pid_t)(uintptr_t)pthread_self();
1293
# else
1294
    tid = (pid_t)pthread_self();
1295
# endif
1296
#elif defined(__HAIKU__)
1297
    tid = get_pthread_thread_id(pthread_self());
1298
#elif defined(__linux__) || defined(__serenity__)
1299
# if (defined(__GLIBC__) && GLIBC_VERSION >= 23000) || defined(__serenity__)
1300
    tid = gettid();
978✔
1301
# else
1302
    tid = syscall(SYS_gettid);
1303
# endif
1304
#elif defined(__WIN__)
1305
    tid = (pid_t)GetCurrentThreadId();
1306
#elif defined(ESP32) || defined(ESP8266)
1307
    tid = (pid_t)(uintptr_t)xTaskGetCurrentTaskHandle();
1308
#else
1309
# error "unable to determine how to obtain the current thread identifier."
1310
#endif
1311
    return tid;
978✔
1312
}
1313

1314
bool _sir_getthreadname(char name[SIR_MAXPID]) {
837✔
1315
    _sir_resetstr(name);
837✔
1316
#if defined(__MACOS__) || (defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_12_2__)) || \
1317
    (defined(__linux__) && defined(__UCLIBC__) && defined(_GNU_SOURCE)) || \
1318
    (defined(__GLIBC__) && GLIBC_VERSION >= 21200 && defined(_GNU_SOURCE)) || \
1319
    (defined(__ANDROID__) &&  __ANDROID_API__ >= 26) || defined(SIR_PTHREAD_GETNAME_NP) || \
1320
    defined(__serenity__) || (defined(__linux__) && !defined(__GLIBC__) && \
1321
    defined(_GNU_SOURCE) && defined(__NEED_pthread_t))
1322
    int ret = pthread_getname_np(pthread_self(), name, SIR_MAXPID);
837✔
1323
    if (0 != ret)
837✔
1324
        return _sir_handleerr(ret);
×
1325
# if defined(__HAIKU__)
1326
    if (!(strncmp(name, "pthread func", SIR_MAXPID)))
1327
        (void)snprintf(name, SIR_MAXPID, "%ld", (long)get_pthread_thread_id(pthread_self()));
1328
# endif
1329
    return _sir_validstrnofail(name);
837✔
1330
#elif defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_11_3__)
1331
    pthread_get_name_np(pthread_self(), name, SIR_MAXPID);
1332
    return _sir_validstrnofail(name);
1333
#elif defined(__WIN__)
1334
    wchar_t* wname = NULL;
1335
    HRESULT hr     = GetThreadDescription(GetCurrentThread(), &wname);
1336
    if (FAILED(hr))
1337
        return _sir_handlewin32err(GetLastError());
1338
    bool success = true;
1339
# if defined(__HAVE_STDC_SECURE_OR_EXT1__)
1340
    size_t wlen = wcsnlen_s(wname, SIR_MAXPID);
1341
# elif defined(__EMBARCADEROC__) && (__clang_major__ < 15)
1342
    size_t wlen = wcslen(wname);
1343
# else
1344
    size_t wlen = wcsnlen(wname, SIR_MAXPID);
1345
# endif
1346
    if (wlen > 0) {
1347
        if (!WideCharToMultiByte(CP_UTF8, 0UL, wname, (int)wlen, name,
1348
            SIR_MAXPID, NULL, NULL)) {
1349
            success = false;
1350
            (void)_sir_handlewin32err(GetLastError());
1351
        }
1352
    }
1353
    (void)LocalFree(wname);
1354
    return success && _sir_validstrnofail(name);
1355
#elif defined(ESP32) || defined(ESP8266)
1356
    char *task_name = pcTaskGetName(NULL);
1357
    if (_sir_validstr(task_name)) {
1358
        (void)_sir_strncpy(name, SIR_MAXPID, task_name, strnlen(task_name, SIR_MAXPID));
1359
        return true;
1360
    }
1361
    return false;
1362
#else
1363
# if !defined(SUNLINT) && !defined(_AIX) && !defined(__HURD__)
1364
#  pragma message("unable to determine how to get a thread name")
1365
# endif
1366
    SIR_UNUSED(name);
1367
    return false;
1368
#endif
1369
}
1370

1371
bool _sir_setthreadname(const char* name) {
209✔
1372
    if (!_sir_validptr(name))
209✔
1373
        return false;
×
1374
#if defined(__MACOS__)
1375
    int ret = pthread_setname_np(name);
1376
    return (0 != ret) ? _sir_handleerr(ret) : true;
1377
#elif defined(__HAIKU__)
1378
    status_t ret = rename_thread(find_thread(NULL), name);
1379
    return (B_OK != ret) ? _sir_handleerr((int)ret) : true;
1380
#elif defined(__NetBSD__)
1381
    int ret = pthread_setname_np(pthread_self(), "%s", name);
1382
    return (0 != ret) ? _sir_handleerr(ret) : true;
1383
#elif (defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_12_2__)) || \
1384
      (defined(__linux__) && defined(__UCLIBC__) && defined(_GNU_SOURCE)) || \
1385
      (defined(__GLIBC__) && GLIBC_VERSION >= 21200 && defined(_GNU_SOURCE)) || \
1386
       defined(__QNXNTO__) || defined(__SOLARIS__) || defined(SIR_PTHREAD_GETNAME_NP) || \
1387
       defined(__ANDROID__) && !defined(__OpenBSD__) || defined(__serenity__) || \
1388
      (defined(__linux__) && !defined(__GLIBC__) && \
1389
       defined(_GNU_SOURCE) && defined(__NEED_pthread_t))
1390
    int ret = pthread_setname_np(pthread_self(), name);
209✔
1391
    return (0 != ret) ? _sir_handleerr(ret) : true;
209✔
1392
#elif defined(__OpenBSD__) || defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_11_3__)
1393
    pthread_set_name_np(pthread_self(), name);
1394
    return true;
1395
#elif defined(__WIN__)
1396
# if defined(__HAVE_STDC_SECURE_OR_EXT1__)
1397
    size_t name_len = strnlen_s(name, SIR_MAXPID);
1398
# else
1399
    size_t name_len = strnlen(name, SIR_MAXPID);
1400
# endif
1401
    if (0 == name_len)
1402
        name_len = 1;
1403

1404
    wchar_t buf[SIR_MAXPID] = {0};
1405
    if (!MultiByteToWideChar(CP_UTF8, 0UL, name, (int)name_len, buf, SIR_MAXPID))
1406
        return _sir_handlewin32err(GetLastError());
1407

1408
    HRESULT hr = SetThreadDescription(GetCurrentThread(), buf);
1409
    return FAILED(hr) ? _sir_handlewin32err(hr) : true;
1410
#else
1411
# if !defined(SUNLINT) && !defined(_AIX)
1412
#  pragma message("unable to determine how to set a thread name")
1413
# endif
1414
    SIR_UNUSED(name);
1415
    return false;
1416
#endif
1417
}
1418

1419
bool _sir_gethostname(char name[SIR_MAXHOST]) {
6,163✔
1420
#if defined(SIR_EMBEDDED)
1421
# pragma message("obtaining the machine's hostname is not implemented.")
1422
    _sir_resetstr(name);
1423
    return true;
1424
#endif
1425
#if !defined(__WIN__)
1426
    int ret = gethostname(name, SIR_MAXHOST - 1);
6,090✔
1427
    return 0 == ret ? true : _sir_handleerr(errno);
6,163✔
1428
#else
1429
    WSADATA wsad = {0};
1430
    int ret      = WSAStartup(MAKEWORD(2, 2), &wsad);
1431
    if (0 != ret)
1432
        return _sir_handlewin32err(ret);
1433

1434
    if (SOCKET_ERROR == gethostname(name, SIR_MAXHOST)) {
1435
        int err = WSAGetLastError();
1436
        WSACleanup();
1437
        return _sir_handlewin32err(err);
1438
    }
1439

1440
    WSACleanup();
1441
    return true;
1442
#endif /* !__WIN__ */
1443
}
1444

1445
long __sir_nprocs(bool test_mode) {
23✔
1446
    long nprocs = 0;
20✔
1447

1448
#if defined(_AIX)
1449
    nprocs = (long)_system_configuration.ncpus;
1450
    _sir_selflog("AIX _system_configuration.ncpus reports %ld processor(s)", nprocs);
1451
#endif
1452

1453
#if defined(__WIN__)
1454
    SYSTEM_INFO system_info;
1455
    ZeroMemory(&system_info, sizeof(system_info));
1456
    GetSystemInfo(&system_info);
1457
    nprocs = (long)system_info.dwNumberOfProcessors;
1458
    _sir_selflog("Windows GetSystemInfo() reports %ld processor(s)", nprocs);
1459
#endif
1460

1461
#if defined(__HAIKU__)
1462
    system_info hinfo;
1463
    get_system_info(&hinfo);
1464
    nprocs = (long)hinfo.cpu_count;
1465
    _sir_selflog("Haiku get_system_info() reports %ld processor(s)", nprocs);
1466
#endif
1467

1468
#if defined(SC_NPROCESSORS_ONLN)
1469
# define SIR_SC_NPROCESSORS SC_NPROCESSORS_ONLN
1470
#elif defined(_SC_NPROCESSORS_ONLN)
1471
# define SIR_SC_NPROCESSORS _SC_NPROCESSORS_ONLN
1472
#endif
1473
#if defined(SIR_SC_NPROCESSORS)
1474
    long tprocs = sysconf(SIR_SC_NPROCESSORS);
23✔
1475
    _sir_selflog("sysconf() reports %ld processor(s)", tprocs);
22✔
1476
    if (tprocs > nprocs)
23✔
1477
        nprocs = tprocs;
20✔
1478
#endif
1479

1480
#if defined(__linux__) && defined(CPU_COUNT) && !defined(__ANDROID__) && !defined(__UCLIBC__)
1481
    long ctprocs;
1482
    cpu_set_t p_aff;
1483
    memset(&p_aff, 0, sizeof(p_aff));
20✔
1484
    if (sched_getaffinity(0, sizeof(p_aff), &p_aff)) {
23✔
1485
        ctprocs = 0;
×
1486
    } else {
1487
        ctprocs = CPU_COUNT(&p_aff);
23✔
1488
        _sir_selflog("sched_getaffinity() reports %ld processor(s)", ctprocs);
22✔
1489
    }
1490
    if (ctprocs > nprocs)
23✔
1491
        nprocs = ctprocs;
×
1492
#endif
1493

1494
#if defined(CTL_HW) && defined(HW_AVAILCPU)
1495
    int ntprocs = 0;
1496
    size_t sntprocs = sizeof(ntprocs);
1497
    if (sysctl ((int[2]) {CTL_HW, HW_AVAILCPU}, 2, &ntprocs, &sntprocs, NULL, 0)) {
1498
        ntprocs = 0;
1499
    } else {
1500
        _sir_selflog("sysctl(CTL_HW, HW_AVAILCPU) reports %d processor(s)", ntprocs);
1501
        if (ntprocs > nprocs)
1502
            nprocs = (long)ntprocs;
1503
    }
1504
#elif defined(CTL_HW) && defined(HW_NCPU)
1505
    int ntprocs = 0;
1506
    size_t sntprocs = sizeof(ntprocs);
1507
    if (sysctl ((int[2]) {CTL_HW, HW_NCPU}, 2, &ntprocs, &sntprocs, NULL, 0)) {
1508
        ntprocs = 0;
1509
    } else {
1510
        _sir_selflog("sysctl(CTL_HW, HW_NCPU) reports %d processor(s)", ntprocs);
1511
        if (ntprocs > nprocs)
1512
            nprocs = (long)ntprocs;
1513
    }
1514
#elif defined(CTL_HW) && defined(HW_NCPUFOUND)
1515
    int ntprocs = 0;
1516
    size_t sntprocs = sizeof(ntprocs);
1517
    if (sysctl ((int[2]) {CTL_HW, HW_NCPUFOUND}, 2, &ntprocs, &sntprocs, NULL, 0)) {
1518
        ntprocs = 0;
1519
    } else {
1520
        _sir_selflog("sysctl(CTL_HW, HW_NCPUFOUND) reports %d processor(s)", ntprocs);
1521
        if (ntprocs > nprocs)
1522
            nprocs = (long)ntprocs;
1523
    }
1524
#endif
1525

1526
#if defined(__MACOS__)
1527
    int antprocs = 0;
1528
    size_t asntprocs = sizeof(antprocs);
1529
    if (sysctlbyname("hw.ncpu", &antprocs, &asntprocs, NULL, 0)) {
1530
        antprocs = 0;
1531
    } else {
1532
        _sir_selflog("sysctlbyname(hw.ncpu) reports %d processor(s)", antprocs);
1533
        if (antprocs > nprocs)
1534
            nprocs = (long)antprocs;
1535
    }
1536
#endif
1537

1538
#if defined(__QNX__) || defined(__QNXNTO__)
1539
    long qtprocs = (long)_syspage_ptr->num_cpu;
1540
    _sir_selflog("QNX _syspage_ptr->num_cpu reports %ld processor(s)", qtprocs);
1541
    if (qtprocs > nprocs)
1542
        nprocs = qtprocs;
1543
#endif
1544

1545
#if defined(__VXWORKS__)
1546
# if defined(_WRS_CONFIG_SMP)
1547
    long vtprocs = 0;
1548
    cpuset_t vset = vxCpuEnabledGet();
1549
    for (int count = 0; count < 512 && !CPUSET_ISZERO(vset); ++count) {
1550
        if (CPUSET_ISSET(vset, count)) {
1551
            CPUSET_CLR(vset, count);
1552
            vtprocs++;
1553
        }
1554
    }
1555
    _sir_selflog("VxWorks vxCpuEnabledGet() reports %ld processor(s)", vtprocs);
1556
# else
1557
    long vtprocs = 1;
1558
    _sir_selflog("Uniprocessor system or VxWorks SMP is not enabled");
1559
# endif
1560
    if (vtprocs > nprocs)
1561
        nprocs = vtprocs;
1562
#endif
1563

1564
    if (nprocs < 1) {
23✔
1565
        _sir_selflog(BRED("Failed to determine processor count!"));
×
1566
        if (!test_mode)
×
1567
            nprocs = 1;
×
1568
    }
1569

1570
    _sir_selflog("Detected %ld processor(s)", nprocs);
22✔
1571
    return nprocs;
23✔
1572
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc