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

aremmell / libsir / 1890

27 Mar 2025 07:24AM UTC coverage: 95.499%. Remained the same
1890

Pull #452

gitlab-ci

johnsonjh
Merge branch 'master' into 20250326/johnsonjh/ci

Signed-off-by: Jeffrey H. Johnson <trnsz@pobox.com>
Pull Request #452: CI overhaul; update Doxygen

3692 of 3866 relevant lines covered (95.5%)

355137.13 hits per line

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

93.6
/src/sirinternal.c
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) {
81✔
91
    bool retval = _sir_validptr(si);
81✔
92

93
    if (retval) {
81✔
94
        (void)memset(si, 0, sizeof(sirinit));
72✔
95

96
        si->d_stdout.opts   = SIRO_DEFAULT;
81✔
97
        si->d_stdout.levels = SIRL_DEFAULT;
81✔
98

99
        si->d_stderr.opts   = SIRO_DEFAULT;
81✔
100
        si->d_stderr.levels = SIRL_DEFAULT;
81✔
101

102
#if !defined(SIR_NO_SYSTEM_LOGGERS)
103
        si->d_syslog.opts   = SIRO_DEFAULT;
68✔
104
        si->d_syslog.levels = SIRL_DEFAULT;
68✔
105
#else
106
        si->d_syslog.opts   = SIRO_MSGONLY;
107
        si->d_syslog.levels = SIRL_NONE;
108
#endif
109
    }
110

111
    return retval;
81✔
112
}
113

114
bool _sir_init(sirinit* si) {
1,146✔
115
    (void)_sir_seterror(_SIR_E_NOERROR);
1,146✔
116

117
    /* can only fail on Windows. */
118
    bool once_init = _sir_once(&static_once, _sir_init_static_once);
1,146✔
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))
1,146✔
129
        return false;
23✔
130

131
#if defined(__HAVE_ATOMIC_H__)
132
    if (_SIR_MAGIC == atomic_load(&_sir_magic))
1,119✔
133
#else
134
    if (_SIR_MAGIC == _sir_magic)
135
#endif
136
        return _sir_seterror(_SIR_E_ALREADY);
30✔
137

138
    _sir_defaultlevels(&si->d_stdout.levels, sir_stdout_def_lvls);
1,089✔
139
    _sir_defaultopts(&si->d_stdout.opts, sir_stdout_def_opts);
1,089✔
140

141
    _sir_defaultlevels(&si->d_stderr.levels, sir_stderr_def_lvls);
1,089✔
142
    _sir_defaultopts(&si->d_stderr.opts, sir_stderr_def_opts);
1,089✔
143

144
#if !defined(SIR_NO_SYSTEM_LOGGERS)
145
    _sir_defaultlevels(&si->d_syslog.levels, sir_syslog_def_lvls);
862✔
146
    _sir_defaultopts(&si->d_syslog.opts, sir_syslog_def_opts);
862✔
147
#endif
148

149
    if (!_sir_init_sanity(si))
1,089✔
150
        return false;
23✔
151

152
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
1,062✔
153

154
    bool init = true;
905✔
155

156
#if defined(__HAVE_ATOMIC_H__)
157
    atomic_store(&_sir_magic, _SIR_MAGIC);
1,062✔
158
#else
159
    _sir_magic = _SIR_MAGIC;
160
#endif
161

162
    _sir_reset_tls();
1,062✔
163

164
#if defined(__WIN__)
165
    _sir_initialize_stdio();
166
#else
167
    tzset();
1,062✔
168
#endif
169

170
#if !defined(SIR_NO_TEXT_STYLING)
171
    if (!_sir_setcolormode(SIRCM_16)) {
945✔
172
        init = false;
×
173
        _sir_selflog("error: failed to set color mode!");
×
174
    }
175

176
    if (!_sir_resettextstyles()) {
945✔
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));
1,062✔
183
    (void)memcpy(&_cfg->si, si, sizeof(sirinit));
1,062✔
184

185
    /* forcibly null-terminate the process name. */
186
    _cfg->si.name[SIR_MAXNAME - 1] = '\0';
1,062✔
187

188
    /* store PID. */
189
    _cfg->state.pid = _sir_getpid();
1,062✔
190

191
    (void)snprintf(_cfg->state.pidbuf, SIR_MAXPID, SIR_PIDFORMAT,
1,062✔
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);
841✔
197

198
    if (_cfg->si.d_syslog.levels != SIRL_NONE &&
865✔
199
        !_sir_syslog_init(_cfg->si.name, &_cfg->si.d_syslog)) {
138✔
200
        init = false;
×
201
        _sir_selflog("failed to initialize system logger!");
×
202
    }
203
#endif
204

205
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
1,062✔
206

207
    _sir_selflog("initialized %s", (init ? "successfully" : "with errors")); //-V547
984✔
208

209
    SIR_ASSERT(init);
982✔
210
    return init;
983✔
211
}
212

213
bool _sir_cleanup(void) {
1,089✔
214
    if (!_sir_sanity())
1,089✔
215
        return false;
25✔
216

217
    _SIR_LOCK_SECTION(sirfcache, sfc, SIRMI_FILECACHE, false);
1,060✔
218
    bool cleanup   = true;
903✔
219
    bool destroyfc = _sir_fcache_destroy(sfc);
1,060✔
220
    SIR_ASSERT(destroyfc);
980✔
221

222
    _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
1,060✔
223
    _sir_eqland(cleanup, destroyfc);
903✔
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);
1,060✔
234

235
#if !defined(SIR_NO_SYSTEM_LOGGERS)
236
    if (!_sir_syslog_close(&_cfg->si.d_syslog)) {
839✔
237
        cleanup = false;
×
238
        _sir_selflog("error: failed to close system logger!");
×
239
    }
240

241
    _sir_syslog_reset(&_cfg->si.d_syslog);
839✔
242
#endif
243

244
#if !defined(SIR_NO_TEXT_STYLING)
245
    if (!_sir_resettextstyles()) {
943✔
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);
1,060✔
253
#else
254
    _sir_magic = 0U;
255
#endif
256

257
    _sir_reset_tls();
1,060✔
258

259
    (void)memset(_cfg, 0, sizeof(sirconfig));
903✔
260
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
1,060✔
261

262
    _sir_selflog("cleaned up %s", (cleanup ? "successfully" : "with errors"));
982✔
263

