ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
time.c File Reference

⏱️ High-precision timing utilities implementation More...

Go to the source code of this file.

Macros

#define SOKOL_TIME_IMPL
 

Functions

uint64_t time_get_ns (void)
 
uint64_t time_get_realtime_ns (void)
 
void time_sleep_ns (uint64_t ns)
 
uint64_t time_elapsed_ns (uint64_t start_ns, uint64_t end_ns)
 
uint64_t time_timespec_to_ns (const struct timespec *ts)
 
void time_ns_to_timespec (uint64_t ns, struct timespec *ts)
 
bool timer_system_init (void)
 
void timer_system_destroy (void)
 
bool timer_start (const char *name)
 
double timer_stop (const char *name)
 
bool timer_is_initialized (void)
 
int format_duration_ns (double nanoseconds, char *buffer, size_t buffer_size)
 
int format_duration_ms (double milliseconds, char *buffer, size_t buffer_size)
 
int format_duration_s (double seconds, char *buffer, size_t buffer_size)
 
int format_uptime_hms (int hours, int minutes, int seconds, char *buffer, size_t buffer_size)
 
void adaptive_sleep_init (adaptive_sleep_state_t *state, const adaptive_sleep_config_t *config)
 
uint64_t adaptive_sleep_calculate (adaptive_sleep_state_t *state, size_t queue_depth, size_t target_depth)
 
void adaptive_sleep_do (adaptive_sleep_state_t *state, size_t queue_depth, size_t target_depth)
 
bool time_format_is_valid_strftime (const char *format_str)
 
int time_format_now (const char *format_str, char *buf, size_t buf_size)
 
asciichat_error_t time_format_safe (const char *format_str, char *buf, size_t buf_size)
 

Detailed Description

⏱️ High-precision timing utilities implementation

Definition in file util/time.c.

Macro Definition Documentation

◆ SOKOL_TIME_IMPL

#define SOKOL_TIME_IMPL

Definition at line 11 of file util/time.c.

Function Documentation

◆ adaptive_sleep_calculate()

uint64_t adaptive_sleep_calculate ( adaptive_sleep_state_t *  state,
size_t  queue_depth,
size_t  target_depth 
)

Definition at line 408 of file util/time.c.

408 {
409 if (!state) {
410 return 0;
411 }
412
413 const adaptive_sleep_config_t *cfg = &state->config;
414
415 // Determine if we need to speed up or slow down
416 double desired_multiplier;
417
418 if (queue_depth > target_depth) {
419 // Queue is building up - speed up processing
420 // The more items in queue, the faster we should process
421 size_t backlog = queue_depth - target_depth;
422
423 // Calculate desired speed based on backlog
424 // Each item above target increases speed proportionally
425 // This ensures we drain the queue faster the more backed up we are
426 double backlog_factor = 1.0 + ((double)backlog / (double)(target_depth + 1));
427 desired_multiplier = cfg->min_speed_multiplier * backlog_factor;
428
429 // Clamp to max speed
430 if (desired_multiplier > cfg->max_speed_multiplier) {
431 desired_multiplier = cfg->max_speed_multiplier;
432 }
433
434 // Ramp up gradually based on speedup_rate
435 double delta = desired_multiplier - state->current_speed_multiplier;
436 state->current_speed_multiplier += delta * cfg->speedup_rate;
437
438 } else {
439 // Queue is at or below target - slow down to baseline
440 desired_multiplier = cfg->min_speed_multiplier;
441
442 // Ramp down gradually based on slowdown_rate
443 double delta = desired_multiplier - state->current_speed_multiplier;
444 state->current_speed_multiplier += delta * cfg->slowdown_rate;
445 }
446
447 // Ensure we stay within configured bounds
448 if (state->current_speed_multiplier < cfg->min_speed_multiplier) {
449 state->current_speed_multiplier = cfg->min_speed_multiplier;
450 }
451 if (state->current_speed_multiplier > cfg->max_speed_multiplier) {
452 state->current_speed_multiplier = cfg->max_speed_multiplier;
453 }
454
455 // Calculate actual sleep time: baseline / speed_multiplier
456 // Higher multiplier = shorter sleep = faster processing
457 uint64_t sleep_ns = (uint64_t)(cfg->baseline_sleep_ns / state->current_speed_multiplier);
458
459 // Store for debugging
460 state->last_sleep_ns = sleep_ns;
461
462 return sleep_ns;
463}

