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

aremmell / libsir / 839

23 Sep 2023 06:32AM UTC coverage: 94.27% (-0.3%) from 94.537%
839

Pull #292

gitlab-ci

johnsonjh
Docs ...

Signed-off-by: Jeffrey H. Johnson <trnsz@pobox.com>
Pull Request #292: Python/Ch bindings (& general support for new bindings), WIP C++ header-only wrapper implementation

877 of 877 new or added lines in 9 files covered. (100.0%)

3570 of 3787 relevant lines covered (94.27%)

530034.79 hits per line

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

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

35
#if defined(__WIN__)
36
# if defined(__EMBARCADEROC__) && defined(_WIN64)
37
#  pragma comment(lib, "ws2_32.a")
38
# else
39
#  pragma comment(lib, "ws2_32.lib")
40
# endif
41
#endif
42

43
static sirconfig _sir_cfg      = {0};
44
static sirfcache _sir_fc       = {0};
45
static sir_plugincache _sir_pc = {0};
46

47
static sir_mutex cfg_mutex  = SIR_MUTEX_INIT;
48
static sir_mutex fc_mutex   = SIR_MUTEX_INIT;
49
static sir_mutex pc_mutex   = SIR_MUTEX_INIT;
50
static sir_mutex ts_mutex   = SIR_MUTEX_INIT;
51
static sir_once static_once = SIR_ONCE_INIT;
52

53
#if defined(__WIN__)
54
static LARGE_INTEGER _sir_perfcntr_freq = {0};
55
#endif
56

57
#if defined(__HAVE_ATOMIC_H__)
58
static atomic_uint_fast32_t _sir_magic;
59
#else
60
static volatile uint32_t _sir_magic = 0U;
61
#endif
62

63
static _sir_thread_local char _sir_tid[SIR_MAXPID]   = {0};
64
static _sir_thread_local sir_time _sir_last_thrd_chk = {0};
65
static _sir_thread_local time_t _sir_last_timestamp  = 0;
66

67
bool _sir_makeinit(sirinit* si) {
66✔
68
    bool retval = _sir_validptr(si);
66✔
69

70
    if (retval) {
66✔
71
        memset(si, 0, sizeof(sirinit));
60✔
72

73
        si->d_stdout.opts   = SIRO_DEFAULT;
66✔
74
        si->d_stdout.levels = SIRL_DEFAULT;
66✔
75

76
        si->d_stderr.opts   = SIRO_DEFAULT;
66✔
77
        si->d_stderr.levels = SIRL_DEFAULT;
66✔
78

79
#if !defined(SIR_NO_SYSTEM_LOGGERS)
80
        si->d_syslog.opts   = SIRO_DEFAULT;
53✔
81
        si->d_syslog.levels = SIRL_DEFAULT;
53✔
82
#else
83
        si->d_syslog.opts   = SIRO_MSGONLY;
13✔
84
        si->d_syslog.levels = SIRL_NONE;
13✔
85
#endif
86
    }
87

88
    return retval;
66✔
89
}
90

91
bool _sir_init(sirinit* si) {
856✔
92
    (void)_sir_seterror(_SIR_E_NOERROR);
856✔
93

94
    /* can only fail on Windows. */
95
    bool once_init = _sir_once(&static_once, _sir_init_static_once);
856✔
96
#if !defined(__WIN__)
97
    SIR_UNUSED(once_init);
98
#else
99
    if (!once_init) {
100
        _sir_selflog("error: static data initialization routine failed!");
101
        return false;
102
    }
103
#endif
104

105
    if (!_sir_validptr(si))
856✔
106
        return false;
19✔
107

108
#if defined(__HAVE_ATOMIC_H__)
109
    if (_SIR_MAGIC == atomic_load(&_sir_magic))
834✔
110
#else
111
    if (_SIR_MAGIC == _sir_magic)
112
#endif
113
        return _sir_seterror(_SIR_E_ALREADY);
24✔
114

115
    _sir_defaultlevels(&si->d_stdout.levels, sir_stdout_def_lvls);
810✔
116
    _sir_defaultopts(&si->d_stdout.opts, sir_stdout_def_opts);
810✔
117

118
    _sir_defaultlevels(&si->d_stderr.levels, sir_stderr_def_lvls);
810✔
119
    _sir_defaultopts(&si->d_stderr.opts, sir_stderr_def_opts);
810✔
120

121
#if !defined(SIR_NO_SYSTEM_LOGGERS)
122
    _sir_defaultlevels(&si->d_syslog.levels, sir_syslog_def_lvls);
612✔
123
    _sir_defaultopts(&si->d_syslog.opts, sir_syslog_def_opts);
612✔
124
#endif
125

126
    if (!_sir_init_sanity(si))
810✔
127
        return false;
19✔
128

129
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
788✔
130

131
    bool init = true;
680✔
132

133
#if !defined(__WIN__)
134
    tzset();
788✔
135
#endif
136

137
#if defined(__HAVE_ATOMIC_H__)
138
    atomic_store(&_sir_magic, _SIR_MAGIC);
788✔
139
#else
140
    _sir_magic = _SIR_MAGIC;
141
#endif
142

143
    _sir_reset_tls();
788✔
144

145
#if defined(__WIN__)
146
    _sir_initialize_stdio();
147
#endif
148

149
    if (!_sir_setcolormode(SIRCM_16)) {
788✔
150
        init = false;
×
151
        _sir_selflog("error: failed to set color mode!");
×
152
    }
153

154
    if (!_sir_resettextstyles()) {
788✔
155
        init = false;
×
156
        _sir_selflog("error: failed to reset text styles!");
×
157
    }
158

159
    memset(&_cfg->state, 0, sizeof(_cfg->state));
788✔
160
    memcpy(&_cfg->si, si, sizeof(sirinit));
788✔
161

162
    /* forcibly null-terminate the process name. */
163
    _cfg->si.name[SIR_MAXNAME - 1] = '\0';
788✔
164

165
    /* Store PID. */
166
    _cfg->state.pid = _sir_getpid();
788✔
167

168
    (void)snprintf(_cfg->state.pidbuf, SIR_MAXPID, SIR_PIDFORMAT,
788✔
169
        PID_CAST _cfg->state.pid);
170

171
#if !defined(SIR_NO_SYSTEM_LOGGERS)
172
    /* initialize system logger. */
173
    _sir_syslog_reset(&_cfg->si.d_syslog);
596✔
174

175
    if (_cfg->si.d_syslog.levels != SIRL_NONE &&
614✔
176
        !_sir_syslog_init(_cfg->si.name, &_cfg->si.d_syslog)) {
105✔
177
        init = false;
×
178
        _sir_selflog("failed to initialize system logger!");
×
179
    }
180
#endif
181

182
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
788✔
183

184
    _sir_selflog("initialized %s", (init ? "successfully" : "with errors"));
752✔
185

186
    SIR_ASSERT(init);
752✔
187
    return init;
716✔
188
}
189