264
    SIR_ASSERT(cleanup);
980✔
265
    return cleanup;
981✔
266
}
267

268
bool _sir_isinitialized(void) {
2,320,422✔
269
#if defined(__HAVE_ATOMIC_H__)
270
    if (_SIR_MAGIC == atomic_load(&_sir_magic))
2,320,422✔
271
        return true;
2,320,280✔
272
#else
273
    if (_SIR_MAGIC == _sir_magic)
274
        return true;
275
#endif
276
    return false;
122✔
277
}
278

279
bool _sir_sanity(void) {
2,320,325✔
280
    if (_sir_isinitialized())
2,320,325✔
281
        return true;
2,269,728✔
282
    return _sir_seterror(_SIR_E_NOTREADY);
80✔
283
}
284

285
bool _sir_init_sanity(const sirinit* si) {
1,089✔
286
    if (!_sir_validptr(si))
1,089✔
287
        return false;
×
288

289
    bool levelcheck = true;
928✔
290
    _sir_eqland(levelcheck, _sir_validlevels(si->d_stdout.levels));
1,089✔
291
    _sir_eqland(levelcheck, _sir_validlevels(si->d_stderr.levels));
1,089✔
292

293
    bool regcheck = true;
928✔
294
    _sir_eqland(regcheck, SIRL_NONE == si->d_stdout.levels);
1,009✔
295
    _sir_eqland(regcheck, SIRL_NONE == si->d_stderr.levels);
1,009✔
296

297
#if !defined(SIR_NO_SYSTEM_LOGGERS)
298
    _sir_eqland(levelcheck, _sir_validlevels(si->d_syslog.levels));
862✔
299
    _sir_eqland(regcheck, SIRL_NONE == si->d_syslog.levels);
782✔
300
#endif
301

302
    if (regcheck)
928✔
303
        _sir_selflog("warning: no level registrations set!");
70✔
304

305
    bool optscheck = true;
928✔
306
    _sir_eqland(optscheck, _sir_validopts(si->d_stdout.opts));
1,089✔
307
    _sir_eqland(optscheck, _sir_validopts(si->d_stderr.opts));
1,089✔
308

309
#if !defined(SIR_NO_SYSTEM_LOGGERS)
310
    _sir_eqland(optscheck, _sir_validopts(si->d_syslog.opts));
862✔
311
#endif
312

313
    return levelcheck && optscheck;
1,089✔
314
}
315

316
void _sir_reset_tls(void) {
2,122✔
317
    _sir_resetstr(_sir_tid);
2,122✔
318
    (void)memset(&_sir_last_thrd_chk, 0, sizeof(sir_time));
1,808✔
319
    _sir_last_timestamp = 0;
2,122✔
320
    _sir_reset_tls_error();
2,122✔
321
}
2,122✔
322

323
static
324
bool _sir_updatelevels(const char* name, sir_levels* old, const sir_levels* new) {
1,107✔
325
    bool retval = _sir_validstr(name) && _sir_validptr(old) && _sir_validptr(new);
1,107✔
326
    if (retval) {
917✔
327
        if (*old != *new) {
1,107✔
328
            _sir_selflog("updating %s levels from %04"PRIx16" to %04"PRIx16, name, *old, *new);
967✔
329
            *old = *new;
1,059✔
330
        } else {
331
            _sir_selflog("skipped superfluous update of %s levels: %04"PRIx16, name, *old);
44✔
332
        }
333
    }
334
    return retval;
1,107✔
335
}
336

337
static
338
bool _sir_updateopts(const char* name, sir_options* old, const sir_options* new) {
37,853✔
339
    bool retval = _sir_validstr(name) && _sir_validptr(old) && _sir_validptr(new);
37,853✔
340
    if (retval) {
31,271✔
341
        if (*old != *new) {
37,853✔
342
            _sir_selflog("updating %s options from %08"PRIx32" to %08"PRIx32, name, *old, *new);
17,761✔
343
            *old = *new;
19,457✔
344
        } else {
345
            _sir_selflog("skipped superfluous update of %s options: %08"PRIx32, name, *old);
16,800✔
346
        }
347
    }
348
    return retval;
37,853✔
349
}
350

351
bool _sir_stdoutlevels(sirinit* si, const sir_update_config_data* data) {
539✔
352
    return _sir_updatelevels(SIR_DESTNAME_STDOUT, &si->d_stdout.levels, data->levels);
539✔
353
}
354

355
bool _sir_stdoutopts(sirinit* si, const sir_update_config_data* data) {
37,285✔
356
    return _sir_updateopts(SIR_DESTNAME_STDOUT, &si->d_stdout.opts, data->opts);
37,285✔
357
}
358

359
bool _sir_stderrlevels(sirinit* si, const sir_update_config_data* data) {
485✔
360
    return _sir_updatelevels(SIR_DESTNAME_STDERR, &si->d_stderr.levels, data->levels);
485✔
361
}
362

363
bool _sir_stderropts(sirinit* si, const sir_update_config_data* data) {
485✔
364
    return _sir_updateopts(SIR_DESTNAME_STDERR, &si->d_stderr.opts, data->opts);
485✔
365
}
366

367
bool _sir_sysloglevels(sirinit* si, const sir_update_config_data* data) {
83✔
368
    bool updated = _sir_updatelevels(SIR_DESTNAME_SYSLOG, &si->d_syslog.levels, data->levels);
83✔
369
    if (updated) {
83✔
370
        _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_LEVELS);
83✔
371
        updated = _sir_syslog_updated(si, data);
83✔
372
        _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_LEVELS);
83✔
373
    }
374
    return updated;
83✔
375
}
376

377
bool _sir_syslogopts(sirinit* si, const sir_update_config_data* data) {
83✔
378
    bool updated = _sir_updateopts(SIR_DESTNAME_SYSLOG, &si->d_syslog.opts, data->opts);
83✔
379
    if (updated) {
83✔
380
        _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_OPTIONS);
83✔
381
        updated = _sir_syslog_updated(si, data);
83✔
382
        _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_OPTIONS);
83✔
383
    }
384
    return updated;
83✔
385
}
386

