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

aremmell / libsir / 1700

25 Mar 2024 06:06PM UTC coverage: 95.493%. Remained the same
1700

Pull #410

gitlab-ci

johnsonjh
Sync mcmb with DPS8M

Signed-off-by: Jeffrey H. Johnson <trnsz@pobox.com>
Pull Request #410: Add support for building with Cisco OpenOSC

3877 of 4060 relevant lines covered (95.49%)

477464.16 hits per line

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

92.96
/src/sirinternal.c
1
/*
2
 * sirinternal.c
3
 *
4
 * Version: 2.2.5
5
 *
6
 * -----------------------------------------------------------------------------
7
 *
8
 * SPDX-License-Identifier: MIT
9
 *
10
 * Copyright (c) 2018-2024 Ryan M. Lederman <lederman@gmail.com>
11
 * Copyright (c) 2018-2024 Jeffrey H. Johnson <trnsz@pobox.com>
12
 *
13
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
14
 * this software and associated documentation files (the "Software"), to deal in
15
 * the Software without restriction, including without limitation the rights to
16
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
17
 * the Software, and to permit persons to whom the Software is furnished to do so,
18
 * subject to the following conditions:
19
 *
20
 * The above copyright notice and this permission notice shall be included in all
21
 * copies or substantial portions of the Software.
22
 *
23
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
25
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
26
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
27
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
28
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
 *
30
 * -----------------------------------------------------------------------------
31
 */
32

33
#include "sir/internal.h"
34
#include "sir/console.h"
35
#include "sir/defaults.h"
36
#include "sir/filecache.h"
37
#include "sir/plugins.h"
38
#include "sir/textstyle.h"
39
#include "sir/filesystem.h"
40
#include "sir/mutex.h"
41

42
#if defined(__WIN__)
43
# if defined(SIR_EVENTLOG_ENABLED)
44
#  include "sir/wineventlog.h"
45
#  pragma comment(lib, "advapi32.lib")
46
# endif
47
# if defined(__EMBARCADEROC__) && defined(_WIN64)
48
#  pragma comment(lib, "ws2_32.a")
49
# else
50
#  pragma comment(lib, "ws2_32.lib")
51
# endif
52
#endif
53

54
static sirconfig _sir_cfg      = {0};
55
static sirfcache _sir_fc       = {0};
56
static sir_plugincache _sir_pc = {0};
57

58
#if !defined(__IMPORTC__)
59
static sir_mutex cfg_mutex  = SIR_MUTEX_INIT;
60
static sir_mutex fc_mutex   = SIR_MUTEX_INIT;
61
static sir_mutex pc_mutex   = SIR_MUTEX_INIT;
62
# if !defined(SIR_NO_TEXT_STYLING)
63
static sir_mutex ts_mutex   = SIR_MUTEX_INIT;
64
# endif
65
#else
66
static sir_mutex cfg_mutex  = {0};
67
static sir_mutex fc_mutex   = {0};
68
static sir_mutex pc_mutex   = {0};
69
# if !defined(SIR_NO_TEXT_STYLING)
70
static sir_mutex ts_mutex   = {0};
71
# endif
72
#endif
73
static sir_once static_once = SIR_ONCE_INIT;
74

75
#if defined(__WIN__)
76
static LARGE_INTEGER _sir_perfcntr_freq = {0};
77
#endif
78

79
#if defined(__HAVE_ATOMIC_H__)
80
static atomic_uint_fast32_t _sir_magic;
81
#else
82
static volatile uint32_t _sir_magic = 0U;
83
#endif
84

85
static _sir_thread_local char _sir_tid[SIR_MAXPID]   = {0};
86
static _sir_thread_local sir_time _sir_last_thrd_chk = {0};
87
static _sir_thread_local time_t _sir_last_timestamp  = 0;
88

89
bool _sir_makeinit(sirinit* si) {
81✔
90
    bool retval = _sir_validptr(si);
81✔
91

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

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

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

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

110
    return retval;
81✔
111
}
112

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