190
bool _sir_cleanup(void) {
811✔
191
    if (!_sir_sanity())
811✔
192
        return false;
20✔
193

194
    _SIR_LOCK_SECTION(sirfcache, sfc, SIRMI_FILECACHE, false);
788✔
195
    bool cleanup   = true;
680✔
196
    bool destroyfc = _sir_fcache_destroy(sfc);
788✔
197
    SIR_ASSERT(destroyfc);
752✔
198

199
    _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
788✔
200
    _sir_eqland(cleanup, destroyfc);
680✔
201

202
#if !defined(SIR_NO_PLUGINS)
203
    _SIR_LOCK_SECTION(sir_plugincache, spc, SIRMI_PLUGINCACHE, false);
735✔
204
    bool destroypc = _sir_plugin_cache_destroy(spc);
735✔
205
    SIR_ASSERT(destroypc);
699✔
206
    _SIR_UNLOCK_SECTION(SIRMI_PLUGINCACHE);
735✔
207
    _sir_eqland(cleanup, destroypc);
735✔
208
#endif
209

210
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
788✔
211

212
#if !defined(SIR_NO_SYSTEM_LOGGERS)
213
    if (!_sir_syslog_close(&_cfg->si.d_syslog)) {
596✔
214
        cleanup = false;
×
215
        _sir_selflog("error: failed to close system logger!");
×
216
    }
217

218
    _sir_syslog_reset(&_cfg->si.d_syslog);
596✔
219
#endif
220

221
    if (!_sir_resettextstyles()) {
788✔
222
        cleanup = false;
×
223
        _sir_selflog("error: failed to reset text styles!");
×
224
    }
225

226
#if defined(__HAVE_ATOMIC_H__)
227
    atomic_store(&_sir_magic, 0);
788✔
228
#else
229
    _sir_magic = 0U;
230
#endif
231

232
    _sir_reset_tls();
788✔
233

234
    memset(_cfg, 0, sizeof(sirconfig));
680✔
235
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
788✔
236

237
    _sir_selflog("cleaned up %s", (cleanup ? "successfully" : "with errors"));
752✔
238

239
    SIR_ASSERT(cleanup);
752✔
240
    return cleanup;
716✔
241
}
242

243
bool _sir_isinitialized(void) {
2,497,773✔
244
#if defined(__HAVE_ATOMIC_H__)
245
    if (_SIR_MAGIC == atomic_load(&_sir_magic))
2,497,773✔
246
        return true;
2,497,750✔
247
#else
248
    if (_SIR_MAGIC == _sir_magic)
249
        return true;
250
#endif
251
    return false;
41✔
252
}
253

254
bool _sir_sanity(void) {
2,497,670✔
255
    if (_sir_isinitialized())
2,497,670✔
256
        return true;
2,417,880✔
257
    return _sir_seterror(_SIR_E_NOTREADY);
59✔
258
}
259

260
bool _sir_init_sanity(const sirinit* si) {
810✔
261
    if (!_sir_validptr(si))
810✔
262
        return false;
×
263

264
    bool levelcheck = true;
699✔
265
    _sir_eqland(levelcheck, _sir_validlevels(si->d_stdout.levels));
810✔
266
    _sir_eqland(levelcheck, _sir_validlevels(si->d_stderr.levels));
810✔
267

268
    bool regcheck = true;
699✔
269
    _sir_eqland(regcheck, SIRL_NONE == si->d_stdout.levels);
773✔
270
    _sir_eqland(regcheck, SIRL_NONE == si->d_stderr.levels);
773✔
271

272
#if !defined(SIR_NO_SYSTEM_LOGGERS)
273
    _sir_eqland(levelcheck, _sir_validlevels(si->d_syslog.levels));
612✔
274
    _sir_eqland(regcheck, SIRL_NONE == si->d_syslog.levels);
575✔
275
#endif
276

277
    if (regcheck)
699✔
278
        _sir_selflog("warning: no level registrations set!");
41✔
279

280
    bool optscheck = true;
699✔
281
    _sir_eqland(optscheck, _sir_validopts(si->d_stdout.opts));
810✔
282
    _sir_eqland(optscheck, _sir_validopts(si->d_stderr.opts));
810✔
283

284
#if !defined(SIR_NO_SYSTEM_LOGGERS)
285
    _sir_eqland(optscheck, _sir_validopts(si->d_syslog.opts));
612✔
286
#endif
287

288
    return levelcheck && optscheck;
810✔
289
}
290

291
void _sir_reset_tls(void) {
1,576✔
292
    _sir_resetstr(_sir_tid);
1,576✔
293
    memset(&_sir_last_thrd_chk, 0, sizeof(sir_time));
1,360✔
294
    _sir_last_timestamp = 0;
1,576✔
295
    _sir_reset_tls_error();
1,576✔
296
}
1,576✔
297

298
static
299
bool _sir_updatelevels(const char* name, sir_levels* old, const sir_levels* new) {
859✔
300
    if (*old != *new) {
859✔
301
        _sir_selflog("updating %s levels from %04"PRIx16" to %04"PRIx16, name, *old, *new);
776✔
302
        *old = *new;
821✔
303
    } else {
304
        _sir_selflog("skipped superfluous update of %s levels: %04"PRIx16, name, *old);
36✔
305
    }
306
    return true;
859✔
307
}
308

309
static
310
bool _sir_updateopts(const char* name, sir_options* old, const sir_options* new) {
72,815✔
311
    if (*old != *new) {
72,815✔
312
        _sir_selflog("updating %s options from %08"PRIx32" to %08"PRIx32, name, *old, *new);
35,406✔
313
        *old = *new;
37,424✔
314
    } else {
315
        _sir_selflog("skipped superfluous update of %s options: %08"PRIx32, name, *old);
33,364✔
316
    }
317
    return true;
72,815✔
318
}
319

320
bool _sir_stdoutlevels(sirinit* si, const sir_update_config_data* data) {
424✔
321
    return _sir_updatelevels(SIR_DESTNAME_STDOUT, &si->d_stdout.levels, data->levels);
424✔
322
}
323

324
bool _sir_stdoutopts(sirinit* si, const sir_update_config_data* data) {
72,380✔
325
    return _sir_updateopts(SIR_DESTNAME_STDOUT, &si->d_stdout.opts, data->opts);
72,380✔
326
}
327

328
bool _sir_stderrlevels(sirinit* si, const sir_update_config_data* data) {
380✔
329
    return _sir_updatelevels(SIR_DESTNAME_STDERR, &si->d_stderr.levels, data->levels);
380✔
330
}
331

332
bool _sir_stderropts(sirinit* si, const sir_update_config_data* data) {
380✔
333
    return _sir_updateopts(SIR_DESTNAME_STDERR, &si->d_stderr.opts, data->opts);
380✔
334
}
335

336
bool _sir_sysloglevels(sirinit* si, const sir_update_config_data* data) {
55✔
337
    bool updated = _sir_updatelevels(SIR_DESTNAME_SYSLOG, &si->d_syslog.levels, data->levels);
55✔
338
    if (updated) {
55✔
339
        _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_LEVELS);
55✔
340
        updated = _sir_syslog_updated(si, data);
55✔
341
        _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_LEVELS);
55✔
342
    }
343
    return updated;
55✔
344
}
345

346
bool _sir_syslogopts(sirinit* si, const sir_update_config_data* data) {
55✔
347
    bool updated = _sir_updateopts(SIR_DESTNAME_SYSLOG, &si->d_syslog.opts, data->opts);
55✔
348
    if (updated) {
55✔
349
        _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_OPTIONS);
55✔
350
        updated = _sir_syslog_updated(si, data);
55✔
351
        _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_OPTIONS);
55✔
352
    }
353
    return updated;
55✔
354
}
355

356
bool _sir_syslogid(sirinit* si, const sir_update_config_data* data) {
119✔
357
    bool cur_valid = _sir_validstrnofail(si->d_syslog.identity);
119✔
358
    if (!cur_valid || 0 != strncmp(si->d_syslog.identity, data->sl_identity, SIR_MAX_SYSLOG_ID)) {
119✔
359
        _sir_selflog("updating %s identity from '%s' to '%s'", SIR_DESTNAME_SYSLOG,
73✔
360
            si->d_syslog.identity, data->sl_identity);
361
        _sir_strncpy(si->d_syslog.identity, SIR_MAX_SYSLOG_ID, data->sl_identity,
73✔
362
            strnlen(data->sl_identity, SIR_MAX_SYSLOG_ID));
70✔
363
    } else {
364
        _sir_selflog("skipped superfluous update of %s identity: '%s'", SIR_DESTNAME_SYSLOG,
44✔
365
            si->d_syslog.identity);
366
        return true;
44✔
367
    }
368

369
    _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_IDENTITY);