Referenced by adaptive_sleep_do().

◆ adaptive_sleep_do()

void adaptive_sleep_do ( adaptive_sleep_state_t *  state,
size_t  queue_depth,
size_t  target_depth 
)

Definition at line 465 of file util/time.c.

465 {
466 uint64_t sleep_ns = adaptive_sleep_calculate(state, queue_depth, target_depth);
467
468 if (sleep_ns > 0) {
469 platform_sleep_ns(sleep_ns);
470 }
471}
uint64_t adaptive_sleep_calculate(adaptive_sleep_state_t *state, size_t queue_depth, size_t target_depth)
Definition util/time.c:408

References adaptive_sleep_calculate().

Referenced by client_audio_render_thread(), client_video_render_thread(), and session_capture_sleep_for_fps().

◆ adaptive_sleep_init()

void adaptive_sleep_init ( adaptive_sleep_state_t *  state,
const adaptive_sleep_config_t *  config 
)

Definition at line 393 of file util/time.c.

393 {
394 if (!state || !config) {
395 return;
396 }
397
398 // Copy configuration
399 state->config = *config;
400
401 // Start at baseline speed (no speedup initially)
402 state->current_speed_multiplier = config->min_speed_multiplier;
403
404 // Initial sleep is the baseline
405 state->last_sleep_ns = config->baseline_sleep_ns;
406}

Referenced by client_audio_render_thread(), client_video_render_thread(), session_capture_create(), and session_network_capture_create().

◆ format_duration_ms()

int format_duration_ms ( double  milliseconds,
char *  buffer,
size_t  buffer_size 
)

Definition at line 357 of file util/time.c.

357 {
358 // Convert milliseconds to nanoseconds and use the nanosecond formatter
359 double nanoseconds = milliseconds * NS_PER_MS;
360 return format_duration_ns(nanoseconds, buffer, buffer_size);
361}
int buffer_size
Size of circular buffer.
Definition grep.c:84
int format_duration_ns(double nanoseconds, char *buffer, size_t buffer_size)
Definition util/time.c:275

References buffer_size, and format_duration_ns().

◆ format_duration_ns()

int format_duration_ns ( double  nanoseconds,
char *  buffer,
size_t  buffer_size 
)

Definition at line 275 of file util/time.c.

