This source file includes following definitions.
- _sir_makeinit
- _sir_init
- _sir_cleanup
- _sir_isinitialized
- _sir_sanity
- _sir_init_sanity
- _sir_reset_tls
- _sir_updatelevels
- _sir_updateopts
- _sir_stdoutlevels
- _sir_stdoutopts
- _sir_stderrlevels
- _sir_stderropts
- _sir_sysloglevels
- _sir_syslogopts
- _sir_syslogid
- _sir_syslogcat
- _sir_writeinit
- _sir_locksection
- _sir_unlocksection
- _sir_mapmutexid
- _sir_init_static_once
- _sir_init_static_once
- _sir_init_common_static
- _sir_once
- PRINTF_FORMAT_ATTR
- _sir_dispatch
- _sir_format
- _sir_syslog_init
- _sir_syslog_open
- _sir_syslog_write
- _sir_syslog_updated
- _sir_syslog_close
- _sir_syslog_reset
- _sir_formattedlevelstr
- _sir_clock_gettime
- _sir_msec_since
- _sir_getpid
- _sir_gettid
- _sir_getthreadname
- _sir_setthreadname
- _sir_gethostname
- __sir_nprocs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 #include "sir/internal.h"
35 #include "sir/console.h"
36 #include "sir/defaults.h"
37 #include "sir/filecache.h"
38 #include "sir/plugins.h"
39 #include "sir/textstyle.h"
40 #include "sir/filesystem.h"
41 #include "sir/mutex.h"
42
43 #if defined(__WIN__)
44 # if defined(SIR_EVENTLOG_ENABLED)
45 # include "sir/wineventlog.h"
46 # pragma comment(lib, "advapi32.lib")
47 # endif
48 # if defined(__EMBARCADEROC__) && defined(_WIN64)
49 # pragma comment(lib, "ws2_32.a")
50 # else
51 # pragma comment(lib, "ws2_32.lib")
52 # endif
53 #endif
54
55 static sirconfig _sir_cfg = {0};
56 static sirfcache _sir_fc = {0};
57 static sir_plugincache _sir_pc = {0};
58
59 #if !defined(__IMPORTC__)
60 static sir_mutex cfg_mutex = SIR_MUTEX_INIT;
61 static sir_mutex fc_mutex = SIR_MUTEX_INIT;
62 static sir_mutex pc_mutex = SIR_MUTEX_INIT;
63 # if !defined(SIR_NO_TEXT_STYLING)
64 static sir_mutex ts_mutex = SIR_MUTEX_INIT;
65 # endif
66 #else
67 static sir_mutex cfg_mutex = {0};
68 static sir_mutex fc_mutex = {0};
69 static sir_mutex pc_mutex = {0};
70 # if !defined(SIR_NO_TEXT_STYLING)
71 static sir_mutex ts_mutex = {0};
72 # endif
73 #endif
74 static sir_once static_once = SIR_ONCE_INIT;
75
76 #if defined(__WIN__)
77 static LARGE_INTEGER _sir_perfcntr_freq = {0};
78 #endif
79
80 #if defined(__HAVE_ATOMIC_H__)
81 static atomic_uint_fast32_t _sir_magic;
82 #else
83 static volatile uint32_t _sir_magic = 0U;
84 #endif
85
86 static _sir_thread_local char _sir_tid[SIR_MAXPID] = {0};
87 static _sir_thread_local sir_time _sir_last_thrd_chk = {0};
88 static _sir_thread_local time_t _sir_last_timestamp = 0;
89
90 bool _sir_makeinit(sirinit* si) {
91 bool retval = _sir_validptr(si);
92
93 if (retval) {
94 (void)memset(si, 0, sizeof(sirinit));
95
96 si->d_stdout.opts = SIRO_DEFAULT;
97 si->d_stdout.levels = SIRL_DEFAULT;
98
99 si->d_stderr.opts = SIRO_DEFAULT;
100 si->d_stderr.levels = SIRL_DEFAULT;
101
102 #if !defined(SIR_NO_SYSTEM_LOGGERS)
103 si->d_syslog.opts = SIRO_DEFAULT;
104 si->d_syslog.levels = SIRL_DEFAULT;
105 #else
106 si->d_syslog.opts = SIRO_MSGONLY;
107 si->d_syslog.levels = SIRL_NONE;
108 #endif
109 }
110
111 return retval;
112 }
113
114 bool _sir_init(sirinit* si) {
115 (void)_sir_seterror(_SIR_E_NOERROR);
116
117
118 bool once_init = _sir_once(&static_once, _sir_init_static_once);
119 #if !defined(__WIN__)
120 SIR_UNUSED(once_init);
121 #else
122 if (!once_init) {
123 _sir_selflog("error: static data initialization routine failed!");
124 return false;
125 }
126 #endif
127
128 if (!_sir_validptr(si))
129 return false;
130
131 #if defined(__HAVE_ATOMIC_H__)
132 if (_SIR_MAGIC == atomic_load(&_sir_magic))
133 #else
134 if (_SIR_MAGIC == _sir_magic)
135 #endif
136 return _sir_seterror(_SIR_E_ALREADY);
137
138 _sir_defaultlevels(&si->d_stdout.levels, sir_stdout_def_lvls);
139 _sir_defaultopts(&si->d_stdout.opts, sir_stdout_def_opts);
140
141 _sir_defaultlevels(&si->d_stderr.levels, sir_stderr_def_lvls);
142 _sir_defaultopts(&si->d_stderr.opts, sir_stderr_def_opts);
143
144 #if !defined(SIR_NO_SYSTEM_LOGGERS)
145 _sir_defaultlevels(&si->d_syslog.levels, sir_syslog_def_lvls);
146 _sir_defaultopts(&si->d_syslog.opts, sir_syslog_def_opts);
147 #endif
148
149 if (!_sir_init_sanity(si))
150 return false;
151
152 _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
153
154 bool init = true;
155
156 #if defined(__HAVE_ATOMIC_H__)
157 atomic_store(&_sir_magic, _SIR_MAGIC);
158 #else
159 _sir_magic = _SIR_MAGIC;
160 #endif
161
162 _sir_reset_tls();
163
164 #if defined(__WIN__)
165 _sir_initialize_stdio();
166 #else
167 tzset();
168 #endif
169
170 #if !defined(SIR_NO_TEXT_STYLING)
171 if (!_sir_setcolormode(SIRCM_16)) {
172 init = false;
173 _sir_selflog("error: failed to set color mode!");
174 }
175
176 if (!_sir_resettextstyles()) {
177 init = false;
178 _sir_selflog("error: failed to reset text styles!");
179 }
180 #endif
181
182 (void)memset(&_cfg->state, 0, sizeof(_cfg->state));
183 (void)memcpy(&_cfg->si, si, sizeof(sirinit));
184
185
186 _cfg->si.name[SIR_MAXNAME - 1] = '\0';
187
188
189 _cfg->state.pid = _sir_getpid();
190
191 (void)snprintf(_cfg->state.pidbuf, SIR_MAXPID, SIR_PIDFORMAT,
192 PID_CAST _cfg->state.pid);
193
194 #if !defined(SIR_NO_SYSTEM_LOGGERS)
195
196 _sir_syslog_reset(&_cfg->si.d_syslog);
197
198 if (_cfg->si.d_syslog.levels != SIRL_NONE &&
199 !_sir_syslog_init(_cfg->si.name, &_cfg->si.d_syslog)) {
200 init = false;
201 _sir_selflog("failed to initialize system logger!");
202 }
203 #endif
204
205 _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
206
207 _sir_selflog("initialized %s", (init ? "successfully" : "with errors"));
208
209 SIR_ASSERT(init);
210 return init;
211 }
212
213 bool _sir_cleanup(void) {
214 if (!_sir_sanity())
215 return false;
216
217 _SIR_LOCK_SECTION(sirfcache, sfc, SIRMI_FILECACHE, false);
218 bool cleanup = true;
219 bool destroyfc = _sir_fcache_destroy(sfc);
220 SIR_ASSERT(destroyfc);
221
222 _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
223 _sir_eqland(cleanup, destroyfc);
224
225 #if !defined(SIR_NO_PLUGINS)
226 _SIR_LOCK_SECTION(sir_plugincache, spc, SIRMI_PLUGINCACHE, false);
227 bool destroypc = _sir_plugin_cache_destroy(spc);
228 SIR_ASSERT(destroypc);
229 _SIR_UNLOCK_SECTION(SIRMI_PLUGINCACHE);
230 _sir_eqland(cleanup, destroypc);
231 #endif
232
233 _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
234
235 #if !defined(SIR_NO_SYSTEM_LOGGERS)
236 if (!_sir_syslog_close(&_cfg->si.d_syslog)) {
237 cleanup = false;
238 _sir_selflog("error: failed to close system logger!");
239 }
240
241 _sir_syslog_reset(&_cfg->si.d_syslog);
242 #endif
243
244 #if !defined(SIR_NO_TEXT_STYLING)
245 if (!_sir_resettextstyles()) {
246 cleanup = false;
247 _sir_selflog("error: failed to reset text styles!");
248 }
249 #endif
250
251 #if defined(__HAVE_ATOMIC_H__)
252 atomic_store(&_sir_magic, 0);
253 #else
254 _sir_magic = 0U;
255 #endif
256
257 _sir_reset_tls();
258
259 (void)memset(_cfg, 0, sizeof(sirconfig));
260 _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
261
262 _sir_selflog("cleaned up %s", (cleanup ? "successfully" : "with errors"));
263
264 SIR_ASSERT(cleanup);
265 return cleanup;
266 }
267
268 bool _sir_isinitialized(void) {
269 #if defined(__HAVE_ATOMIC_H__)
270 if (_SIR_MAGIC == atomic_load(&_sir_magic))
271 return true;
272 #else
273 if (_SIR_MAGIC == _sir_magic)
274 return true;
275 #endif
276 return false;
277 }
278
279 bool _sir_sanity(void) {
280 if (_sir_isinitialized())
281 return true;
282 return _sir_seterror(_SIR_E_NOTREADY);
283 }
284
285 bool _sir_init_sanity(const sirinit* si) {
286 if (!_sir_validptr(si))
287 return false;
288
289 bool levelcheck = true;
290 _sir_eqland(levelcheck, _sir_validlevels(si->d_stdout.levels));
291 _sir_eqland(levelcheck, _sir_validlevels(si->d_stderr.levels));
292
293 bool regcheck = true;
294 _sir_eqland(regcheck, SIRL_NONE == si->d_stdout.levels);
295 _sir_eqland(regcheck, SIRL_NONE == si->d_stderr.levels);
296
297 #if !defined(SIR_NO_SYSTEM_LOGGERS)
298 _sir_eqland(levelcheck, _sir_validlevels(si->d_syslog.levels));
299 _sir_eqland(regcheck, SIRL_NONE == si->d_syslog.levels);
300 #endif
301
302 if (regcheck)
303 _sir_selflog("warning: no level registrations set!");
304
305 bool optscheck = true;
306 _sir_eqland(optscheck, _sir_validopts(si->d_stdout.opts));
307 _sir_eqland(optscheck, _sir_validopts(si->d_stderr.opts));
308
309 #if !defined(SIR_NO_SYSTEM_LOGGERS)
310 _sir_eqland(optscheck, _sir_validopts(si->d_syslog.opts));
311 #endif
312
313 return levelcheck && optscheck;
314 }
315
316 void _sir_reset_tls(void) {
317 _sir_resetstr(_sir_tid);
318 (void)memset(&_sir_last_thrd_chk, 0, sizeof(sir_time));
319 _sir_last_timestamp = 0;
320 _sir_reset_tls_error();
321 }
322
323 static
324 bool _sir_updatelevels(const char* name, sir_levels* old, const sir_levels* new) {
325 bool retval = _sir_validstr(name) && _sir_validptr(old) && _sir_validptr(new);
326 if (retval) {
327 if (*old != *new) {
328 _sir_selflog("updating %s levels from %04"PRIx16" to %04"PRIx16, name, *old, *new);
329 *old = *new;
330 } else {
331 _sir_selflog("skipped superfluous update of %s levels: %04"PRIx16, name, *old);
332 }
333 }
334 return retval;
335 }
336
337 static
338 bool _sir_updateopts(const char* name, sir_options* old, const sir_options* new) {
339 bool retval = _sir_validstr(name) && _sir_validptr(old) && _sir_validptr(new);
340 if (retval) {
341 if (*old != *new) {
342 _sir_selflog("updating %s options from %08"PRIx32" to %08"PRIx32, name, *old, *new);
343 *old = *new;
344 } else {
345 _sir_selflog("skipped superfluous update of %s options: %08"PRIx32, name, *old);
346 }
347 }
348 return retval;
349 }
350
351 bool _sir_stdoutlevels(sirinit* si, const sir_update_config_data* data) {
352 return _sir_updatelevels(SIR_DESTNAME_STDOUT, &si->d_stdout.levels, data->levels);
353 }
354
355 bool _sir_stdoutopts(sirinit* si, const sir_update_config_data* data) {
356 return _sir_updateopts(SIR_DESTNAME_STDOUT, &si->d_stdout.opts, data->opts);
357 }
358
359 bool _sir_stderrlevels(sirinit* si, const sir_update_config_data* data) {
360 return _sir_updatelevels(SIR_DESTNAME_STDERR, &si->d_stderr.levels, data->levels);
361 }
362
363 bool _sir_stderropts(sirinit* si, const sir_update_config_data* data) {
364 return _sir_updateopts(SIR_DESTNAME_STDERR, &si->d_stderr.opts, data->opts);
365 }
366
367 bool _sir_sysloglevels(sirinit* si, const sir_update_config_data* data) {
368 bool updated = _sir_updatelevels(SIR_DESTNAME_SYSLOG, &si->d_syslog.levels, data->levels);
369 if (updated) {
370 _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_LEVELS);
371 updated = _sir_syslog_updated(si, data);
372 _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_LEVELS);
373 }
374 return updated;
375 }
376
377 bool _sir_syslogopts(sirinit* si, const sir_update_config_data* data) {
378 bool updated = _sir_updateopts(SIR_DESTNAME_SYSLOG, &si->d_syslog.opts, data->opts);
379 if (updated) {
380 _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_OPTIONS);
381 updated = _sir_syslog_updated(si, data);
382 _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_OPTIONS);
383 }
384 return updated;
385 }
386
387 bool _sir_syslogid(sirinit* si, const sir_update_config_data* data) {
388 bool retval = _sir_validptr(si) && _sir_validptr(data);
389
390 if (retval) {
391 bool cur_ok = _sir_validstrnofail(si->d_syslog.identity);
392 if (!cur_ok || 0 != strncmp(si->d_syslog.identity, data->sl_identity, SIR_MAX_SYSLOG_ID)) {
393 _sir_selflog("updating %s identity from '%s' to '%s'", SIR_DESTNAME_SYSLOG,
394 si->d_syslog.identity, data->sl_identity);
395 (void)_sir_strncpy(si->d_syslog.identity, SIR_MAX_SYSLOG_ID, data->sl_identity,
396 strnlen(data->sl_identity, SIR_MAX_SYSLOG_ID));
397 _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_IDENTITY);
398 retval = _sir_syslog_updated(si, data);
399 _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_IDENTITY);
400 } else {
401 _sir_selflog("skipped superfluous update of %s identity: '%s'", SIR_DESTNAME_SYSLOG,
402 si->d_syslog.identity);
403 }
404 }
405
406 return retval;
407 }
408
409 bool _sir_syslogcat(sirinit* si, const sir_update_config_data* data) {
410 bool retval = _sir_validptr(si) && _sir_validptr(data);
411
412 if (retval) {
413 bool cur_ok = _sir_validstrnofail(si->d_syslog.category);
414 if (!cur_ok || 0 != strncmp(si->d_syslog.category, data->sl_category, SIR_MAX_SYSLOG_CAT)) {
415 _sir_selflog("updating %s category from '%s' to '%s'", SIR_DESTNAME_SYSLOG,
416 si->d_syslog.category, data->sl_category);
417 (void)_sir_strncpy(si->d_syslog.category, SIR_MAX_SYSLOG_CAT, data->sl_category,
418 strnlen(data->sl_category, SIR_MAX_SYSLOG_CAT));
419 _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_CATEGORY);
420 retval = _sir_syslog_updated(si, data);
421 _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_CATEGORY);
422 } else {
423 _sir_selflog("skipped superfluous update of %s category: '%s'", SIR_DESTNAME_SYSLOG,
424 si->d_syslog.identity);
425 }
426 }
427
428 return retval;
429 }
430
431 bool _sir_writeinit(const sir_update_config_data* data, sirinit_update update) {
432 (void)_sir_seterror(_SIR_E_NOERROR);
433
434 if (!_sir_sanity() || !_sir_validupdatedata(data) || !_sir_validfnptr(update))
435 return false;
436
437 _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
438
439 bool updated = update(&_cfg->si, data);
440 if (!updated)
441 _sir_selflog("error: update routine failed!");
442
443 _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
444 return updated;
445 }
446
447 void* _sir_locksection(sir_mutex_id mid) {
448 sir_mutex* m = NULL;
449 void* sec = NULL;
450
451 bool enter = _sir_mapmutexid(mid, &m, &sec) && _sir_mutexlock(m);
452 SIR_ASSERT(enter);
453
454 return enter ? sec : NULL;
455 }
456
457 void _sir_unlocksection(sir_mutex_id mid) {
458 sir_mutex* m = NULL;
459 void* sec = NULL;
460
461 bool leave = _sir_mapmutexid(mid, &m, &sec) && _sir_mutexunlock(m);
462 SIR_ASSERT_UNUSED(leave, leave);
463 }
464
465 bool _sir_mapmutexid(sir_mutex_id mid, sir_mutex** m, void** section) {
466 sir_mutex* tmpm;
467 void* tmpsec;
468
469 switch (mid) {
470 case SIRMI_CONFIG:
471 tmpm = &cfg_mutex;
472 tmpsec = &_sir_cfg;
473 break;
474 case SIRMI_FILECACHE:
475 tmpm = &fc_mutex;
476 tmpsec = &_sir_fc;
477 break;
478 case SIRMI_PLUGINCACHE:
479 tmpm = &pc_mutex;
480 tmpsec = &_sir_pc;
481 break;
482 #if !defined(SIR_NO_TEXT_STYLING)
483 case SIRMI_TEXTSTYLE:
484 tmpm = &ts_mutex;
485 tmpsec = &sir_text_style_section;
486 break;
487 #endif
488 default:
489 #if !defined(SIR_NO_TEXT_STYLING)
490 SIR_ASSERT(false);
491 #endif
492 tmpm = NULL;
493 tmpsec = NULL;
494 break;
495 }
496
497 *m = tmpm;
498
499 if (section)
500 *section = tmpsec;
501
502 return *m != NULL && (!section || *section != NULL);
503 }
504
505 #if !defined(__WIN__)
506 void _sir_init_static_once(void) {
507 (void)_sir_init_common_static();
508 }
509 #else
510 BOOL CALLBACK _sir_init_static_once(PINIT_ONCE ponce, PVOID param, PVOID* ctx) {
511 SIR_UNUSED(ponce);
512 SIR_UNUSED(param);
513 SIR_UNUSED(ctx);
514 return _sir_init_common_static() ? TRUE : FALSE;
515 }
516 #endif
517
518 bool _sir_init_common_static(void) {
519 #if defined(__HAVE_ATOMIC_H__)
520 atomic_init(&_sir_magic, 0);
521 #endif
522
523 #if defined(__WIN__)
524 (void)QueryPerformanceFrequency(&_sir_perfcntr_freq);
525 #endif
526
527 bool created = _sir_mutexcreate(&cfg_mutex);
528 SIR_ASSERT(created);
529
530 _sir_eqland(created, _sir_mutexcreate(&fc_mutex));
531 SIR_ASSERT(created);
532
533 _sir_eqland(created, _sir_mutexcreate(&pc_mutex));
534 SIR_ASSERT(created);
535
536 #if !defined(SIR_NO_TEXT_STYLING)
537 _sir_eqland(created, _sir_mutexcreate(&ts_mutex));
538 SIR_ASSERT(created);
539 #endif
540
541 return created;
542 }
543
544 bool _sir_once(sir_once* once, sir_once_fn func) {
545 #if !defined(__WIN__)
546 int ret = pthread_once(once, func);
547 return 0 == ret ? true : _sir_handleerr(ret);
548 #else
549 return (FALSE != InitOnceExecuteOnce(once, func, NULL, NULL)) ? true
550 : _sir_handlewin32err(GetLastError());
551 #endif
552 }
553
554 PRINTF_FORMAT_ATTR(2, 0)
555 bool _sir_logv(sir_level level, PRINTF_FORMAT const char* format, va_list args) {
556 if (!_sir_sanity() || !_sir_validlevel(level) || !_sir_validstr(format))
557 return false;
558
559 (void)_sir_seterror(_SIR_E_NOERROR);
560
561 _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
562
563 sirbuf buf = {0};
564
565
566 time_t now_sec = -1;
567 if (-1 != time(&now_sec) &&
568 (now_sec - _cfg->state.last_hname_chk) > SIR_HNAME_CHK_INTERVAL) {
569 _sir_selflog("updating hostname...");
570 if (!_sir_gethostname(_cfg->state.hostname)) {
571 _sir_selflog("error: failed to get hostname!");
572 } else {
573 _cfg->state.last_hname_chk = now_sec;
574 _sir_selflog("hostname: '%s'", _cfg->state.hostname);
575 }
576 }
577
578
579 long now_msec = 0L;
580 bool gettime = _sir_clock_gettime(SIR_WALLCLOCK, &now_sec, &now_msec);
581 SIR_ASSERT_UNUSED(gettime, gettime);
582
583
584 _sir_snprintf_trunc(buf.msec, SIR_MAXMSEC, SIR_MSECFORMAT, now_msec);
585
586
587 if (now_sec > _sir_last_timestamp || !*_cfg->state.timestamp) {
588 _sir_last_timestamp = now_sec;
589 bool fmt = _sir_formattime(now_sec, _cfg->state.timestamp, SIR_TIMEFORMAT);
590 SIR_ASSERT_UNUSED(fmt, fmt);
591 }
592
593
594 sir_time thrd_chk;
595 double msec_since_thrd_chk = _sir_msec_since(&_sir_last_thrd_chk, &thrd_chk);
596
597
598 if (msec_since_thrd_chk > SIR_THRD_CHK_INTERVAL) {
599 _sir_last_thrd_chk = thrd_chk;
600
601 pid_t tid = _sir_gettid();
602 bool resolved_tid = false;
603
604
605 resolved_tid = _sir_getthreadname(_sir_tid);
606
607
608 if (!resolved_tid && tid == _cfg->state.pid) {
609
610 _sir_resetstr(_sir_tid);
611 resolved_tid = true;
612 }
613
614
615 if (!resolved_tid)
616 _sir_snprintf_trunc(_sir_tid, SIR_MAXPID, SIR_TIDFORMAT,
617 PID_CAST tid);
618 }
619
620 sirconfig cfg;
621 (void)memcpy(&cfg, _cfg, sizeof(sirconfig));
622 _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
623
624 buf.timestamp = cfg.state.timestamp;
625 buf.hostname = cfg.state.hostname;
626 buf.pid = cfg.state.pidbuf;
627 buf.name = cfg.si.name;
628
629 #if !defined(SIR_NO_TEXT_STYLING)
630 const char* style_str = _sir_gettextstyle(level);
631
632 SIR_ASSERT(NULL != style_str);
633 if (NULL != style_str)
634 (void)_sir_strncpy(buf.style, SIR_MAXSTYLE, style_str,
635 strnlen(style_str, SIR_MAXSTYLE));
636 #endif
637
638 buf.level = _sir_formattedlevelstr(level);
639
640 if (_sir_validstrnofail(_sir_tid))
641 (void)_sir_strncpy(buf.tid, SIR_MAXPID, _sir_tid,
642 strnlen(_sir_tid, SIR_MAXPID));
643
644 (void)vsnprintf(buf.message, SIR_MAXMESSAGE, format, args);
645
646 if (!_sir_validstrnofail(buf.message))
647 return _sir_seterror(_SIR_E_INTERNAL);
648
649 bool match = false;
650 bool exit_early = false;
651 bool update_last_props = true;
652 uint64_t hash = 0ULL;
653
654 if (cfg.state.last.level == level &&
655 cfg.state.last.prefix[0] == buf.message[0] &&
656 cfg.state.last.prefix[1] == buf.message[1]) {
657 hash = FNV64_1a(buf.message);
658 match = cfg.state.last.hash == hash;
659 }
660
661 if (match) {
662 cfg.state.last.counter++;
663
664 if (cfg.state.last.counter >= cfg.state.last.threshold - 2) {
665 size_t old_threshold = cfg.state.last.threshold;
666
667 update_last_props = false;
668 cfg.state.last.threshold *= SIR_SQUELCH_BACKOFF_FACTOR;
669 cfg.state.last.squelch = true;
670
671 _sir_selflog("hit squelch threshold of %zu; setting new threshold"
672 " to %zu (factor: %d)", old_threshold,
673 cfg.state.last.threshold, SIR_SQUELCH_BACKOFF_FACTOR);
674
675 (void)snprintf(buf.message, SIR_MAXMESSAGE, SIR_SQUELCH_MSG_FORMAT, old_threshold);
676 } else if (cfg.state.last.squelch) {
677 exit_early = true;
678 }
679 } else {
680 cfg.state.last.squelch = false;
681 cfg.state.last.counter = 0;
682 cfg.state.last.threshold = SIR_SQUELCH_THRESHOLD;
683
684 }
685
686 _cfg = _sir_locksection(SIRMI_CONFIG);
687 if (!_cfg)
688 return _sir_seterror(_SIR_E_INTERNAL);
689
690 _cfg->state.last.squelch = cfg.state.last.squelch;
691
692 if (update_last_props) {
693 _cfg->state.last.level = level;
694 _cfg->state.last.hash = hash;
695 _cfg->state.last.prefix[0] = buf.message[0];
696 _cfg->state.last.prefix[1] = buf.message[1];
697 }
698
699 _cfg->state.last.counter = cfg.state.last.counter;
700 _cfg->state.last.threshold = cfg.state.last.threshold;
701
702 _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
703
704 if (exit_early)
705 return false;
706
707 bool dispatched = _sir_dispatch(&cfg.si, level, &buf);
708 return update_last_props ? dispatched : false;
709 }
710
711 bool _sir_dispatch(const sirinit* si, sir_level level, sirbuf* buf) {
712 bool retval = true;
713 size_t dispatched = 0;
714 size_t wanted = 0;
715
716 #if !defined(SIR_NO_TEXT_STYLING)
717 static const bool styling = true;
718 #else
719 static const bool styling = false;
720 #endif
721
722 if (_sir_bittest(si->d_stdout.levels, level)) {
723 const char* writef = _sir_format(styling, si->d_stdout.opts, buf);
724 bool wrote = _sir_validstrnofail(writef) &&
725 _sir_write_stdout(writef, buf->output_len);
726 _sir_eqland(retval, wrote);
727
728 if (wrote)
729 dispatched++;
730 wanted++;
731 }
732
733 if (_sir_bittest(si->d_stderr.levels, level)) {
734 const char* writef = _sir_format(styling, si->d_stderr.opts, buf);
735 bool wrote = _sir_validstrnofail(writef) &&
736 _sir_write_stderr(writef, buf->output_len);
737 _sir_eqland(retval, wrote);
738
739 if (wrote)
740 dispatched++;
741 wanted++;
742 }
743
744 #if !defined(SIR_NO_SYSTEM_LOGGERS)
745 if (_sir_bittest(si->d_syslog.levels, level)) {
746 if (_sir_syslog_write(level, buf, &si->d_syslog))
747 dispatched++;
748 wanted++;
749 }
750 #endif
751
752 _SIR_LOCK_SECTION(const sirfcache, sfc, SIRMI_FILECACHE, false);
753 size_t fdispatched = 0;
754 size_t fwanted = 0;
755 _sir_eqland(retval, _sir_fcache_dispatch(sfc, level, buf, &fdispatched, &fwanted));
756 _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
757
758 dispatched += fdispatched;
759 wanted += fwanted;
760
761 #if !defined(SIR_NO_PLUGINS)
762 _SIR_LOCK_SECTION(const sir_plugincache, spc, SIRMI_PLUGINCACHE, false);
763 size_t pdispatched = 0;
764 size_t pwanted = 0;
765 _sir_eqland(retval, _sir_plugin_cache_dispatch(spc, level, buf, &pdispatched, &pwanted));
766 _SIR_UNLOCK_SECTION(SIRMI_PLUGINCACHE);
767
768 dispatched += pdispatched;
769 wanted += pwanted;
770 #endif
771
772 if (0 == wanted) {
773 _sir_selflog("error: no destinations registered for level %04"PRIx16, level);
774 return _sir_seterror(_SIR_E_NODEST);
775 }
776
777 return retval && (dispatched == wanted);
778 }
779
780 const char* _sir_format(bool styling, sir_options opts, sirbuf* buf) {
781 if (_sir_validptr(buf)) {
782 bool first = true;
783
784 _sir_resetstr(buf->output);
785
786 if (styling)
787 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->style, SIR_MAXSTYLE);
788
789 if (!_sir_bittest(opts, SIRO_NOTIME)) {
790 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->timestamp, SIR_MAXTIME);
791 first = false;
792
793 #if defined(SIR_MSEC_TIMER)
794 if (!_sir_bittest(opts, SIRO_NOMSEC))
795 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->msec, SIR_MAXMSEC);
796 #endif
797 }
798
799 if (!_sir_bittest(opts, SIRO_NOHOST) && _sir_validstrnofail(buf->hostname)) {
800 if (!first)
801 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
802 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->hostname, SIR_MAXHOST);
803 first = false;
804 }
805
806 if (!_sir_bittest(opts, SIRO_NOLEVEL)) {
807 if (!first)
808 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
809 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->level, SIR_MAXLEVEL);
810 first = false;
811 }
812
813 bool name = false;
814 if (!_sir_bittest(opts, SIRO_NONAME) && _sir_validstrnofail(buf->name)) {
815 if (!first)
816 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
817 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->name, SIR_MAXNAME);
818 first = false;
819 name = true;
820 }
821
822 bool wantpid = !_sir_bittest(opts, SIRO_NOPID) && _sir_validstrnofail(buf->pid);
823 bool wanttid = !_sir_bittest(opts, SIRO_NOTID) && _sir_validstrnofail(buf->tid);
824
825 if (wantpid || wanttid) {
826 if (name)
827 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDPREFIX, 1);
828 else if (!first)
829 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
830
831 if (wantpid)
832 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->pid, SIR_MAXPID);
833
834 if (wanttid) {
835 if (wantpid)
836 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDSEPARATOR, 1);
837 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->tid, SIR_MAXPID);
838 }
839
840 if (name)
841 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDSUFFIX, 1);
842
843 first = false;
844 }
845
846 if (!first)
847 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, ": ", 2);
848
849 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, buf->message, SIR_MAXMESSAGE);
850
851 if (styling)
852 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_ESC_RST, SIR_MAXSTYLE);
853
854 #if defined(SIR_USE_EOL_CRLF)
855 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_EOL, 2);
856 #else
857 (void)_sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_EOL, 1);
858 #endif
859
860 buf->output_len = strnlen(buf->output, SIR_MAXOUTPUT);
861
862 return buf->output;
863 }
864
865 return NULL;
866 }
867
868 bool _sir_syslog_init(const char* name, sir_syslog_dest* ctx) {
869 #if !defined(SIR_NO_SYSTEM_LOGGERS)
870 if (!_sir_validptr(name) || !_sir_validptr(ctx))
871 return false;
872
873
874 if (!_sir_validstrnofail(ctx->identity)) {
875 _sir_selflog("ctx->identity is no good; trying name");
876 if (_sir_validstrnofail(name)) {
877 _sir_selflog("using name");
878 (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, name, strnlen(name, SIR_MAX_SYSLOG_ID));
879 } else {
880 _sir_selflog("name is no good; trying filename");
881 char* appbasename = _sir_getappbasename();
882 if (_sir_validstrnofail(appbasename)) {
883 _sir_selflog("filename is good: %s", appbasename);
884 (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, appbasename,
885 strnlen(appbasename, SIR_MAX_SYSLOG_ID));
886 } else {
887 _sir_selflog("filename no good; using fallback");
888 (void)_sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, SIR_FALLBACK_SYSLOG_ID,
889 strnlen(SIR_FALLBACK_SYSLOG_ID, SIR_MAX_SYSLOG_ID));
890 }
891 _sir_safefree(&appbasename);
892 }
893 } else {
894 _sir_selflog("already have identity");
895 }
896
897
898 if (!_sir_validstrnofail(ctx->category)) {
899 _sir_selflog("category not set; using fallback");
900 (void)_sir_strncpy(ctx->category, SIR_MAX_SYSLOG_CAT, SIR_FALLBACK_SYSLOG_CAT,
901 strnlen(SIR_FALLBACK_SYSLOG_CAT, SIR_MAX_SYSLOG_CAT));
902 } else {
903 _sir_selflog("already have category");
904 }
905
906 _sir_setbitshigh(&ctx->_state.mask, SIRSL_IS_INIT);
907 _sir_selflog("resolved (identity: '%s', category: '%s')", ctx->identity, ctx->category);
908
909 return _sir_syslog_open(ctx);
910 #else
911 SIR_UNUSED(name);
912 SIR_UNUSED(ctx);
913 return false;
914 #endif
915 }
916
917 bool _sir_syslog_open(sir_syslog_dest* ctx) {
918 #if !defined(SIR_NO_SYSTEM_LOGGERS)
919 if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_INIT)) {
920 _sir_selflog("not initialized; ignoring");
921 return _sir_seterror(_SIR_E_INVALID);
922 }
923
924 if (_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
925 _sir_selflog("log already open; ignoring");
926 return true;
927 }
928
929 _sir_selflog("opening log (levels: %04"PRIx16", options: %08"PRIx32")", ctx->levels,
930 ctx->opts);
931
932 # if defined(SIR_OS_LOG_ENABLED)
933 ctx->_state.logger = (void*)os_log_create(ctx->identity, ctx->category);
934 _sir_selflog("opened os_log ('%s', '%s')", ctx->identity, ctx->category);
935 # elif defined(SIR_SYSLOG_ENABLED)
936 int logopt = LOG_NDELAY | (_sir_bittest(ctx->opts, SIRO_NOPID) ? 0 : LOG_PID);
937 int facility = LOG_USER;
938
939 openlog(ctx->identity, logopt, facility);
940 _sir_selflog("opened syslog('%s', %x, %x)", ctx->identity, logopt, facility);
941 # elif defined(SIR_EVENTLOG_ENABLED)
942 DWORD reg = EventRegister(&SIR_EVENTLOG_GUID, NULL, NULL,
943 (PREGHANDLE)&ctx->_state.logger);
944 if (ERROR_SUCCESS == reg) {
945 _sir_selflog("opened eventlog('%s')", ctx->identity);
946 } else {
947
948 _sir_selflog("failed to open eventlog! error: %lu", reg);
949 (void)_sir_handlewin32err(reg);
950 }
951 # endif
952
953 _sir_setbitshigh(&ctx->_state.mask, SIRSL_IS_OPEN);
954 return true;
955 #else
956 SIR_UNUSED(ctx);
957 return false;
958 #endif
959 }
960
961 bool _sir_syslog_write(sir_level level, const sirbuf* buf, const sir_syslog_dest* ctx) {
962 #if !defined(SIR_NO_SYSTEM_LOGGERS)
963 if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_INIT)) {
964 _sir_selflog("not initialized; ignoring");
965 return _sir_seterror(_SIR_E_INVALID);
966 }
967
968 if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
969 _sir_selflog("log not open; ignoring");
970 return _sir_seterror(_SIR_E_INVALID);
971 }
972
973 # if defined(SIR_OS_LOG_ENABLED)
974 if (SIRL_DEBUG == level)
975 os_log_debug((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
976 else if (SIRL_INFO == level || SIRL_NOTICE == level)
977 os_log_info((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
978 else if (SIRL_WARN == level || SIRL_ERROR == level)
979 os_log_error((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
980 else if (SIRL_CRIT == level || SIRL_ALERT == level || SIRL_EMERG == level)
981 os_log_fault((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
982
983 return true;
984 # elif defined(SIR_SYSLOG_ENABLED)
985 int syslog_level;
986 switch (level) {
987 case SIRL_DEBUG: syslog_level = LOG_DEBUG; break;
988 case SIRL_INFO: syslog_level = LOG_INFO; break;
989 case SIRL_NOTICE: syslog_level = LOG_NOTICE; break;
990 case SIRL_WARN: syslog_level = LOG_WARNING; break;
991 case SIRL_ERROR: syslog_level = LOG_ERR; break;
992 case SIRL_CRIT: syslog_level = LOG_CRIT; break;
993 case SIRL_ALERT: syslog_level = LOG_ALERT; break;
994 case SIRL_EMERG: syslog_level = LOG_EMERG; break;
995
996 default:
997 SIR_ASSERT(false);
998 syslog_level = LOG_DEBUG;
999
1000 }
1001
1002 syslog(syslog_level, "%s", buf->message);
1003 return true;
1004 # elif defined(SIR_EVENTLOG_ENABLED)
1005 const EVENT_DESCRIPTOR* edesc = NULL;
1006 if (SIRL_DEBUG == level)
1007 edesc = &SIR_EVT_DEBUG;
1008 else if (SIRL_INFO == level || SIRL_NOTICE == level)
1009 edesc = &SIR_EVT_INFO;
1010 else if (SIRL_WARN == level)
1011 edesc = &SIR_EVT_WARNING;
1012 else if (SIRL_ERROR == level)
1013 edesc = &SIR_EVT_ERROR;
1014 else if (SIRL_CRIT == level || SIRL_ALERT == level || SIRL_EMERG == level)
1015 edesc = &SIR_EVT_CRITICAL;
1016
1017 SIR_ASSERT(NULL != edesc);
1018 if (NULL == edesc)
1019 return _sir_seterror(_SIR_E_INTERNAL);
1020
1021 # if defined(__HAVE_STDC_SECURE_OR_EXT1__)
1022 size_t msg_len = strnlen_s(buf->message, SIR_MAXMESSAGE) + 1;
1023 # else
1024 size_t msg_len = strnlen(buf->message, SIR_MAXMESSAGE) + 1;
1025 # endif
1026 int wlen = MultiByteToWideChar(CP_UTF8, 0UL, buf->message, (int)msg_len, NULL, 0);
1027 if (wlen <= 0)
1028 return _sir_handlewin32err(GetLastError());
1029
1030 DWORD write = 1UL;
1031 wchar_t* wmsg = calloc(wlen, sizeof(wchar_t));
1032 if (NULL != wmsg) {
1033 int conv = MultiByteToWideChar(CP_UTF8, 0UL, buf->message, (int)msg_len, wmsg, wlen);
1034 if (conv > 0) {
1035 EVENT_DATA_DESCRIPTOR eddesc = {0};
1036 EventDataDescCreate(&eddesc, wmsg, (ULONG)(wlen * sizeof(wchar_t)));
1037
1038 write = EventWrite((REGHANDLE)ctx->_state.logger, edesc, 1UL, &eddesc);
1039 if (ERROR_SUCCESS != write) {
1040 _sir_selflog("failed to write eventlog! error: %lu", write);
1041 (void)_sir_handlewin32err(write);
1042 }
1043 }
1044 _sir_safefree(&wmsg);
1045 }
1046
1047 return ERROR_SUCCESS == write;
1048 # else
1049 SIR_UNUSED(level);
1050 SIR_UNUSED(buf);
1051 SIR_UNUSED(ctx);
1052 return false;
1053 # endif
1054 #else
1055 SIR_UNUSED(level);
1056 SIR_UNUSED(buf);
1057 SIR_UNUSED(ctx);
1058 return false;
1059 #endif
1060 }
1061
1062 bool _sir_syslog_updated(sirinit* si, const sir_update_config_data* data) {
1063 #if !defined(SIR_NO_SYSTEM_LOGGERS)
1064 if (!_sir_validptr(si) || !_sir_validptr(data))
1065 return false;
1066
1067 if (_sir_bittest(si->d_syslog._state.mask, SIRSL_UPDATED)) {
1068 bool levels = _sir_bittest(si->d_syslog._state.mask, SIRSL_LEVELS);
1069 bool options = _sir_bittest(si->d_syslog._state.mask, SIRSL_OPTIONS);
1070 bool category = _sir_bittest(si->d_syslog._state.mask, SIRSL_CATEGORY);
1071 bool identity = _sir_bittest(si->d_syslog._state.mask, SIRSL_IDENTITY);
1072 bool is_init = _sir_bittest(si->d_syslog._state.mask, SIRSL_IS_INIT);
1073 bool is_open = _sir_bittest(si->d_syslog._state.mask, SIRSL_IS_OPEN);
1074
1075 _sir_selflog("config update: (levels: %u, options: %u, category: %u,"
1076 " identity: %u, is_init: %u, is_open: %u)",
1077 levels, options, category, identity, is_init, is_open);
1078
1079 bool must_init = false;
1080 # if defined(SIR_OS_LOG_ENABLED)
1081
1082
1083 must_init = (!is_init || !is_open) || (identity || category);
1084 # elif defined(SIR_SYSLOG_ENABLED)
1085
1086
1087 must_init = (!is_init || !is_open) || (identity || options);
1088 # elif defined(SIR_EVENTLOG_ENABLED)
1089
1090
1091 must_init = (!is_init || !is_open) || identity;
1092 # endif
1093 bool init = true;
1094 if (must_init) {
1095 if (is_open)
1096 init = _sir_syslog_close(&si->d_syslog);
1097
1098 _sir_selflog("re-init...");
1099 _sir_eqland(init, _sir_syslog_init(si->name, &si->d_syslog));
1100 _sir_selflog("re-init %s", init ? "succeeded" : "failed");
1101 } else {
1102 _sir_selflog("no re-init necessary");
1103 }
1104
1105 return init;
1106 }
1107
1108 return false;
1109 #else
1110 SIR_UNUSED(si);
1111 SIR_UNUSED(data);
1112 return false;
1113 #endif
1114 }
1115
1116 bool _sir_syslog_close(sir_syslog_dest* ctx) {
1117 #if !defined(SIR_NO_SYSTEM_LOGGERS)
1118 if (!_sir_validptr(ctx))
1119 return false;
1120
1121 if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
1122 _sir_selflog("log not open; ignoring");
1123 return true;
1124 }
1125
1126 # if defined(SIR_OS_LOG_ENABLED)
1127
1128
1129
1130 _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
1131 _sir_selflog("log closure not necessary");
1132 return true;
1133 # elif defined(SIR_SYSLOG_ENABLED)
1134 closelog();
1135 _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
1136 _sir_selflog("closed log");
1137 return true;
1138 # elif defined(SIR_EVENTLOG_ENABLED)
1139 ULONG unreg = EventUnregister((REGHANDLE)ctx->_state.logger);
1140 _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
1141 if (ERROR_SUCCESS == unreg)
1142 _sir_selflog("closed log");
1143 else
1144 _sir_selflog("error: failed to close log");
1145
1146 return ERROR_SUCCESS == unreg;
1147 # else
1148 SIR_UNUSED(ctx);
1149 return false;
1150 # endif
1151 #else
1152 SIR_UNUSED(ctx);
1153 return false;
1154 #endif
1155 }
1156
1157 void _sir_syslog_reset(sir_syslog_dest* ctx) {
1158 #if !defined(SIR_NO_SYSTEM_LOGGERS)
1159 if (_sir_validptr(ctx)) {
1160 uint32_t old = ctx->_state.mask;
1161 ctx->_state.mask = 0U;
1162 ctx->_state.logger = NULL;
1163 _sir_selflog("state reset; mask was %08"PRIx32, old);
1164 }
1165 #else
1166 SIR_UNUSED(ctx);
1167 #endif
1168 }
1169
1170 const char* _sir_formattedlevelstr(sir_level level) {
1171 static const size_t low = 0;
1172 static const size_t high = SIR_NUMLEVELS - 1;
1173
1174 const char* retval = SIR_UNKNOWN;
1175
1176 _SIR_DECLARE_BIN_SEARCH(low, high);
1177 _SIR_BEGIN_BIN_SEARCH()
1178
1179 if (sir_level_to_str_map[_mid].level == level) {
1180 retval = sir_level_to_str_map[_mid].fmt;
1181 break;
1182 }
1183
1184 _SIR_ITERATE_BIN_SEARCH((sir_level_to_str_map[_mid].level < level ? 1 : -1));
1185 _SIR_END_BIN_SEARCH();
1186
1187 return retval;
1188 }
1189
1190 bool _sir_clock_gettime(int clock, time_t* tbuf, long* msecbuf) {
1191 if (tbuf) {
1192 #if defined(SIR_MSEC_POSIX)
1193 struct timespec ts = {0};
1194 int ret = clock_gettime(clock, &ts);
1195 SIR_ASSERT(0 == ret);
1196
1197 if (0 == ret) {
1198 *tbuf = ts.tv_sec;
1199 if (msecbuf)
1200 *msecbuf = ts.tv_nsec / 1000000L;
1201 } else {
1202 if (msecbuf)
1203 *msecbuf = 0L;
1204 return _sir_handleerr(errno);
1205 }
1206 #elif defined(SIR_MSEC_WIN32)
1207 SIR_UNUSED(clock);
1208 static const ULONGLONG uepoch = (ULONGLONG)116444736e9;
1209
1210 FILETIME ftutc = {0};
1211 GetSystemTimePreciseAsFileTime(&ftutc);
1212
1213 ULARGE_INTEGER ftnow = {0};
1214 ftnow.HighPart = ftutc.dwHighDateTime;
1215 ftnow.LowPart = ftutc.dwLowDateTime;
1216 ftnow.QuadPart = (ULONGLONG)((ftnow.QuadPart - uepoch) / 10000000ULL);
1217
1218 *tbuf = (time_t)ftnow.QuadPart;
1219
1220 SYSTEMTIME st = {0};
1221 if (FileTimeToSystemTime(&ftutc, &st)) {
1222 if (msecbuf)
1223 *msecbuf = (long)st.wMilliseconds;
1224 } else {
1225 if (msecbuf)
1226 *msecbuf = 0L;
1227 return _sir_handlewin32err(GetLastError());
1228 }
1229 #else
1230 SIR_UNUSED(clock);
1231 (void)time(tbuf);
1232 if (msecbuf)
1233 *msecbuf = 0L;
1234 #endif
1235 return true;
1236 }
1237 return false;
1238 }
1239
1240 double _sir_msec_since(const sir_time* when, sir_time* out) {
1241 if (!_sir_validptr(out))
1242 return 0.0;
1243 #if !defined(__WIN__)
1244 out->sec = 0;
1245 out->msec = 0L;
1246
1247 bool gettime = _sir_clock_gettime(SIR_INTERVALCLOCK, &out->sec, &out->msec);
1248 SIR_ASSERT(gettime);
1249
1250 if (!_sir_validptrnofail(when) || !gettime || (out->sec < when->sec ||
1251 (out->sec == when->sec && out->msec < when->msec)))
1252 return 0.0;
1253
1254 return ((((double)out->sec) * 1e3) + (double)out->msec) -
1255 ((((double)when->sec) * 1e3) + (double)when->msec);
1256 #else
1257 SIR_ASSERT(_sir_perfcntr_freq.QuadPart > 0LL);
1258
1259 if (_sir_perfcntr_freq.QuadPart <= 0LL)
1260 (void)QueryPerformanceFrequency(&_sir_perfcntr_freq);
1261
1262 (void)QueryPerformanceCounter(&out->counter);
1263
1264 if (!_sir_validptrnofail(when) || out->counter.QuadPart <= when->counter.QuadPart)
1265 return 0.0;
1266
1267 double msec_ratio = ((double)_sir_perfcntr_freq.QuadPart) / 1e3;
1268 return ((double)(out->counter.QuadPart - when->counter.QuadPart)) / msec_ratio;
1269 #endif
1270 }
1271
1272 pid_t _sir_getpid(void) {
1273 #if !defined(__WIN__)
1274 return getpid();
1275 #else
1276 return (pid_t)GetCurrentProcessId();
1277 #endif
1278 }
1279
1280 pid_t _sir_gettid(void) {
1281 pid_t tid = 0;
1282 #if defined(__MACOS__)
1283 uint64_t tid64 = 0ULL;
1284 int gettid = pthread_threadid_np(NULL, &tid64);
1285 if (0 != gettid)
1286 (void)_sir_handleerr(gettid);
1287 tid = (pid_t)tid64;
1288 #elif (defined(__BSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)) || \
1289 defined(__DragonFly_getthreadid__)
1290 tid = (pid_t)pthread_getthreadid_np();
1291 #elif defined(__OpenBSD__)
1292 tid = (pid_t)getthrid();
1293 #elif defined(__SOLARIS__) || defined(__NetBSD__) || defined(__HURD__) || \
1294 defined(__DragonFly__) || defined(__CYGWIN__) || defined(_AIX) || \
1295 defined(__EMSCRIPTEN__) || defined(__QNX__)
1296 # if defined(__CYGWIN__)
1297 tid = (pid_t)(uintptr_t)pthread_self();
1298 # else
1299 tid = (pid_t)pthread_self();
1300 # endif
1301 #elif defined(__HAIKU__)
1302 tid = get_pthread_thread_id(pthread_self());
1303 #elif defined(__linux__) || defined(__serenity__) || defined(__managarm__)
1304 # if (defined(__GLIBC__) && GLIBC_VERSION >= 23000) || defined(__serenity__) || \
1305 defined(__managarm__)
1306 tid = gettid();
1307 # else
1308 tid = syscall(SYS_gettid);
1309 # endif
1310 #elif defined(__WIN__)
1311 tid = (pid_t)GetCurrentThreadId();
1312 #else
1313 # error "unable to determine how to get a thread identifier"
1314 #endif
1315 return tid;
1316 }
1317
1318 bool _sir_getthreadname(char name[SIR_MAXPID]) {
1319 _sir_resetstr(name);
1320 #if defined(__MACOS__) || (defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_12_2__)) || \
1321 (defined(__linux__) && defined(__UCLIBC__) && defined(_GNU_SOURCE)) || \
1322 (defined(__GLIBC__) && GLIBC_VERSION >= 21200 && defined(_GNU_SOURCE)) || \
1323 (defined(__ANDROID__) && __ANDROID_API__ >= 26) || defined(SIR_PTHREAD_GETNAME_NP) || \
1324 defined(__serenity__) || (defined(__linux__) && !defined(__GLIBC__) && \
1325 defined(_GNU_SOURCE) && defined(__NEED_pthread_t)) || defined(__QNX__) || \
1326 defined(__managarm__)
1327 int ret = pthread_getname_np(pthread_self(), name, SIR_MAXPID);
1328 if (0 != ret)
1329 return _sir_handleerr(ret);
1330 # if defined(__HAIKU__)
1331 if (!(strncmp(name, "pthread func", SIR_MAXPID)))
1332 (void)snprintf(name, SIR_MAXPID, "%ld", (long)get_pthread_thread_id(pthread_self()));
1333 # endif
1334 return _sir_validstrnofail(name);
1335 #elif defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_11_3__)
1336 pthread_get_name_np(pthread_self(), name, SIR_MAXPID);
1337 return _sir_validstrnofail(name);
1338 #elif defined(__WIN__)
1339 wchar_t* wname = NULL;
1340 HRESULT hr = GetThreadDescription(GetCurrentThread(), &wname);
1341 if (FAILED(hr))
1342 return _sir_handlewin32err(GetLastError());
1343 bool success = true;
1344 # if defined(__HAVE_STDC_SECURE_OR_EXT1__)
1345 size_t wlen = wcsnlen_s(wname, SIR_MAXPID);
1346 # elif defined(__EMBARCADEROC__) && (__clang_major__ < 15)
1347 size_t wlen = wcslen(wname);
1348 # else
1349 size_t wlen = wcsnlen(wname, SIR_MAXPID);
1350 # endif
1351 if (wlen > 0) {
1352 if (!WideCharToMultiByte(CP_UTF8, 0UL, wname, (int)wlen, name,
1353 SIR_MAXPID, NULL, NULL)) {
1354 success = false;
1355 (void)_sir_handlewin32err(GetLastError());
1356 }
1357 }
1358 (void)LocalFree(wname);
1359 return success && _sir_validstrnofail(name);
1360 #else
1361 # if !defined(SUNLINT) && !defined(_AIX) && !defined(__HURD__)
1362 # pragma message("unable to determine how to get a thread name")
1363 # endif
1364 SIR_UNUSED(name);
1365 return false;
1366 #endif
1367 }
1368
1369 bool _sir_setthreadname(const char* name) {
1370 if (!_sir_validptr(name))
1371 return false;
1372 #if defined(__MACOS__)
1373 int ret = pthread_setname_np(name);
1374 return (0 != ret) ? _sir_handleerr(ret) : true;
1375 #elif defined(__HAIKU__)
1376 status_t ret = rename_thread(find_thread(NULL), name);
1377 return (B_OK != ret) ? _sir_handleerr((int)ret) : true;
1378 #elif defined(__NetBSD__)
1379 int ret = pthread_setname_np(pthread_self(), "%s", name);
1380 return (0 != ret) ? _sir_handleerr(ret) : true;
1381 #elif (defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_12_2__)) || \
1382 (defined(__linux__) && defined(__UCLIBC__) && defined(_GNU_SOURCE)) || \
1383 (defined(__GLIBC__) && GLIBC_VERSION >= 21200 && defined(_GNU_SOURCE)) || \
1384 defined(__QNXNTO__) || defined(__SOLARIS__) || defined(SIR_PTHREAD_GETNAME_NP) || \
1385 defined(__ANDROID__) && !defined(__OpenBSD__) || defined(__serenity__) || \
1386 (defined(__linux__) && !defined(__GLIBC__) && \
1387 defined(_GNU_SOURCE) && defined(__NEED_pthread_t)) || defined(__managarm__)
1388 int ret = pthread_setname_np(pthread_self(), name);
1389 return (0 != ret) ? _sir_handleerr(ret) : true;
1390 #elif defined(__OpenBSD__) || defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_11_3__)
1391 pthread_set_name_np(pthread_self(), name);
1392 return true;
1393 #elif defined(__WIN__)
1394 # if defined(__HAVE_STDC_SECURE_OR_EXT1__)
1395 size_t name_len = strnlen_s(name, SIR_MAXPID);
1396 # else
1397 size_t name_len = strnlen(name, SIR_MAXPID);
1398 # endif
1399 if (0 == name_len)
1400 name_len = 1;
1401
1402 wchar_t buf[SIR_MAXPID] = {0};
1403 if (!MultiByteToWideChar(CP_UTF8, 0UL, name, (int)name_len, buf, SIR_MAXPID))
1404 return _sir_handlewin32err(GetLastError());
1405
1406 HRESULT hr = SetThreadDescription(GetCurrentThread(), buf);
1407 return FAILED(hr) ? _sir_handlewin32err(hr) : true;
1408 #else
1409 # if !defined(SUNLINT) && !defined(_AIX)
1410 # pragma message("unable to determine how to set a thread name")
1411 # endif
1412 SIR_UNUSED(name);
1413 return false;
1414 #endif
1415 }
1416
1417 bool _sir_gethostname(char name[SIR_MAXHOST]) {
1418 #if !defined(__WIN__)
1419 int ret = gethostname(name, SIR_MAXHOST - 1);
1420 return 0 == ret ? true : _sir_handleerr(errno);
1421 #else
1422 WSADATA wsad = {0};
1423 int ret = WSAStartup(MAKEWORD(2, 2), &wsad);
1424 if (0 != ret)
1425 return _sir_handlewin32err(ret);
1426
1427 if (SOCKET_ERROR == gethostname(name, SIR_MAXHOST)) {
1428 int err = WSAGetLastError();
1429 WSACleanup();
1430 return _sir_handlewin32err(err);
1431 }
1432
1433 WSACleanup();
1434 return true;
1435 #endif
1436 }
1437
1438 long __sir_nprocs(bool test_mode) {
1439 long nprocs = 0;
1440
1441 #if defined(_AIX)
1442 nprocs = (long)_system_configuration.ncpus;
1443 _sir_selflog("AIX _system_configuration.ncpus reports %ld processor(s)", nprocs);
1444 #endif
1445
1446 #if defined(__WIN__)
1447 SYSTEM_INFO system_info;
1448 ZeroMemory(&system_info, sizeof(system_info));
1449 GetSystemInfo(&system_info);
1450 nprocs = (long)system_info.dwNumberOfProcessors;
1451 _sir_selflog("Windows GetSystemInfo() reports %ld processor(s)", nprocs);
1452 #endif
1453
1454 #if defined(__HAIKU__)
1455 system_info hinfo;
1456 get_system_info(&hinfo);
1457 nprocs = (long)hinfo.cpu_count;
1458 _sir_selflog("Haiku get_system_info() reports %ld processor(s)", nprocs);
1459 #endif
1460
1461 #if defined(SC_NPROCESSORS_ONLN)
1462 # define SIR_SC_NPROCESSORS SC_NPROCESSORS_ONLN
1463 #elif defined(_SC_NPROCESSORS_ONLN)
1464 # define SIR_SC_NPROCESSORS _SC_NPROCESSORS_ONLN
1465 #endif
1466 #if defined(SIR_SC_NPROCESSORS)
1467 long tprocs = sysconf(SIR_SC_NPROCESSORS);
1468 _sir_selflog("sysconf() reports %ld processor(s)", tprocs);
1469 if (tprocs > nprocs)
1470 nprocs = tprocs;
1471 #endif
1472
1473 #if defined(__linux__) && defined(CPU_COUNT) && !defined(__ANDROID__) && !defined(__UCLIBC__)
1474 long ctprocs;
1475 cpu_set_t p_aff;
1476 memset(&p_aff, 0, sizeof(p_aff));
1477 if (sched_getaffinity(0, sizeof(p_aff), &p_aff)) {
1478 ctprocs = 0;
1479 } else {
1480 ctprocs = CPU_COUNT(&p_aff);
1481 _sir_selflog("sched_getaffinity() reports %ld processor(s)", ctprocs);
1482 }
1483 if (ctprocs > nprocs)
1484 nprocs = ctprocs;
1485 #endif
1486
1487 #if defined(CTL_HW) && defined(HW_AVAILCPU)
1488 int ntprocs = 0;
1489 size_t sntprocs = sizeof(ntprocs);
1490 if (sysctl ((int[2]) {CTL_HW, HW_AVAILCPU}, 2, &ntprocs, &sntprocs, NULL, 0)) {
1491 ntprocs = 0;
1492 } else {
1493 _sir_selflog("sysctl(CTL_HW, HW_AVAILCPU) reports %d processor(s)", ntprocs);
1494 if (ntprocs > nprocs)
1495 nprocs = (long)ntprocs;
1496 }
1497 #elif defined(CTL_HW) && defined(HW_NCPU)
1498 int ntprocs = 0;
1499 size_t sntprocs = sizeof(ntprocs);
1500 if (sysctl ((int[2]) {CTL_HW, HW_NCPU}, 2, &ntprocs, &sntprocs, NULL, 0)) {
1501 ntprocs = 0;
1502 } else {
1503 _sir_selflog("sysctl(CTL_HW, HW_NCPU) reports %d processor(s)", ntprocs);
1504 if (ntprocs > nprocs)
1505 nprocs = (long)ntprocs;
1506 }
1507 #elif defined(CTL_HW) && defined(HW_NCPUFOUND)
1508 int ntprocs = 0;
1509 size_t sntprocs = sizeof(ntprocs);
1510 if (sysctl ((int[2]) {CTL_HW, HW_NCPUFOUND}, 2, &ntprocs, &sntprocs, NULL, 0)) {
1511 ntprocs = 0;
1512 } else {
1513 _sir_selflog("sysctl(CTL_HW, HW_NCPUFOUND) reports %d processor(s)", ntprocs);
1514 if (ntprocs > nprocs)
1515 nprocs = (long)ntprocs;
1516 }
1517 #endif
1518
1519 #if defined(__MACOS__)
1520 int antprocs = 0;
1521 size_t asntprocs = sizeof(antprocs);
1522 if (sysctlbyname("hw.ncpu", &antprocs, &asntprocs, NULL, 0)) {
1523 antprocs = 0;
1524 } else {
1525 _sir_selflog("sysctlbyname(hw.ncpu) reports %d processor(s)", antprocs);
1526 if (antprocs > nprocs)
1527 nprocs = (long)antprocs;
1528 }
1529 #endif
1530
1531 #if defined(__QNX__) || defined(__QNXNTO__)
1532 long qtprocs = (long)_syspage_ptr->num_cpu;
1533 _sir_selflog("QNX _syspage_ptr->num_cpu reports %ld processor(s)", qtprocs);
1534 if (qtprocs > nprocs)
1535 nprocs = qtprocs;
1536 #endif
1537
1538 #if defined(__VXWORKS__)
1539 # if defined(_WRS_CONFIG_SMP)
1540 long vtprocs = 0;
1541 cpuset_t vset = vxCpuEnabledGet();
1542 for (int count = 0; count < 512 && !CPUSET_ISZERO(vset); ++count) {
1543 if (CPUSET_ISSET(vset, count)) {
1544 CPUSET_CLR(vset, count);
1545 vtprocs++;
1546 }
1547 }
1548 _sir_selflog("VxWorks vxCpuEnabledGet() reports %ld processor(s)", vtprocs);
1549 # else
1550 long vtprocs = 1;
1551 _sir_selflog("Uniprocessor system or VxWorks SMP is not enabled");
1552 # endif
1553 if (vtprocs > nprocs)
1554 nprocs = vtprocs;
1555 #endif
1556
1557 if (nprocs < 1) {
1558 _sir_selflog(SIR_BRED("Failed to determine processor count!"));
1559 if (!test_mode)
1560 nprocs = 1;
1561 }
1562
1563 _sir_selflog("Detected %ld processor(s)", nprocs);
1564 return nprocs;
1565 }