ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
sync.c File Reference

Go to the source code of this file.

Data Structures

struct  sync_row_t
struct  sync_sample_t
 sync row keeps the values that move through the subsystem: key, owner, waiter, generation. Some members are pointers into caller- or subsystem-owned memory, so lifetime follows the API that populated them rather than the struct copy itself. More...

Macros

#define TUI_SYNC_NAME_BUFFER_SIZE   256
#define TUI_SYNC_TYPE_BUFFER_SIZE   24
#define TUI_SYNC_FILE_BUFFER_SIZE   160
#define TUI_SYNC_OUTPUT_BUFFER_SIZE   2048
#define TUI_SYNC_LINE_BUFFER_SIZE   2048
#define TUI_SYNC_LABEL_BUFFER_SIZE   288
#define TUI_SYNC_DEADLOCK_BUFFER_SIZE   128
#define TUI_SYNC_LINE_SHORT_BUFFER_SIZE   1024
#define TUI_SYNC_NAME_EXTENDED_BUFFER_SIZE   288
#define TUI_SYNC_STATE_BUFFER_SIZE   128
#define TUI_SYNC_PADDED_STATE_BUFFER_SIZE   256
#define TUI_SYNC_PLAIN_ACTIONS_BUFFER_SIZE   32
#define TUI_SYNC_ACTIONS_BUFFER_SIZE   256
#define TUI_SYNC_PADDED_ACTIONS_BUFFER_SIZE   32
#define TUI_SYNC_CHANGES_BUFFER_SIZE   64
#define TUI_SYNC_PADDED_WAIT_BUFFER_SIZE   48
#define TUI_SYNC_COLORED_WAIT_BUFFER_SIZE   512
#define TUI_SYNC_LOCKS_BUFFER_SIZE   96
#define TUI_SYNC_UNLOCKS_BUFFER_SIZE   96
#define TUI_SYNC_NUMBERS_BUFFER_SIZE   512
#define TUI_SYNC_FULL_NAME_BUFFER_SIZE   288
#define TUI_SYNC_COLORED_NAME_BUFFER_SIZE   640
#define TUI_SYNC_OUTPUT_SHORT_BUFFER_SIZE   512
#define SYNC_WAIT_SNAPSHOT_CAPACITY   256
#define SYNC_ROW_CAPACITY   128
#define SYNC_OUTPUT_BUFFER_SIZE   (64 * 1024)

Functions

asciichat_error_t ui_sync_start (int fd)
void ui_sync_stop (void)
bool ui_sync_is_visible (void)
int ui_sync_output_fd (void)
keyboard_key_t ui_sync_handle_key (keyboard_key_t key)
void ui_sync_render (terminal_size_t size)

Macro Definition Documentation

◆ SYNC_OUTPUT_BUFFER_SIZE

#define SYNC_OUTPUT_BUFFER_SIZE   (64 * 1024)

Definition at line 30 of file sync.c.

◆ SYNC_ROW_CAPACITY

#define SYNC_ROW_CAPACITY   128

Definition at line 29 of file sync.c.

Referenced by ui_sync_render().

◆ SYNC_WAIT_SNAPSHOT_CAPACITY

#define SYNC_WAIT_SNAPSHOT_CAPACITY   256

Definition at line 28 of file sync.c.

◆ TUI_SYNC_ACTIONS_BUFFER_SIZE

#define TUI_SYNC_ACTIONS_BUFFER_SIZE   256

Definition at line 15 of file sync.c.

Referenced by ui_sync_render().

◆ TUI_SYNC_CHANGES_BUFFER_SIZE

#define TUI_SYNC_CHANGES_BUFFER_SIZE   64

Definition at line 17 of file sync.c.

Referenced by ui_sync_render().

◆ TUI_SYNC_COLORED_NAME_BUFFER_SIZE

#define TUI_SYNC_COLORED_NAME_BUFFER_SIZE   640

Definition at line 24 of file sync.c.

Referenced by ui_sync_render().

◆ TUI_SYNC_COLORED_WAIT_BUFFER_SIZE

#define TUI_SYNC_COLORED_WAIT_BUFFER_SIZE   512

Definition at line 19 of file sync.c.

Referenced by ui_sync_render().

◆ TUI_SYNC_DEADLOCK_BUFFER_SIZE

#define TUI_SYNC_DEADLOCK_BUFFER_SIZE   128

Definition at line 9 of file sync.c.

Referenced by ui_sync_render().

◆ TUI_SYNC_FILE_BUFFER_SIZE

#define TUI_SYNC_FILE_BUFFER_SIZE   160

Definition at line 5 of file sync.c.

◆ TUI_SYNC_FULL_NAME_BUFFER_SIZE