387
bool _sir_syslogid(sirinit* si, const sir_update_config_data* data) {
133✔
388
    bool retval = _sir_validptr(si) && _sir_validptr(data);
133✔
389

390
    if (retval) {
108✔
391
        bool cur_ok = _sir_validstrnofail(si->d_syslog.identity);
133✔
392
        if (!cur_ok || 0 != strncmp(si->d_syslog.identity, data->sl_identity, SIR_MAX_SYSLOG_ID)) {
133✔
393
            _sir_selflog("updating %s identity from '%s' to '%s'", SIR_DESTNAME_SYSLOG,
82✔
394
                si->d_syslog.identity, data->sl_identity);
395
            (void)_sir_strncpy(si->d_syslog.identity, SIR_MAX_SYSLOG_ID, data->sl_identity,
82✔
396
                strnlen(data->sl_identity, SIR_MAX_SYSLOG_ID));
73✔
397
            _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_IDENTITY);
82✔
398
            retval = _sir_syslog_updated(si, data);
82✔
399
            _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_IDENTITY);
82✔
400
        } else {
401
            _sir_selflog("skipped superfluous update of %s identity: '%s'", SIR_DESTNAME_SYSLOG,
44✔
402
                si->d_syslog.identity);
403
        }
404
    }
405

406
    return retval;
133✔
407
}
408

409
bool _sir_syslogcat(sirinit* si, const sir_update_config_data* data) {
100✔
410
    bool retval = _sir_validptr(si) && _sir_validptr(data);
100✔
411

412
    if (retval) {
82✔
413
        bool cur_ok = _sir_validstrnofail(si->d_syslog.category);
100✔
414
        if (!cur_ok || 0 != strncmp(si->d_syslog.category, data->sl_category, SIR_MAX_SYSLOG_CAT)) {
100✔
415
            _sir_selflog("updating %s category from '%s' to '%s'", SIR_DESTNAME_SYSLOG,
50✔
416
                si->d_syslog.category, data->sl_category);
417
            (void)_sir_strncpy(si->d_syslog.category, SIR_MAX_SYSLOG_CAT, data->sl_category,
50✔
418
                strnlen(data->sl_category, SIR_MAX_SYSLOG_CAT));
45✔
419
            _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_CATEGORY);
50✔
420
            retval = _sir_syslog_updated(si, data);
50✔
421
            _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_CATEGORY);
50✔
422
        } else {
423
            _sir_selflog("skipped superfluous update of %s category: '%s'", SIR_DESTNAME_SYSLOG,
45✔
424
                si->d_syslog.identity);
425
        }
426
    }
427

428
    return retval;
100✔
429
}
430

431
bool _sir_writeinit(const sir_update_config_data* data, sirinit_update update) {
39,193✔
432
    (void)_sir_seterror(_SIR_E_NOERROR);
39,193✔
433

434
    if (!_sir_sanity() || !_sir_validupdatedata(data) || !_sir_validfnptr(update))
39,193✔
435
        return false;
×
436

437
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
39,192✔
438

439
    bool updated = update(&_cfg->si, data);
39,193✔
440
    if (!updated)
35,779✔
441
        _sir_selflog("error: update routine failed!");
×
442

443
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
39,193✔
444
    return updated;
39,193✔
445
}
446

447
void* _sir_locksection(sir_mutex_id mid) {
8,803,835✔
448
    sir_mutex* m = NULL;
8,803,835✔
449
    void* sec    = NULL;
8,803,835✔
450

451
    bool enter = _sir_mapmutexid(mid, &m, &sec) && _sir_mutexlock(m);
8,803,835✔
452
    SIR_ASSERT(enter);
8,681,030✔
453

454
    return enter ? sec : NULL;
8,804,729✔
455
}
456

457
void _sir_unlocksection(sir_mutex_id mid) {
8,804,447✔
458
    sir_mutex* m = NULL;
8,804,447✔
459
    void* sec    = NULL;
8,804,447✔
460

461
    bool leave = _sir_mapmutexid(mid, &m, &sec) && _sir_mutexunlock(m);
8,804,447✔
462
    SIR_ASSERT_UNUSED(leave, leave);
8,681,120✔
463
}
8,804,863✔
464