275 {
276 if (!buffer || buffer_size == 0) {
277 return -1;
278 }
279
280 // Handle negative durations
281 if (nanoseconds < 0) {
282 nanoseconds = -nanoseconds;
283 }
284
285 int written = 0;
286
287 // Nanoseconds (< 1µs)
288 if (nanoseconds < NS_PER_US) {
289 written = safe_snprintf(buffer, buffer_size, "%.0fns", nanoseconds);
290 }
291 // Microseconds (< 1ms)
292 else if (nanoseconds < NS_PER_MS) {
293 double us = nanoseconds / NS_PER_US;
294 if (us < 10.0) {
295 written = safe_snprintf(buffer, buffer_size, "%.1fµs", us);
296 } else {
297 written = safe_snprintf(buffer, buffer_size, "%.0fµs", us);
298 }
299 }
300 // Milliseconds (< 1s)
301 else if (nanoseconds < NS_PER_SEC) {
302 double ms = nanoseconds / NS_PER_MS;
303 if (ms < 10.0) {
304 written = safe_snprintf(buffer, buffer_size, "%.1fms", ms);
305 } else {
306 written = safe_snprintf(buffer, buffer_size, "%.0fms", ms);
307 }
308 }
309 // Seconds (< 1m)
310 else if (nanoseconds < NS_PER_MIN) {
311 double s = nanoseconds / NS_PER_SEC;
312 if (s < 10.0) {
313 written = safe_snprintf(buffer, buffer_size, "%.2fs", s);
314 } else {
315 written = safe_snprintf(buffer, buffer_size, "%.1fs", s);
316 }
317 }
318 // Minutes (< 1h) - show minutes and seconds
319 else if (nanoseconds < NS_PER_HOUR) {
320 int minutes = (int)(nanoseconds / NS_PER_MIN);
321 int seconds = (int)((nanoseconds - (minutes * NS_PER_MIN)) / NS_PER_SEC);
322 written = safe_snprintf(buffer, buffer_size, "%dm%ds", minutes, seconds);
323 }
324 // Hours (< 1d) - show hours, minutes, and seconds
325 else if (nanoseconds < NS_PER_DAY) {
326 int hours = (int)(nanoseconds / NS_PER_HOUR);
327 double remaining_ns = nanoseconds - ((double)hours * NS_PER_HOUR);
328 int minutes = (int)(remaining_ns / NS_PER_MIN);
329 double remaining_after_min = remaining_ns - ((double)minutes * NS_PER_MIN);
330 int seconds = (int)(remaining_after_min / NS_PER_SEC);
331 written = safe_snprintf(buffer, buffer_size, "%dh%dm%ds", hours, minutes, seconds);
332 }
333 // Days (< 1y) - show days, hours, minutes, and seconds
334 else if (nanoseconds < NS_PER_YEAR) {
335 int days = (int)(nanoseconds / NS_PER_DAY);
336 double remaining_ns = nanoseconds - ((double)days * NS_PER_DAY);
337 int hours = (int)(remaining_ns / NS_PER_HOUR);
338 remaining_ns = remaining_ns - ((double)hours * NS_PER_HOUR);
339 int minutes = (int)(remaining_ns / NS_PER_MIN);
340 double remaining_after_min = remaining_ns - ((double)minutes * NS_PER_MIN);
341 int seconds = (int)(remaining_after_min / NS_PER_SEC);
342 written = safe_snprintf(buffer, buffer_size, "%dd%dh%dm%ds", days, hours, minutes, seconds);
343 }
344 // Years - show years with one decimal
345 else {
346 double years = nanoseconds / NS_PER_YEAR;
347 written = safe_snprintf(buffer, buffer_size, "%.1fy", years);
348 }
349
350 if (written < 0 || (size_t)written >= buffer_size) {
351 return -1;
352 }
353
354 return written;
355}
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe formatted string printing to buffer.
Definition system.c:456

References buffer_size, and safe_snprintf().

Referenced by acip_server_receive_and_dispatch(), asciichat_instr_log_line(), broadcast_server_state_to_all_clients(), client_video_render_thread(), create_mixed_ascii_frame_for_client(), format_duration_ms(), format_duration_s(), session_render_loop(), and timer_stop().

◆ format_duration_s()

int format_duration_s ( double  seconds,
char *  buffer,
size_t  buffer_size 
)

Definition at line 363 of file util/time.c.

363 {
364 // Convert seconds to nanoseconds and use the nanosecond formatter
365 double nanoseconds = seconds * NS_PER_SEC;
366 return format_duration_ns(nanoseconds, buffer, buffer_size);
367}

References buffer_size, and format_duration_ns().

Referenced by crypto_init(), and crypto_rekey_init().

◆ format_uptime_hms()

int format_uptime_hms ( int  hours,
int  minutes,
int  seconds,
char *  buffer,
size_t  buffer_size 
)

Definition at line 369 of file util/time.c.

369 {
370 if (!buffer || buffer_size == 0) {
371 return -1;
372 }
373
374 // Validate components
375 if (hours < 0 || minutes < 0 || minutes >= 60 || seconds < 0 || seconds >= 60) {
376 return -1;
377 }
378
379 // Format as HH:MM:SS with zero-padding
380 int written = safe_snprintf(buffer, buffer_size, "%02d:%02d:%02d", hours, minutes, seconds);
381
382 if (written < 0 || (size_t)written >= buffer_size) {
383 return -1;
384 }
385
386 return written;
387}

References buffer_size, and safe_snprintf().

Referenced by discovery_status_display().

◆ time_elapsed_ns()

uint64_t time_elapsed_ns ( uint64_t  start_ns,
uint64_t  end_ns 
)

Definition at line 90 of file util/time.c.

90 {
91 // Handle wraparound (defensive - uint64_t won't wrap in practice at nanosecond resolution)
92 // but this is safe and handles any theoretical edge cases
93 if (end_ns >= start_ns) {
94 return end_ns - start_ns;
95 }
96 // Wraparound case (extremely unlikely)
97 return (UINT64_MAX - start_ns) + end_ns + 1;
98}