#define TUI_SYNC_FULL_NAME_BUFFER_SIZE   288

Definition at line 23 of file sync.c.

Referenced by ui_sync_render().

◆ TUI_SYNC_LABEL_BUFFER_SIZE

#define TUI_SYNC_LABEL_BUFFER_SIZE   288

Definition at line 8 of file sync.c.

Referenced by ui_sync_render().

◆ TUI_SYNC_LINE_BUFFER_SIZE

#define TUI_SYNC_LINE_BUFFER_SIZE   2048

Definition at line 7 of file sync.c.

◆ TUI_SYNC_LINE_SHORT_BUFFER_SIZE

#define TUI_SYNC_LINE_SHORT_BUFFER_SIZE   1024

Definition at line 10 of file sync.c.

Referenced by ui_sync_render().

◆ TUI_SYNC_LOCKS_BUFFER_SIZE

#define TUI_SYNC_LOCKS_BUFFER_SIZE   96

Definition at line 20 of file sync.c.

Referenced by ui_sync_render().

◆ TUI_SYNC_NAME_BUFFER_SIZE

#define TUI_SYNC_NAME_BUFFER_SIZE   256

Definition at line 3 of file sync.c.

◆ TUI_SYNC_NAME_EXTENDED_BUFFER_SIZE

#define TUI_SYNC_NAME_EXTENDED_BUFFER_SIZE   288

Definition at line 11 of file sync.c.

Referenced by ui_sync_render().

◆ TUI_SYNC_NUMBERS_BUFFER_SIZE

#define TUI_SYNC_NUMBERS_BUFFER_SIZE   512

Definition at line 22 of file sync.c.

Referenced by ui_sync_render().

◆ TUI_SYNC_OUTPUT_BUFFER_SIZE

#define TUI_SYNC_OUTPUT_BUFFER_SIZE   2048

Definition at line 6 of file sync.c.

◆ TUI_SYNC_OUTPUT_SHORT_BUFFER_SIZE

#define TUI_SYNC_OUTPUT_SHORT_BUFFER_SIZE   512

Definition at line 25 of file sync.c.

Referenced by ui_sync_render().

◆ TUI_SYNC_PADDED_ACTIONS_BUFFER_SIZE

#define TUI_SYNC_PADDED_ACTIONS_BUFFER_SIZE   32

Definition at line 16 of file sync.c.

Referenced by ui_sync_render().

◆ TUI_SYNC_PADDED_STATE_BUFFER_SIZE

#define TUI_SYNC_PADDED_STATE_BUFFER_SIZE   256

Definition at line 13 of file sync.c.

Referenced by ui_sync_render().

◆ TUI_SYNC_PADDED_WAIT_BUFFER_SIZE

#define TUI_SYNC_PADDED_WAIT_BUFFER_SIZE   48

Definition at line 18 of file sync.c.

Referenced by ui_sync_render().

◆ TUI_SYNC_PLAIN_ACTIONS_BUFFER_SIZE

#define TUI_SYNC_PLAIN_ACTIONS_BUFFER_SIZE   32

Definition at line 14 of file sync.c.

Referenced by ui_sync_render().

◆ TUI_SYNC_STATE_BUFFER_SIZE

#define TUI_SYNC_STATE_BUFFER_SIZE   128

Definition at line 12 of file sync.c.

Referenced by ui_sync_render().

◆ TUI_SYNC_TYPE_BUFFER_SIZE

#define TUI_SYNC_TYPE_BUFFER_SIZE   24

Definition at line 4 of file sync.c.

◆ TUI_SYNC_UNLOCKS_BUFFER_SIZE

#define TUI_SYNC_UNLOCKS_BUFFER_SIZE   96

Definition at line 21 of file sync.c.

Referenced by ui_sync_render().

Function Documentation

◆ ui_sync_handle_key()

keyboard_key_t ui_sync_handle_key ( keyboard_key_t key)

Definition at line 364 of file sync.c.

