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

aremmell / libsir / 1872

06 Mar 2025 04:25PM UTC coverage: 95.5% (+0.001%) from 95.499%
1872

Pull #449

gitlab-ci

johnsonjh
Portability improvements

Portability improvements; found when targeting IBM z/OS.

Signed-off-by: Jeffrey H. Johnson <trnsz@pobox.com>
Pull Request #449: Portability improvements

7 of 7 new or added lines in 1 file covered. (100.0%)

3 existing lines in 2 files now uncovered.

3693 of 3867 relevant lines covered (95.5%)

355117.72 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
#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,348✔
268
#if defined(__HAVE_ATOMIC_H__)
269
    if (_SIR_MAGIC == atomic_load(&_sir_magic))
2,320,348✔
270
        return true;
2,320,266✔
271
#else
272
    if (_SIR_MAGIC == _sir_magic)
273
        return true;
274
#endif
275
    return false;
69✔
276
}
277

278
bool _sir_sanity(void) {
2,320,240✔
279
    if (_sir_isinitialized())
2,320,240✔
280
        return true;
2,269,800✔
281
    return _sir_seterror(_SIR_E_NOTREADY);
82✔
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,111✔
324
    bool retval = _sir_validstr(name) && _sir_validptr(old) && _sir_validptr(new);
1,111✔
325
    if (retval) {
920✔
326
        if (*old != *new) {
1,111✔
327
            _sir_selflog("updating %s levels from %04"PRIx16" to %04"PRIx16, name, *old, *new);
974✔
328
            *old = *new;
1,063✔
329
        } else {
330
            _sir_selflog("skipped superfluous update of %s levels: %04"PRIx16, name, *old);
44✔
331
        }
332
    }
333
    return retval;
1,111✔
334
}
335

336
static
337
bool _sir_updateopts(const char* name, sir_options* old, const sir_options* new) {
37,857✔
338
    bool retval = _sir_validstr(name) && _sir_validptr(old) && _sir_validptr(new);
37,857✔
339
    if (retval) {
31,274✔
340
        if (*old != *new) {
37,857✔
341
            _sir_selflog("updating %s options from %08"PRIx32" to %08"PRIx32, name, *old, *new);
17,931✔
342
            *old = *new;
19,507✔
343
        } else {
344
            _sir_selflog("skipped superfluous update of %s options: %08"PRIx32, name, *old);
16,637✔
345
        }
346
    }
347
    return retval;
37,857✔
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) {
87✔
367
    bool updated = _sir_updatelevels(SIR_DESTNAME_SYSLOG, &si->d_syslog.levels, data->levels);
87✔
368
    if (updated) {
87✔
369
        _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_LEVELS);
87✔
370
        updated = _sir_syslog_updated(si, data);
87✔
371
        _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_LEVELS);
87✔
372
    }
373
    return updated;
87✔
374
}
375

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

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

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

405
    return retval;
135✔
406
}
407

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

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

427
    return retval;
106✔
428
}
429

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

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

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

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

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

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

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

453
    return enter ? sec : NULL;
8,804,004✔
454
}
455

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

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

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

468
    switch (mid) {
17,601,325✔
469
        case SIRMI_CONFIG:
8,556,101✔
470
            tmpm   = &cfg_mutex;
8,556,101✔
471
            tmpsec = &_sir_cfg;
8,556,101✔
472
            break;
8,556,101✔
473
        case SIRMI_FILECACHE:
4,328,433✔
474
            tmpm   = &fc_mutex;
4,275,331✔
475
            tmpsec = &_sir_fc;
4,275,331✔
476
            break;
4,328,433✔
477
        case SIRMI_PLUGINCACHE:
205,745✔
478
            tmpm   = &pc_mutex;
172,141✔
479
            tmpsec = &_sir_pc;
172,141✔
480
            break;
205,745✔
481
#if !defined(SIR_NO_TEXT_STYLING)
482
        case SIRMI_TEXTSTYLE:
4,415,714✔
483
            tmpm   = &ts_mutex;
4,358,617✔
484
            tmpsec = &sir_text_style_section;
4,358,617✔
485
            break;
4,415,714✔
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,552✔
497

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

501
    return *m != NULL && (!section || *section != NULL);
17,608,552✔
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,251✔
555
    if (!_sir_sanity() || !_sir_validlevel(level) || !_sir_validstr(format))
2,144,251✔
556
        return false;
54✔
557

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

560
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
2,144,199✔
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,713✔
588
        bool fmt = _sir_formattime(now_sec, _cfg->state.timestamp, SIR_TIMEFORMAT);
6,713✔
589
        SIR_ASSERT_UNUSED(fmt, fmt);
6,631✔
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,202✔
624
    buf.hostname  = cfg.state.hostname;
2,144,202✔
625
    buf.pid       = cfg.state.pidbuf;
2,144,202✔
626
    buf.name      = cfg.si.name;
2,144,202✔
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,201✔
638

639
    if (_sir_validstrnofail(_sir_tid))
2,144,201✔
640
        (void)_sir_strncpy(buf.tid, SIR_MAXPID, _sir_tid,
2,056,977✔
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,200✔
646
        return _sir_seterror(_SIR_E_INTERNAL);
26✔
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,175✔
654
        cfg.state.last.prefix[0] == buf.message[0]  &&
2,116,447✔
655
        cfg.state.last.prefix[1] == buf.message[1]) {
2,063,206✔
656
        hash  = FNV64_1a(buf.message);
2,072,932✔
657
        match = cfg.state.last.hash == hash;
2,072,932✔
658
    }
659

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

663
        if (cfg.state.last.counter >= cfg.state.last.threshold - 2) {
40,853✔
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,557✔
676
            exit_early = true;
32,361✔
677
        }
678
    } else {
679
        cfg.state.last.squelch   = false;
2,103,322✔
680
        cfg.state.last.counter   = 0;
2,103,322✔
681
        cfg.state.last.threshold = SIR_SQUELCH_THRESHOLD;
2,103,322✔
682
        /* _sir_selflog("message '%s' does not match last; resetting", buf.message); */
683
    }