465
bool _sir_mapmutexid(sir_mutex_id mid, sir_mutex** m, void** section) {
17,606,505✔
466
    sir_mutex* tmpm;
467
    void* tmpsec;
468

469
    switch (mid) {
17,606,505✔
470
        case SIRMI_CONFIG:
8,555,827✔
471
            tmpm   = &cfg_mutex;
8,555,827✔
472
            tmpsec = &_sir_cfg;
8,555,827✔
473
            break;
8,555,827✔
474
        case SIRMI_FILECACHE:
4,328,602✔
475
            tmpm   = &fc_mutex;
4,275,321✔
476
            tmpsec = &_sir_fc;
4,275,321✔
477
            break;
4,328,602✔
478
        case SIRMI_PLUGINCACHE:
205,605✔
479
            tmpm   = &pc_mutex;
172,034✔
480
            tmpsec = &_sir_pc;
172,034✔
481
            break;
205,605✔
482
#if !defined(SIR_NO_TEXT_STYLING)
483
        case SIRMI_TEXTSTYLE:
4,416,405✔
484
            tmpm   = &ts_mutex;
4,359,149✔
485
            tmpsec = &sir_text_style_section;
4,359,149✔
486
            break;
4,416,405✔
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;
17,609,345✔
498

499
    if (section)
17,609,345✔
500
        *section = tmpsec;
17,606,607✔
501

502
    return *m != NULL && (!section || *section != NULL);
17,609,345✔
503
}
504

505
#if !defined(__WIN__)
506
void _sir_init_static_once(void) {
72✔
507
    (void)_sir_init_common_static();
72✔
508
}
72✔
509
#else /* __WIN__ */
510
BOOL CALLBACK _sir_init_static_once(PINIT_ONCE ponce, PVOID param, PVOID* ctx) {
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) {
72✔
519
#if defined(__HAVE_ATOMIC_H__)
520
    atomic_init(&_sir_magic, 0);
72✔
521
#endif
522

523
#if defined(__WIN__)
524
    (void)QueryPerformanceFrequency(&_sir_perfcntr_freq);
525
#endif
526

527
    bool created = _sir_mutexcreate(&cfg_mutex);
72✔
528
    SIR_ASSERT(created);
66✔
529

530
    _sir_eqland(created, _sir_mutexcreate(&fc_mutex));
72✔
531
    SIR_ASSERT(created);
61✔
532

533
    _sir_eqland(created, _sir_mutexcreate(&pc_mutex));
72✔
534
    SIR_ASSERT(created);
61✔
535

536
#if !defined(SIR_NO_TEXT_STYLING)
537
    _sir_eqland(created, _sir_mutexcreate(&ts_mutex));
66✔
538
    SIR_ASSERT(created);
57✔
539
#endif
540

541
    return created;
72✔
542
}
543

544
bool _sir_once(sir_once* once, sir_once_fn func) {
1,146✔
545
#if !defined(__WIN__)
546
    int ret = pthread_once(once, func);
1,146✔
547
    return 0 == ret ? true : _sir_handleerr(ret);
1,146✔
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)
555
bool _sir_logv(sir_level level, PRINTF_FORMAT const char* format, va_list args) {
2,144,191✔
556
    if (!_sir_sanity() || !_sir_validlevel(level) || !_sir_validstr(format))
2,144,191✔
557
        return false;
54✔
558

559
    (void)_sir_seterror(_SIR_E_NOERROR);
2,144,124✔
560

561
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
2,144,123✔
562

563
    sirbuf buf = {0};
2,144,139✔
564

565
    /* from time to time, update the host name in the config, just in case. */
566
    time_t now_sec = -1;
2,144,139✔
567
    if (-1 != time(&now_sec) &&
2,144,139✔
568
        (now_sec - _cfg->state.last_hname_chk) > SIR_HNAME_CHK_INTERVAL) {
2,138,444✔
569
        _sir_selflog("updating hostname...");
6,216✔
570
        if (!_sir_gethostname(_cfg->state.hostname)) {
6,263✔
571
            _sir_selflog("error: failed to get hostname!");
5,695✔
572
        } else {
573
            _cfg->state.last_hname_chk = now_sec;
568✔
574
            _sir_selflog("hostname: '%s'", _cfg->state.hostname);
521✔
575
        }
576
    }
577

578
    /* format timestamp (h/m/s only if the integer time has changed). */
579
    long now_msec = 0L;
2,144,139✔
580
    bool gettime = _sir_clock_gettime(SIR_WALLCLOCK, &now_sec, &now_msec);
2,144,139✔
581
    SIR_ASSERT_UNUSED(gettime, gettime);
2,133,287✔
582

583
    /* milliseconds. */
584
    _sir_snprintf_trunc(buf.msec, SIR_MAXMSEC, SIR_MSECFORMAT, now_msec);
2,144,139✔
585

586
    /* hours/minutes/seconds. */
587
    if (now_sec > _sir_last_timestamp || !*_cfg->state.timestamp) {
2,144,139✔
588
        _sir_last_timestamp = now_sec;
6,679✔
589
        bool fmt = _sir_formattime(now_sec, _cfg->state.timestamp, SIR_TIMEFORMAT);
6,679✔
590
        SIR_ASSERT_UNUSED(fmt, fmt);
6,604✔
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);
2,144,139✔
596

597
    /* update the thread identifier/name if enough time has elapsed. */
598
    if (msec_since_thrd_chk > SIR_THRD_CHK_INTERVAL) {
2,144,139✔
599
        _sir_last_thrd_chk = thrd_chk;
1,012✔
600

601
        pid_t tid         = _sir_gettid();
1,012✔
602
        bool resolved_tid = false;
853✔
603

604
        /* prefer thread names. */
605
        resolved_tid = _sir_getthreadname(_sir_tid);
1,012✔
606

607
        /* if tid is identical to pid... */
608
        if (!resolved_tid && tid == _cfg->state.pid) {
1,012✔
609
            /* don't use anything to identify the thread. */
610
            _sir_resetstr(_sir_tid);
208✔
611
            resolved_tid = true;
172✔
612
        }
613

614
        /* fall back on tid. */
615
        if (!resolved_tid)
853✔
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));
2,121,897✔
622
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
2,144,139✔
623

624
    buf.timestamp = cfg.state.timestamp;
2,144,139✔
625
    buf.hostname  = cfg.state.hostname;
2,144,139✔
626
    buf.pid       = cfg.state.pidbuf;
2,144,139✔
627
    buf.name      = cfg.si.name;
2,144,139✔
628

629
#if !defined(SIR_NO_TEXT_STYLING)
630
    const char* style_str = _sir_gettextstyle(level);
2,128,681✔
631

632
    SIR_ASSERT(NULL != style_str);
2,122,979✔
633
    if (NULL != style_str)
2,117,278✔
634
        (void)_sir_strncpy(buf.style, SIR_MAXSTYLE, style_str,
2,128,681✔
635
            strnlen(style_str, SIR_MAXSTYLE));
636
#endif
637

638
    buf.level = _sir_formattedlevelstr(level);
2,144,139✔
639

640
    if (_sir_validstrnofail(_sir_tid))
2,144,139✔
641
        (void)_sir_strncpy(buf.tid, SIR_MAXPID, _sir_tid,
2,056,915✔
642
            strnlen(_sir_tid, SIR_MAXPID));
643

644
    (void)vsnprintf(buf.message, SIR_MAXMESSAGE, format, args);
2,121,897✔
645

646
    if (!_sir_validstrnofail(buf.message))
2,144,139✔
647
        return _sir_seterror(_SIR_E_INTERNAL);
27✔
648

649
    bool match             = false;
2,121,874✔
650
    bool exit_early        = false;
2,121,874✔
651
    bool update_last_props = true;
2,121,874✔
652
    uint64_t hash          = 0ULL;
2,121,874✔
653

654
    if (cfg.state.last.level == level &&
2,144,112✔
655
        cfg.state.last.prefix[0] == buf.message[0]  &&
2,103,386✔
656
        cfg.state.last.prefix[1] == buf.message[1]) {
2,061,411✔
657
        hash  = FNV64_1a(buf.message);
2,059,863✔
658
        match = cfg.state.last.hash == hash;
2,059,863✔
659
    }
660

661
    if (match) {
2,130,991✔
662
        cfg.state.last.counter++;
39,942✔
663

664
        if (cfg.state.last.counter >= cfg.state.last.threshold - 2) {
39,942✔
665
            size_t old_threshold = cfg.state.last.threshold;
1,104✔
666

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

671
            _sir_selflog("hit squelch threshold of %zu; setting new threshold"
1,200✔
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);
1,104✔
676
        } else if (cfg.state.last.squelch) {
38,646✔
677
            exit_early = true;
32,361✔
678
        }
679
    } else {
680
        cfg.state.last.squelch   = false;
2,104,170✔
681
        cfg.state.last.counter   = 0;
2,104,170✔
682
        cfg.state.last.threshold = SIR_SQUELCH_THRESHOLD;
2,104,170✔
683
        /* _sir_selflog("message '%s' does not match last; resetting", buf.message); */
684
    }
685

686
    _cfg = _sir_locksection(SIRMI_CONFIG);
2,144,112✔
687
    if (!_cfg)
2,144,112✔
688
        return _sir_seterror(_SIR_E_INTERNAL);
×
689

690
    _cfg->state.last.squelch = cfg.state.last.squelch;
2,144,112✔
691

692
    if (update_last_props) {
2,144,112✔
693
        _cfg->state.last.level     = level;
2,142,816✔
694
        _cfg->state.last.hash      = hash;
2,142,816✔
695
        _cfg->state.last.prefix[0] = buf.message[0];
2,142,816✔
696
        _cfg->state.last.prefix[1] = buf.message[1];
2,142,816✔
697
    }
698

699
    _cfg->state.last.counter   = cfg.state.last.counter;
2,144,112✔
700
    _cfg->state.last.threshold = cfg.state.last.threshold;
2,144,112✔
701

702
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
2,144,112✔
703

704
    if (exit_early)
2,144,111✔
705
        return false;
32,361✔
706

707
    bool dispatched = _sir_dispatch(&cfg.si, level, &buf);
2,106,122✔
708
    return update_last_props ? dispatched : false;
2,106,123✔
709
}
710

