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

aremmell / libsir / 430

04 Sep 2023 11:04PM UTC coverage: 94.551% (-0.3%) from 94.865%
430

Pull #257

gitlab-ci

johnsonjh
Actually add tests_malloc header

Signed-off-by: Jeffrey H. Johnson <trnsz@pobox.com>
Pull Request #257: WIP

239 of 239 new or added lines in 13 files covered. (100.0%)

3019 of 3193 relevant lines covered (94.55%)

633797.64 hits per line

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

93.48
/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.3
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

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

69
    if (retval) {
57✔
70
        memset(si, 0, sizeof(sirinit));
51✔
71

72
        si->d_stdout.opts   = SIRO_DEFAULT;
57✔
73
        si->d_stdout.levels = SIRL_DEFAULT;
57✔
74

75
        si->d_stderr.opts   = SIRO_DEFAULT;
57✔
76
        si->d_stderr.levels = SIRL_DEFAULT;
57✔
77

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

87
    return retval;
57✔
88
}
89

90
bool _sir_init(sirinit* si) {
815✔
91
    (void)_sir_seterror(_SIR_E_NOERROR);
815✔
92

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

104
    if (!_sir_validptr(si))
815✔
105
        return false;
20✔
106

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

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

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

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

125
    if (!_sir_init_sanity(si))
768✔
126
        return false;
20✔
127

128
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
745✔
129

130
#if !defined(__WIN__)
131
    tzset();
745✔
132
#endif
133

134
#if defined(__HAVE_ATOMIC_H__)
135
    atomic_store(&_sir_magic, _SIR_MAGIC);
745✔
136
#else
137
    _sir_magic = _SIR_MAGIC;
138
#endif
139

140
#if defined(__WIN__)
141
    _sir_initialize_stdio();
142
#endif
143

144
    _sir_setcolormode(SIRCM_16);
745✔
145

146
    if (!_sir_resettextstyles())
745✔
147
        _sir_selflog("error: failed to reset text styles!");
×
148

149
    memset(&_cfg->state, 0, sizeof(_cfg->state));
745✔
150
    memcpy(&_cfg->si, si, sizeof(sirinit));
745✔
151

152
    /* forcibly null-terminate the process name. */
153
    _cfg->si.name[SIR_MAXNAME - 1] = '\0';
745✔
154

155
    /* Store PID. */
156
    _cfg->state.pid = _sir_getpid();
745✔
157

158
    (void)snprintf(_cfg->state.pidbuf, SIR_MAXPID, SIR_PIDFORMAT,
745✔
159
        PID_CAST _cfg->state.pid);
160

161
#if !defined(SIR_NO_SYSTEM_LOGGERS)
162
    /* initialize system logger. */
163
    _sir_syslog_reset(&_cfg->si.d_syslog);
571✔
164

165
    if (_cfg->si.d_syslog.levels != SIRL_NONE) {
571✔
166
        if (!_sir_syslog_init(_cfg->si.name, &_cfg->si.d_syslog))
102✔
167
            _sir_selflog("failed to initialize system logger!");
×
168
    }
169
#endif
170

171
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
745✔
172

173
    return true;
745✔
174
}
175

176
bool _sir_cleanup(void) {
768✔
177
    if (!_sir_sanity())
768✔
178
        return false;
20✔
179

180
    _SIR_LOCK_SECTION(sirfcache, sfc, SIRMI_FILECACHE, false);
745✔
181
    bool cleanup   = true;
646✔
182
    bool destroyfc = _sir_fcache_destroy(sfc);
745✔
183
    SIR_ASSERT(destroyfc);
712✔
184

185
    _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
745✔
186
    cleanup &= destroyfc;
646✔
187

188
#if !defined(SIR_NO_PLUGINS)
189
    _SIR_LOCK_SECTION(sir_plugincache, spc, SIRMI_PLUGINCACHE, false);
704✔
190
    bool destroypc = _sir_plugin_cache_destroy(spc);
704✔
191
    SIR_ASSERT(destroypc);
671✔
192
    _SIR_UNLOCK_SECTION(SIRMI_PLUGINCACHE);
704✔
193
    cleanup &= destroypc;
605✔
194
#endif
195

196
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
745✔
197

198
#if !defined(SIR_NO_SYSTEM_LOGGERS)
199
    if (!_sir_syslog_close(&_cfg->si.d_syslog)) {
571✔
200
        cleanup = false;
×
201
        _sir_selflog("error: failed to close system logger!");
×
202
    }
203

204
    _sir_syslog_reset(&_cfg->si.d_syslog);
571✔
205
#endif
206

207
    if (!_sir_resettextstyles()) {
745✔
208
        cleanup = false;
×
209
        _sir_selflog("error: failed to reset text styles!");
×
210
    }
211

212
#if defined(__HAVE_ATOMIC_H__)
213
    atomic_store(&_sir_magic, 0);
745✔
214
#else
215
    _sir_magic = 0U;
216
#endif
217

218
    memset(_cfg, 0, sizeof(sirconfig));
646✔
219
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
745✔
220

221
    _sir_selflog("cleanup: %s", (cleanup ? "successful" : "with errors"));
712✔
222

223
    SIR_ASSERT(cleanup);
712✔
224
    return cleanup;
679✔
225
}
226

227
bool _sir_sanity(void) {
2,508,828✔
228
#if defined(__HAVE_ATOMIC_H__)
229
    if (_SIR_MAGIC == atomic_load(&_sir_magic))
2,508,828✔
230
        return true;
2,428,491✔
231
#else
232
    if (_SIR_MAGIC == _sir_magic)
233
        return true;
234
#endif
235
    return _sir_seterror(_SIR_E_NOTREADY);
66✔
236
}
237

238
bool _sir_init_sanity(const sirinit* si) {
768✔
239
    if (!_sir_validptr(si))
768✔
240
        return false;
×
241

242
    bool levelcheck = true;
666✔
243
    levelcheck &= _sir_validlevels(si->d_stdout.levels);
768✔
244
    levelcheck &= _sir_validlevels(si->d_stderr.levels);
768✔
245

246
#if !defined(SIR_NO_SYSTEM_LOGGERS)
247
    levelcheck &= _sir_validlevels(si->d_syslog.levels);
588✔
248
#endif
249

250
    bool optscheck = true;
666✔
251
    optscheck &= _sir_validopts(si->d_stdout.opts);
768✔
252
    optscheck &= _sir_validopts(si->d_stderr.opts);
768✔
253

254
#if !defined(SIR_NO_SYSTEM_LOGGERS)
255
    optscheck &= _sir_validopts(si->d_syslog.opts);
588✔
256
#endif
257

258
    return levelcheck && optscheck;
768✔
259
}
260