Referenced by ascii_convert_with_capabilities(), asciichat_instr_log_line(), audio_analysis_print_report(), broadcast_server_state_to_all_clients(), client_send_thread_func(), fps_frame_ns(), media_source_read_video(), media_source_seek(), mixer_process_excluding_source(), session_capture_get_current_fps(), session_capture_read_frame(), and session_render_loop().

◆ time_format_is_valid_strftime()

bool time_format_is_valid_strftime ( const char *  format_str)

Definition at line 483 of file util/time.c.

483 {
484 if (!format_str) {
485 return false;
486 }
487
488 for (const char *p = format_str; *p; p++) {
489 if (*p == '%') {
490 p++;
491 if (!*p) {
492 /* Unterminated % at end of string */
493 log_error("Invalid time format: unterminated %% at end");
494 return false;
495 }
496
497 if (*p == '%') {
498 /* Escaped %% - this is valid, just skip it */
499 continue;
500 }
501
502 /* Optional: flag characters (-, 0, +, space) */
503 if (*p == '-' || *p == '0' || *p == '+' || *p == ' ') {
504 p++;
505 if (!*p) {
506 log_error("Invalid time format: flag character without specifier");
507 return false;
508 }
509 }
510
511 /* Optional: width specifier (digits or *) */
512 if (*p == '*' || isdigit((unsigned char)*p)) {
513 while (*p && (isdigit((unsigned char)*p) || *p == '*')) {
514 p++;
515 }
516 if (!*p) {
517 log_error("Invalid time format: width specifier without specifier character");
518 return false;
519 }
520 }
521
522 /* Optional: precision specifier (.digits or .*) */
523 if (*p == '.') {
524 p++;
525 if (!*p) {
526 log_error("Invalid time format: precision specifier incomplete");
527 return false;
528 }
529 while (*p && (isdigit((unsigned char)*p) || *p == '*')) {
530 p++;
531 }
532 if (!*p) {
533 log_error("Invalid time format: precision specifier without specifier character");
534 return false;
535 }
536 }
537
538 /* Optional: modifier characters (E for %Ex, O for %Ox) */
539 if (*p == 'E' || *p == 'O') {
540 p++;
541 if (!*p) {
542 log_error("Invalid time format: modifier character without specifier");
543 return false;
544 }
545 }
546
547 /* Validate that the final character is a supported specifier */
548 if (!strchr(SUPPORTED_SPECIFIERS, *p)) {
549 log_error("Invalid time format: unsupported specifier %%%c (at position %ld)", *p, (p - format_str));
550 return false;
551 }
552 }
553 }
554
555 return true;
556}

Referenced by time_format_safe().

◆ time_format_now()

int time_format_now ( const char *  format_str,
char *  buf,
size_t  buf_size 
)

Definition at line 558 of file util/time.c.

558 {
559 if (!format_str || !buf || buf_size < 2) {
560 SET_ERRNO(ERROR_INVALID_PARAM, "time_format_now: invalid arguments - format_str=%p, buf=%p, buf_size=%zu",
561 format_str, buf, buf_size);
562 return 0;
563 }
564
565 /* Get current wall-clock time in nanoseconds */
566 uint64_t ts_ns = time_get_realtime_ns();
567
568 /* Extract seconds and nanoseconds */
569 time_t seconds = (time_t)(ts_ns / NS_PER_SEC_INT);
570 long nanoseconds = (long)(ts_ns % NS_PER_SEC_INT);
571
572 /* Convert seconds to struct tm */
573 struct tm tm_info;
574 platform_localtime(&seconds, &tm_info);
575
576 /* Format using strftime */
577 size_t len = strftime(buf, buf_size, format_str, &tm_info);
578
579 /* Check for strftime errors or buffer overflow */
580 if (len == 0) {
581 /* strftime returned 0 - either error or exact buffer fill */
582 log_debug("strftime returned 0 for format: %s", format_str);
583 return 0;
584 }
585
586 if (len >= buf_size - 1) {
587 /* Buffer would overflow - strftime filled entire buffer or hit exact size */
588 log_error("time_format_now: buffer too small (need %zu, have %zu)", len + 1, buf_size);
589 return 0;
590 }
591
592 return (int)len;
593}
uint64_t time_get_realtime_ns(void)
Definition util/time.c:59
asciichat_error_t platform_localtime(const time_t *timer, struct tm *result)
Definition util.c:48