73✔
370
    bool updated = _sir_syslog_updated(si, data);
73✔
371
    _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_IDENTITY);
73✔
372

373
    return updated;
73✔
374
}
375

376
bool _sir_syslogcat(sirinit* si, const sir_update_config_data* data) {
82✔
377
    bool cur_valid = _sir_validstrnofail(si->d_syslog.category);
82✔
378
    if (!cur_valid || 0 != strncmp(si->d_syslog.category, data->sl_category, SIR_MAX_SYSLOG_CAT)) {
82✔
379
        _sir_selflog("updating %s category from '%s' to '%s'", SIR_DESTNAME_SYSLOG,
41✔
380
            si->d_syslog.category, data->sl_category);
381
        _sir_strncpy(si->d_syslog.category, SIR_MAX_SYSLOG_CAT, data->sl_category,
41✔
382
            strnlen(data->sl_category, SIR_MAX_SYSLOG_CAT));
37✔
383
    } else {
384
        _sir_selflog("skipped superfluous update of %s category: '%s'", SIR_DESTNAME_SYSLOG,
37✔
385
            si->d_syslog.identity);
386
        return true;
37✔
387
    }
388

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

393
    return updated;
41✔
394
}
395

396
bool _sir_writeinit(const sir_update_config_data* data, sirinit_update update) {
73,872✔
397
    (void)_sir_seterror(_SIR_E_NOERROR);
73,872✔
398

399
    if (!_sir_sanity() || !_sir_validupdatedata(data) || !_sir_validfnptr(update))
73,870✔
400
        return false;
×
401

402
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
73,857✔
403

404
    bool updated = update(&_cfg->si, data);
73,875✔
405
    if (!updated)
69,770✔
406
        _sir_selflog("error: update routine failed!");
×
407

408
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
73,875✔
409
    return updated;
73,875✔
410
}
411

412
void* _sir_locksection(sir_mutex_id mid) {
9,054,427✔
413
    sir_mutex* m = NULL;
9,054,427✔
414
    void* sec    = NULL;
9,054,427✔
415

416
    bool enter = _sir_mapmutexid(mid, &m, &sec) && _sir_mutexlock(m);
9,054,427✔
417
    SIR_ASSERT(enter);
9,003,796✔
418

419
    return enter ? sec : NULL;
9,059,210✔
420
}
421

422
void _sir_unlocksection(sir_mutex_id mid) {
9,058,881✔
423
    sir_mutex* m = NULL;
9,058,881✔
424
    void* sec    = NULL;
9,058,881✔
425

426
    bool leave = _sir_mapmutexid(mid, &m, &sec) && _sir_mutexunlock(m);
9,058,881✔
427
    SIR_ASSERT_UNUSED(leave, leave);
9,005,138✔
428
}
9,060,806✔
429

430
bool _sir_mapmutexid(sir_mutex_id mid, sir_mutex** m, void** section) {
18,106,488✔
431
    sir_mutex* tmpm;
432
    void* tmpsec;
433

434
    switch (mid) {
18,106,488✔
435
        case SIRMI_CONFIG:
8,659,182✔
436
            tmpm   = &cfg_mutex;
8,659,182✔
437
            tmpsec = &_sir_cfg;
8,659,182✔
438
            break;
8,659,182✔
439
        case SIRMI_FILECACHE:
4,472,120✔
440
            tmpm   = &fc_mutex;
4,396,767✔
441
            tmpsec = &_sir_fc;
4,396,767✔
442
            break;
4,472,120✔
443
        case SIRMI_PLUGINCACHE:
240,638✔
444
            tmpm   = &pc_mutex;
201,324✔
445
            tmpsec = &_sir_pc;
201,324✔
446
            break;
240,638✔
447
        case SIRMI_TEXTSTYLE:
4,628,563✔
448
            tmpm   = &ts_mutex;
4,529,643✔
449
            tmpsec = &sir_text_style_section;
4,529,643✔
450
            break;
4,628,563✔
451
        // GCOVR_EXCL_START
452
        default: /* this should never happen. */
453
            SIR_ASSERT(false);
454
            tmpm   = NULL;
455
            tmpsec = NULL;
456
            break;
457
        // GCOVR_EXCL_STOP
458
    }
459

460
    *m = tmpm;
18,120,371✔
461

462
    if (section)
18,120,371✔
463
        *section = tmpsec;
18,107,131✔
464

465
    return *m != NULL && (!section || *section != NULL);
18,120,371✔
466
}
467

468
#if !defined(__WIN__)
469
void _sir_init_static_once(void) {
59✔
470
    (void)_sir_init_common_static();
59✔
471
}
59✔
472
#else /* __WIN__ */
473
BOOL CALLBACK _sir_init_static_once(PINIT_ONCE ponce, PVOID param, PVOID* ctx) {
474
    SIR_UNUSED(ponce);
475
    SIR_UNUSED(param);
476
    SIR_UNUSED(ctx);
477
    return _sir_init_common_static() ? TRUE : FALSE;
478
}
479
#endif
480

481
bool _sir_init_common_static(void) {
59✔
482
#if defined(__HAVE_ATOMIC_H__)
483
    atomic_init(&_sir_magic, 0);
59✔
484
#endif
485

486
#if defined(__WIN__)
487
    (void)QueryPerformanceFrequency(&_sir_perfcntr_freq);
488
#endif
489

490
    bool created = _sir_mutexcreate(&cfg_mutex);
59✔
491
    SIR_ASSERT(created);
57✔
492

493
    _sir_eqland(created, _sir_mutexcreate(&fc_mutex));
59✔
494
    SIR_ASSERT(created);
57✔
495

496
    _sir_eqland(created, _sir_mutexcreate(&pc_mutex));
59✔
497
    SIR_ASSERT(created);
57✔
498

499
    _sir_eqland(created, _sir_mutexcreate(&ts_mutex));
59✔
500
    SIR_ASSERT(created);
57✔
501

502
    return created;
59✔
503
}
504

505
bool _sir_once(sir_once* once, sir_once_fn func) {
856✔
506
#if !defined(__WIN__)
507
    int ret = pthread_once(once, func);
856✔
508
    return 0 == ret ? true : _sir_handleerr(ret);
856✔
509
#else /* __WIN__ */
510
    return (FALSE != InitOnceExecuteOnce(once, func, NULL, NULL)) ? true
511
        : _sir_handlewin32err(GetLastError());
512
#endif
513
}
514