261
static
262
bool _sir_updatelevels(const char* name, sir_levels* old, sir_levels* new) {
909✔
263
    if (*old != *new) {
909✔
264
        _sir_selflog("updating %s levels from %04"PRIx16" to %04"PRIx16, name, *old, *new);
824✔
265
        *old = *new;
869✔
266
    } else {
267
        _sir_selflog("skipped superfluous update of %s levels: %04"PRIx16, name, *old);
38✔
268
    }
269
    return true;
909✔
270
}
271

272
static
273
bool _sir_updateopts(const char* name, sir_options* old, sir_options* new) {
73,863✔
274
    if (*old != *new) {
73,863✔
275
        _sir_selflog("updating %s options from %08"PRIx32" to %08"PRIx32, name, *old, *new);
36,087✔
276
        *old = *new;
38,148✔
277
    } else {
278
        _sir_selflog("skipped superfluous update of %s options: %08"PRIx32, name, *old);
33,731✔
279
    }
280
    return true;
73,863✔
281
}
282

283
bool _sir_stdoutlevels(sirinit* si, sir_update_config_data* data) {
447✔
284
    return _sir_updatelevels(SIR_DESTNAME_STDOUT, &si->d_stdout.levels, data->levels);
447✔
285
}
286

287
bool _sir_stdoutopts(sirinit* si, sir_update_config_data* data) {
73,401✔
288
    return _sir_updateopts(SIR_DESTNAME_STDOUT, &si->d_stdout.opts, data->opts);
73,401✔
289
}
290

291
bool _sir_stderrlevels(sirinit* si, sir_update_config_data* data) {
401✔
292
    return _sir_updatelevels(SIR_DESTNAME_STDERR, &si->d_stderr.levels, data->levels);
401✔
293
}
294

295
bool _sir_stderropts(sirinit* si, sir_update_config_data* data) {
401✔
296
    return _sir_updateopts(SIR_DESTNAME_STDERR, &si->d_stderr.opts, data->opts);
401✔
297
}
298

299
bool _sir_sysloglevels(sirinit* si, sir_update_config_data* data) {
61✔
300
    bool updated = _sir_updatelevels(SIR_DESTNAME_SYSLOG, &si->d_syslog.levels, data->levels);
61✔
301
    if (updated) {
61✔
302
        _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_LEVELS);
61✔
303
        updated = _sir_syslog_updated(si, data);
61✔
304
        _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_LEVELS);
61✔
305
    }
306
    return updated;
61✔
307
}
308

309
bool _sir_syslogopts(sirinit* si, sir_update_config_data* data) {
61✔
310
    bool updated = _sir_updateopts(SIR_DESTNAME_SYSLOG, &si->d_syslog.opts, data->opts);
61✔
311
    if (updated) {
61✔
312
        _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_OPTIONS);
61✔
313
        updated = _sir_syslog_updated(si, data);
61✔
314
        _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_OPTIONS);
61✔
315
    }
316
    return updated;
61✔
317
}
318

319
bool _sir_syslogid(sirinit* si, sir_update_config_data* data) {
125✔
320
    bool cur_valid = _sir_validstrnofail(si->d_syslog.identity);
125✔
321
    if (!cur_valid || 0 != strncmp(si->d_syslog.identity, data->sl_identity, SIR_MAX_SYSLOG_ID)) {
125✔
322
        _sir_selflog("updating %s identity from '%s' to '%s'", SIR_DESTNAME_SYSLOG,
76✔
323
            si->d_syslog.identity, data->sl_identity);
324
        _sir_strncpy(si->d_syslog.identity, SIR_MAX_SYSLOG_ID, data->sl_identity,
76✔
325
            strnlen(data->sl_identity, SIR_MAX_SYSLOG_ID));
326
    } else {
327
        _sir_selflog("skipped superfluous update of %s identity: '%s'", SIR_DESTNAME_SYSLOG,
46✔
328
            si->d_syslog.identity);
329
        return true;
46✔
330
    }
331

332
    _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_IDENTITY);
76✔
333
    bool updated = _sir_syslog_updated(si, data);
76✔
334
    _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_IDENTITY);
76✔
335

336
    return updated;
76✔
337
}
338

339
bool _sir_syslogcat(sirinit* si, sir_update_config_data* data) {
98✔
340
    bool cur_valid = _sir_validstrnofail(si->d_syslog.category);
98✔
341
    if (!cur_valid || 0 != strncmp(si->d_syslog.category, data->sl_category, SIR_MAX_SYSLOG_CAT)) {
98✔
342
        _sir_selflog("updating %s category from '%s' to '%s'", SIR_DESTNAME_SYSLOG,
49✔
343
            si->d_syslog.category, data->sl_category);
344
        _sir_strncpy(si->d_syslog.category, SIR_MAX_SYSLOG_CAT, data->sl_category,
49✔
345
            strnlen(data->sl_category, SIR_MAX_SYSLOG_CAT));
346
    } else {
347
        _sir_selflog("skipped superfluous update of %s category: '%s'", SIR_DESTNAME_SYSLOG,
46✔
348
            si->d_syslog.identity);
349
        return true;
46✔
350
    }
351

352
    _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_CATEGORY);
49✔
353
    bool updated = _sir_syslog_updated(si, data);
49✔
354
    _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_CATEGORY);
49✔
355

356
    return updated;
49✔
357
}
358

359
bool _sir_writeinit(sir_update_config_data* data, sirinit_update update) {
74,994✔
360
    (void)_sir_seterror(_SIR_E_NOERROR);
74,994✔
361

362
    if (!_sir_sanity() || !_sir_validupdatedata(data) || !_sir_validfnptr(update))
74,994✔
363
        return false;
×
364

365
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
74,994✔
366

367
    bool updated = update(&_cfg->si, data);
74,995✔
368
    if (!updated)
70,890✔
369
        _sir_selflog("error: update routine failed!");
×
370

371
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
74,995✔
372
    return updated;
74,995✔
373
}
374

375
void* _sir_locksection(sir_mutex_id mid) {
9,085,697✔
376
    sir_mutex* m = NULL;
9,085,697✔
377
    void* sec    = NULL;
9,085,697✔
378

379
    bool enter = _sir_mapmutexid(mid, &m, &sec) && _sir_mutexlock(m);
9,085,697✔
380
    SIR_ASSERT(enter);
9,030,889✔
381

382
    return enter ? sec : NULL;
9,086,535✔
383
}
384

385
void _sir_unlocksection(sir_mutex_id mid) {
9,086,147✔
386
    sir_mutex* m = NULL;
9,086,147✔
387
    void* sec    = NULL;
9,086,147✔
388

389
    bool leave = _sir_mapmutexid(mid, &m, &sec) && _sir_mutexunlock(m);
9,086,147✔
390
    SIR_ASSERT_UNUSED(leave, leave);
9,031,203✔
391
}
9,086,893✔
392

