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