711
bool _sir_dispatch(const sirinit* si, sir_level level, sirbuf* buf) {
2,106,122✔
712
    bool retval       = true;
2,089,512✔
713
    size_t dispatched = 0;
2,089,512✔
714
    size_t wanted     = 0;
2,089,512✔
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)) {
2,106,122✔
723
        const char* writef = _sir_format(styling, si->d_stdout.opts, buf);
1,100,027✔
724
        bool wrote         = _sir_validstrnofail(writef) &&
2,200,055✔
725
            _sir_write_stdout(writef, buf->output_len);
1,100,028✔
726
        _sir_eqland(retval, wrote);
1,084,493✔
727

728
        if (wrote)
1,084,493✔
729
            dispatched++;
1,080,570✔
730
        wanted++;
1,084,493✔
731
    }
732

733
    if (_sir_bittest(si->d_stderr.levels, level)) {
2,106,121✔
734
        const char* writef = _sir_format(styling, si->d_stderr.opts, buf);
1,503✔
735
        bool wrote         = _sir_validstrnofail(writef) &&
3,006✔
736
            _sir_write_stderr(writef, buf->output_len);
1,503✔
737
        _sir_eqland(retval, wrote);
1,257✔
738

739
        if (wrote)
1,257✔
740
            dispatched++;
1,495✔
741
        wanted++;
1,503✔
742
    }
743

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

752
    _SIR_LOCK_SECTION(const sirfcache, sfc, SIRMI_FILECACHE, false);
2,106,121✔
753
    size_t fdispatched = 0;
2,106,123✔
754
    size_t fwanted     = 0;
2,106,123✔
755
    _sir_eqland(retval, _sir_fcache_dispatch(sfc, level, buf, &fdispatched, &fwanted));
2,106,123✔
756
    _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
2,106,123✔
757

758
    dispatched += fdispatched;
2,106,123✔
759
    wanted += fwanted;
2,106,123✔
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) {
2,106,123✔
773
        _sir_selflog("error: no destinations registered for level %04"PRIx16, level);
960✔
774
        return _sir_seterror(_SIR_E_NODEST);
1,054✔
775
    }
776

777
    return retval && (dispatched == wanted);
2,105,069✔
778
}
779

780
const char* _sir_format(bool styling, sir_options opts, sirbuf* buf) {
2,189,672✔
781
    if (_sir_validptr(buf)) {
2,189,672✔
782
        bool first = true;
2,159,119✔
783

784
        _sir_resetstr(buf->output);
2,189,667✔
785

786
        if (styling)
2,189,670✔
787
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->style, SIR_MAXSTYLE);
1,090,902✔
788

789
        if (!_sir_bittest(opts, SIRO_NOTIME)) {
2,189,669✔
790
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->timestamp, SIR_MAXTIME);
2,063,238✔
791
            first = false;
2,052,911✔
792

793
#if defined(SIR_MSEC_TIMER)
794
            if (!_sir_bittest(opts, SIRO_NOMSEC))
2,063,241✔
795
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->msec, SIR_MAXMSEC);
44,929✔
796
#endif
797
        }
798

799
        if (!_sir_bittest(opts, SIRO_NOHOST) && _sir_validstrnofail(buf->hostname)) {
2,189,658✔
800
            if (!first)
1,019,237✔
801
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,002,022✔
802
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->hostname, SIR_MAXHOST);
1,019,237✔
803
            first = false;
1,015,572✔
804
        }
805

806
        if (!_sir_bittest(opts, SIRO_NOLEVEL)) {
2,189,649✔
807
            if (!first)
2,126,649✔
808
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
2,063,418✔
809
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->level, SIR_MAXLEVEL);
2,126,651✔
810
            first = false;
2,107,174✔
811
        }
812

813
        bool name = false;
2,159,095✔
814
        if (!_sir_bittest(opts, SIRO_NONAME) && _sir_validstrnofail(buf->name)) {
2,189,651✔
815
            if (!first)
1,063,141✔
816
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,061,559✔
817
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->name, SIR_MAXNAME);
1,063,145✔
818
            first = false;
1,052,801✔
819
            name  = true;
1,052,801✔
820
        }
821

822
        bool wantpid = !_sir_bittest(opts, SIRO_NOPID) && _sir_validstrnofail(buf->pid);
2,189,676✔
823
        bool wanttid = !_sir_bittest(opts, SIRO_NOTID) && _sir_validstrnofail(buf->tid);
2,189,698✔
824

825
        if (wantpid || wanttid) {
2,176,117✔
826
            if (name)
2,081,755✔
827
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDPREFIX, 1);
1,059,204✔
828
            else if (!first)
1,022,551✔
829
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,022,548✔
830

831
            if (wantpid)
2,081,755✔
832
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->pid, SIR_MAXPID);
2,042,542✔
833