364 {
365 if (key == KEY_0) {
367 return KEY_NONE;
368 }
369 if (!ui_sync_is_visible())
370 return key;
371 // Leave sync selected until the replacement has a complete snapshot.
372 if (key == '=' || key == KEY_BACKTICK || key == KEY_QUESTION || key == ']' || key == 'o' || key == 'O' || key == 15)
373 return key;
374 if (key == KEY_ESCAPE) {
376 return KEY_NONE;
377 }
378 ui_viewport_t viewport = {.selected = (size_t)atomic_load(&g_sync_selected),
379 .page_size = (size_t)atomic_load(&g_sync_page_size)};
380 ui_viewport_key(&viewport, (size_t)atomic_load(&g_sync_total), viewport.page_size, key);
381 atomic_store(&g_sync_selected, (int)viewport.selected);
382 return key == 'q' || key == 3 ? key : KEY_NONE;
383}
@ KEY_BACKTICK
'`' key - print lock state (debug builds)
Definition keyboard.h:84
@ KEY_ESCAPE
Escape key (ESC).
Definition keyboard.h:55
@ KEY_0
'0' key - toggle sync debug screen
Definition keyboard.h:75
@ KEY_NONE
No key pressed or no input available.
Definition keyboard.h:54
@ KEY_QUESTION
'?' key - show help screen
Definition keyboard.h:83
For ui viewport, this is the live record that ties selected, first_visible, page_size together....
Definition viewport.h:10
size_t selected
Definition viewport.h:11
size_t page_size
Definition viewport.h:11
bool ui_sync_is_visible(void)
Definition sync.c:357
void ui_controller_select_interactive(int screen)
@ UI_SCREEN_SYNC
bool ui_viewport_key(ui_viewport_t *v, size_t count, size_t rows, keyboard_key_t key)
Definition viewport.c:38

References KEY_0, KEY_BACKTICK, KEY_ESCAPE, KEY_NONE, KEY_QUESTION, ui_viewport_t::page_size, ui_viewport_t::selected, ui_controller_select_interactive(), UI_SCREEN_SYNC, ui_sync_is_visible(), and ui_viewport_key().

Referenced by ui_input_poll_sync(), and ui_input_read_key().

◆ ui_sync_is_visible()

bool ui_sync_is_visible ( void )

Definition at line 357 of file sync.c.

357 {
359}
int ui_controller_interactive_screen(void)

References ui_controller_interactive_screen(), and UI_SCREEN_SYNC.

Referenced by ui_sync_handle_key(), and ui_sync_stop().

◆ ui_sync_output_fd()

int ui_sync_output_fd ( void )

Definition at line 360 of file sync.c.

360 {
361 return g_sync_fd;
362}

Referenced by ui_sync_render().

◆ ui_sync_render()

void ui_sync_render ( terminal_size_t size)

Called only by the presentation thread; uses already-owned snapshots.

Definition at line 486 of file sync.c.