393
bool _sir_mapmutexid(sir_mutex_id mid, sir_mutex** m, void** section) {
18,168,914✔
394
    sir_mutex* tmpm;
395
    void* tmpsec;
396

397
    switch (mid) {
18,168,914✔
398
        case SIRMI_CONFIG:
8,679,731✔
399
            tmpm   = &cfg_mutex;
8,679,731✔
400
            tmpsec = &_sir_cfg;
8,679,731✔
401
            break;
8,679,731✔
402
        case SIRMI_FILECACHE:
4,482,708✔
403
            tmpm   = &fc_mutex;
4,406,909✔
404
            tmpsec = &_sir_fc;
4,406,909✔
405
            break;
4,482,708✔
406
        case SIRMI_PLUGINCACHE:
247,095✔
407
            tmpm   = &pc_mutex;
207,873✔
408
            tmpsec = &_sir_pc;
207,873✔
409
            break;
247,095✔
410
        case SIRMI_TEXTSTYLE:
4,643,978✔
411
            tmpm   = &ts_mutex;
4,544,775✔
412
            tmpsec = &sir_text_style_section;
4,544,775✔
413
            break;
4,643,978✔
414
        // GCOVR_EXCL_START
415
        default: /* this should never happen. */
416
            SIR_ASSERT(mid);
417
            tmpm   = NULL;
418
            tmpsec = NULL;
419
            break;
420
        // GCOVR_EXCL_STOP
421
    }
422

423
    *m = tmpm;
18,173,381✔
424

425
    if (section)
18,173,381✔
426
        *section = tmpsec;
18,169,001✔
427

428
    return *m != NULL && (!section || *section != NULL);
18,173,381✔
429
}
430

431
#if !defined(__WIN__)
432
void _sir_init_static_once(void) {
59✔
433
    (void)_sir_init_common_static();
59✔
434
}
59✔
435
#else /* __WIN__ */
436
BOOL CALLBACK _sir_init_static_once(PINIT_ONCE ponce, PVOID param, PVOID* ctx) {
437
    SIR_UNUSED(ponce);
438
    SIR_UNUSED(param);
439
    SIR_UNUSED(ctx);
440
    return _sir_init_common_static() ? TRUE : FALSE;
441
}
442
#endif
443

444
bool _sir_init_common_static(void) {
59✔
445
#if defined(__HAVE_ATOMIC_H__)
446
    atomic_init(&_sir_magic, 0);
59✔
447
#endif
448

449
#if defined(__WIN__)
450
    (void)QueryPerformanceFrequency(&_sir_perfcntr_freq);
451
#endif
452

453
    bool created = _sir_mutexcreate(&cfg_mutex);
59✔
454
    SIR_ASSERT_UNUSED(created, created);
57✔
455

456
    created &= _sir_mutexcreate(&fc_mutex);
59✔
457
    SIR_ASSERT_UNUSED(created, created);
57✔
458

459
    created &= _sir_mutexcreate(&pc_mutex);
59✔
460
    SIR_ASSERT_UNUSED(created, created);
57✔
461

462
    created &= _sir_mutexcreate(&ts_mutex);
59✔
463
    SIR_ASSERT_UNUSED(created, created);
57✔
464

465
    return created;
59✔
466
}
467

468
bool _sir_once(sir_once* once, sir_once_fn func) {
815✔
469
#if !defined(__WIN__)
470
    int ret = pthread_once(once, func);
815✔
471
    return 0 == ret ? true : _sir_handleerr(ret);
815✔
472
#else /* __WIN__ */
473
    return (FALSE != InitOnceExecuteOnce(once, func, NULL, NULL)) ? true
474
        : _sir_handlewin32err(GetLastError());
475
#endif
476
}
477