References platform_localtime(), and time_get_realtime_ns().

Referenced by log_template_apply(), and time_format_safe().

◆ time_format_safe()

asciichat_error_t time_format_safe ( const char *  format_str,
char *  buf,
size_t  buf_size 
)

Definition at line 595 of file util/time.c.

595 {
596 /* Check NULL pointers */
597 if (!format_str) {
598 return SET_ERRNO(ERROR_INVALID_STATE, "time_format_safe: format_str is NULL");
599 }
600
601 if (!buf) {
602 return SET_ERRNO(ERROR_INVALID_STATE, "time_format_safe: buf is NULL");
603 }
604
605 /* Check minimum buffer size */
606 if (buf_size < 64) {
607 return SET_ERRNO(ERROR_INVALID_STATE, "time_format_safe: buffer too small (minimum 64 bytes, got %zu)", buf_size);
608 }
609
610 /* Validate format string */
611 if (!time_format_is_valid_strftime(format_str)) {
612 return SET_ERRNO(ERROR_INVALID_STATE, "time_format_safe: invalid time format: %s", format_str);
613 }
614
615 /* Format the time */
616 int result = time_format_now(format_str, buf, buf_size);
617 if (result <= 0) {
618 return SET_ERRNO(ERROR_INVALID_STATE, "time_format_safe: strftime formatting failed");
619 }
620
621 return ASCIICHAT_OK;
622}
bool time_format_is_valid_strftime(const char *format_str)
Definition util/time.c:483
int time_format_now(const char *format_str, char *buf, size_t buf_size)
Definition util/time.c:558

References time_format_is_valid_strftime(), and time_format_now().

◆ time_get_ns()

uint64_t time_get_ns ( void  )

Definition at line 48 of file util/time.c.

48 {
49 // sokol_time provides monotonic clock that never goes backwards
50 // stm_ns() converts ticks to nanoseconds
51 // Ensure sokol_time is initialized before use (defensive programming)
52 if (!g_sokol_time_initialized) {
53 stm_setup();
54 g_sokol_time_initialized = true;
55 }
56 return (uint64_t)stm_ns(stm_now());
57}

Referenced by acip_server_receive_and_dispatch(), ascii_convert_with_capabilities(), asciichat_instr_log_line(), audio_analysis_init(), audio_analysis_print_report(), audio_analysis_track_received_packet(), audio_analysis_track_sent_packet(), benchmark_simd_color_conversion(), benchmark_simd_color_conversion_with_source(), benchmark_simd_conversion(), benchmark_simd_conversion_with_source(), broadcast_server_state_to_all_clients(), buffer_pool_free(), buffer_pool_shrink(), client_audio_render_thread(), client_dispatch_thread(), client_send_thread_func(), client_video_render_thread(), consensus_coordinator_create(), consensus_coordinator_on_collection_start(), consensus_coordinator_process(), consensus_coordinator_time_until_next_round(), create_mixed_ascii_frame_for_client(), discovery_mdns_query(), get_utf8_palette_cache(), media_source_read_video(), media_source_seek(), mixer_process_excluding_source(), nat_measure_bandwidth(), session_capture_create(), session_capture_get_current_fps(), session_capture_read_frame(), session_display_convert_to_ascii(), session_display_create(), session_network_capture_create(), session_render_loop(), simple_frame_swap_update(), and websocket_server_run().

◆ time_get_realtime_ns()

uint64_t time_get_realtime_ns ( void  )

Definition at line 59 of file util/time.c.

59 {
60#ifdef _WIN32
61 // Windows: Use GetSystemTimePreciseAsFileTime (Win8+) for high-precision wall clock
62 // FILETIME is 100-nanosecond intervals since January 1, 1601
63 FILETIME ft;
64 GetSystemTimePreciseAsFileTime(&ft);
65 // Convert FILETIME to nanoseconds
66 uint64_t filetime = ((uint64_t)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
67 // Convert 100-nanosecond intervals to nanoseconds
68 return filetime * 100;
69#else
70 // Get wall-clock (real-time) timestamp
71 struct timespec ts;
72 if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
73 // Fallback on error (unlikely)
74 return 0;
75 }
76 return time_timespec_to_ns(&ts);
77#endif
78}
uint64_t time_timespec_to_ns(const struct timespec *ts)
Definition util/time.c:104