834
            if (wanttid) {
2,081,755✔
835
                if (wantpid)
2,078,364✔
836
                    (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDSEPARATOR, 1);
2,039,179✔
837
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->tid, SIR_MAXPID);
2,078,364✔
838
            }
839

840
            if (name)
2,081,746✔
841
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDSUFFIX, 1);
1,059,190✔
842

843
            first = false;
2,067,882✔
844
        }
845

846
        if (!first)
2,175,816✔
847
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, ": ", 2);
2,145,245✔
848

849
        (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->message, SIR_MAXMESSAGE);
2,189,657✔
850

851
        if (styling)
2,189,655✔
852
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_ESC_RST, SIR_MAXSTYLE);
1,090,897✔
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);
2,174,440✔
858
#endif
859

860
        buf->output_len = strnlen(buf->output, SIR_MAXOUTPUT);
2,189,652✔
861

862
        return buf->output;
2,189,652✔
863
    }
864

865
    return NULL;
×
866
}
867

868
bool _sir_syslog_init(const char* name, sir_syslog_dest* ctx) {
303✔
869
#if !defined(SIR_NO_SYSTEM_LOGGERS)
870
    if (!_sir_validptr(name) || !_sir_validptr(ctx))
303✔
871
        return false;
×
872

873
    /* begin resolve identity. */
874
    if (!_sir_validstrnofail(ctx->identity)) {
303✔
875
        _sir_selflog("ctx->identity is no good; trying name");
82✔
876
        if (_sir_validstrnofail(name)) {
87✔
877
            _sir_selflog("using name");
23✔
878
            (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, name, strnlen(name, SIR_MAX_SYSLOG_ID));
24✔
879
        } else {
880
            _sir_selflog("name is no good; trying filename");
59✔
881
            char* appbasename = _sir_getappbasename();
63✔
882
            if (_sir_validstrnofail(appbasename)) {
63✔
883
                _sir_selflog("filename is good: %s", appbasename);
59✔
884
                (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, appbasename,
59✔
885
                    strnlen(appbasename, SIR_MAX_SYSLOG_ID));
886
            } else {
887
                _sir_selflog("filename no good; using fallback");
4✔
888
                (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, SIR_FALLBACK_SYSLOG_ID,
4✔
889
                    strnlen(SIR_FALLBACK_SYSLOG_ID, SIR_MAX_SYSLOG_ID));
890
            }
891
            _sir_safefree(&appbasename);
63✔
892
        }
893
    } else {
894
        _sir_selflog("already have identity");
192✔
895
    }
896

897
    /* category */
898
    if (!_sir_validstrnofail(ctx->category)) {
303✔
899
        _sir_selflog("category not set; using fallback");
110✔
900
        (void)_sir_strncpy(ctx->category, SIR_MAX_SYSLOG_CAT, SIR_FALLBACK_SYSLOG_CAT,
119✔
901
            strnlen(SIR_FALLBACK_SYSLOG_CAT, SIR_MAX_SYSLOG_CAT));
902
    } else {
903
        _sir_selflog("already have category");
164✔
904
    }
905

906
    _sir_setbitshigh(&ctx->_state.mask, SIRSL_IS_INIT);
303✔
907
    _sir_selflog("resolved (identity: '%s', category: '%s')", ctx->identity, ctx->category);
274✔
908

909
    return _sir_syslog_open(ctx);
303✔
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) {
303✔
918
#if !defined(SIR_NO_SYSTEM_LOGGERS)
919
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_INIT)) {
303✔
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)) {
303✔
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,
303✔
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);
303✔
937
    int facility = LOG_USER;
250✔
938

939
    openlog(ctx->identity, logopt, facility);
303✔
940
    _sir_selflog("opened syslog('%s', %x, %x)", ctx->identity, logopt, facility);
274✔
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);
303✔
954
    return true;
303✔
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) {
869✔
962
#if !defined(SIR_NO_SYSTEM_LOGGERS)
963
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_INIT)) {
869✔
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)) {
869✔
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) {
791✔
987
        case SIRL_DEBUG:  syslog_level = LOG_DEBUG; break;
43✔
988
        case SIRL_INFO:   syslog_level = LOG_INFO; break;
43✔
989
        case SIRL_NOTICE: syslog_level = LOG_NOTICE; break;
102✔
990
        case SIRL_WARN:   syslog_level = LOG_WARNING; break;
102✔
991
        case SIRL_ERROR:  syslog_level = LOG_ERR; break;
102✔
992
        case SIRL_CRIT:   syslog_level = LOG_CRIT; break;
131✔
993
        case SIRL_ALERT:  syslog_level = LOG_ALERT; break;
131✔
994
        case SIRL_EMERG:  syslog_level = LOG_EMERG; break;
131✔
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);
869✔
1003
    return true;
869✔
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) {
298✔
1063
#if !defined(SIR_NO_SYSTEM_LOGGERS)
1064
    if (!_sir_validptr(si) || !_sir_validptr(data))
298✔
1065
        return false;
×
1066

1067
    if (_sir_bittest(si->d_syslog._state.mask, SIRSL_UPDATED)) {
298✔
1068
        bool levels   = _sir_bittest(si->d_syslog._state.mask, SIRSL_LEVELS);
268✔
1069
        bool options  = _sir_bittest(si->d_syslog._state.mask, SIRSL_OPTIONS);
298✔
1070
        bool category = _sir_bittest(si->d_syslog._state.mask, SIRSL_CATEGORY);
268✔
1071
        bool identity = _sir_bittest(si->d_syslog._state.mask, SIRSL_IDENTITY);
298✔
1072
        bool is_init  = _sir_bittest(si->d_syslog._state.mask, SIRSL_IS_INIT);
298✔
1073
        bool is_open  = _sir_bittest(si->d_syslog._state.mask, SIRSL_IS_OPEN);
298✔
1074

1075
        _sir_selflog("config update: (levels: %u, options: %u, category: %u,"
268✔
1076
                     " identity: %u, is_init: %u, is_open: %u)",
1077
                     levels, options, category, identity, is_init, is_open);
1078

1079
        bool must_init = false;
246✔
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);
298✔
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;
246✔
1094
        if (must_init) {
246✔
1095
            if (is_open) /* close first; open will fail otherwise. */
165✔
1096
                init = _sir_syslog_close(&si->d_syslog);
134✔
1097

1098
            _sir_selflog("re-init...");
148✔
1099
            _sir_eqland(init, _sir_syslog_init(si->name, &si->d_syslog));
165✔
1100
            _sir_selflog("re-init %s", init ? "succeeded" : "failed");
148✔
1101
        } else {
1102
            _sir_selflog("no re-init necessary");
120✔
1103
        }
1104

1105
        return init;
298✔
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) {
973✔
1117
#if !defined(SIR_NO_SYSTEM_LOGGERS)
1118
    if (!_sir_validptr(ctx))
973✔
1119
        return false;
×
1120

1121
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
973✔
1122
        _sir_selflog("log not open; ignoring");
606✔
1123
        return true;
606✔
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();
303✔
1135
    _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
303✔
1136
    _sir_selflog("closed log");
274✔
1137
    return true;
303✔
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) {
1,680✔
1158
#if !defined(SIR_NO_SYSTEM_LOGGERS)
1159
    if (_sir_validptr(ctx)) {
1,680✔
1160
        uint32_t old       = ctx->_state.mask;
1,524✔
1161
        ctx->_state.mask   = 0U;
1,680✔
1162
        ctx->_state.logger = NULL;
1,680✔
1163
        _sir_selflog("state reset; mask was %08"PRIx32, old);
1,524✔
1164
    }
1165
#else
1166
    SIR_UNUSED(ctx);
1167
#endif
1168
}
1,680✔
1169