684

685
    _cfg = _sir_locksection(SIRMI_CONFIG);
2,144,175✔
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,173✔
704
        return false;
32,361✔
705

706
    bool dispatched = _sir_dispatch(&cfg.si, level, &buf);
2,106,184✔
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,185✔
711
    bool retval       = true;
2,089,559✔
712
    size_t dispatched = 0;
2,089,559✔
713
    size_t wanted     = 0;
2,089,559✔
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,185✔
722
        const char* writef = _sir_format(styling, si->d_stdout.opts, buf);
1,100,075✔
723
        bool wrote         = _sir_validstrnofail(writef) &&
2,200,149✔
724
            _sir_write_stdout(writef, buf->output_len);
1,100,073✔
725
        _sir_eqland(retval, wrote);
1,084,528✔
726

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

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

738
        if (wrote)
1,335✔
739
            dispatched++;
1,576✔
740
        wanted++;
1,584✔
741
    }
742

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

751
    _SIR_LOCK_SECTION(const sirfcache, sfc, SIRMI_FILECACHE, false);
2,106,185✔
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);
901✔
773
        return _sir_seterror(_SIR_E_NODEST);
994✔
774
    }
775

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

779
const char* _sir_format(bool styling, sir_options opts, sirbuf* buf) {
2,182,210✔
780
    if (_sir_validptr(buf)) {
2,182,210✔
781
        bool first = true;
2,152,192✔
782

783
        _sir_resetstr(buf->output);
2,182,210✔
784

785
        if (styling)
2,182,214✔
786
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->style, SIR_MAXSTYLE);
1,091,011✔
787

788
        if (!_sir_bittest(opts, SIRO_NOTIME)) {
2,182,203✔
789
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->timestamp, SIR_MAXTIME);
2,058,011✔
790
            first = false;
2,047,722✔
791

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

798
        if (!_sir_bittest(opts, SIRO_NOHOST) && _sir_validstrnofail(buf->hostname)) {
2,182,220✔
799
            if (!first)
1,019,011✔
800
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,001,998✔
801
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->hostname, SIR_MAXHOST);
1,019,011✔
802
            first = false;
1,015,410✔
803
        }
804

805
        if (!_sir_bittest(opts, SIRO_NOLEVEL)) {
2,182,179✔
806
            if (!first)
2,121,468✔
807
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
2,058,188✔
808
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->level, SIR_MAXLEVEL);
2,121,471✔
809
            first = false;
2,102,009✔
810
        }
811

812
        bool name = false;
2,152,183✔
813
        if (!_sir_bittest(opts, SIRO_NONAME) && _sir_validstrnofail(buf->name)) {
2,182,237✔
814
            if (!first)
1,057,581✔
815
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,056,014✔
816
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->name, SIR_MAXNAME);
1,057,583✔
817
            first = false;
1,047,331✔
818
            name  = true;
1,047,331✔
819
        }
820

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

824
        if (wantpid || wanttid) {
2,168,865✔
825
            if (name)
2,076,701✔
826
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDPREFIX, 1);
1,053,960✔
827
            else if (!first)
1,022,741✔
828
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,022,730✔
829

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

833
            if (wanttid) {
2,076,712✔
834
                if (wantpid)
2,073,211✔
835
                    (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDSEPARATOR, 1);
2,039,176✔
836
                (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->tid, SIR_MAXPID);
2,073,202✔
837
            }
838

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

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

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

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

850
        if (styling)