References time_timespec_to_ns().

Referenced by acds_validate_timestamp(), asciichat_error_stats_record(), asciichat_instr_log_line(), asciichat_set_errno(), connection_attempt_tcp(), connection_attempt_websocket(), connection_check_timeout(), connection_context_init(), consensus_metrics_measure(), consensus_state_compute_election(), database_session_is_migration_ready(), database_session_start_migration(), get_current_time_formatted(), log_json_async_safe(), log_msg(), log_plain_msg(), log_terminal_msg(), and time_format_now().

◆ time_ns_to_timespec()

void time_ns_to_timespec ( uint64_t  ns,
struct timespec *  ts 
)

Definition at line 112 of file util/time.c.

112 {
113 if (!ts) {
114 SET_ERRNO(ERROR_INVALID_PARAM, "null ts");
115 return;
116 }
117 ts->tv_sec = (time_t)(ns / NS_PER_SEC_INT);
118 ts->tv_nsec = (long)(ns % NS_PER_SEC_INT);
119}

◆ time_sleep_ns()

void time_sleep_ns ( uint64_t  ns)

Definition at line 80 of file util/time.c.

80 {
81 // Use platform abstraction for cross-platform sleep
82 // Convert nanoseconds to microseconds (1 us = 1000 ns)
83 unsigned int usec = (unsigned int)(ns / 1000);
84 if (usec == 0 && ns > 0) {
85 usec = 1; // Minimum 1 microsecond
86 }
88}
void platform_sleep_us(unsigned int us)

References platform_sleep_us().

◆ time_timespec_to_ns()

uint64_t time_timespec_to_ns ( const struct timespec *  ts)

Definition at line 104 of file util/time.c.

104 {
105 if (!ts) {
106 SET_ERRNO(ERROR_INVALID_PARAM, "null ts");
107 return 0;
108 }
109 return (uint64_t)ts->tv_sec * NS_PER_SEC_INT + (uint64_t)ts->tv_nsec;
110}

Referenced by time_get_realtime_ns().

◆ timer_is_initialized()

bool timer_is_initialized ( void  )

Definition at line 267 of file util/time.c.

267 {
268 return g_timer_manager.initialized;
269}

◆ timer_start()

bool timer_start ( const char *  name)

Definition at line 172 of file util/time.c.

172 {
173 if (!g_timer_manager.initialized) {
174 SET_ERRNO(ERROR_INVALID_STATE, "Timer system not initialized");
175 return false;
176 }
177
178 if (!name) {
179 SET_ERRNO(ERROR_INVALID_PARAM, "Timer name is NULL");
180 return false;
181 }
182
183 rwlock_wrlock(&g_timer_manager.rwlock);
184
185 // Check if timer already exists - this is an error, timers must be unique
186 timer_record_t *existing = NULL;
187 HASH_FIND_STR(g_timer_manager.timers, name, existing);
188
189 if (existing) {
190 rwlock_wrunlock(&g_timer_manager.rwlock);
191 SET_ERRNO(ERROR_INVALID_STATE, "Timer '%s' already exists - timers must have unique names", name);
192 return false;
193 }
194
195 // Create new timer record
196 timer_record_t *timer = SAFE_MALLOC(sizeof(timer_record_t), timer_record_t *);
197 if (!timer) {
198 rwlock_wrunlock(&g_timer_manager.rwlock);
199 SET_ERRNO(ERROR_MEMORY, "Failed to allocate timer record");
200 return false;
201 }
202
203 // Use platform-safe string duplication
204 size_t name_len = strlen(name) + 1;
205 timer->name = SAFE_MALLOC(name_len, char *);
206 if (!timer->name) {
207 SAFE_FREE(timer);
208 rwlock_wrunlock(&g_timer_manager.rwlock);
209 SET_ERRNO(ERROR_MEMORY, "Failed to allocate timer name");
210 return false;
211 }
212 SAFE_STRNCPY(timer->name, name, name_len);
213
214 timer->start_ticks = stm_now();
215
216 // Add to hashtable
217 HASH_ADD_KEYPTR(hh, g_timer_manager.timers, timer->name, strlen(timer->name), timer);
218
219 rwlock_wrunlock(&g_timer_manager.rwlock);
220 return true;
221}

◆ timer_stop()