116
    /* can only fail on Windows. */
117
    bool once_init = _sir_once(&static_once, _sir_init_static_once);
1,146✔
118
#if !defined(__WIN__)
119
    SIR_UNUSED(once_init);
120
#else
121
    if (!once_init) {
122
        _sir_selflog("error: static data initialization routine failed!");
123
        return false;
124
    }
125
#endif
126

127
    if (!_sir_validptr(si))
1,146✔
128
        return false;
23✔
129

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

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

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

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

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

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

153
    bool init = true;
905✔
154

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

161
    _sir_reset_tls();
1,062✔
162

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

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

175
    if (!_sir_resettextstyles()) {
945✔
176
        init = false;
×
177
        _sir_selflog("error: failed to reset text styles!");
×
178
    }
179
#endif
180

181
    (void)memset(&_cfg->state, 0, sizeof(_cfg->state));
1,062✔
182
    (void)memcpy(&_cfg->si, si, sizeof(sirinit));
1,062✔
183

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

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

190
    (void)snprintf(_cfg->state.pidbuf, SIR_MAXPID, SIR_PIDFORMAT,
1,062✔
191
        PID_CAST _cfg->state.pid);
192

193
#if !defined(SIR_NO_SYSTEM_LOGGERS)
194
    /* initialize system logger. */
195
    _sir_syslog_reset(&_cfg->si.d_syslog);
841✔
196

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

204
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
1,062✔
205

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

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

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

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

221
    _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
1,060✔
222
    _sir_eqland(cleanup, destroyfc);
903✔
223

224
#if !defined(SIR_NO_PLUGINS)
225
    _SIR_LOCK_SECTION(sir_plugincache, spc, SIRMI_PLUGINCACHE, false);
1,001✔
226
    bool destroypc = _sir_plugin_cache_destroy(spc);
1,001✔
227
    SIR_ASSERT(destroypc);
921✔
228
    _SIR_UNLOCK_SECTION(SIRMI_PLUGINCACHE);
1,001✔
229
    _sir_eqland(cleanup, destroypc);
1,001✔
230
#endif
231

232
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
1,060✔
233

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

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

243
#if !defined(SIR_NO_TEXT_STYLING)
244
    if (!_sir_resettextstyles()) {
943✔
245
        cleanup = false;
×
246
        _sir_selflog("error: failed to reset text styles!");
×
247
    }
248
#endif
249

250
#if defined(__HAVE_ATOMIC_H__)
251
    atomic_store(&_sir_magic, 0);
1,060✔
252
#else
253
    _sir_magic = 0U;
254
#endif
255

256
    _sir_reset_tls();
1,060✔
257

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

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

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

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

278
bool _sir_sanity(void) {
2,320,152✔
279
    if (_sir_isinitialized())
2,320,152✔
280
        return true;
2,269,743✔
281
    return _sir_seterror(_SIR_E_NOTREADY);
81✔
282
}
283

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

405
    return retval;
139✔
406
}
407

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

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

427
    return retval;
92✔
428
}
429

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

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

436
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
39,167✔
437

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

442
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
39,183✔
443
    return updated;
39,183✔
444
}
445

446
void* _sir_locksection(sir_mutex_id mid) {
8,801,494✔
447
    sir_mutex* m = NULL;
8,801,494✔
448
    void* sec    = NULL;
8,801,494✔
449

450
    bool enter = _sir_mapmutexid(mid, &m, &sec) && _sir_mutexlock(m);
8,801,494✔
451
    SIR_ASSERT(enter);
8,680,420✔
452

453
    return enter ? sec : NULL;
8,803,964✔
454
}
455

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

460
    bool leave = _sir_mapmutexid(mid, &m, &sec) && _sir_mutexunlock(m);
8,803,803✔
461
    SIR_ASSERT_UNUSED(leave, leave);