2,182,209✔
851
            (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_ESC_RST, SIR_MAXSTYLE);
1,090,979✔
852

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

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

861
        return buf->output;
2,182,232✔
862
    }
863

864
    return NULL;
×
865
}
866

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

872
    /* begin resolve identity. */
873
    if (!_sir_validstrnofail(ctx->identity)) {
308✔
874
        _sir_selflog("ctx->identity is no good; trying name");
80✔
875
        if (_sir_validstrnofail(name)) {
86✔
876
            _sir_selflog("using name");
27✔
877
            (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, name, strnlen(name, SIR_MAX_SYSLOG_ID));
30✔
878
        } else {
879
            _sir_selflog("name is no good; trying filename");
53✔
880
            char* appbasename = _sir_getappbasename();
56✔
881
            if (_sir_validstrnofail(appbasename)) {
56✔
882
                _sir_selflog("filename is good: %s", appbasename);
52✔
883
                (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, appbasename,
52✔
884
                    strnlen(appbasename, SIR_MAX_SYSLOG_ID));
885
            } else {
886
                _sir_selflog("filename no good; using fallback");
4✔
887
                (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, SIR_FALLBACK_SYSLOG_ID,
4✔
888
                    strnlen(SIR_FALLBACK_SYSLOG_ID, SIR_MAX_SYSLOG_ID));
889
            }
890
            _sir_safefree(&appbasename);
56✔
891
        }
892
    } else {
893
        _sir_selflog("already have identity");
203✔
894
    }
895

896
    /* category */
897
    if (!_sir_validstrnofail(ctx->category)) {
308✔
898
        _sir_selflog("category not set; using fallback");
106✔
899
        (void)_sir_strncpy(ctx->category, SIR_MAX_SYSLOG_CAT, SIR_FALLBACK_SYSLOG_CAT,
116✔
900
            strnlen(SIR_FALLBACK_SYSLOG_CAT, SIR_MAX_SYSLOG_CAT));
901
    } else {
902
        _sir_selflog("already have category");
177✔
903
    }
904

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

908
    return _sir_syslog_open(ctx);
308✔
909
#else
910
    SIR_UNUSED(name);
911
    SIR_UNUSED(ctx);
912
    return false;
×
913
#endif
914
}
915

916
bool _sir_syslog_open(sir_syslog_dest* ctx) {
308✔
917
#if !defined(SIR_NO_SYSTEM_LOGGERS)
918
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_INIT)) {
308✔
919
        _sir_selflog("not initialized; ignoring");
×
920
        return _sir_seterror(_SIR_E_INVALID);
×
921
    }
922

923
    if (_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
308✔
924
        _sir_selflog("log already open; ignoring");
×
925
        return true;
×
926
    }
927

928
    _sir_selflog("opening log (levels: %04"PRIx16", options: %08"PRIx32")", ctx->levels,
308✔
929
        ctx->opts);
930

931
# if defined(SIR_OS_LOG_ENABLED)
932
    ctx->_state.logger = (void*)os_log_create(ctx->identity, ctx->category);
933
    _sir_selflog("opened os_log ('%s', '%s')", ctx->identity, ctx->category);
934
# elif defined(SIR_SYSLOG_ENABLED)
935
    int logopt   = LOG_NDELAY | (_sir_bittest(ctx->opts, SIRO_NOPID) ? 0 : LOG_PID);
308✔
936
    int facility = LOG_USER;
253✔
937

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

952
    _sir_setbitshigh(&ctx->_state.mask, SIRSL_IS_OPEN);
308✔
953
    return true;
308✔
954
#else
955
    SIR_UNUSED(ctx);
956
    return false;
×
957
#endif
958
}
959

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

967
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
877✔
968
        _sir_selflog("log not open; ignoring");
×
969
        return _sir_seterror(_SIR_E_INVALID);
×
970
    }
971

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

982
    return true;
983
# elif defined(SIR_SYSLOG_ENABLED)
984
    int syslog_level;
985
    switch (level) {
877✔
986
        case SIRL_DEBUG:  syslog_level = LOG_DEBUG; break;
46✔
987
        case SIRL_INFO:   syslog_level = LOG_INFO; break;
49✔
988
        case SIRL_NOTICE: syslog_level = LOG_NOTICE; break;
112✔
989
        case SIRL_WARN:   syslog_level = LOG_WARNING; break;
112✔
990
        case SIRL_ERROR:  syslog_level = LOG_ERR; break;
112✔
991
        case SIRL_CRIT:   syslog_level = LOG_CRIT; break;
143✔
992
        case SIRL_ALERT:  syslog_level = LOG_ALERT; break;
143✔
993
        case SIRL_EMERG:  syslog_level = LOG_EMERG; break;
143✔
994
        // GCOVR_EXCL_START
995
        default: /* this should never happen. */
996
            SIR_ASSERT(false);
997
            syslog_level = LOG_DEBUG;
998
        // GCOVR_EXCL_STOP
999
    }