1170
const char* _sir_formattedlevelstr(sir_level level) {
2,144,139✔
1171
    static const size_t low  = 0;
1172
    static const size_t high = SIR_NUMLEVELS - 1;
1173

1174
    const char* retval = SIR_UNKNOWN;
2,121,897✔
1175

1176
    _SIR_DECLARE_BIN_SEARCH(low, high);
2,121,897✔
1177
    _SIR_BEGIN_BIN_SEARCH()
1178

1179
    if (sir_level_to_str_map[_mid].level == level) {
8,547,316✔
1180
        retval = sir_level_to_str_map[_mid].fmt;
2,144,139✔
1181
        break;
2,144,139✔
1182
    }
1183

1184
    _SIR_ITERATE_BIN_SEARCH((sir_level_to_str_map[_mid].level < level ? 1 : -1));
6,403,177✔
1185
    _SIR_END_BIN_SEARCH();
1186

1187
    return retval;
2,144,139✔
1188
}
1189

1190
bool _sir_clock_gettime(int clock, time_t* tbuf, long* msecbuf) {
6,288,375✔
1191
    if (tbuf) {
6,288,375✔
1192
#if defined(SIR_MSEC_POSIX)
1193
        struct timespec ts = {0};
6,288,375✔
1194
        int ret            = clock_gettime(clock, &ts);
6,288,375✔
1195
        SIR_ASSERT(0 == ret);
6,266,663✔
1196

1197
        if (0 == ret) {
6,265,563✔
1198
            *tbuf = ts.tv_sec;
6,277,058✔
1199
            if (msecbuf)
6,277,058✔
1200
                *msecbuf = ts.tv_nsec / 1000000L;
6,277,058✔
1201
        } else {
1202
            if (msecbuf)
11,317✔
1203
                *msecbuf = 0L;
11,317✔
1204
            return _sir_handleerr(errno);
11,317✔
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;
6,277,058✔
1236
    }
1237
    return false;
×
1238
}
1239

1240
double _sir_msec_since(const sir_time* when, sir_time* out) {
4,144,236✔
1241
    if (!_sir_validptr(out))
4,144,236✔
1242
        return 0.0;
×
1243
#if !defined(__WIN__)
1244
    out->sec = 0;
4,144,236✔
1245
    out->msec = 0L;
4,144,236✔
1246

1247
    bool gettime = _sir_clock_gettime(SIR_INTERVALCLOCK, &out->sec, &out->msec);
4,144,236✔
1248
    SIR_ASSERT(gettime);
4,133,376✔
1249

1250
    if (!_sir_validptrnofail(when) || !gettime || (out->sec < when->sec ||
4,144,236✔
1251
        (out->sec == when->sec && out->msec < when->msec)))
4,137,775✔
1252
        return 0.0;
5,712✔
1253

1254
    return ((((double)out->sec) * 1e3) + (double)out->msec) -
4,138,516✔
1255
           ((((double)when->sec) * 1e3) + (double)when->msec);
4,138,516✔
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) {
1,083✔
1273
#if !defined(__WIN__)
1274
    return getpid();
1,083✔
1275
#else /* __WIN__ */
1276
    return (pid_t)GetCurrentProcessId();
1277
#endif
1278
}
1279

1280
pid_t _sir_gettid(void) {
1,181✔
1281
    pid_t tid = 0;
994✔
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__)
1304
# if (defined(__GLIBC__) && GLIBC_VERSION >= 23000) || defined(__serenity__)
1305
    tid = gettid();
1,181✔
1306
# else
1307
    tid = syscall(SYS_gettid);
1308
# endif
1309
#elif defined(__WIN__)
1310
    tid = (pid_t)GetCurrentThreadId();
1311
#else
1312
# error "unable to determine how to get a thread identifier"
1313
#endif
1314
    return tid;
1,181✔
1315
}
1316

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

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

1400
    wchar_t buf[SIR_MAXPID] = {0};
1401
    if (!MultiByteToWideChar(CP_UTF8, 0UL, name, (int)name_len, buf, SIR_MAXPID))
1402
        return _sir_handlewin32err(GetLastError());
1403

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

1415
bool _sir_gethostname(char name[SIR_MAXHOST]) {
6,263✔
1416
#if !defined(__WIN__)
1417
    int ret = gethostname(name, SIR_MAXHOST - 1);
6,167✔
1418
    return 0 == ret ? true : _sir_handleerr(errno);
6,263✔
1419
#else
1420
    WSADATA wsad = {0};
1421
    int ret      = WSAStartup(MAKEWORD(2, 2), &wsad);
1422
    if (0 != ret)
1423
        return _sir_handlewin32err(ret);
1424

1425
    if (SOCKET_ERROR == gethostname(name, SIR_MAXHOST)) {
1426
        int err = WSAGetLastError();
1427
        WSACleanup();
1428
        return _sir_handlewin32err(err);
1429
    }
1430

1431
    WSACleanup();
1432
    return true;
1433
#endif /* !__WIN__ */
1434
}
1435