515
PRINTF_FORMAT_ATTR(2, 0)
516
bool _sir_logv(sir_level level, PRINTF_FORMAT const char* format, va_list args) {
2,157,150✔
517
    if (!_sir_sanity() || !_sir_validlevel(level) || !_sir_validstr(format))
2,157,150✔
518
        return false;
44✔
519

520
    (void)_sir_seterror(_SIR_E_NOERROR);
2,157,101✔
521

522
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
2,157,103✔
523

524
    sirbuf buf = {0};
2,157,117✔
525

526
    /* from time to time, update the host name in the config, just in case. */
527
    time_t now_sec = -1;
2,157,117✔
528
    if (-1 != time(&now_sec) &&
2,157,117✔
529
        (now_sec - _cfg->state.last_hname_chk) > SIR_HNAME_CHK_INTERVAL) {
2,149,196✔
530
        _sir_selflog("updating hostname...");
8,335✔
531
        if (!_sir_gethostname(_cfg->state.hostname)) {
8,358✔
532
            _sir_selflog("error: failed to get hostname!");
7,921✔
533
        } else {
534
            _cfg->state.last_hname_chk = now_sec;
437✔
535
            _sir_selflog("hostname: '%s'", _cfg->state.hostname);
414✔
536
        }
537
    }
538

539
    /* format timestamp (h/m/s only if the integer time has changed). */
540
    long now_msec = 0L;
2,157,117✔
541
    bool gettime = _sir_clock_gettime(SIR_WALLCLOCK, &now_sec, &now_msec);
2,157,117✔
542
    SIR_ASSERT_UNUSED(gettime, gettime);
2,149,196✔
543

544
    /* milliseconds. */
545
    _sir_snprintf_trunc(buf.msec, SIR_MAXMSEC, SIR_MSECFORMAT, now_msec);
2,157,117✔
546

547
    /* hours/minutes/seconds. */
548
    if (now_sec > _sir_last_timestamp || !*_cfg->state.timestamp) {
2,157,117✔
549
        _sir_last_timestamp = now_sec;
8,730✔
550
        bool fmt = _sir_formattime(now_sec, _cfg->state.timestamp, SIR_TIMEFORMAT);
8,730✔
551
        SIR_ASSERT_UNUSED(fmt, fmt);
8,686✔
552
    }
553

554
    /* check elapsed time since updating thread identifier/name. */
555
    sir_time thrd_chk;
556
    double msec_since_thrd_chk = _sir_msec_since(&_sir_last_thrd_chk, &thrd_chk);
2,157,117✔
557

558
    /* update the thread identifier/name if enough time has elapsed. */
559
    if (msec_since_thrd_chk > SIR_THRD_CHK_INTERVAL) {
2,157,117✔
560
        _sir_last_thrd_chk = thrd_chk;
844✔
561

562
        pid_t tid         = _sir_gettid();
844✔
563
        bool resolved_tid = false;
721✔
564

565
        /* prefer thread names. */
566
        resolved_tid = _sir_getthreadname(_sir_tid);
844✔
567

568
        /* if tid is identical to pid... */
569
        if (!resolved_tid && tid == _cfg->state.pid) {
844✔
570
            /* don't use anything to identify the thread. */
571
            _sir_resetstr(_sir_tid);
163✔
572
            resolved_tid = true;
136✔
573
        }
574

575
        /* fall back on tid. */
576
        if (!resolved_tid)
721✔
577
            _sir_snprintf_trunc(_sir_tid, SIR_MAXPID, SIR_PIDFORMAT,
×
578
                PID_CAST tid);
579
    }
580

581
    sirconfig cfg;
582
    memcpy(&cfg, _cfg, sizeof(sirconfig));
2,133,354✔
583
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
2,157,117✔
584

585
    buf.timestamp = cfg.state.timestamp;
2,157,117✔
586
    buf.hostname  = cfg.state.hostname;
2,157,117✔
587
    buf.pid       = cfg.state.pidbuf;
2,157,117✔
588
    buf.name      = cfg.si.name;
2,157,117✔
589

590
    const char* style_str = _sir_gettextstyle(level);
2,157,117✔
591

592
    SIR_ASSERT(NULL != style_str);
2,149,196✔
593
    if (NULL != style_str)
2,141,275✔
594
        (void)_sir_strncpy(buf.style, SIR_MAXSTYLE, style_str,
2,157,117✔
595
            strnlen(style_str, SIR_MAXSTYLE));
596

597
    buf.level = _sir_formattedlevelstr(level);
2,157,117✔
598

599
    if (_sir_validstrnofail(_sir_tid))
2,157,117✔
600
        (void)_sir_strncpy(buf.tid, SIR_MAXPID, _sir_tid,
2,085,494✔
601
            strnlen(_sir_tid, SIR_MAXPID));
602

603
    (void)vsnprintf(buf.message, SIR_MAXMESSAGE, format, args);
2,133,354✔
604

605
    if (!_sir_validstrnofail(buf.message))
2,157,115✔
606
        return _sir_seterror(_SIR_E_INTERNAL);
22✔
607

608
    bool match             = false;
2,133,335✔
609
    bool exit_early        = false;
2,133,335✔
610
    bool update_last_props = true;
2,133,335✔
611
    uint64_t hash          = 0ULL;
2,133,335✔
612

613
    if (cfg.state.last.prefix[0] == buf.message[0]  &&
2,157,095✔
614
        cfg.state.last.prefix[1] == buf.message[1]) {
2,102,711✔
615
        hash  = FNV64_1a(buf.message);
2,120,887✔
616
        match = cfg.state.last.hash == hash;
2,120,887✔
617
    }
618

619
    if (match) {
2,152,159✔
620
        cfg.state.last.counter++;
34,944✔
621

622
        /* _sir_selflog("message '%s' matches last; incremented counter to %zu", buf.message,
623
            cfg.state.last.counter); */
624

625
        if (cfg.state.last.counter >= cfg.state.last.threshold - 2) {
34,944✔
626
            size_t old_threshold = cfg.state.last.threshold;
924✔
627

628
            update_last_props = false;
924✔
629
            cfg.state.last.threshold *= SIR_SQUELCH_BACKOFF_FACTOR;
1,068✔
630
            cfg.state.last.squelch = true;
1,068✔
631

632
            _sir_selflog("hit squelch threshold of %zu; setting new threshold"
1,020✔
633
                         " to %zu (factor: %d)",
634
                old_threshold, cfg.state.last.threshold, SIR_SQUELCH_BACKOFF_FACTOR);
635

636
            (void)snprintf(buf.message, SIR_MAXMESSAGE, SIR_SQUELCH_MSG_FORMAT, old_threshold);
924✔
637
        } else if (cfg.state.last.squelch) {
33,876✔
638
            exit_early = true;
26,740✔
639
        }
640
    } else {
641
        cfg.state.last.squelch   = false;
2,122,151✔
642
        cfg.state.last.counter   = 0;
2,122,151✔
643
        cfg.state.last.threshold = SIR_SQUELCH_THRESHOLD;
2,122,151✔
644
        /* _sir_selflog("message '%s' does not match last; resetting", buf.message); */
645
    }
646

647
    _cfg = _sir_locksection(SIRMI_CONFIG);
2,157,095✔
648
    if (!_cfg)
2,157,095✔
649
        return _sir_seterror(_SIR_E_INTERNAL);
×
650

651
    _cfg->state.last.squelch = cfg.state.last.squelch;
2,157,095✔
652

653
    if (update_last_props) {
2,157,095✔
654
        _cfg->state.last.hash      = hash;
2,156,027✔
655
        _cfg->state.last.prefix[0] = buf.message[0];
2,156,027✔
656
        _cfg->state.last.prefix[1] = buf.message[1];
2,156,027✔
657
    }
658

659
    _cfg->state.last.counter   = cfg.state.last.counter;
2,157,095✔
660
    _cfg->state.last.threshold = cfg.state.last.threshold;
2,157,095✔
661

662
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
2,157,095✔
663

664
    if (exit_early)
2,157,094✔
665
        return false;
26,740✔
666

667
    bool dispatched = _sir_dispatch(&cfg.si, level, &buf);
2,126,133✔
668
    return update_last_props ? dispatched : false;
2,126,134✔
669
}
670