8,681,133✔
462
}
8,804,891✔
463

464
bool _sir_mapmutexid(sir_mutex_id mid, sir_mutex** m, void** section) {
17,601,312✔
465
    sir_mutex* tmpm;
466
    void* tmpsec;
467

468
    switch (mid) {
17,601,312✔
469
        case SIRMI_CONFIG:
8,556,062✔
470
            tmpm   = &cfg_mutex;
8,556,062✔
471
            tmpsec = &_sir_cfg;
8,556,062✔
472
            break;
8,556,062✔
473
        case SIRMI_FILECACHE:
4,328,432✔
474
            tmpm   = &fc_mutex;
4,275,358✔
475
            tmpsec = &_sir_fc;
4,275,358✔
476
            break;
4,328,432✔
477
        case SIRMI_PLUGINCACHE:
205,738✔
478
            tmpm   = &pc_mutex;
172,141✔
479
            tmpsec = &_sir_pc;
172,141✔
480
            break;
205,738✔
481
#if !defined(SIR_NO_TEXT_STYLING)
482
        case SIRMI_TEXTSTYLE:
4,415,566✔
483
            tmpm   = &ts_mutex;
4,358,480✔
484
            tmpsec = &sir_text_style_section;
4,358,480✔
485
            break;
4,415,566✔
486
#endif
487
        default: // GCOVR_EXCL_START
488
#if !defined(SIR_NO_TEXT_STYLING)
489
            SIR_ASSERT(false);
490
#endif
491
            tmpm   = NULL;
492
            tmpsec = NULL;
493
            break;
494
    } // GCOVR_EXCL_STOP
495

496
    *m = tmpm;
17,608,190✔
497

498
    if (section)
17,608,190✔
499
        *section = tmpsec;
17,601,429✔
500

501
    return *m != NULL && (!section || *section != NULL);
17,608,190✔
502
}
503

504
#if !defined(__WIN__)
505
void _sir_init_static_once(void) {
72✔
506
    (void)_sir_init_common_static();
72✔
507
}
72✔
508
#else /* __WIN__ */
509
BOOL CALLBACK _sir_init_static_once(PINIT_ONCE ponce, PVOID param, PVOID* ctx) {
510
    SIR_UNUSED(ponce);
511
    SIR_UNUSED(param);
512
    SIR_UNUSED(ctx);
513
    return _sir_init_common_static() ? TRUE : FALSE;
514
}
515
#endif
516

517
bool _sir_init_common_static(void) {
72✔
518
#if defined(__HAVE_ATOMIC_H__)
519
    atomic_init(&_sir_magic, 0);
72✔
520
#endif
521

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

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

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

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

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

540
    return created;
72✔
541
}
542

543
bool _sir_once(sir_once* once, sir_once_fn func) {
1,146✔
544
#if !defined(__WIN__)
545
    int ret = pthread_once(once, func);
1,146✔
546
    return 0 == ret ? true : _sir_handleerr(ret);
1,146✔
547
#else /* __WIN__ */
548
    return (FALSE != InitOnceExecuteOnce(once, func, NULL, NULL)) ? true
549
        : _sir_handlewin32err(GetLastError());
550
#endif
551
}
552