486 {
488 terminal_capabilities_t caps = detect_terminal_capabilities(options_terminal_settings());
489 terminal_color_mode_t mode = GET_OPTION(color_mode);
490 g_sync_use_color = mode != TERM_COLOR_NONE && GET_OPTION(color) != COLOR_SETTING_FALSE && !GET_OPTION(strip_ansi) &&
491 (mode != TERM_COLOR_AUTO || caps.color_level != TERM_COLOR_NONE);
492 g_sync_use_utf8 = terminal_should_use_utf8(GET_OPTION(force_utf8));
493 // Copy only the visible page before terminal writes; the collector never
494 // waits for output, and the renderer never waits for collection.
496 size_t count = 0, total = 0, cycles = 0;
497 size_t mutexes = 0, conditions = 0, rwlocks = 0, atomics = 0;
498 uint64_t sampled = 0;
499 bool waits_complete = false, limited = false;
500 enum { header_rows = 4, detail_rows = 3, footer_rows = 1 };
501 const int fixed_rows = header_rows + detail_rows + footer_rows;
502 int name_width = (int)strlen("Name");
503 ui_layout_t layout;
504 if (ui_layout_measure(size, header_rows, detail_rows, footer_rows, &layout) != ASCIICHAT_OK)
505 return;
506 int per_page = layout.body_rows > 0 ? layout.body_rows : 1;
507 if (per_page > 128)
508 per_page = 128;
509 atomic_store(&g_sync_page_size, per_page);
510 int selected = atomic_load(&g_sync_selected);
511 int page = 0, pages = 1;
512 int slot = atomic_load(&g_sync_published);
513 if (slot >= 0) {
514 // Keep the last complete screen if collection is reusing this mailbox.
515 if (atomic_flag_test_and_set(&g_sync_samples[slot].busy)) {
516 return;
517 }
518 sync_sample_t *s = &g_sync_samples[slot];
519 total = s->count;
520 atomic_store(&g_sync_total, total > INT_MAX ? INT_MAX : (int)total);
521 if ((size_t)selected >= total) {
522 int previous = selected;
523 selected = total ? (int)total - 1 : 0;
524 // Do not overwrite a key received while the renderer copies a sample.
525 atomic_compare_exchange_strong(&g_sync_selected, &previous, selected);
526 }
527 pages = total ? (int)((total + per_page - 1) / per_page) : 1;
528 page = selected / per_page;
529 size_t first = (size_t)page * per_page;
530 count = total > first ? total - first : 0;
531 if (count > (size_t)per_page)
532 count = per_page;
533 if (count)
534 memcpy(rows, s->rows + first, count * sizeof(*rows));
535 for (size_t i = 0; i < total; ++i) {
536 cycles += s->rows[i].cycle;
537 const char *type = s->rows[i].type;
538 mutexes += !strcmp(type, "mutex");
539 conditions += !strcmp(type, "cond");
540 rwlocks += !strcmp(type, "rwlock");
541 atomics += !strncmp(type, "atomic", 6);
542 char label[TUI_SYNC_LABEL_BUFFER_SIZE];
543 sync_row_label(&s->rows[i], label, sizeof(label));
544 int width = (int)strlen(label);
545 if (width > name_width)
546 name_width = width;
547 }
548 sampled = s->sampled_ns;
549 waits_complete = s->waits_complete;
550 limited = s->limited;
551 atomic_flag_clear(&s->busy);
552 }
553 if (name_width > 30)
554 name_width = 30;
555 uint64_t now = time_get_ns();
556 selected %= per_page;
557 if ((size_t)selected >= count)
558 selected = count ? (int)count - 1 : 0;
559 char deadlock[TUI_SYNC_DEADLOCK_BUFFER_SIZE];
560 snprintf(deadlock, sizeof(deadlock), "%s%s%s", sync_color(LOG_COLOR_ERROR),
561 g_sync_use_utf8 ? "DEADLOCK ❌" : "DEADLOCK!", sync_color(LOG_COLOR_RESET));
562 int measured_width = 0;
563 for (int pass = 0; pass < 2; ++pass) {
564 int *measure = pass == 0 ? &measured_width : NULL;
566 if (!measure)
567 sync_write("\033[?2026h\033[H", 11);
568 snprintf(line, sizeof(line), "Sync primitives | %zu objects | page %d/%d | item %zu/%zu | age %.1fs", total,
569 page + 1, pages, count ? (size_t)page * per_page + selected + 1 : 0, total,
570 sampled ? (double)(now - sampled) / NS_PER_SEC_INT : 0.0);
571 sync_write_numbers(line, size.cols, measure);
572 snprintf(line, sizeof(line), "%s%s | M=%zu RW=%zu C=%zu A=%zu | %zu mutexes in wait cycles%s",
573 cycles ? sync_color(LOG_COLOR_ERROR) : "",
574 !sampled ? "Waiting for registry"
575 : now - sampled > NS_PER_SEC_INT ? "STALE: collection unavailable"
576 : "Live registered",
577 mutexes, rwlocks, conditions, atomics, cycles,
578 !waits_complete ? " | wait tracker busy"
579 : limited ? " | wait tracker capacity reached"
580 : "");
581 sync_write_numbers(line, size.cols, measure);
582 snprintf(line, sizeof(line), "%s %-8s %-*s %-12s %13s %6s %6s %7s %12s%s", sync_color(LOG_COLOR_GREY), "Type",
583 name_width, "Name", "State/value", "Total Actions", "L/s", "U/s", "Change/s", "Total Wait",
584 sync_color(LOG_COLOR_RESET));
585 sync_write_line(line, size.cols, true, measure);
586 sync_separator(size.cols, measure);
587 for (size_t i = 0; i < count; ++i) {
588 sync_row_t *r = &rows[i];
589 // Parent names may be media paths; keep the primitive visible in the table.
590 // The detail row identifies the source location and address.
592 sync_row_label(r, name, sizeof(name));
593 if (strlen(name) > (size_t)name_width) {
594 const char *suffix = strrchr(name, '.');
595 size_t suffix_bytes = suffix && strspn(suffix + 1, "0123456789") == strlen(suffix + 1) ? strlen(suffix) : 0;
596 if (suffix_bytes >= (size_t)name_width - 1)
597 suffix_bytes = 0;
598 size_t used = 0;
599 int columns = 0;
600 while (name[used]) {
601 int bytes = utf8_next_char_bytes(name + used, strlen(name + used));
602 if (bytes <= 0)
603 break;
604 int width = utf8_display_width_n(name + used, bytes);
605 if (columns + width > name_width - 1 - (int)suffix_bytes)
606 break;
607 used += bytes;
608 columns += width;
609 }
610 name[used++] = '~';
611 if (suffix_bytes) {
612 memmove(name + used, suffix, suffix_bytes);
613 used += suffix_bytes;
614 }
615 name[used] = '\0';
616 }
617 char state[TUI_SYNC_STATE_BUFFER_SIZE];
618 if (r->cycle)
619 snprintf(state, sizeof(state), "DEADLOCK");
620 else if (!strcmp(r->type, "mutex"))
621 snprintf(state, sizeof(state), "%s t=%" PRIxPTR " w=%u",
622 r->cycle ? "CYCLE"
623 : r->owner ? "HELD"
624 : "FREE",
625 r->owner, r->waiters);
626 else if (!strcmp(r->type, "rwlock"))
627 snprintf(state, sizeof(state), "W=%" PRIxPTR " R=%" PRIu64, r->owner, r->value);
628 else if (!strcmp(r->type, "cond"))
629 snprintf(state, sizeof(state), "waiting=%" PRIu64, r->value);
630 else
631 snprintf(state, sizeof(state), "0x%" PRIx64 " (%" PRIu64 ")", r->value, r->value);
632 // Prefer the complete hex value over a clipped redundant decimal copy.
633 if (!strncmp(r->type, "atomic", 6) && strlen(state) > 12)
634 snprintf(state, sizeof(state), "0x%" PRIx64, r->value);
635 char padded_state[TUI_SYNC_PADDED_STATE_BUFFER_SIZE];
636 if (r->cycle) {
637 int width = utf8_display_width(g_sync_use_utf8 ? "DEADLOCK ❌" : "DEADLOCK!");
638 snprintf(padded_state, sizeof(padded_state), "%s%*s", deadlock, 12 - width, "");
639 } else {
640 snprintf(padded_state, sizeof(padded_state), "%-12.12s", state);
641 }
643 format_number_compact(r->actions, plain_actions, sizeof(plain_actions));
644 char padded_actions[TUI_SYNC_PADDED_ACTIONS_BUFFER_SIZE];
645 snprintf(padded_actions, sizeof(padded_actions), "%13s", plain_actions);
646 sync_color_numbers(padded_actions, actions, sizeof(actions));
647 char changes[TUI_SYNC_CHANGES_BUFFER_SIZE];
648 if (!strncmp(r->type, "atomic", 6))
649 snprintf(changes, sizeof(changes), "%s%7.1f", sync_rate_color(r->change_rate), r->change_rate);
650 else
651 snprintf(changes, sizeof(changes), "%s%7s", sync_color(LOG_COLOR_RESET), "-");
652 char wait[TIME_DURATION_BUFFER_SIZE] = "-";
653 if (!strcmp(r->type, "cond")) {
654 if (r->wait_known)
655 time_pretty(r->wait_ns, -1, wait, sizeof(wait));
656 else
657 snprintf(wait, sizeof(wait), "busy");
658 }
660 snprintf(padded_wait, sizeof(padded_wait), "%12s", wait);
661 sync_color_numbers(padded_wait, colored_wait, sizeof(colored_wait));
663 snprintf(locks, sizeof(locks), "%s%6.1f%s", sync_rate_color(r->lock_rate), r->lock_rate,
664 sync_color(LOG_COLOR_RESET));
665 snprintf(unlocks, sizeof(unlocks), "%s%6.1f%s", sync_rate_color(r->unlock_rate), r->unlock_rate,
666 sync_color(LOG_COLOR_RESET));
667 const ui_table_column_t columns[] = {
668 {"Type", 8, UI_ALIGN_LEFT, false}, {"Name", name_width, UI_ALIGN_LEFT, false},
669 {"State/value", 13, UI_ALIGN_LEFT, false}, {"Total Actions", 13, UI_ALIGN_RIGHT, false},
670 {"L/s", 6, UI_ALIGN_RIGHT, false}, {"U/s", 6, UI_ALIGN_RIGHT, false},
671 {"Change/s", 7, UI_ALIGN_RIGHT, false}, {"Total Wait", 12, UI_ALIGN_RIGHT, false}};
672 const char *cells[] = {r->type, name, padded_state, actions, locks, unlocks, changes, colored_wait};
673 ui_table_row(line, sizeof(line), columns, cells, 8, name_width + 83, true, (int)i == selected);
674 sync_write_line(line, size.cols, true, measure);
675 }
676 if (!measure) {
677 // Clear only unused table rows, leaving the live footer in place.
678 for (int row = header_rows + (int)count + 1; row < size.rows - 3; ++row) {
679 snprintf(line, sizeof(line), "\033[%d;1H\033[K", row);
680 sync_write(line, strlen(line));
681 }
682 snprintf(line, sizeof(line), "\033[%d;1H", size.rows > 3 ? size.rows - 3 : 1);
683 sync_write(line, strlen(line));
684 }
685 sync_separator(size.cols, measure);
686 if (count) {
687 sync_row_t *r = &rows[selected];
688 snprintf(line, sizeof(line), "%d @0x%" PRIxPTR, r->line, r->key);
689 char numbers[TUI_SYNC_NUMBERS_BUFFER_SIZE];
690 sync_color_numbers(line, numbers, sizeof(numbers));
692 sync_row_label(r, full_name, sizeof(full_name));
693 sync_color_numbers(full_name, colored_name, sizeof(colored_name));
694 snprintf(line, sizeof(line), "%s%s%s:%s | %s", sync_color(LOG_COLOR_DEV), r->file, sync_color(LOG_COLOR_RESET),
695 numbers, colored_name);
696 sync_write_line(line, size.cols, true, measure);
697 snprintf(line, sizeof(line),
698 "owner=0x%" PRIxPTR " waiter=0x%" PRIxPTR " | value=%" PRIu64 " | last operation %.2fs ago%s%s",
699 r->owner, r->waiter, r->value, r->last_ns ? (double)(now - r->last_ns) / NS_PER_SEC_INT : 0.0,
700 r->cycle ? " " : "", r->cycle ? deadlock : "");
701 sync_write_numbers(line, size.cols, measure);
702 } else if (!measure) {
703 snprintf(line, sizeof(line), "\033[%d;1H\033[K\033[%d;1H\033[K", size.rows - 2, size.rows - 1);
704 sync_write(line, strlen(line));
705 }
706 snprintf(line, sizeof(line), "\033[%d;1H", size.rows);
707 if (!measure)
708 sync_write(line, strlen(line));
709 snprintf(line, sizeof(line),
710 "%s0%s/%sEsc%s close | %s?%s help | %sLeft%s/%sRight%s page | %sUp%s/%sDown%s select | "
711 "%sHome%s/%sEnd%s first/last",
712 sync_color(LOG_COLOR_FATAL), sync_color(LOG_COLOR_RESET), sync_color(LOG_COLOR_WARN),
713 sync_color(LOG_COLOR_RESET), sync_color(LOG_COLOR_WARN), sync_color(LOG_COLOR_RESET),
714 sync_color(LOG_COLOR_WARN), sync_color(LOG_COLOR_RESET), sync_color(LOG_COLOR_WARN),
715 sync_color(LOG_COLOR_RESET), sync_color(LOG_COLOR_WARN), sync_color(LOG_COLOR_RESET),
716 sync_color(LOG_COLOR_WARN), sync_color(LOG_COLOR_RESET), sync_color(LOG_COLOR_WARN),
717 sync_color(LOG_COLOR_RESET), sync_color(LOG_COLOR_WARN), sync_color(LOG_COLOR_RESET));
718 sync_write_line(line, size.cols, false, measure);
719 if (measure) {
720 terminal_size_t minimum = {.cols = measured_width + 1, .rows = fixed_rows + 1};
721 if (ui_too_small(size, minimum)) {
723 size_t length = ui_too_small_format(output, sizeof(output), size, minimum);
724 ui_controller_write(g_sync_fd, output, length);
725 return;
726 }
727 }
728 }
729 sync_write("\033[?2026l", 8);
730 sync_flush();
731}
int color_mode
Definition fft.c:25
char cells[(512 *256 *2)]
Definition fft.c:21
unsigned int width
Definition fft.c:23
unsigned long long uint64_t
Definition common.h:63
@ ASCIICHAT_OK
Definition error_codes.h:46
@ LOG_COLOR_RESET
Definition log/log.h:155
@ LOG_COLOR_GREY
Definition log/log.h:154
@ LOG_COLOR_FATAL
Definition log/log.h:153
@ LOG_COLOR_ERROR
Definition log/log.h:152
@ LOG_COLOR_DEV
Definition log/log.h:148
@ LOG_COLOR_WARN
Definition log/log.h:151
#define NS_PER_SEC_INT
Definition time.h:169
int time_pretty(uint64_t nanoseconds, int decimals, char *buffer, size_t buffer_size)
Format nanoseconds as a compact duration with configurable sub-minute precision.
Definition time.c:374
#define TIME_DURATION_BUFFER_SIZE
Definition time.h:40
#define GET_OPTION(field)
Safely get a specific option field (lock-free read).
Definition options.h:1336
#define options_terminal_settings()
Definition options.h:1296
@ COLOR_SETTING_FALSE
Force colors OFF: disable all colors and logging colors.
Definition options.h:249
int utf8_display_width_n(const char *str, size_t max_bytes)
Calculate terminal display width of a UTF-8 string up to byte limit.
Definition utf8.c:102
int colored_string_set_output_fd(int fd)
Definition string.c:274
int utf8_display_width(const char *str)
Calculate terminal display width of a UTF-8 string.
Definition utf8.c:98
int utf8_next_char_bytes(const char *str, size_t max_bytes)
Get byte length of next UTF-8 character.
Definition utf8.c:177
char type[24]
Definition sync.c:68
uint64_t actions
Definition sync.c:66
double unlock_rate
Definition sync.c:67
unsigned waiters
Definition sync.c:70
bool cycle
Definition sync.c:71
uintptr_t key
Definition sync.c:65
int line
Definition sync.c:69
char file[160]
Definition sync.c:68
uint64_t wait_ns
Definition sync.c:66
uint64_t value
Definition sync.c:66
uintptr_t owner
Definition sync.c:65
double change_rate
Definition sync.c:67
uint64_t last_ns
Definition sync.c:66
uintptr_t waiter
Definition sync.c:65
double lock_rate
Definition sync.c:67
bool wait_known
Definition sync.c:71
sync row keeps the values that move through the subsystem: key, owner, waiter, generation....
Definition sync.c:81
bool waits_complete
Definition sync.c:86
size_t count
Definition sync.c:84
sync_row_t * rows
Definition sync.c:83
bool limited
Definition sync.c:86
atomic_flag busy
Definition sync.c:82
uint64_t sampled_ns
Definition sync.c:85
int body_rows
Definition ui/layout.h:5
#define TUI_SYNC_STATE_BUFFER_SIZE
Definition sync.c:12
#define TUI_SYNC_FULL_NAME_BUFFER_SIZE
Definition sync.c:23
#define TUI_SYNC_DEADLOCK_BUFFER_SIZE
Definition sync.c:9
#define TUI_SYNC_ACTIONS_BUFFER_SIZE
Definition sync.c:15
#define TUI_SYNC_CHANGES_BUFFER_SIZE
Definition sync.c:17
#define TUI_SYNC_PLAIN_ACTIONS_BUFFER_SIZE
Definition sync.c:14
#define TUI_SYNC_PADDED_ACTIONS_BUFFER_SIZE
Definition sync.c:16
#define TUI_SYNC_NAME_EXTENDED_BUFFER_SIZE
Definition sync.c:11
#define SYNC_ROW_CAPACITY
Definition sync.c:29
#define TUI_SYNC_LOCKS_BUFFER_SIZE
Definition sync.c:20
#define TUI_SYNC_LABEL_BUFFER_SIZE
Definition sync.c:8
#define TUI_SYNC_COLORED_WAIT_BUFFER_SIZE
Definition sync.c:19
#define TUI_SYNC_COLORED_NAME_BUFFER_SIZE
Definition sync.c:24
#define TUI_SYNC_PADDED_WAIT_BUFFER_SIZE
Definition sync.c:18
#define TUI_SYNC_NUMBERS_BUFFER_SIZE
Definition sync.c:22
#define TUI_SYNC_UNLOCKS_BUFFER_SIZE
Definition sync.c:21
#define TUI_SYNC_OUTPUT_SHORT_BUFFER_SIZE
Definition sync.c:25
int ui_sync_output_fd(void)
Definition sync.c:360
#define TUI_SYNC_PADDED_STATE_BUFFER_SIZE
Definition sync.c:13
#define TUI_SYNC_LINE_SHORT_BUFFER_SIZE
Definition sync.c:10
size_t ui_table_row(char *out, size_t cap, const ui_table_column_t *cols, const char *const *cells, size_t count, int width, bool selectable, bool selected)
When code needs to work with ui table, it keeps columns, column_count, row_count, viewport here inste...
Definition table.c:18
@ UI_ALIGN_RIGHT
Definition text.h:9
@ UI_ALIGN_LEFT
Definition text.h:9
size_t ui_too_small_format(char *output, size_t capacity, terminal_size_t actual, terminal_size_t minimum)
Definition too_small.c:14
bool ui_too_small(terminal_size_t actual, terminal_size_t minimum)
Definition too_small.c:10
asciichat_error_t ui_controller_write(int fd, const char *data, size_t len)
asciichat_error_t ui_layout_measure(terminal_size_t size, int header, int detail, int footer, ui_layout_t *out)
Definition ui/layout.c:3
void format_number_compact(uint64_t value, char *out, size_t out_capacity)
Definition util/format.c:46