671
bool _sir_dispatch(const sirinit* si, sir_level level, sirbuf* buf) {
2,126,133✔
672
    bool retval       = true;
2,106,594✔
673
    size_t dispatched = 0;
2,106,594✔
674
    size_t wanted     = 0;
2,106,594✔
675

676
    if (_sir_bittest(si->d_stdout.levels, level)) {
2,126,133✔
677
        const char* write = _sir_format(true, si->d_stdout.opts, buf);
1,122,535✔
678
        bool wrote        = _sir_validstrnofail(write) &&
2,245,063✔
679
            _sir_write_stdout(write, buf->output_len);
1,122,527✔
680
        _sir_eqland(retval, wrote);
1,103,590✔
681

682
        if (wrote)
1,103,590✔
683
            dispatched++;
1,097,363✔
684
        wanted++;
1,103,590✔
685
    }
686

687
    if (_sir_bittest(si->d_stderr.levels, level)) {
2,126,134✔
688
        const char* write = _sir_format(true, si->d_stderr.opts, buf);
1,217✔
689
        bool wrote        = _sir_validstrnofail(write) &&
2,434✔
690
            _sir_write_stderr(write, buf->output_len);
1,217✔
691
        _sir_eqland(retval, wrote);
1,217✔
692

693
        if (wrote)
1,217✔
694
            dispatched++;
1,208✔
695
        wanted++;
1,217✔
696
    }
697

698
#if !defined(SIR_NO_SYSTEM_LOGGERS)
699
    if (_sir_bittest(si->d_syslog.levels, level)) {
2,091,698✔
700
        if (_sir_syslog_write(level, buf, &si->d_syslog))
620✔
701
            dispatched++;
620✔
702
        wanted++;
620✔
703
    }
704
#endif
705

706
    _SIR_LOCK_SECTION(sirfcache, sfc, SIRMI_FILECACHE, false);
2,126,134✔
707
    size_t fdispatched = 0;
2,126,134✔
708
    size_t fwanted     = 0;
2,126,134✔
709
    _sir_eqland(retval, _sir_fcache_dispatch(sfc, level, buf, &fdispatched, &fwanted));
2,126,134✔
710
    _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
2,126,134✔
711

712
    dispatched += fdispatched;
2,126,134✔
713
    wanted += fwanted;
2,126,134✔
714

715
#if !defined(SIR_NO_PLUGINS)
716
    _SIR_LOCK_SECTION(sir_plugincache, spc, SIRMI_PLUGINCACHE, false);
119,496✔
717
    size_t pdispatched = 0;
119,496✔
718
    size_t pwanted     = 0;
119,496✔
719
    _sir_eqland(retval, _sir_plugin_cache_dispatch(spc, level, buf, &pdispatched, &pwanted));
119,496✔
720
    _SIR_UNLOCK_SECTION(SIRMI_PLUGINCACHE);
119,496✔
721

722
    dispatched += pdispatched;
119,496✔
723
    wanted += pwanted;
119,496✔
724
#endif
725

726
    if (0 == wanted) {
2,126,134✔
727
        _sir_selflog("error: no destinations registered for level %04"PRIx16, level);
801✔
728
        return _sir_seterror(_SIR_E_NODEST);
854✔
729
    }
730

731
    return retval && (dispatched == wanted);
2,125,280✔
732
}
733

734
const char* _sir_format(bool styling, sir_options opts, sirbuf* buf) {
2,269,632✔
735
    if (_sir_validptr(buf)) {
2,269,632✔
736
        bool first = true;
2,225,750✔
737

738
        _sir_resetstr(buf->output);
2,269,622✔
739

740
        if (styling)
2,269,668✔
741
            _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->style, SIR_MAXSTYLE);
1,123,750✔
742

743
        if (!_sir_bittest(opts, SIRO_NOTIME)) {
2,269,668✔
744
            _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->timestamp, SIR_MAXTIME);
2,108,700✔
745
            first = false;
2,090,255✔
746

747
#if defined(SIR_MSEC_TIMER)
748
            if (!_sir_bittest(opts, SIRO_NOMSEC))
2,108,723✔
749
                _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->msec, SIR_MAXMSEC);
72,671✔
750
#endif
751
        }
752

753
        if (!_sir_bittest(opts, SIRO_NOHOST) && _sir_validstrnofail(buf->hostname)) {
2,269,739✔
754
            if (!first)
1,033,708✔
755
                _sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,001,557✔
756
            _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->hostname, SIR_MAXHOST);
1,033,708✔
757
            first = false;
1,027,413✔
758
        }
759

760
        if (!_sir_bittest(opts, SIRO_NOLEVEL)) {
2,269,700✔
761
            if (!first)
2,159,472✔
762
                _sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
2,108,848✔
763
            _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->level, SIR_MAXLEVEL);
2,159,460✔
764
            first = false;
2,134,025✔
765
        }
766

767
        bool name = false;
2,225,808✔
768
        if (!_sir_bittest(opts, SIRO_NONAME) && _sir_validstrnofail(buf->name)) {
2,269,734✔
769
            if (!first)
1,108,242✔
770
                _sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,104,293✔
771
            _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->name, SIR_MAXNAME);
1,108,244✔
772
            first = false;
1,089,880✔
773
            name  = true;
1,089,880✔
774
        }
775

776
        bool wantpid = !_sir_bittest(opts, SIRO_NOPID) && _sir_validstrnofail(buf->pid);
2,269,758✔
777
        bool wanttid = !_sir_bittest(opts, SIRO_NOTID) && _sir_validstrnofail(buf->tid);
2,269,958✔
778

779
        if (wantpid || wanttid) {
2,269,857✔
780
            if (name)
2,142,288✔
781
                _sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDPREFIX, 1);
1,102,768✔
782
            else if (!first)
1,039,520✔
783
                _sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,039,514✔
784

785
            if (wantpid)
2,142,291✔
786
                _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->pid, SIR_MAXPID);
2,076,589✔
787

788
            if (wanttid) {
2,142,273✔
789
                if (wantpid)
2,136,611✔
790
                    _sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDSEPARATOR, 1);
2,071,086✔
791
                _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->tid, SIR_MAXPID);
2,136,602✔
792
            }
793

794
            if (name)
2,142,245✔
795
                _sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDSUFFIX, 1);
1,102,654✔
796

797
            first = false;
2,117,504✔
798
        }
799

800
        if (!first)
2,245,073✔
801
            _sir_strncat(buf->output, SIR_MAXOUTPUT, ": ", 2);
2,195,214✔
802

803
        _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->message, SIR_MAXMESSAGE);
2,269,664✔
804

805
        if (styling)
2,269,650✔
806
            _sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_ESC_RST, SIR_MAXSTYLE);
1,123,704✔
807

808
        _sir_strncat(buf->output, SIR_MAXOUTPUT, "\n", 1);
2,269,651✔
809

810
        buf->output_len = strnlen(buf->output, SIR_MAXOUTPUT);
2,269,703✔
811

812
        return buf->output;
2,269,703✔
813
    }
814

815
    return NULL;
×
816
}
817

818
bool _sir_syslog_init(const char* name, sir_syslog_dest* ctx) {
233✔
819
#if !defined(SIR_NO_SYSTEM_LOGGERS)
820
    if (!_sir_validptr(name) || !_sir_validptr(ctx))
233✔
821
        return false;
×
822

823
    /* begin resolve identity. */
824
    if (!_sir_validstrnofail(ctx->identity)) {
233✔
825
        _sir_selflog("ctx->identity is no good; trying name");
55✔
826
        if (_sir_validstrnofail(name)) {
59✔
827
            _sir_selflog("using name");
13✔
828
            _sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, name, strnlen(name, SIR_MAX_SYSLOG_ID));
15✔
829
        } else {
830
            _sir_selflog("name is no good; trying filename");
42✔
831
            char* appbasename = _sir_getappbasename();
44✔
832
            if (_sir_validstrnofail(appbasename)) {
44✔
833
                _sir_selflog("filename is good: %s", appbasename);
40✔
834
                _sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, appbasename,
40✔
835
                    strnlen(appbasename, SIR_MAX_SYSLOG_ID));
836
            } else {
837
                _sir_selflog("filename no good; using fallback");
4✔
838
                _sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, SIR_FALLBACK_SYSLOG_ID,
4✔
839
                    strnlen(SIR_FALLBACK_SYSLOG_ID, SIR_MAX_SYSLOG_ID));
840
            }
841
            _sir_safefree(&appbasename);
44✔
842
        }