553
PRINTF_FORMAT_ATTR(2, 0)
554
bool _sir_logv(sir_level level, PRINTF_FORMAT const char* format, va_list args) {
2,144,250✔
555
    if (!_sir_sanity() || !_sir_validlevel(level) || !_sir_validstr(format))
2,144,250✔
556
        return false;
54✔
557

558
    (void)_sir_seterror(_SIR_E_NOERROR);
2,144,200✔
559

560
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
2,144,200✔
561

562
    sirbuf buf = {0};
2,144,203✔
563

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

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

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

585
    /* hours/minutes/seconds. */
586
    if (now_sec > _sir_last_timestamp || !*_cfg->state.timestamp) {
2,144,203✔
587
        _sir_last_timestamp = now_sec;
6,702✔
588
        bool fmt = _sir_formattime(now_sec, _cfg->state.timestamp, SIR_TIMEFORMAT);
6,702✔
589
        SIR_ASSERT_UNUSED(fmt, fmt);
6,616✔
590
    }
591

592
    /* check elapsed time since updating thread identifier/name. */
593
    sir_time thrd_chk;
594
    double msec_since_thrd_chk = _sir_msec_since(&_sir_last_thrd_chk, &thrd_chk);
2,144,203✔
595

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

600
        pid_t tid         = _sir_gettid();
1,041✔
601
        bool resolved_tid = false;
873✔
602

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

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

613
        /* fall back on tid. */
614
        if (!resolved_tid)
873✔
615
            _sir_snprintf_trunc(_sir_tid, SIR_MAXPID, SIR_TIDFORMAT,
×
616
                PID_CAST tid);
617
    }
618

619
    sirconfig cfg;
620
    (void)memcpy(&cfg, _cfg, sizeof(sirconfig));
2,121,943✔
621
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
2,144,203✔
622

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

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

631
    SIR_ASSERT(NULL != style_str);
2,123,025✔
632
    if (NULL != style_str)
2,117,328✔
633
        (void)_sir_strncpy(buf.style, SIR_MAXSTYLE, style_str,
2,128,735✔
634
            strnlen(style_str, SIR_MAXSTYLE));
635
#endif
636

637
    buf.level = _sir_formattedlevelstr(level);
2,144,202✔
638

639
    if (_sir_validstrnofail(_sir_tid))
2,144,202✔
640
        (void)_sir_strncpy(buf.tid, SIR_MAXPID, _sir_tid,
2,056,978✔
641
            strnlen(_sir_tid, SIR_MAXPID));
642

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

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

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

653
    if (cfg.state.last.level == level &&
2,144,176✔
654
        cfg.state.last.prefix[0] == buf.message[0]  &&
2,116,222✔
655
        cfg.state.last.prefix[1] == buf.message[1]) {
2,062,971✔
656
        hash  = FNV64_1a(buf.message);
2,072,708✔
657
        match = cfg.state.last.hash == hash;
2,072,708✔
658
    }
659

660
    if (match) {
2,132,951✔
661
        cfg.state.last.counter++;
40,893✔
662

663
        if (cfg.state.last.counter >= cfg.state.last.threshold - 2) {
40,893✔
664
            size_t old_threshold = cfg.state.last.threshold;
1,104✔
665

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

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

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

689
    _cfg->state.last.squelch = cfg.state.last.squelch;
2,144,176✔
690

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

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

701
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
2,144,176✔
702

703
    if (exit_early)
2,144,171✔
704
        return false;
32,361✔
705

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

710
bool _sir_dispatch(const sirinit* si, sir_level level, sirbuf* buf) {
2,106,182✔
711
    bool retval       = true;
2,089,555✔
712
    size_t dispatched = 0;
2,089,555✔
713
    size_t wanted     = 0;
2,089,555✔
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,106,182✔
722
        const char* writef = _sir_format(styling, si->d_stdout.opts, buf);
1,100,100✔
723
        bool wrote         = _sir_validstrnofail(writef) &&
2,200,199✔
724
            _sir_write_stdout(writef, buf->output_len);
1,100,098✔
725
        _sir_eqland(retval, wrote);
1,084,518✔
726

727
        if (wrote)
1,084,518✔
728
            dispatched++;
1,080,593✔
729
        wanted++;
1,084,518✔
730
    }
731

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

738
        if (wrote)
1,310✔
739
            dispatched++;
1,568✔
740
        wanted++;
1,577✔
741
    }
742

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

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

757
    dispatched += fdispatched;
2,106,187✔
758
    wanted += fwanted;
2,106,187✔
759

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

767
    dispatched += pdispatched;
101,758✔
768
    wanted += pwanted;
101,758✔
769
#endif
770

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

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

779
const char* _sir_format(bool styling, sir_options opts, sirbuf* buf) {
2,181,768✔
780
    if (_sir_validptr(buf)) {
2,181,768✔
781
        bool first = true;
2,151,907✔
782

783
        _sir_resetstr(buf->output);
2,181,775✔
784

785
        if (styling)
2,181,780✔
786
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->style, SIR_MAXSTYLE);
1,091,021✔
787

788
        if (!_sir_bittest(opts, SIRO_NOTIME)) {
2,181,777✔
789
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->timestamp, SIR_MAXTIME);
2,057,727✔
790
            first = false;
2,047,569✔
791

792
#if defined(SIR_MSEC_TIMER)
793
            if (!_sir_bittest(opts, SIRO_NOMSEC))
2,057,736✔
794
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->msec, SIR_MAXMSEC);
39,263✔
795
#endif
796
        }