References sync_row_t::actions, ASCIICHAT_OK, ui_layout_t::body_rows, sync_sample_t::busy, cells, sync_row_t::change_rate, color_mode, COLOR_SETTING_FALSE, colored_string_set_output_fd(), sync_sample_t::count, sync_row_t::cycle, sync_row_t::file, format_number_compact(), GET_OPTION, sync_row_t::key, sync_row_t::last_ns, sync_sample_t::limited, sync_row_t::line, sync_row_t::lock_rate, LOG_COLOR_DEV, LOG_COLOR_ERROR, LOG_COLOR_FATAL, LOG_COLOR_GREY, LOG_COLOR_RESET, LOG_COLOR_WARN, NS_PER_SEC_INT, options_terminal_settings, sync_row_t::owner, sync_sample_t::rows, sync_sample_t::sampled_ns, SYNC_ROW_CAPACITY, TIME_DURATION_BUFFER_SIZE, time_pretty(), TUI_SYNC_ACTIONS_BUFFER_SIZE, TUI_SYNC_CHANGES_BUFFER_SIZE, TUI_SYNC_COLORED_NAME_BUFFER_SIZE, TUI_SYNC_COLORED_WAIT_BUFFER_SIZE, TUI_SYNC_DEADLOCK_BUFFER_SIZE, TUI_SYNC_FULL_NAME_BUFFER_SIZE, TUI_SYNC_LABEL_BUFFER_SIZE, TUI_SYNC_LINE_SHORT_BUFFER_SIZE, TUI_SYNC_LOCKS_BUFFER_SIZE, TUI_SYNC_NAME_EXTENDED_BUFFER_SIZE, TUI_SYNC_NUMBERS_BUFFER_SIZE, TUI_SYNC_OUTPUT_SHORT_BUFFER_SIZE, TUI_SYNC_PADDED_ACTIONS_BUFFER_SIZE, TUI_SYNC_PADDED_STATE_BUFFER_SIZE, TUI_SYNC_PADDED_WAIT_BUFFER_SIZE, TUI_SYNC_PLAIN_ACTIONS_BUFFER_SIZE, TUI_SYNC_STATE_BUFFER_SIZE, TUI_SYNC_UNLOCKS_BUFFER_SIZE, sync_row_t::type, UI_ALIGN_LEFT, UI_ALIGN_RIGHT, ui_controller_write(), ui_layout_measure(), ui_sync_output_fd(), ui_table_row(), ui_too_small(), ui_too_small_format(), sync_row_t::unlock_rate, utf8_display_width(), utf8_display_width_n(), utf8_next_char_bytes(), sync_row_t::value, sync_row_t::wait_known, sync_row_t::wait_ns, sync_row_t::waiter, sync_row_t::waiters, sync_sample_t::waits_complete, and width.