double timer_stop ( const char *  name)

Definition at line 223 of file util/time.c.

223 {
224 if (!g_timer_manager.initialized) {
225 SET_ERRNO(ERROR_INVALID_STATE, "Timer system not initialized");
226 return -1.0;
227 }
228
229 if (!name) {
230 SET_ERRNO(ERROR_INVALID_PARAM, "Timer name is NULL");
231 return -1.0;
232 }
233
234 rwlock_wrlock(&g_timer_manager.rwlock);
235
236 // Find timer
237 timer_record_t *timer = NULL;
238 HASH_FIND_STR(g_timer_manager.timers, name, timer);
239
240 if (!timer) {
241 rwlock_wrunlock(&g_timer_manager.rwlock);
242 log_warn("Timer '%s' not found", name);
243 return -1.0;
244 }
245
246 // Calculate elapsed time in nanoseconds for maximum precision
247 uint64_t end_ticks = stm_now();
248 uint64_t elapsed_ticks = stm_diff(end_ticks, timer->start_ticks);
249 double elapsed_ns = stm_ns(elapsed_ticks);
250
251 // Format duration for human-readable logging
252 char duration_str[32];
253 format_duration_ns(elapsed_ns, duration_str, sizeof(duration_str));
254
255 // Log the result (dev level - only shown with --verbose)
256 log_dev("Timer '%s': %s", name, duration_str);
257
258 // Remove from hashtable
259 HASH_DEL(g_timer_manager.timers, timer);
260 SAFE_FREE(timer->name);
261 SAFE_FREE(timer);
262
263 rwlock_wrunlock(&g_timer_manager.rwlock);
264 return elapsed_ns; // Return nanoseconds
265}

References format_duration_ns().

◆ timer_system_destroy()

void timer_system_destroy ( void  )

Definition at line 146 of file util/time.c.

146 {
147 if (!g_timer_manager.initialized) {
148 return;
149 }
150
151 rwlock_wrlock(&g_timer_manager.rwlock);
152
153 // Free all timer records
154 int timer_count = 0;
155 timer_record_t *current, *tmp;
156 HASH_ITER(hh, g_timer_manager.timers, current, tmp) {
157 HASH_DEL(g_timer_manager.timers, current);
158 SAFE_FREE(current->name);
159 SAFE_FREE(current);
160 timer_count++;
161 }
162
163 g_timer_manager.timers = NULL;
164 g_timer_manager.initialized = false;
165
166 rwlock_wrunlock(&g_timer_manager.rwlock);
167 rwlock_destroy(&g_timer_manager.rwlock);
168
169 log_debug("Timer system cleaned up (freed %d timers)", timer_count);
170}

Referenced by asciichat_shared_destroy().

◆ timer_system_init()

bool timer_system_init ( void  )

Definition at line 125 of file util/time.c.

125 {
126 if (g_timer_manager.initialized) {
127 return true;
128 }
129
130 // Initialize sokol_time
131 stm_setup();
132
133 // Initialize rwlock (uthash requires external locking for writes, rwlock allows concurrent reads)
134 if (rwlock_init(&g_timer_manager.rwlock) != 0) {
135 SET_ERRNO(ERROR_PLATFORM_INIT, "Failed to initialize timer rwlock");
136 return false;
137 }
138
139 g_timer_manager.timers = NULL;
140 g_timer_manager.initialized = true;
141
142 log_dev("Timer system initialized");
143 return true;
144}
int rwlock_init(rwlock_t *rwlock)
Definition threading.c:63

References rwlock_init().

Referenced by asciichat_shared_init().

Variable Documentation

◆ initialized

bool initialized

Initialization state.

Definition at line 33 of file util/time.c.

◆ rwlock

rwlock_t rwlock

Read-write lock for thread-safe access (uthash requires external locking)

Definition at line 32 of file util/time.c.

Referenced by debug_rwlock_rdlock(), debug_rwlock_rdunlock(), debug_rwlock_wrlock(), debug_rwlock_wrunlock(), rwlock_init(), rwlock_rdlock_impl(), rwlock_rdunlock_impl(), rwlock_wrlock_impl(), and rwlock_wrunlock_impl().

◆ timers

timer_record_t* timers

Hash table of active timers (uthash head pointer)

Definition at line 31 of file util/time.c.