478
PRINTF_FORMAT_ATTR(2, 0)
479
bool _sir_logv(sir_level level, PRINTF_FORMAT const char* format, va_list args) {
2,161,751✔
480
    if (!_sir_sanity() || !_sir_validlevel(level) || !_sir_validstr(format))
2,161,751✔
481
        return false;
46✔
482

483
    (void)_sir_seterror(_SIR_E_NOERROR);
2,161,705✔
484

485
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
2,161,705✔
486

487
    sirbuf buf = {0};
2,161,705✔
488

489
    /* from time to time, update the host name in the config, just in case. */
490
    time_t now_sec = -1;
2,161,705✔
491
    if (-1 != time(&now_sec) &&
2,161,705✔
492
        (now_sec - _cfg->state.last_hname_chk) > SIR_HNAME_CHK_INTERVAL) { //-V522
2,153,799✔
493
        _sir_selflog("updating hostname...");
8,297✔
494
        if (!_sir_gethostname(_cfg->state.hostname)) {
8,318✔
495
            _sir_selflog("error: failed to get hostname!");
7,909✔
496
        } else {
497
            _cfg->state.last_hname_chk = now_sec;
409✔
498
            _sir_selflog("hostname: '%s'", _cfg->state.hostname);
388✔
499
        }
500
    }
501

502
    /* format timestamp. */
503
    long now_msec = 0L;
2,161,705✔
504
    bool gettime = _sir_clock_gettime(SIR_WALLCLOCK, &now_sec, &now_msec);
2,161,705✔
505
    SIR_ASSERT_UNUSED(gettime, gettime);
2,153,798✔
506

507
    /* milliseconds. */
508
    _sir_snprintf_trunc(buf.msec, SIR_MAXMSEC, SIR_MSECFORMAT, now_msec);
2,161,705✔
509

510
    /* hours/minutes/seconds. */
511
    bool fmt = _sir_formattime(now_sec, _cfg->state.timestamp, SIR_TIMEFORMAT);
2,161,705✔
512
    SIR_ASSERT_UNUSED(fmt, fmt);
2,153,798✔
513

514
    /* check elapsed time since updating thread identifier/name. */
515
    sir_time thrd_chk;
516
    double msec_since_thrd_chk = _sir_msec_since(&_sir_last_thrd_chk, &thrd_chk);
2,161,705✔
517

518
    /* update the thread identifier/name if enough time has elapsed. */
519
    if (msec_since_thrd_chk > SIR_THRD_CHK_INTERVAL) {
2,161,705✔
520
        _sir_last_thrd_chk = thrd_chk;
329✔
521

522
        pid_t tid         = _sir_gettid();
329✔
523
        bool resolved_tid = false;
287✔
524

525
        /* prefer thread names. */
526
        resolved_tid = _sir_getthreadname(_sir_tid);
329✔
527

528
        /* if tid is identical to pid... */
529
        if (!resolved_tid && tid == _cfg->state.pid) {
329✔
530
            /* don't use anything to identify the thread. */
531
            _sir_resetstr(_sir_tid);
×
532
            resolved_tid = true;
×
533
        }
534

535
        /* fall back on tid. */
536
        if (!resolved_tid)
287✔
537
            _sir_snprintf_trunc(_sir_tid, SIR_MAXPID, SIR_PIDFORMAT,
×
538
                PID_CAST tid);
539
    }
540

541
    sirconfig cfg;
542
    memcpy(&cfg, _cfg, sizeof(sirconfig));
2,137,984✔
543
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
2,161,705✔
544

545
    buf.timestamp = cfg.state.timestamp;
2,161,705✔
546
    buf.hostname  = cfg.state.hostname;
2,161,705✔
547
    buf.pid       = cfg.state.pidbuf;
2,161,705✔
548
    buf.name      = cfg.si.name;
2,161,705✔
549

550
    const char* style_str = _sir_gettextstyle(level);
2,161,705✔
551

552
    SIR_ASSERT(NULL != style_str);
2,153,798✔
553
    if (NULL != style_str)
2,145,891✔
554
        (void)_sir_strncpy(buf.style, SIR_MAXSTYLE, style_str,
2,161,705✔
555
            strnlen(style_str, SIR_MAXSTYLE));
556

557
    buf.level = _sir_formattedlevelstr(level);
2,161,705✔
558

559
    (void)_sir_strncpy(buf.tid, SIR_MAXPID, _sir_tid, SIR_MAXPID);
2,161,705✔
560

561
    (void)vsnprintf(buf.message, SIR_MAXMESSAGE, format, args);
2,137,984✔
562

563
    if (!_sir_validstr(buf.message))
2,161,705✔
564
        return _sir_seterror(_SIR_E_INTERNAL);
23✔
565

566
    bool match             = false;
2,137,964✔
567
    bool exit_early        = false;
2,137,964✔
568
    bool update_last_props = true;
2,137,964✔
569
    uint64_t hash          = 0ULL;
2,137,964✔
570

571
    if (cfg.state.last.prefix[0] == buf.message[0]  &&
2,161,682✔
572
        cfg.state.last.prefix[1] == buf.message[1]) {
2,105,856✔
573
        hash  = FNV64_1a(buf.message);
2,123,993✔
574
        match = cfg.state.last.hash == hash;
2,123,992✔
575
    }
576

577
    if (match) {
2,156,779✔
578
        cfg.state.last.counter++;
34,142✔
579

580
        /* _sir_selflog("message '%s' matches last; incremented counter to %zu", buf.message,
581
            cfg.state.last.counter); */
582

583
        if (cfg.state.last.counter >= cfg.state.last.threshold - 2) {
34,142✔
584
            size_t old_threshold = cfg.state.last.threshold;
960✔
585

586
            update_last_props = false;
960✔
587
            cfg.state.last.threshold *= SIR_SQUELCH_BACKOFF_FACTOR;
1,104✔
588
            cfg.state.last.squelch = true;
1,104✔
589

590
            _sir_selflog("hit squelch threshold of %zu; setting new threshold"
1,056✔
591
                         " to %zu (factor: %d)",
592
                old_threshold, cfg.state.last.threshold, SIR_SQUELCH_BACKOFF_FACTOR);
593

594
            (void)snprintf(buf.message, SIR_MAXMESSAGE, SIR_SQUELCH_MSG_FORMAT, old_threshold);
960✔
595
        } else if (cfg.state.last.squelch) {
33,038✔
596
            exit_early = true;
28,140✔
597
        }
598
    } else {
599
        cfg.state.last.squelch   = false;
2,127,539✔
600
        cfg.state.last.counter   = 0;
2,127,539✔
601
        cfg.state.last.threshold = SIR_SQUELCH_THRESHOLD;
2,127,539✔
602
        /* _sir_selflog("message '%s' does not match last; resetting", buf.message); */
603
    }
604

605
    _cfg = _sir_locksection(SIRMI_CONFIG);
2,161,681✔
606
    if (!_cfg)
2,161,682✔
607
        return _sir_seterror(_SIR_E_INTERNAL);
×
608

609
    _cfg->state.last.squelch = cfg.state.last.squelch;
2,161,682✔
610

611
    if (update_last_props) {
2,161,682✔
612
        _cfg->state.last.hash      = hash;
2,160,578✔
613
        _cfg->state.last.prefix[0] = buf.message[0];
2,160,578✔
614
        _cfg->state.last.prefix[1] = buf.message[1];
2,160,578✔
615
    }
616

617
    _cfg->state.last.counter   = cfg.state.last.counter;
2,161,682✔
618
    _cfg->state.last.threshold = cfg.state.last.threshold;
2,161,682✔
619

620
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
2,161,682✔
621

622
    if (exit_early)
2,161,681✔
623
        return false;
28,140✔
624

625
    bool dispatched = _sir_dispatch(&cfg.si, level, &buf);
2,129,320✔
626
    return update_last_props ? dispatched : false;
2,129,321✔
627
}
628