843
    } else {
844
        _sir_selflog("already have identity");
166✔
845
    }
846

847
    /* category */
848
    if (!_sir_validstrnofail(ctx->category)) {
233✔
849
        _sir_selflog("category not set; using fallback");
88✔
850
        _sir_strncpy(ctx->category, SIR_MAX_SYSLOG_CAT, SIR_FALLBACK_SYSLOG_CAT,
91✔
851
            strnlen(SIR_FALLBACK_SYSLOG_CAT, SIR_MAX_SYSLOG_CAT));
852
    } else {
853
        _sir_selflog("already have category");
133✔
854
    }
855

856
    _sir_setbitshigh(&ctx->_state.mask, SIRSL_IS_INIT);
233✔
857
    _sir_selflog("resolved (identity: '%s', category: '%s')", ctx->identity, ctx->category);
221✔
858

859
    return _sir_syslog_open(ctx);
233✔
860
#else
861
    SIR_UNUSED(name);
862
    SIR_UNUSED(ctx);
863
    return false;
×
864
#endif
865
}
866

867
bool _sir_syslog_open(sir_syslog_dest* ctx) {
233✔
868
#if !defined(SIR_NO_SYSTEM_LOGGERS)
869
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_INIT)) {
233✔
870
        _sir_selflog("not initialized; ignoring");
×
871
        return _sir_seterror(_SIR_E_INVALID);
×
872
    }
873

874
    if (_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
233✔
875
        _sir_selflog("log already open; ignoring");
96✔
876
        return true;
96✔
877
    }
878

879
    _sir_selflog("opening log (levels: %04"PRIx16", options: %08"PRIx32")", ctx->levels,
132✔
880
        ctx->opts);
881

882
# if defined(SIR_OS_LOG_ENABLED)
883
    ctx->_state.logger = (void*)os_log_create(ctx->identity, ctx->category);
884
    _sir_selflog("opened os_log ('%s', '%s')", ctx->identity, ctx->category);
885
# elif defined(SIR_SYSLOG_ENABLED)
886
    int logopt   = LOG_NDELAY | (_sir_bittest(ctx->opts, SIRO_NOPID) ? 0 : LOG_PID);
132✔
887
    int facility = LOG_USER;
111✔
888

889
    openlog(ctx->identity, logopt, facility);
132✔
890
    _sir_selflog("opened syslog('%s', %x, %x)", ctx->identity, logopt, facility);
125✔
891
# endif
892

893
    _sir_setbitshigh(&ctx->_state.mask, SIRSL_IS_OPEN);
132✔
894
    return true;
132✔
895
#else
896
    SIR_UNUSED(ctx);
897
    return false;
×
898
#endif
899
}
900

901
bool _sir_syslog_write(sir_level level, const sirbuf* buf, const sir_syslog_dest* ctx) {
620✔
902
#if !defined(SIR_NO_SYSTEM_LOGGERS)
903
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_INIT)) {
620✔
904
        _sir_selflog("not initialized; ignoring");
×
905
        return _sir_seterror(_SIR_E_INVALID);
×
906
    }
907

908
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
620✔
909
        _sir_selflog("log not open; ignoring");
×
910
        return _sir_seterror(_SIR_E_INVALID);
×
911
    }
912

913
# if defined(SIR_OS_LOG_ENABLED)
914
    if (SIRL_DEBUG == level)