1000

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

1016
    SIR_ASSERT(NULL != edesc);
1017
    if (NULL == edesc)
1018
        return _sir_seterror(_SIR_E_INTERNAL);
1019

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

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

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

1046
    return ERROR_SUCCESS == write;
1047
# else
1048
    SIR_UNUSED(level);
1049
    SIR_UNUSED(buf);
1050
    SIR_UNUSED(ctx);
1051
    return false;
1052
# endif
1053
#else
1054
    SIR_UNUSED(level);
1055
    SIR_UNUSED(buf);
1056
    SIR_UNUSED(ctx);
1057
    return false;
×
1058
#endif
1059
}
1060

1061
bool _sir_syslog_updated(sirinit* si, const sir_update_config_data* data) {
310✔
1062
#if !defined(SIR_NO_SYSTEM_LOGGERS)
1063
    if (!_sir_validptr(si) || !_sir_validptr(data))
310✔
1064
        return false;
×
1065

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

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

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

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

1104
        return init;
310✔
1105
    }
1106

1107
    return false;
×
1108
#else
1109
    SIR_UNUSED(si);
1110
    SIR_UNUSED(data);
1111
    return false;
×
1112
#endif
1113
}
1114

1115
bool _sir_syslog_close(sir_syslog_dest* ctx) {
978✔
1116
#if !defined(SIR_NO_SYSTEM_LOGGERS)
1117
    if (!_sir_validptr(ctx))
978✔
1118
        return false;
×
1119

1120
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
978✔
1121
        _sir_selflog("log not open; ignoring");
606✔
1122
        return true;
606✔
1123
    }
1124

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

1145
    return ERROR_SUCCESS == unreg;
1146
# else
1147
    SIR_UNUSED(ctx);
1148
    return false;
1149
# endif
1150
#else
1151
    SIR_UNUSED(ctx);
1152
    return false;
×
1153
#endif
1154
}
1155

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

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

1173
    const char* retval = SIR_UNKNOWN;
2,121,942✔
1174

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

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

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

1186
    return retval;
2,144,201✔
1187
}
1188

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

1196
        if (0 == ret) {
6,265,683✔
1197
            *tbuf = ts.tv_sec;
6,277,186✔
1198
            if (msecbuf)
6,277,186✔
1199
                *msecbuf = ts.tv_nsec / 1000000L;
6,277,186✔
1200
        } else {
1201
            if (msecbuf)
11,317✔
1202
                *msecbuf = 0L;
11,317✔
1203
            return _sir_handleerr(errno);
11,317✔
1204
        }
1205
#elif defined(SIR_MSEC_WIN32)
1206
        SIR_UNUSED(clock);
1207
        static const ULONGLONG uepoch = (ULONGLONG)116444736e9;
1208

1209
        FILETIME ftutc = {0};
1210
        GetSystemTimePreciseAsFileTime(&ftutc);
1211

1212
        ULARGE_INTEGER ftnow = {0};
1213
        ftnow.HighPart = ftutc.dwHighDateTime;
1214
        ftnow.LowPart  = ftutc.dwLowDateTime;
1215
        ftnow.QuadPart = (ULONGLONG)((ftnow.QuadPart - uepoch) / 10000000ULL);
1216

1217
        *tbuf = (time_t)ftnow.QuadPart;
1218

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

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

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

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

1253
    return ((((double)out->sec) * 1e3) + (double)out->msec) -
4,138,580✔
1254
           ((((double)when->sec) * 1e3) + (double)when->msec);
4,138,580✔
1255
#else /* __WIN__ */
1256
    SIR_ASSERT(_sir_perfcntr_freq.QuadPart > 0LL);
1257

1258
    if (_sir_perfcntr_freq.QuadPart <= 0LL)
1259
        (void)QueryPerformanceFrequency(&_sir_perfcntr_freq);
1260

1261
    (void)QueryPerformanceCounter(&out->counter);
1262

1263
    if (!_sir_validptrnofail(when) || out->counter.QuadPart <= when->counter.QuadPart)
1264
        return 0.0;
1265

1266
    double msec_ratio = ((double)_sir_perfcntr_freq.QuadPart) / 1e3;
1267
    return ((double)(out->counter.QuadPart - when->counter.QuadPart)) / msec_ratio;
1268
#endif
1269
}
1270

1271
pid_t _sir_getpid(void) {
1,083✔
1272
#if !defined(__WIN__)
1273
    return getpid();
1,083✔
1274
#else /* __WIN__ */
1275
    return (pid_t)GetCurrentProcessId();
1276
#endif
1277
}
1278

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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