629
bool _sir_dispatch(sirinit* si, sir_level level, sirbuf* buf) {
2,129,320✔
630
    bool retval       = true;
2,109,824✔
631
    size_t dispatched = 0;
2,109,824✔
632
    size_t wanted     = 0;
2,109,824✔
633

634
    if (_sir_bittest(si->d_stdout.levels, level)) {
2,129,320✔
635
        const char* write = _sir_format(true, si->d_stdout.opts, buf);
1,125,499✔
636
        bool wrote        = _sir_validstrnofail(write) &&
2,250,999✔
637
            _sir_write_stdout(write, buf->output_len);
1,125,498✔
638
        retval &= wrote;
1,125,499✔
639

640
        if (wrote)
1,125,499✔
641
            dispatched++;
1,100,379✔
642
        wanted++;
1,106,593✔
643
    }
644

645
    if (_sir_bittest(si->d_stderr.levels, level)) {
2,129,320✔
646
        const char* write = _sir_format(true, si->d_stderr.opts, buf);
1,169✔
647
        bool wrote        = _sir_validstrnofail(write) &&
2,338✔
648
            _sir_write_stderr(write, buf->output_len);
1,169✔
649
        retval &= wrote;
1,169✔
650

651
        if (wrote)
1,169✔
652
            dispatched++;
1,160✔
653
        wanted++;
1,169✔
654
    }
655

656
#if !defined(SIR_NO_SYSTEM_LOGGERS)
657
    if (_sir_bittest(si->d_syslog.levels, level)) {
2,094,957✔
658
        if (_sir_syslog_write(level, buf, &si->d_syslog))
632✔
659
            dispatched++;
632✔
660
        wanted++;
632✔
661
    }
662
#endif
663

664
    _SIR_LOCK_SECTION(sirfcache, sfc, SIRMI_FILECACHE, false);
2,129,318✔
665
    size_t fdispatched = 0;
2,129,321✔
666
    size_t fwanted     = 0;
2,129,321✔
667
    retval &= _sir_fcache_dispatch(sfc, level, buf, &fdispatched, &fwanted);
2,129,321✔
668
    _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
2,129,321✔
669

670
    dispatched += fdispatched;
2,129,321✔
671
    wanted += fwanted;
2,129,321✔
672

673
#if !defined(SIR_NO_PLUGINS)
674
    _SIR_LOCK_SECTION(sir_plugincache, spc, SIRMI_PLUGINCACHE, false);
122,746✔
675
    size_t pdispatched = 0;
122,746✔
676
    size_t pwanted     = 0;
122,746✔
677
    retval &= _sir_plugin_cache_dispatch(spc, level, buf, &pdispatched, &pwanted);
122,746✔
678
    _SIR_UNLOCK_SECTION(SIRMI_PLUGINCACHE);
122,746✔
679

680
    dispatched += pdispatched;
122,746✔
681
    wanted += pwanted;
122,746✔
682
#endif
683

684
    if (0 == wanted) {
2,129,321✔
685
        _sir_selflog("error: no destinations registered for level %04"PRIx16, level);
936✔
686
        return _sir_seterror(_SIR_E_NODEST);
989✔
687
    }
688

689
    return retval && (dispatched == wanted);
2,128,332✔
690
}
691

692
const char* _sir_format(bool styling, sir_options opts, sirbuf* buf) {
2,291,181✔
693
    if (_sir_validptr(buf)) {
2,291,181✔
694
        bool first = true;
2,245,275✔
695

696
        _sir_resetstr(buf->output);
2,291,172✔
697

698
        if (styling)
2,291,184✔
699
            _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->style, SIR_MAXSTYLE);
1,126,668✔
700

701
        if (!_sir_bittest(opts, SIRO_NOTIME)) {
2,291,178✔
702
            _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->timestamp, SIR_MAXTIME);
2,122,044✔
703
            first = false;
2,102,013✔
704

705
#if defined(SIR_MSEC_TIMER)
706
            if (!_sir_bittest(opts, SIRO_NOMSEC))
2,122,043✔
707
                _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->msec, SIR_MAXMSEC);
85,127✔
708
#endif
709
        }
710

711
        if (!_sir_bittest(opts, SIRO_NOHOST) && _sir_validstrnofail(buf->hostname)) {
2,291,206✔
712
            if (!first)
1,034,046✔
713
                _sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,001,634✔
714
            _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->hostname, SIR_MAXHOST);
1,034,046✔
715
            first = false;
1,027,829✔
716
        }
717

718
        if (!_sir_bittest(opts, SIRO_NOLEVEL)) {
2,291,149✔
719
            if (!first)
2,174,820✔
720
                _sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
2,122,232✔
721
            _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->level, SIR_MAXLEVEL);
2,174,827✔
722
            first = false;
2,147,864✔
723
        }
724

725
        bool name = false;
2,245,214✔
726
        if (!_sir_bittest(opts, SIRO_NONAME) && _sir_validstrnofail(buf->name)) {
2,291,143✔
727
            if (!first)
1,120,698✔
728
                _sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,116,677✔
729
            _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->name, SIR_MAXNAME);
1,120,700✔
730
            first = false;
1,100,905✔
731
            name  = true;
1,100,905✔
732
        }
733

734
        bool wantpid = !_sir_bittest(opts, SIRO_NOPID) && _sir_validstrnofail(buf->pid);
2,291,195✔
735
        bool wanttid = !_sir_bittest(opts, SIRO_NOTID) && _sir_validstrnofail(buf->tid);
2,291,328✔
736

737
        if (wantpid || wanttid) {
2,291,265✔
738
            if (name)
2,155,506✔
739
                _sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDPREFIX, 1);
1,114,821✔
740
            else if (!first)
1,040,685✔
741
                _sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,040,679✔
742

743
            if (wantpid)
2,155,508✔
744
                _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->pid, SIR_MAXPID);
2,077,578✔
745

746
            if (wanttid) {
2,155,505✔
747
                if (wantpid)
2,150,069✔
748
                    _sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDSEPARATOR, 1);
2,072,171✔
749
                _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->tid, SIR_MAXPID);
2,150,069✔
750
            }
751

752
            if (name)
2,155,492✔
753
                _sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDSUFFIX, 1);
1,114,803✔
754

755
            if (first)
2,129,382✔
756
                first = false;
6✔
757
        }
758

759
        if (!first)
2,265,141✔
760
            _sir_strncat(buf->output, SIR_MAXOUTPUT, ": ", 2);
2,211,000✔
761

762
        _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->message, SIR_MAXMESSAGE);
2,291,254✔
763

764
        if (styling)
2,291,184✔
765
            _sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_ESC_RST, SIR_MAXSTYLE);
1,126,652✔
766

767
        _sir_strncat(buf->output, SIR_MAXOUTPUT, "\n", 1);
2,291,186✔
768

769
        buf->output_len = strnlen(buf->output, SIR_MAXOUTPUT);
2,291,174✔
770

771
        return buf->output;
2,291,174✔
772
    }
773

774
    return NULL;
×
775
}
776

777
bool _sir_syslog_init(const char* name, sir_syslog_dest* ctx) {
239✔
778
#if !defined(SIR_NO_SYSTEM_LOGGERS)
779
    if (!_sir_validptr(name) || !_sir_validptr(ctx))
239✔
780
        return false;
×
781

782
    /* begin resolve identity. */
783
    if (!_sir_validstrnofail(ctx->identity)) {
239✔
784
        _sir_selflog("ctx->identity is no good; trying name");
50✔
785
        if (_sir_validstrnofail(name)) {
53✔
786
            _sir_selflog("using name");
30✔
787
            _sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, name, strnlen(name, SIR_MAX_SYSLOG_ID));
32✔
788
        } else {
789
            _sir_selflog("name is no good; trying filename");
20✔
790
            char* appbasename = _sir_getappbasename();
21✔
791
            if (_sir_validstrnofail(appbasename)) {
21✔
792
                _sir_selflog("filename is good: %s", appbasename);
15✔
793
                _sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, appbasename,
15✔
794
                    strnlen(appbasename, SIR_MAX_SYSLOG_ID));
795
            } else {
796
                _sir_selflog("filename no good; using fallback");
6✔
797
                _sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, SIR_FALLBACK_SYSLOG_ID,
6✔
798
                    strnlen(SIR_FALLBACK_SYSLOG_ID, SIR_MAX_SYSLOG_ID));
799
            }