915
        os_log_debug((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
916
    else if (SIRL_INFO == level || SIRL_NOTICE == level)
917
        os_log_info((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
918
    else if (SIRL_WARN == level || SIRL_ERROR == level)
919
        os_log_error((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
920
    else if (SIRL_ALERT == level || SIRL_CRIT == level || SIRL_EMERG == level)
921
        os_log_fault((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
922

923
    return true;
924
# elif defined(SIR_SYSLOG_ENABLED)
925
    int syslog_level;
926
    switch (level) {
620✔
927
        case SIRL_DEBUG:  syslog_level = LOG_DEBUG; break;
23✔
928
        case SIRL_INFO:   syslog_level = LOG_INFO; break;
25✔
929
        case SIRL_NOTICE: syslog_level = LOG_NOTICE; break;
85✔
930
        case SIRL_WARN:   syslog_level = LOG_WARNING; break;
85✔
931
        case SIRL_ERROR:  syslog_level = LOG_ERR; break;
85✔
932
        case SIRL_CRIT:   syslog_level = LOG_CRIT; break;
112✔
933
        case SIRL_ALERT:  syslog_level = LOG_ALERT; break;
85✔
934
        case SIRL_EMERG:  syslog_level = LOG_EMERG; break;
112✔
935
        // GCOVR_EXCL_START
936
        default: /* this should never happen. */
937
            SIR_ASSERT(false);
938
            syslog_level = LOG_DEBUG;
939
        // GCOVR_EXCL_STOP
940
    }
941

942
    syslog(syslog_level, "%s", buf->message);
620✔
943
    return true;
620✔
944
# else
945
    SIR_UNUSED(level);
946
    SIR_UNUSED(buf);
947
    SIR_UNUSED(ctx);
948
    return false;
949
# endif
950
#else
951
    SIR_UNUSED(level);
952
    SIR_UNUSED(buf);
953
    SIR_UNUSED(ctx);
954
    return false;
×
955
#endif
956
}
957

958
bool _sir_syslog_updated(sirinit* si, const sir_update_config_data* data) {
224✔
959
#if !defined(SIR_NO_SYSTEM_LOGGERS)
960
    if (!_sir_validptr(si) || !_sir_validptr(data))
224✔
961
        return false;
×
962

963
    if (_sir_bittest(si->d_syslog._state.mask, SIRSL_UPDATED)) {
224✔
964
        bool levels   = _sir_bittest(si->d_syslog._state.mask, SIRSL_LEVELS);
211✔
965
        bool options  = _sir_bittest(si->d_syslog._state.mask, SIRSL_OPTIONS);
224✔
966
        bool category = _sir_bittest(si->d_syslog._state.mask, SIRSL_CATEGORY);
211✔
967
        bool identity = _sir_bittest(si->d_syslog._state.mask, SIRSL_IDENTITY);
224✔
968
        bool is_init  = _sir_bittest(si->d_syslog._state.mask, SIRSL_IS_INIT);
224✔
969
        bool is_open  = _sir_bittest(si->d_syslog._state.mask, SIRSL_IS_OPEN);
224✔
970

971
        _sir_selflog("config update: (levels: %u, options: %u, category: %u,"
211✔
972
                     " identity: %u, is_init: %u, is_open: %u)",
973
                     levels, options, category, identity, is_init, is_open);
974

975
        bool must_init = false;
187✔
976

977
# if defined(SIR_OS_LOG_ENABLED)
978
        /*
979
         * for os_log, if initialized and open already, only need to reconfigure
980
         * if identity or category changed.
981
         */
982
        must_init = (!is_init || !is_open) || (identity || category);
983
# elif defined(SIR_SYSLOG_ENABLED)
984
        /*
985
         * for os_log, if initialized and open already, only need to reconfigure
986
         * if identity or options changed.
987
         */
988
        must_init = (!is_init || !is_open) || (identity || options);
224✔
989
# endif
990
        bool init = true;
187✔
991
        if (must_init) {
187✔
992
            _sir_selflog("re-init...");
122✔
993
            init = _sir_syslog_init(si->name, &si->d_syslog);
128✔
994
            _sir_selflog("re-init %s", init ? "succeeded" : "failed");
122✔
995
        } else {
996
            _sir_selflog("no re-init necessary");
89✔
997
        }
998

999
        return init;
224✔
1000
    } else {
1001
        _sir_selflog("BUG: called without 'updated' flag set!");
×
1002
        return false;
×
1003
    }
1004
#else
1005
    SIR_UNUSED(si);
1006
    SIR_UNUSED(data);
1007
    return false;
×
1008
#endif
1009
}
1010

1011
bool _sir_syslog_close(sir_syslog_dest* ctx) {
596✔
1012
#if !defined(SIR_NO_SYSTEM_LOGGERS)
1013
    if (!_sir_validptr(ctx))
596✔
1014
        return false;
×
1015

1016
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
596✔
1017
        _sir_selflog("log not open; ignoring");
435✔
1018
        return true;
435✔
1019
    }
1020

1021
# if defined(SIR_OS_LOG_ENABLED)
1022
    /* Evidently, you don't need to close the handle returned from os_log_create(), and
1023
     * if you make that call again, you'll get the same cached value. so let's keep the
1024
     * value we've got in the global context. */
1025
    _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
1026
    _sir_selflog("log closure not necessary");
1027
    return true;
1028
# elif defined(SIR_SYSLOG_ENABLED)
1029
    closelog();
132✔
1030
    _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
132✔
1031
    _sir_selflog("closed log");
125✔
1032
    return true;
132✔
1033
# else
1034
    SIR_UNUSED(ctx);
1035
    return false;
1036
# endif
1037
#else
1038
    SIR_UNUSED(ctx);
1039
    return false;
×
1040
#endif
1041
}
1042

1043
void _sir_syslog_reset(sir_syslog_dest* ctx) {
1,192✔
1044
#if !defined(SIR_NO_SYSTEM_LOGGERS)
1045
    if (_sir_validptr(ctx)) {
1,192✔
1046
        uint32_t old       = ctx->_state.mask;
1,120✔
1047
        ctx->_state.mask   = 0U;
1,192✔
1048
        ctx->_state.logger = NULL;
1,192✔
1049
        _sir_selflog("state reset; mask was %08"PRIx32, old);
1,120✔
1050
    }
1051
#else
1052
    SIR_UNUSED(ctx);
1053
#endif
1054
}
1,192✔
1055

1056
const char* _sir_formattedlevelstr(sir_level level) {
2,157,117✔
1057
    static const size_t low  = 0;
1058
    static const size_t high = SIR_NUMLEVELS - 1;
1059

1060
    const char* retval = SIR_UNKNOWN;
2,133,354✔
1061

1062
    _SIR_DECLARE_BIN_SEARCH(low, high);
2,133,354✔
1063
    _SIR_BEGIN_BIN_SEARCH()
1064

1065
    if (sir_level_to_str_map[_mid].level == level) {
8,584,868✔
1066
        retval = sir_level_to_str_map[_mid].fmt;
2,157,117✔
1067
        break;
2,157,117✔
1068
    }
1069

1070
    _SIR_ITERATE_BIN_SEARCH((sir_level_to_str_map[_mid].level < level ? 1 : -1));
6,427,751✔
1071
    _SIR_END_BIN_SEARCH();
1072

1073
    return retval;
2,157,117✔
1074
}
1075

1076
bool _sir_clock_gettime(int clock, time_t* tbuf, long* msecbuf) {
6,314,312✔
1077
    if (tbuf) {
6,314,312✔
1078
#if defined(SIR_MSEC_POSIX)
1079
        struct timespec ts = {0};
6,314,312✔
1080
        int ret            = clock_gettime(clock, &ts);
6,314,312✔
1081
        SIR_ASSERT(0 == ret);
6,298,467✔
1082

1083
        if (0 == ret) {
6,282,622✔
1084
            *tbuf = ts.tv_sec;
6,298,547✔
1085
            if (msecbuf)
6,298,547✔
1086
                *msecbuf = ts.tv_nsec / 1000000L;
6,298,547✔
1087
        } else {
1088
            if (msecbuf)
15,765✔
1089
                *msecbuf = 0L;
15,765✔
1090
            return _sir_handleerr(errno);
15,765✔
1091
        }
1092
#elif defined(SIR_MSEC_WIN32)
1093
        SIR_UNUSED(clock);
1094
        static const ULONGLONG uepoch = (ULONGLONG)116444736e9;
1095

1096
        FILETIME ftutc = {0};
1097
        GetSystemTimePreciseAsFileTime(&ftutc);
1098

1099
        ULARGE_INTEGER ftnow = {0};
1100
        ftnow.HighPart = ftutc.dwHighDateTime;
1101
        ftnow.LowPart  = ftutc.dwLowDateTime;
1102
        ftnow.QuadPart = (ULONGLONG)((ftnow.QuadPart - uepoch) / 10000000ULL);
1103

1104
        *tbuf = (time_t)ftnow.QuadPart;
1105

1106
        SYSTEMTIME st = {0};
1107
        if (FileTimeToSystemTime(&ftutc, &st)) {
1108
            if (msecbuf)
1109
                *msecbuf = (long)st.wMilliseconds;
1110
        } else {
1111
            if (msecbuf)
1112
                *msecbuf = 0L;
1113
            return _sir_handlewin32err(GetLastError());
1114
        }
1115
#else
1116
        SIR_UNUSED(clock);
1117
        time(tbuf);
1118
        if (msecbuf)
1119
            *msecbuf = 0L;
1120
#endif
1121
        return true;
6,298,547✔
1122
    }
1123
    return false;
×
1124
}
1125

1126
double _sir_msec_since(const sir_time* when, sir_time* out) {
4,157,195✔
1127
    if (!_sir_validptr(out))
4,157,195✔
1128
        return 0.0;
×
1129
#if !defined(__WIN__)
1130
    out->sec = 0;
4,157,195✔
1131
    out->msec = 0L;
4,157,195✔
1132

1133
    bool gettime = _sir_clock_gettime(SIR_INTERVALCLOCK, &out->sec, &out->msec);
4,157,195✔
1134
    SIR_ASSERT(gettime);
4,149,271✔
1135

1136
    if (!_sir_validptrnofail(when) || !gettime || (out->sec < when->sec ||
4,157,195✔
1137
        (out->sec == when->sec && out->msec < when->msec)))
4,148,103✔
1138
        return 0.0;
7,926✔
1139

1140
    return ((((double)out->sec) * 1e3) + (double)out->msec) -
4,149,263✔
1141
           ((((double)when->sec) * 1e3) + (double)when->msec);
4,149,263✔
1142
#else /* __WIN__ */
1143
    SIR_ASSERT(_sir_perfcntr_freq.QuadPart > 0LL);
1144

1145
    if (_sir_perfcntr_freq.QuadPart <= 0LL)
1146
        (void)QueryPerformanceFrequency(&_sir_perfcntr_freq);
1147

1148
    (void)QueryPerformanceCounter(&out->counter);
1149

1150
    if (!_sir_validptrnofail(when) || out->counter.QuadPart <= when->counter.QuadPart)
1151
        return 0.0;
1152

1153
    double msec_ratio = ((double)_sir_perfcntr_freq.QuadPart) / 1e3;
1154
    return ((double)(out->counter.QuadPart - when->counter.QuadPart)) / msec_ratio;
1155
#endif
1156
}
1157

1158
pid_t _sir_getpid(void) {
804✔
1159
#if !defined(__WIN__)
1160
    return getpid();
804✔
1161
#else /* __WIN__ */
1162
    return (pid_t)GetCurrentProcessId();
1163
#endif
1164
}
1165

1166
pid_t _sir_gettid(void) {
978✔
1167
    pid_t tid = 0;
834✔
1168
#if defined(__MACOS__)
1169
    uint64_t tid64 = 0ULL;
1170
    int gettid     = pthread_threadid_np(NULL, &tid64);
1171
    if (0 != gettid)
1172
        (void)_sir_handleerr(gettid);
1173
    tid = (pid_t)tid64;
1174
#elif (defined(__BSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)) || \
1175
      defined(__DragonFly_getthreadid__)
1176
    tid = (pid_t)pthread_getthreadid_np();
1177
#elif defined(__OpenBSD__)
1178
    tid = (pid_t)getthrid();
1179
#elif defined(__SOLARIS__) || defined(__NetBSD__) || defined(__HURD__) || \
1180
      defined(__DragonFly__) || defined(__CYGWIN__) || defined(_AIX) || \
1181
      defined(__EMSCRIPTEN__)
1182
# if defined(__CYGWIN__)
1183
    tid = (pid_t)(uintptr_t)pthread_self();
1184
# else
1185
    tid = (pid_t)pthread_self();
1186
# endif
1187
#elif defined(__HAIKU__)
1188
    tid = get_pthread_thread_id(pthread_self());
1189
#elif defined(__linux__) || defined(__serenity__)
1190
# if (defined(__GLIBC__) && GLIBC_VERSION >= 23000) || defined(__serenity__)
1191
    tid = gettid();
978✔
1192
# else
1193
    tid = syscall(SYS_gettid);
1194
# endif
1195
#elif defined(__WIN__)
1196
    tid = (pid_t)GetCurrentThreadId();
1197
#else
1198
# error "unable to determine how to get a thread identifier"
1199
#endif
1200
    return tid;
978✔
1201
}
1202

1203
bool _sir_getthreadname(char name[SIR_MAXPID]) {
844✔
1204
    _sir_resetstr(name);
844✔
1205
#if defined(__MACOS__) || (defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_12_2__)) || \
1206
    (defined(__linux__) && defined(__UCLIBC__) && defined(_GNU_SOURCE)) || \
1207
    (defined(__GLIBC__) && GLIBC_VERSION >= 21200 && defined(_GNU_SOURCE)) || \
1208
    (defined(__ANDROID__) &&  __ANDROID_API__ >= 26) || defined(SIR_PTHREAD_GETNAME_NP) || \
1209
    defined(__serenity__) || (defined(__linux__) && !defined(__GLIBC__) && \
1210
    defined(_GNU_SOURCE) && defined(__NEED_pthread_t))
1211
    int ret = pthread_getname_np(pthread_self(), name, SIR_MAXPID);
844✔
1212
    if (0 != ret)
844✔
1213
        return _sir_handleerr(ret);
×
1214
# if defined(__HAIKU__)
1215
    if (!(strncmp(name, "pthread func", SIR_MAXPID)))
1216
        (void)snprintf(name, SIR_MAXPID, "%ld", (long)get_pthread_thread_id(pthread_self()));
1217
# endif
1218
    return _sir_validstrnofail(name);
844✔
1219
#elif defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_11_3__)
1220
    pthread_get_name_np(pthread_self(), name, SIR_MAXPID);
1221
    return _sir_validstrnofail(name);
1222
#elif defined(__WIN__)
1223
    wchar_t* wname = NULL;
1224
    HRESULT hr     = GetThreadDescription(GetCurrentThread(), &wname);
1225
    if (FAILED(hr))
1226
        return _sir_handlewin32err(GetLastError());
1227
    bool success = true;
1228
# if defined(__HAVE_STDC_SECURE_OR_EXT1__)
1229
    size_t wlen = wcsnlen_s(wname, SIR_MAXPID);
1230
# elif defined(__EMBARCADEROC__)
1231
    size_t wlen = wcslen(wname);
1232
# else
1233
    size_t wlen = wcsnlen(wname, SIR_MAXPID);
1234
# endif
1235
    if (wlen > 0) {
1236
        if (!WideCharToMultiByte(CP_UTF8, 0UL, wname, (int)wlen, name,
1237
            SIR_MAXPID, NULL, NULL)) {
1238
            success = false;
1239
            (void)_sir_handlewin32err(GetLastError());
1240
        }
1241
    }
1242
    (void)LocalFree(wname);
1243
    return success && _sir_validstrnofail(name);
1244
#else
1245
# if !defined(SUNLINT) && !defined(_AIX) && !defined(__HURD__)
1246
#  pragma message("unable to determine how to get a thread name")
1247
# endif
1248
    SIR_UNUSED(name);
1249
    return false;
1250
#endif
1251
}
1252

1253
bool _sir_setthreadname(const char* name) {
234✔
1254
    if (!_sir_validptr(name))
234✔
1255
        return false;
×
1256
#if defined(__MACOS__)
1257
    int ret = pthread_setname_np(name);
1258
    return (0 != ret) ? _sir_handleerr(ret) : true;
1259
#elif defined(__HAIKU__)
1260
    status_t ret = rename_thread(find_thread(NULL), name);
1261
    return (B_OK != ret) ? _sir_handleerr((int)ret) : true;
1262
#elif defined(__NetBSD__)
1263
    int ret = pthread_setname_np(pthread_self(), "%s", name);
1264
    return (0 != ret) ? _sir_handleerr(ret) : true;
1265
#elif (defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_12_2__)) || \
1266
      (defined(__linux__) && defined(__UCLIBC__) && defined(_GNU_SOURCE)) || \
1267
      (defined(__GLIBC__) && GLIBC_VERSION >= 21200 && defined(_GNU_SOURCE)) || \
1268
       defined(__QNXNTO__) || defined(__SOLARIS__) || defined(SIR_PTHREAD_GETNAME_NP) || \
1269
       defined(__ANDROID__) && !defined(__OpenBSD__) || defined(__serenity__) || \
1270
      (defined(__linux__) && !defined(__GLIBC__) && \
1271
       defined(_GNU_SOURCE) && defined(__NEED_pthread_t))
1272
    int ret = pthread_setname_np(pthread_self(), name);
234✔
1273
    return (0 != ret) ? _sir_handleerr(ret) : true;
234✔
1274
#elif defined(__OpenBSD__) || defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_11_3__)
1275
    pthread_set_name_np(pthread_self(), name);
1276
    return true;
1277
#elif defined(__WIN__)
1278
# if defined(__HAVE_STDC_SECURE_OR_EXT1__)
1279
    size_t name_len = strnlen_s(name, SIR_MAXPID);
1280
# else
1281
    size_t name_len = strnlen(name, SIR_MAXPID);
1282
# endif
1283
    if (0 == name_len)
1284
        name_len = 1;
1285

1286
    wchar_t buf[SIR_MAXPID] = {0};
1287
    if (!MultiByteToWideChar(CP_UTF8, 0UL, name, (int)name_len, buf, SIR_MAXPID))
1288
        return _sir_handlewin32err(GetLastError());
1289

1290
    HRESULT hr = SetThreadDescription(GetCurrentThread(), buf);
1291
    return FAILED(hr) ? _sir_handlewin32err(hr) : true;
1292
#else
1293
# if !defined(SUNLINT) && !defined(_AIX)
1294
#  pragma message("unable to determine how to set a thread name")
1295
# endif
1296
    SIR_UNUSED(name);
1297
    return false;
1298
#endif
1299
}
1300

1301
bool _sir_gethostname(char name[SIR_MAXHOST]) {
8,358✔
1302
#if !defined(__WIN__)
1303
    int ret = gethostname(name, SIR_MAXHOST - 1);
8,289✔
1304
    return 0 == ret ? true : _sir_handleerr(errno);
8,358✔
1305
#else
1306
    WSADATA wsad = {0};
1307
    int ret      = WSAStartup(MAKEWORD(2, 2), &wsad);
1308
    if (0 != ret)
1309
        return _sir_handlewin32err(ret);
1310

1311
    if (SOCKET_ERROR == gethostname(name, SIR_MAXHOST)) {
1312
        int err = WSAGetLastError();
1313
        WSACleanup();
1314
        return _sir_handlewin32err(err);
1315
    }
1316

1317
    WSACleanup();
1318
    return true;
1319
#endif /* !__WIN__ */
1320
}
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