797

798
        if (!_sir_bittest(opts, SIRO_NOHOST) && _sir_validstrnofail(buf->hostname)) {
2,181,824✔
799
            if (!first)
1,018,947✔
800
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,002,017✔
801
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->hostname, SIR_MAXHOST);
1,018,947✔
802
            first = false;
1,015,362✔
803
        }
804

805
        if (!_sir_bittest(opts, SIRO_NOLEVEL)) {
2,181,810✔
806
            if (!first)
2,121,196✔
807
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
2,057,912✔
808
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->level, SIR_MAXLEVEL);
2,121,193✔
809
            first = false;
2,101,875✔
810
        }
811

812
        bool name = false;
2,151,934✔
813
        if (!_sir_bittest(opts, SIRO_NONAME) && _sir_validstrnofail(buf->name)) {
2,181,826✔
814
            if (!first)
1,057,240✔
815
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,055,615✔
816
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->name, SIR_MAXNAME);
1,057,228✔
817
            first = false;
1,047,174✔
818
            name  = true;
1,047,174✔
819
        }
820

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

824
        if (wantpid || wanttid) {
2,168,598✔
825
            if (name)
2,076,301✔
826
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDPREFIX, 1);
1,053,532✔
827
            else if (!first)
1,022,769✔
828
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,022,759✔
829

830
            if (wantpid)
2,076,310✔
831
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->pid, SIR_MAXPID);
2,042,560✔
832

833
            if (wanttid) {
2,076,302✔
834
                if (wantpid)
2,072,799✔
835
                    (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDSEPARATOR, 1);
2,039,168✔
836
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->tid, SIR_MAXPID);
2,072,798✔
837
            }
838

839
            if (name)
2,076,285✔
840
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDSUFFIX, 1);
1,053,470✔
841

842
            first = false;
2,062,627✔
843
        }
844

845
        if (!first)
2,168,241✔
846
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, ": ", 2);
2,139,485✔
847

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

850
        if (styling)
2,181,796✔
851
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_ESC_RST, SIR_MAXSTYLE);
1,091,001✔
852

853
#if defined(SIR_USE_EOL_CRLF)
854
        (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_EOL, 2);
14,562✔
855
#else
856
        (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_EOL, 1);
2,167,230✔
857
#endif
858

859
        buf->output_len = strnlen(buf->output, SIR_MAXOUTPUT);
2,181,838✔
860

861
        return buf->output;
2,181,838✔
862
    }
863

864
    return NULL;
×
865
}
866

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

872
    /* begin resolve identity. */