800
            _sir_safefree(&appbasename);
21✔
801
        }
802
    } else {
803
        _sir_selflog("already have identity");
176✔
804
    }
805

806
    /* category */
807
    if (!_sir_validstrnofail(ctx->category)) {
239✔
808
        _sir_selflog("category not set; using fallback");
76✔
809
        _sir_strncpy(ctx->category, SIR_MAX_SYSLOG_CAT, SIR_FALLBACK_SYSLOG_CAT,
80✔
810
            strnlen(SIR_FALLBACK_SYSLOG_CAT, SIR_MAX_SYSLOG_CAT));
811
    } else {
812
        _sir_selflog("already have category");
150✔
813
    }
814

815
    _sir_setbitshigh(&ctx->_state.mask, SIRSL_IS_INIT);
239✔
816
    _sir_selflog("resolved (identity: '%s', category: '%s')", ctx->identity, ctx->category);
226✔
817

818
    return _sir_syslog_open(ctx);
239✔
819
#else
820
    SIR_UNUSED(name);
821
    SIR_UNUSED(ctx);
822
    return false;
×
823
#endif
824
}
825

826
bool _sir_syslog_open(sir_syslog_dest* ctx) {
239✔
827
#if !defined(SIR_NO_SYSTEM_LOGGERS)
828
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_INIT)) {
239✔
829
        _sir_selflog("not initialized; ignoring");
×
830
        return _sir_seterror(_SIR_E_INVALID);
×
831
    }
832

833
    if (_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
239✔
834
        _sir_selflog("log already open; ignoring");
104✔
835
        return true;
104✔
836
    }
837

838
    _sir_selflog("opening log (levels: %04"PRIx16", options: %08"PRIx32")", ctx->levels,
129✔
839
        ctx->opts);
840

841
# if defined(SIR_OS_LOG_ENABLED)
842
    ctx->_state.logger = (void*)os_log_create(ctx->identity, ctx->category);
843
    _sir_selflog("opened os_log ('%s', '%s')", ctx->identity, ctx->category);
844
# elif defined(SIR_SYSLOG_ENABLED)
845
    int logopt   = LOG_NDELAY | (_sir_bittest(ctx->opts, SIRO_NOPID) ? 0 : LOG_PID);
129✔
846
    int facility = LOG_USER;
108✔
847

848
    openlog(ctx->identity, logopt, facility);
129✔
849
    _sir_selflog("opened syslog('%s', %x, %x)", ctx->identity, logopt, facility);
122✔
850
# endif
851

852
    _sir_setbitshigh(&ctx->_state.mask, SIRSL_IS_OPEN);
129✔
853
    return true;
129✔
854
#else
855
    SIR_UNUSED(ctx);
856
    return false;
×
857
#endif
858
}
859

860
bool _sir_syslog_write(sir_level level, const sirbuf* buf, sir_syslog_dest* ctx) {
632✔
861
#if !defined(SIR_NO_SYSTEM_LOGGERS)
862
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_INIT)) {
632✔
863
        _sir_selflog("not initialized; ignoring");
×
864
        return _sir_seterror(_SIR_E_INVALID);
×
865
    }
866

867
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
632✔
868
        _sir_selflog("log not open; ignoring");
×
869
        return _sir_seterror(_SIR_E_INVALID);
×
870
    }
871

872
# if defined(SIR_OS_LOG_ENABLED)
873
    if (SIRL_DEBUG == level)