◆ ui_sync_start()

asciichat_error_t ui_sync_start ( int fd)

Debug-only service. Collection and input never wait on application locks.

Definition at line 311 of file sync.c.

311 {
312 while (atomic_flag_test_and_set(&g_sync_starting))
315 if (!g_sync_started && platform_isatty(fd) && platform_isatty(STDIN_FILENO)) {
316 g_sync_fd = platform_dup(fd);
317 if (g_sync_fd < 0) {
318 result = SET_ERRNO_SYS(ERROR_FILE_OPERATION, "Cannot retain sync display terminal");
319 } else if ((result = keyboard_init()) != ASCIICHAT_OK) {
320 platform_close(g_sync_fd);
321 g_sync_fd = -1;
322 } else {
323 atomic_store(&g_sync_stop, false);
324 result = platform_thread_create(&g_sync_thread, "sync_collector", sync_collect_main, NULL);
325 if (result == ASCIICHAT_OK) {
326 g_sync_started = true;
327 } else {
329 platform_close(g_sync_fd);
330 g_sync_fd = -1;
331 result = SET_ERRNO(ERROR_THREAD, "Cannot start sync collector");
332 }
333 }
334 }
335 atomic_flag_clear(&g_sync_starting);
336 return result;
337}
#define SET_ERRNO(code,...)
#define SET_ERRNO_SYS(code,...)
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ERROR_FILE_OPERATION
@ ERROR_THREAD
asciichat_error_t keyboard_init(void)
Initialize keyboard input system.
int platform_dup(int fd)
void platform_sleep_ms(unsigned int ms)
Sleep for a specified number of milliseconds.
void keyboard_destroy(void)
Cleanup keyboard input system and restore terminal.

References ASCIICHAT_OK, ERROR_FILE_OPERATION, ERROR_THREAD, keyboard_destroy(), keyboard_init(), platform_dup(), platform_sleep_ms(), SET_ERRNO, and SET_ERRNO_SYS.

Referenced by ui_controller_start_terminal().

◆ ui_sync_stop()

void ui_sync_stop ( void )

Definition at line 339 of file sync.c.

339 {
340 if (!g_sync_started)
341 return;
342 atomic_store(&g_sync_stop, true);
343 thread_join(&g_sync_thread, NULL);
345 platform_close(g_sync_fd);
346 g_sync_fd = -1;
347 for (int i = 0; i < 3; ++i) {
348 UNTRACKED_FREE(g_sync_samples[i].rows);
349 g_sync_samples[i].capacity = g_sync_samples[i].count = 0;
350 }
351 atomic_store(&g_sync_published, -1);
352 if (ui_sync_is_visible())
354 g_sync_started = false;
355}
#define UNTRACKED_FREE(ptr)
Definition common.h:414

References keyboard_destroy(), ui_controller_select_interactive(), ui_sync_is_visible(), and UNTRACKED_FREE.

Referenced by ui_controller_shutdown().