873
    if (!_sir_validstrnofail(ctx->identity)) {
302✔
874
        _sir_selflog("ctx->identity is no good; trying name");
76✔
875
        if (_sir_validstrnofail(name)) {
84✔
876
            _sir_selflog("using name");
25✔
877
            (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, name,
28✔
878
                strnlen_trunc(name, SIR_MAX_SYSLOG_ID));
879
        } else {
880
            _sir_selflog("name is no good; trying filename");
51✔
881
            char* appbasename = _sir_getappbasename();
56✔
882
            if (_sir_validstrnofail(appbasename)) {
56✔
883
                _sir_selflog("filename is good: %s", appbasename);
51✔
884
                (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, appbasename,
51✔
885
                    strnlen_trunc(appbasename, SIR_MAX_SYSLOG_ID));
886
            } else {
887
                _sir_selflog("filename no good; using fallback");
5✔
888
                (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, SIR_FALLBACK_SYSLOG_ID,
5✔
889
                    strnlen_trunc(SIR_FALLBACK_SYSLOG_ID, SIR_MAX_SYSLOG_ID));
890
            }
891
            _sir_safefree(&appbasename);
56✔
892
        }
893
    } else {
894
        _sir_selflog("already have identity");
201✔
895
    }
896

897
    /* category */
898
    if (!_sir_validstrnofail(ctx->category)) {
302✔
899
        _sir_selflog("category not set; using fallback");
112✔
900
        (void)_sir_strncpy(ctx->category, SIR_MAX_SYSLOG_CAT, SIR_FALLBACK_SYSLOG_CAT,
123✔
901
            strnlen_trunc(SIR_FALLBACK_SYSLOG_CAT, SIR_MAX_SYSLOG_CAT));
902
    } else {
903
        _sir_selflog("already have category");
165✔
904
    }
905

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

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

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

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

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

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

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

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

1121
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
972✔
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();
302✔
1135
    _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
302✔
1136
    _sir_selflog("closed log");
277✔
1137
    return true;
302✔
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,202✔
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,942✔
1175

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

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

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

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

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

1197
        if (0 == ret) {
6,265,683✔
1198
            *tbuf = ts.tv_sec;
6,277,186✔
1199
            if (msecbuf)
6,277,186✔
1200
                *msecbuf = ts.tv_nsec / 1000000L;
6,277,186✔
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,186✔
1236
    }
1237
    return false;
×
1238
}
1239

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

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

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

1254
    return ((((double)out->sec) * 1e3) + (double)out->msec) -
4,138,580✔
1255
           ((((double)when->sec) * 1e3) + (double)when->msec);
4,138,580✔
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,210✔
1281
    pid_t tid = 0;
1,014✔
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__)
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,210✔
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,210✔
1315
}
1316

1317
bool _sir_getthreadname(char name[SIR_MAXPID]) {
1,041✔
1318
    _sir_resetstr(name);
1,041✔
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))
1325
    int ret = pthread_getname_np(pthread_self(), name, SIR_MAXPID);
1,041✔
1326
    if (0 != ret)
1,041✔
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,041✔
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) {
294✔
1368
    if (!_sir_validptr(name))
294✔
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);
294✔
1387
    return (0 != ret) ? _sir_handleerr(ret) : true;
294✔
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,265✔
1416
#if !defined(__WIN__)
1417
    int ret = gethostname(name, SIR_MAXHOST - 1);
6,169✔
1418
    return 0 == ret ? true : _sir_handleerr(errno);
6,265✔
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) {
27✔
1437
    long nprocs = 0;
23✔
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);
27✔
1466
    _sir_selflog("sysconf() reports %ld processor(s)", tprocs);
25✔
1467
    if (tprocs > nprocs)
27✔
1468
        nprocs = tprocs;
23✔
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));
23✔
1475
    if (sched_getaffinity(0, sizeof(p_aff), &p_aff)) {
27✔
1476
        ctprocs = 0;
×
1477
    } else {
1478
        ctprocs = CPU_COUNT(&p_aff);
27✔
1479
        _sir_selflog("sched_getaffinity() reports %ld processor(s)", ctprocs);
25✔
1480
    }
1481
    if (ctprocs > nprocs)
27✔
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) {
27✔
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);
25✔
1562
    return nprocs;
27✔
1563
}
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