874
        os_log_debug((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
875
    else if (SIRL_INFO == level || SIRL_NOTICE == level)
876
        os_log_info((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
877
    else if (SIRL_WARN == level || SIRL_ERROR == level)
878
        os_log_error((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
879
    else if (SIRL_ALERT == level || SIRL_CRIT == level || SIRL_EMERG == level)
880
        os_log_fault((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
881

882
    return true;
883
# elif defined(SIR_SYSLOG_ENABLED)
884
    int syslog_level;
885
    switch (level) {
632✔
886
        case SIRL_DEBUG:  syslog_level = LOG_DEBUG; break;
28✔
887
        case SIRL_INFO:   syslog_level = LOG_INFO; break;
30✔
888
        case SIRL_NOTICE: syslog_level = LOG_NOTICE; break;
85✔
889
        case SIRL_WARN:   syslog_level = LOG_WARNING; break;
85✔
890
        case SIRL_ERROR:  syslog_level = LOG_ERR; break;
85✔
891
        case SIRL_CRIT:   syslog_level = LOG_CRIT; break;
112✔
892
        case SIRL_ALERT:  syslog_level = LOG_ALERT; break;
85✔
893
        case SIRL_EMERG:  syslog_level = LOG_EMERG; break;
112✔
894
        // GCOVR_EXCL_START
895
        case SIRL_NONE: /* this should never happen. */
896
        default:
897
            SIR_ASSERT(level);
898
            syslog_level = LOG_DEBUG;
899
        // GCOVR_EXCL_STOP
900
    }
901

902
    syslog(syslog_level, "%s", buf->message);
632✔
903
    return true;
632✔
904
# endif
905
#else
906
    SIR_UNUSED(level);
907
    SIR_UNUSED(buf);
908
    SIR_UNUSED(ctx);
909
    return false;
×
910
#endif
911
}
912

913
bool _sir_syslog_updated(sirinit* si, sir_update_config_data* data) {
247✔
914
#if !defined(SIR_NO_SYSTEM_LOGGERS)
915
    if (!_sir_validptr(si) || !_sir_validptr(data))
247✔
916
        return false;
×
917

918
    if (_sir_bittest(si->d_syslog._state.mask, SIRSL_UPDATED)) {
247✔
919
        bool levels   = _sir_bittest(si->d_syslog._state.mask, SIRSL_LEVELS);
234✔
920
        bool options  = _sir_bittest(si->d_syslog._state.mask, SIRSL_OPTIONS);
247✔
921
        bool category = _sir_bittest(si->d_syslog._state.mask, SIRSL_CATEGORY);
234✔
922
        bool identity = _sir_bittest(si->d_syslog._state.mask, SIRSL_IDENTITY);
247✔
923
        bool is_init  = _sir_bittest(si->d_syslog._state.mask, SIRSL_IS_INIT);
247✔
924
        bool is_open  = _sir_bittest(si->d_syslog._state.mask, SIRSL_IS_OPEN);
247✔
925

926
        _sir_selflog("config update: (levels: %u, options: %u, category: %u,"
234✔
927
                     " identity: %u, is_init: %u, is_open: %u)",
928
                     levels, options, category, identity, is_init, is_open);
929

930
        bool must_init = false;
208✔
931

932
# if defined(SIR_OS_LOG_ENABLED)
933
        /*
934
         * for os_log, if initialized and open already, only need to reconfigure
935
         * if identity or category changed.
936
         */
937
        must_init = (!is_init || !is_open) || (identity || category);
938
# elif defined(SIR_SYSLOG_ENABLED)
939
        /*
940
         * for os_log, if initialized and open already, only need to reconfigure
941
         * if identity or options changed.
942
         */
943
        must_init = (!is_init || !is_open) || (identity || options);
247✔
944
# endif
945
        bool init = true;
208✔
946
        if (must_init) {
208✔
947
            _sir_selflog("re-init...");
130✔
948
            init = _sir_syslog_init(si->name, &si->d_syslog);
137✔
949
            _sir_selflog("re-init %s", init ? "succeeded" : "failed");
130✔
950
        } else {
951
            _sir_selflog("no re-init necessary");
104✔
952
        }
953

954
        return init;
247✔
955
    } else {
956
        _sir_selflog("BUG: called without 'updated' flag set!");
×
957
        return false;
×
958
    }
959
#else
960
    SIR_UNUSED(si);
961
    SIR_UNUSED(data);
962
    return false;
×
963
#endif
964
}
965

966
bool _sir_syslog_close(sir_syslog_dest* ctx) {
571✔
967
#if !defined(SIR_NO_SYSTEM_LOGGERS)
968
    if (!_sir_validptr(ctx))
571✔
969
        return false;
×
970

971
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
571✔
972
        _sir_selflog("log not open; ignoring");
416✔
973
        return true;
416✔
974
    }
975

976
# if defined(SIR_OS_LOG_ENABLED)
977
    /* evidently, you don't need to close the handle returned from os_log_create(), and
978
     * if you make that call again, you'll get the same cached value. so let's keep the
979
     * value we've got in the global context. */
980
    _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
981
    _sir_selflog("log closure not necessary");
982
    return true;
983
# elif defined(SIR_SYSLOG_ENABLED)
984
    closelog();
129✔
985
    _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
129✔
986
    _sir_selflog("closed log");
122✔
987
    return true;
129✔
988
# endif
989
#else
990
    SIR_UNUSED(ctx);
991
    return false;
×
992
#endif
993
}
994

995
void _sir_syslog_reset(sir_syslog_dest* ctx) {
1,142✔
996
#if !defined(SIR_NO_SYSTEM_LOGGERS)
997
    if (_sir_validptr(ctx)) {
1,142✔
998
        uint32_t old       = ctx->_state.mask;
1,076✔
999
        ctx->_state.mask   = 0U;
1,142✔
1000
        ctx->_state.logger = NULL;
1,142✔
1001
        _sir_selflog("state reset; mask was %08"PRIx32, old);
1,076✔
1002
    }
1003
#else
1004
    SIR_UNUSED(ctx);
1005
#endif
1006
}
1,142✔
1007

1008
const char* _sir_formattedlevelstr(sir_level level) {
2,161,705✔
1009
    static const size_t low  = 0;
1010
    static const size_t high = SIR_NUMLEVELS - 1;
1011

1012
    const char* retval = SIR_UNKNOWN;
2,137,984✔
1013

1014
    _SIR_DECLARE_BIN_SEARCH(low, high);
2,137,984✔
1015
    _SIR_BEGIN_BIN_SEARCH()
1016

1017
    if (sir_level_to_str_map[_mid].level == level) {
8,602,390✔
1018
        retval = sir_level_to_str_map[_mid].fmt;
2,161,705✔
1019
        break;
2,161,705✔
1020
    }
1021

1022
    _SIR_ITERATE_BIN_SEARCH((sir_level_to_str_map[_mid].level < level ? 1 : -1));
6,440,685✔
1023
    _SIR_END_BIN_SEARCH();
1024

1025
    return retval;
2,161,705✔
1026
}
1027

1028
bool _sir_clock_gettime(int clock, time_t* tbuf, long* msecbuf) {
6,323,489✔
1029
    if (tbuf) {
6,323,489✔
1030
#if defined(SIR_MSEC_POSIX)
1031
        struct timespec ts = {0};
6,323,489✔
1032
        int ret            = clock_gettime(clock, &ts);
6,323,489✔
1033
        SIR_ASSERT(0 == ret);
6,307,672✔
1034

1035
        if (0 == ret) {
6,291,855✔
1036
            *tbuf = ts.tv_sec;
6,307,750✔
1037
            if (msecbuf)
6,307,750✔
1038
                *msecbuf = (long)(ts.tv_nsec / 1000000L);
6,307,750✔
1039
        } else {
1040
            if (msecbuf)
15,739✔
1041
                *msecbuf = 0L;
15,739✔
1042
            return _sir_handleerr(errno);
15,739✔
1043
        }
1044
#elif defined(SIR_MSEC_WIN32)
1045
        SIR_UNUSED(clock);
1046
        static const ULONGLONG uepoch = (ULONGLONG)116444736e9;
1047

1048
        FILETIME ftutc = {0};
1049
        GetSystemTimePreciseAsFileTime(&ftutc);
1050

1051
        ULARGE_INTEGER ftnow = {0};
1052
        ftnow.HighPart = ftutc.dwHighDateTime;
1053
        ftnow.LowPart  = ftutc.dwLowDateTime;
1054
        ftnow.QuadPart = (ULONGLONG)((ftnow.QuadPart - uepoch) / 10000000ULL);
1055

1056
        *tbuf = (time_t)ftnow.QuadPart;
1057

1058
        SYSTEMTIME st = {0};
1059
        if (FileTimeToSystemTime(&ftutc, &st)) {
1060
            if (msecbuf)
1061
                *msecbuf = (long)st.wMilliseconds;
1062
        } else {
1063
            if (msecbuf)
1064
                *msecbuf = 0L;
1065
            return _sir_handlewin32err(GetLastError());
1066
        }
1067
#else
1068
        time(tbuf);
1069
        if (msecbuf)
1070
            *msecbuf = 0L;
1071
#endif
1072
        return true;
6,307,750✔
1073
    }
1074
    return false;
×
1075
}
1076

1077
double _sir_msec_since(const sir_time* when, sir_time* out) {
4,161,784✔
1078
    if (!_sir_validptr(out))
4,161,784✔
1079
        return 0.0;
×
1080
#if !defined(__WIN__) || defined(__ORANGEC__)
1081
    out->sec = 0;
4,161,784✔
1082
    out->msec = 0L;
4,161,784✔
1083

1084
    bool gettime = _sir_clock_gettime(SIR_INTERVALCLOCK, &out->sec, &out->msec);
4,161,784✔
1085
    SIR_ASSERT(gettime);
4,153,874✔
1086

1087
    if (!_sir_validptrnofail(when) || !gettime || (out->sec < when->sec ||
4,161,784✔
1088
        (out->sec == when->sec && out->msec < when->msec)))
4,151,102✔
1089
        return 0.0;
7,914✔
1090

1091
    return ((((double)out->sec) * 1e3) + (double)out->msec) -
4,153,864✔
1092
           ((((double)when->sec) * 1e3) + (double)when->msec);
4,153,864✔
1093
#else /* __WIN__ */
1094
    SIR_ASSERT(_sir_perfcntr_freq.QuadPart > 0LL);
1095

1096
    if (_sir_perfcntr_freq.QuadPart <= 0LL)
1097
        return 0.0;
1098

1099
    (void)QueryPerformanceCounter(&out->counter);
1100

1101
    if (!_sir_validptrnofail(when) || out->counter.QuadPart <= when->counter.QuadPart)
1102
        return 0.0;
1103

1104
    double msec_ratio = ((double)_sir_perfcntr_freq.QuadPart) / 1e3;
1105
    return ((double)(out->counter.QuadPart - when->counter.QuadPart)) / msec_ratio;
1106
#endif
1107
}
1108

1109
pid_t _sir_getpid(void) {
762✔
1110
#if !defined(__WIN__)
1111
    return getpid();
762✔
1112
#else /* __WIN__ */
1113
    return (pid_t)GetCurrentProcessId();
1114
#endif
1115
}
1116

1117
pid_t _sir_gettid(void) {
430✔
1118
    pid_t tid = 0;
373✔
1119
#if defined(__MACOS__)
1120
    uint64_t tid64 = 0ULL;
1121
    int gettid     = pthread_threadid_np(NULL, &tid64);
1122
    if (0 != gettid)
1123
        (void)_sir_handleerr(gettid);
1124
    tid = (pid_t)tid64;
1125
#elif (defined(__BSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)) || \
1126
      defined(__DragonFly_getthreadid__)
1127
    tid = (pid_t)pthread_getthreadid_np();
1128
#elif defined(__OpenBSD__)
1129
    tid = (pid_t)getthrid();
1130
#elif defined(__SOLARIS__) || defined(__NetBSD__) || defined(__HURD__) || \
1131
      defined(__DragonFly__) || defined(__CYGWIN__) || defined(_AIX)
1132
    tid = (pid_t)pthread_self();
1133
#elif defined(__HAIKU__)
1134
    tid = get_pthread_thread_id(pthread_self());
1135
#elif defined(__linux__) || defined(__serenity__)
1136
# if (defined(__GLIBC__) && GLIBC_VERSION >= 23000) || defined(__serenity__)
1137
    tid = gettid();
430✔
1138
# else
1139
    tid = syscall(SYS_gettid);
1140
# endif
1141
#elif defined(__WIN__)
1142
    tid = (pid_t)GetCurrentThreadId();
1143
#else
1144
# error "cannot determine how to get thread id; please contact the author"
1145
#endif
1146
    return tid;
430✔
1147
}
1148

1149
bool _sir_getthreadname(char name[SIR_MAXPID]) {
329✔
1150
    _sir_resetstr(name);
329✔
1151
#if defined(__MACOS__) || \
1152
   (defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_12_2__)) || \
1153
   (defined(__GLIBC__) && GLIBC_VERSION >= 21200 && defined(_GNU_SOURCE)) || \
1154
    defined(USE_PTHREAD_GETNAME_NP)
1155
    int ret = pthread_getname_np(pthread_self(), name, SIR_MAXPID);
329✔
1156
    if (0 != ret)
329✔
1157
        return _sir_handleerr(ret);
×
1158
# if defined(__HAIKU__)
1159
    if ((strncmp(name, "pthread_func", SIR_MAXPID)) || _sir_validstrnofail(name))
1160
        (void)snprintf(name, SIR_MAXPID, "%ld", (long)get_pthread_thread_id(pthread_self()));
1161
# endif
1162
    return _sir_validstrnofail(name);
329✔
1163
#elif defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_11_3__)
1164
    pthread_get_name_np(pthread_self(), name, SIR_MAXPID);
1165
    return _sir_validstrnofail(name);
1166
#elif defined(__WIN__) && !defined(__ORANGEC__)
1167
    bool success       = false;
1168
    wchar_t* wide_name = NULL;
1169
    HRESULT hr         = GetThreadDescription(GetCurrentThread(), &wide_name);
1170
    if (SUCCEEDED(hr)) {
1171
# if defined(__HAVE_STDC_SECURE_OR_EXT1__)
1172
        size_t wide_len = wcsnlen_s(wide_name, SIR_MAXPID);
1173
# elif defined(__EMBARCADEROC__)
1174
        size_t wide_len = wcslen(wide_name);
1175
# else
1176
        size_t wide_len = wcsnlen(wide_name, SIR_MAXPID);
1177
# endif
1178
        if (wide_len > 0) {
1179
            if (WideCharToMultiByte(CP_UTF8, 0UL, wide_name, (int)wide_len, name, SIR_MAXPID,
1180
                NULL, NULL))
1181
                success = true;
1182
            else
1183
                (void)_sir_handlewin32err(GetLastError());
1184
        } else {
1185
            success = true;
1186
        }
1187
        (void)LocalFree(wide_name);
1188
    }
1189
    return success && _sir_validstrnofail(name);
1190
#else
1191
# if !defined(_AIX) && !defined(__HURD__) && !defined(SUNLINT)
1192
#  pragma message("unable to determine how to get a thread name")
1193
# endif
1194
    SIR_UNUSED(name);
1195
    return false;
1196
#endif
1197
}
1198

1199
bool _sir_gethostname(char name[SIR_MAXHOST]) {
8,318✔
1200
#if !defined(__WIN__)
1201
    int ret = gethostname(name, SIR_MAXHOST - 1);
8,255✔
1202
    return 0 == ret ? true : _sir_handleerr(errno);
8,318✔
1203
#else
1204
    WSADATA wsad = {0};
1205
    int ret      = WSAStartup(MAKEWORD(2, 2), &wsad);
1206
    if (0 != ret)
1207
        return _sir_handlewin32err(ret);
1208

1209
    if (SOCKET_ERROR == gethostname(name, SIR_MAXHOST)) {
1210
        int err = WSAGetLastError();
1211
        WSACleanup();
1212
        return _sir_handlewin32err(err);
1213
    }
1214

1215
    WSACleanup();
1216
    return true;
1217
#endif /* !__WIN__ */
1218
}
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