1436
long __sir_nprocs(bool test_mode) {
1437
    long nprocs = 0;
1438

1439
#if defined(_AIX)
1440
    nprocs = (long)_system_configuration.ncpus;
1441
    _sir_selflog("AIX _system_configuration.ncpus reports %ld processor(s)", nprocs);
1442
#endif
1443

1444
#if defined(__WIN__)
1445
    SYSTEM_INFO system_info;
1446
    ZeroMemory(&system_info, sizeof(system_info));
1447
    GetSystemInfo(&system_info);
1448
    nprocs = (long)system_info.dwNumberOfProcessors;
1449
    _sir_selflog("Windows GetSystemInfo() reports %ld processor(s)", nprocs);
1450
#endif
1451

1452
#if defined(__HAIKU__)
1453
    system_info hinfo;
1454
    get_system_info(&hinfo);
1455
    nprocs = (long)hinfo.cpu_count;
1456
    _sir_selflog("Haiku get_system_info() reports %ld processor(s)", nprocs);
1457
#endif
1458

1459
#if defined(SC_NPROCESSORS_ONLN)
1460
# define SIR_SC_NPROCESSORS SC_NPROCESSORS_ONLN
1461
#elif defined(_SC_NPROCESSORS_ONLN)
1462
# define SIR_SC_NPROCESSORS _SC_NPROCESSORS_ONLN
1463
#endif
1464
#if defined(SIR_SC_NPROCESSORS)
1465
    long tprocs = sysconf(SIR_SC_NPROCESSORS);
1466
    _sir_selflog("sysconf() reports %ld processor(s)", tprocs);
1467
    if (tprocs > nprocs)
1468
        nprocs = tprocs;
1469
#endif
1470

1471
#if defined(__linux__) && defined(CPU_COUNT) && !defined(__ANDROID__) && !defined(__UCLIBC__)
1472
    long ctprocs;
1473
    cpu_set_t p_aff;
1474
    memset(&p_aff, 0, sizeof(p_aff));
1475
    if (sched_getaffinity(0, sizeof(p_aff), &p_aff)) {
1476
        ctprocs = 0;
1477
    } else {
1478
        ctprocs = CPU_COUNT(&p_aff);
1479
        _sir_selflog("sched_getaffinity() reports %ld processor(s)", ctprocs);
1480
    }
1481
    if (ctprocs > nprocs)
1482
        nprocs = ctprocs;
1483
#endif
1484

1485
#if defined(CTL_HW) && defined(HW_AVAILCPU)
1486
    int ntprocs = 0;
1487
    size_t sntprocs = sizeof(ntprocs);
1488
    if (sysctl ((int[2]) {CTL_HW, HW_AVAILCPU}, 2, &ntprocs, &sntprocs, NULL, 0)) {
1489
        ntprocs = 0;
1490
    } else {
1491
        _sir_selflog("sysctl(CTL_HW, HW_AVAILCPU) reports %d processor(s)", ntprocs);
1492
        if (ntprocs > nprocs)
1493
            nprocs = (long)ntprocs;
1494
    }
1495
#elif defined(CTL_HW) && defined(HW_NCPU)
1496
    int ntprocs = 0;
1497
    size_t sntprocs = sizeof(ntprocs);
1498
    if (sysctl ((int[2]) {CTL_HW, HW_NCPU}, 2, &ntprocs, &sntprocs, NULL, 0)) {
1499
        ntprocs = 0;
1500
    } else {
1501
        _sir_selflog("sysctl(CTL_HW, HW_NCPU) reports %d processor(s)", ntprocs);
1502
        if (ntprocs > nprocs)
1503
            nprocs = (long)ntprocs;
1504
    }
1505
#elif defined(CTL_HW) && defined(HW_NCPUFOUND)
1506
    int ntprocs = 0;
1507
    size_t sntprocs = sizeof(ntprocs);
1508
    if (sysctl ((int[2]) {CTL_HW, HW_NCPUFOUND}, 2, &ntprocs, &sntprocs, NULL, 0)) {
1509
        ntprocs = 0;
1510
    } else {
1511
        _sir_selflog("sysctl(CTL_HW, HW_NCPUFOUND) reports %d processor(s)", ntprocs);
1512
        if (ntprocs > nprocs)
1513
            nprocs = (long)ntprocs;
1514
    }
1515
#endif
1516

1517
#if defined(__MACOS__)
1518
    int antprocs = 0;
1519
    size_t asntprocs = sizeof(antprocs);
1520
    if (sysctlbyname("hw.ncpu", &antprocs, &asntprocs, NULL, 0)) {
1521
        antprocs = 0;
1522
    } else {
1523
        _sir_selflog("sysctlbyname(hw.ncpu) reports %d processor(s)", antprocs);
1524
        if (antprocs > nprocs)
1525
            nprocs = (long)antprocs;
1526
    }
1527
#endif
1528

1529
#if defined(__QNX__) || defined(__QNXNTO__)
1530
    long qtprocs = (long)_syspage_ptr->num_cpu;
1531
    _sir_selflog("QNX _syspage_ptr->num_cpu reports %ld processor(s)", qtprocs);
1532
    if (qtprocs > nprocs)
1533
        nprocs = qtprocs;
1534
#endif
1535

1536
#if defined(__VXWORKS__)
1537
# if defined(_WRS_CONFIG_SMP)
1538
    long vtprocs = 0;
1539
    cpuset_t vset = vxCpuEnabledGet();
1540
    for (int count = 0; count < 512 && !CPUSET_ISZERO(vset); ++count) {
1541
        if (CPUSET_ISSET(vset, count)) {
1542
            CPUSET_CLR(vset, count);
1543
            vtprocs++;
1544
        }
1545
    }
1546
    _sir_selflog("VxWorks vxCpuEnabledGet() reports %ld processor(s)", vtprocs);
1547
# else
1548
    long vtprocs = 1;
1549
    _sir_selflog("Uniprocessor system or VxWorks SMP is not enabled");
1550
# endif
1551
    if (vtprocs > nprocs)
1552
        nprocs = vtprocs;
1553
#endif
1554

1555
    if (nprocs < 1) {
1556
        _sir_selflog(SIR_BRED("Failed to determine processor count!"));
1557
        if (!test_mode)
1558
            nprocs = 1;
1559
    }
1560

1561
    _sir_selflog("Detected %ld processor(s)", nprocs);
1562
    return nprocs;
1563
}
1,001✔
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