ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
Common Definitions

⚙️ Code shared throughout the library More...

Files

file  common.c
 🔧 Core utilities: memory management, safe macros, and cross-platform helpers
file  fps.c
 ⏱️ FPS tracking utility implementation (nanosecond-precision)
file  common.h
 ⚙️ Common definitions, error codes, macros, and types shared throughout the application
file  embedded_resources.h
 Embedded resource management for production builds.
file  fps.h
 ⏱️ FPS tracking utility for monitoring frame throughput across all threads

Data Structures

struct  fps_t
 Counters and timestamps used to calculate and report frame rate. More...

Macros

#define ASCII_CHAT_APP_NAME   "ascii-chat"
 Application name for key comments ("ascii-chat").
#define PLATFORM_MAX_PATH_LENGTH   4096
#define NONSTRING   /* nothing */
#define FATAL(code, ...)
 Exit with error code and custom message, with stack trace in debug builds.
#define MIN(a, b)
 Return the minimum of two values.
#define MAX(a, b)
 Return the maximum of two values.
#define ARRAY_SIZE(arr)
 Calculate the number of elements in an array.
#define RUN_BURST_AND_THROTTLE(burst_ns, throttle_ns, code_block)
#define ALLOC_MALLOC(size)
#define ALLOC_CALLOC(count, size)
#define ALLOC_REALLOC(ptr, size)
#define ALLOC_FREE(ptr)
#define ASCIICHAT_CHECK_AND_LOG(expr, ok_value, msg, ...)
 Check result and log error if operation failed.

Typedefs

typedef unsigned char uint8_t
typedef unsigned short uint16_t
typedef unsigned int uint32_t
typedef unsigned long long uint64_t

Functions

void asciichat_fatal_with_context (asciichat_error_t code, const char *file, int line, const char *function, const char *format,...)
asciichat_error_t asciichat_shared_init (const char *log_file, bool is_client, bool quiet_startup)
 Initialize common subsystems shared by client and server.
void asciichat_shared_destroy (void)
 Clean up shared library subsystems.
void fps_init (fps_t *tracker, int expected_fps, const char *name)
 Initialize FPS tracker.
void fps_init_with_interval (fps_t *tracker, int expected_fps, const char *name, uint64_t report_interval_ns)
 Initialize FPS tracker with custom report interval.
void fps_frame_ns (fps_t *tracker, uint64_t current_time_ns, const char *context)
 Track a frame and detect lag conditions (nanosecond version - PRIMARY).

Variables

int g_argc
 Global argc for early argument inspection (e.g., –color flag detection) Set by main() for access from lib/platform/terminal.c during early execution.
char ** g_argv
 Global argv for early argument inspection (e.g., –color flag detection) Set by main() for access from lib/platform/terminal.c during early execution.
bool g_color_flag_passed
 Was –color explicitly passed in command-line arguments? Set by options_init() before RCU is initialized, used by terminal_should_color_output().
bool g_color_flag_value
 Value of –color flag (true if –color was in argv) Set by options_init() before RCU is initialized, used by terminal_should_color_output().

Memory Debugging Macros

#define SAFE_MALLOC(size, cast)
#define SAFE_CALLOC(count, size, cast)
#define SAFE_REALLOC(ptr, size, cast)
#define TRACK_ALIGNED_ALLOC(ptr, size, file, line)
#define SAFE_MALLOC_ALIGNED(size, alignment, cast)
#define SAFE_MALLOC_SIMD(size, cast)
#define SAFE_CALLOC_SIMD(count, size, cast)
#define SAFE_FREE(ptr)
#define SAFE_MALLOC_DEFER_FREE(name, size, cast)
#define SAFE_CALLOC_DEFER_FREE(name, count, size, cast)
#define SAFE_FCLOSE(fp)
#define UNTRACKED_MALLOC(size, cast)
#define UNTRACKED_FREE(ptr)
#define SAFE_STRNCPY(dst, src, size)
#define SAFE_STRDUP(dst, src)
#define SAFE_GETENV(name)
#define SAFE_SSCANF(str, format, ...)
#define SAFE_STRERROR(errnum)
#define SAFE_MEMCPY(dest, dest_size, src, count)
#define SAFE_MEMSET(dest, dest_size, ch, count)
#define SAFE_MEMMOVE(dest, dest_size, src, count)
#define SAFE_STRCPY(dest, dest_size, src)
#define read_u16_unaligned   bytes_read_u16_unaligned
#define read_u32_unaligned   bytes_read_u32_unaligned
#define write_u16_unaligned   bytes_write_u16_unaligned
#define write_u32_unaligned   bytes_write_u32_unaligned
#define safe_size_mul   bytes_safe_size_mul
#define SAFE_SNPRINTF(buffer, buffer_size, ...)
#define SAFE_BUFFER_SIZE(buffer_size, offset)
 Safe buffer size calculation for snprintf.
#define THREAD_CREATE_OR_RETURN(thread, func, arg)
 Create a thread or log error and return.
#define MUTEX_INIT_OR_RETURN(m)
 Initialize a mutex or log error and return.

Detailed Description

⚙️ Code shared throughout the library

This header provides core functionality used throughout ascii-chat:

Note
This header should be included early in other headers as it provides fundamental types and macros that many other modules depend on.

Provides a reusable FPS tracking mechanism for monitoring real-time frame delivery rates across all client threads (data reception, webcam capture, audio capture, keepalive). Tracks frame intervals, detects lag conditions, and generates periodic FPS reports every 7-15 seconds.

USAGE:

fps_t tracker;
fps_init(&tracker, 60, "WEBCAM"); // 60 FPS expected
// In your frame processing loop
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
fps_frame(&tracker, &now, "frame received");
void fps_init(fps_t *tracker, int expected_fps, const char *name)
Initialize FPS tracker.
Definition fps.c:32
Counters and timestamps used to calculate and report frame rate.
Definition fps.h:53

FEATURES:

  • Automatic frame counting and interval measurement
  • Lag detection (when frames arrive late)
  • Periodic FPS report generation (configurable, default 10 seconds)
  • Configurable expected FPS and reporting interval
  • Thread-safe (caller must synchronize if needed)
  • Integrated across all major threads (data reception, webcam, audio, keepalive)
Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
December 2025
Version
2.0 (Refactored with unified thread tracking)

Macro Definition Documentation

◆ ALLOC_CALLOC

#define ALLOC_CALLOC ( count,
size )

#include <include/ascii-chat/common.h>

Value:
calloc((count), (size))

Definition at line 254 of file common.h.

Referenced by buffer_domain_create().

◆ ALLOC_FREE

#define ALLOC_FREE ( ptr)

#include <include/ascii-chat/common.h>

Value:
free(ptr)

Definition at line 256 of file common.h.

◆ ALLOC_MALLOC

#define ALLOC_MALLOC ( size)

#include <include/ascii-chat/common.h>

Value:
malloc(size)

Definition at line 253 of file common.h.

Referenced by buffer_acquire().

◆ ALLOC_REALLOC

#define ALLOC_REALLOC ( ptr,
size )

#include <include/ascii-chat/common.h>

Value:
realloc((ptr), (size))

Definition at line 255 of file common.h.

◆ ARRAY_SIZE

#define ARRAY_SIZE ( arr)

#include <include/ascii-chat/common.h>

Value:
(sizeof(arr) / sizeof((arr)[0]))

Calculate the number of elements in an array.

Definition at line 180 of file common.h.

Referenced by asciichat_error_stats_print(), options_preset_unified(), and ui_error_popup_preserve().

◆ ASCII_CHAT_APP_NAME

#define ASCII_CHAT_APP_NAME   "ascii-chat"

#include <include/ascii-chat/common.h>

Application name for key comments ("ascii-chat").

Definition at line 47 of file common.h.

Referenced by add_known_host().

◆ ASCIICHAT_CHECK_AND_LOG

#define ASCIICHAT_CHECK_AND_LOG ( expr,
ok_value,
msg,
... )

#include <include/ascii-chat/common.h>

Value:
do { \
if ((expr) != (ok_value)) { \
log_error(msg, ##__VA_ARGS__); \
return (expr); \
} \
} while (0)

Check result and log error if operation failed.

Consolidates the pattern:

operation_result_t result = operation();
if (result != OK) {
log_error("Operation failed: %d", result);
return result;
}
#define log_error(...)
Log an ERROR message.
Definition log/log.h:634

Usage:

ASCIICHAT_CHECK_AND_LOG(crypto_result = crypto_operation(args),
ASCIICHAT_OK, "Crypto operation failed: %d",
crypto_result);
action_args_t args
Definition actions.c:78
#define ASCIICHAT_CHECK_AND_LOG(expr, ok_value, msg,...)
Check result and log error if operation failed.
Definition common.h:644
@ ASCIICHAT_OK
Definition error_codes.h:46

Definition at line 644 of file common.h.

644#define ASCIICHAT_CHECK_AND_LOG(expr, ok_value, msg, ...) \
645 do { \
646 if ((expr) != (ok_value)) { \
647 log_error(msg, ##__VA_ARGS__); \
648 return (expr); \
649 } \
650 } while (0)

◆ FATAL

#define FATAL ( code,
... )

#include <include/ascii-chat/common.h>

Value:
asciichat_fatal_with_context(code, __FILE__, __LINE__, __func__, ##__VA_ARGS__)
void asciichat_fatal_with_context(asciichat_error_t code, const char *file, int line, const char *function, const char *format,...)

Exit with error code and custom message, with stack trace in debug builds.

Parameters
codeError code (asciichat_error_t)
...Custom message format string and arguments (printf-style)
Note
In debug builds, includes file, line, and function information. In release builds, file/line/function are omitted to reduce binary size.
Warning
This macro terminates the program. Use only for unrecoverable errors.
Example:
FATAL(ERROR_NETWORK_BIND, "Cannot bind to port %d", port_number);
#define FATAL(code,...)
Exit with error code and custom message, with stack trace in debug builds.
Definition common.h:160
@ ERROR_NETWORK_BIND
Definition error_codes.h:73

Definition at line 160 of file common.h.

Referenced by asciichat_fatal_with_context(), asciichat_shared_init(), debug_errno_cleanup_thread(), debug_stats_cleanup_thread(), main(), ob_reserve(), and server_main().

◆ MAX

#define MAX ( a,
b )

#include <include/ascii-chat/common.h>

Value:
((a) > (b) ? (a) : (b))

Return the maximum of two values.

Definition at line 175 of file common.h.

Referenced by receive_packet_secure_with_timeout(), session_display_write_ascii_frame(), and ui_error_popup_preserve().

◆ MIN

#define MIN ( a,
b )

#include <include/ascii-chat/common.h>

Value:
((a) < (b) ? (a) : (b))

Return the minimum of two values.

Definition at line 170 of file common.h.

Referenced by errno_notifications_snapshot(), network_server_create(), packet_decoder_feed(), session_display_write_ascii_frame(), ui_error_popup_preserve(), and ui_error_popup_render().

◆ MUTEX_INIT_OR_RETURN

#define MUTEX_INIT_OR_RETURN ( m)

#include <include/ascii-chat/common.h>

Value:
do { \
if (mutex_init(&(m)) != 0) { \
log_error("Failed to initialize mutex: %s", #m); \
return -1; \
} \
} while (0)

Initialize a mutex or log error and return.

Parameters
mPointer to mutex_t variable

Handles common pattern: init mutex, log error if failed, then return -1. Example usage:

MUTEX_INIT_OR_RETURN(mutex); // Mutex initialized successfully, continue

Definition at line 557 of file common.h.

557#define MUTEX_INIT_OR_RETURN(m) \
558 do { \
559 if (mutex_init(&(m)) != 0) { \
560 log_error("Failed to initialize mutex: %s", #m); \
561 return -1; \
562 } \
563 } while (0)

◆ NONSTRING

#define NONSTRING   /* nothing */

#include <include/ascii-chat/common.h>

Definition at line 102 of file common.h.

◆ PLATFORM_MAX_PATH_LENGTH

◆ read_u16_unaligned

#define read_u16_unaligned   bytes_read_u16_unaligned

#include <include/ascii-chat/common.h>

Definition at line 499 of file common.h.

◆ read_u32_unaligned

#define read_u32_unaligned   bytes_read_u32_unaligned

#include <include/ascii-chat/common.h>

Definition at line 500 of file common.h.

◆ RUN_BURST_AND_THROTTLE

#define RUN_BURST_AND_THROTTLE ( burst_ns,
throttle_ns,
code_block )

#include <include/ascii-chat/common.h>

Value:
do { \
static uint64_t burst_start = 0; \
uint64_t now = time_get_ns(); \
\
/* First call or timer reset */ \
if (burst_start == 0) { \
burst_start = now; \
code_block; \
} else { \
uint64_t elapsed_ns = now - burst_start; \
\
if (elapsed_ns < (uint64_t)(burst_ns)) { \
/* Within burst window */ \
code_block; \
} else if (elapsed_ns >= (uint64_t)(throttle_ns)) { \
/* Throttle period complete, reset and execute */ \
burst_start = now; \
code_block; \
} \
/* else: in throttle period, do nothing */ \
} \
} while (0)
unsigned long long uint64_t
Definition common.h:63

Definition at line 208 of file common.h.

208#define RUN_BURST_AND_THROTTLE(burst_ns, throttle_ns, code_block) \
209 do { \
210 static uint64_t burst_start = 0; \
211 uint64_t now = time_get_ns(); \
212 \
213 /* First call or timer reset */ \
214 if (burst_start == 0) { \
215 burst_start = now; \
216 code_block; \
217 } else { \
218 uint64_t elapsed_ns = now - burst_start; \
219 \
220 if (elapsed_ns < (uint64_t)(burst_ns)) { \
221 /* Within burst window */ \
222 code_block; \
223 } else if (elapsed_ns >= (uint64_t)(throttle_ns)) { \
224 /* Throttle period complete, reset and execute */ \
225 burst_start = now; \
226 code_block; \
227 } \
228 /* else: in throttle period, do nothing */ \
229 } \
230 } while (0)

◆ SAFE_BUFFER_SIZE

#define SAFE_BUFFER_SIZE ( buffer_size,
offset )

#include <include/ascii-chat/common.h>

Value:
((offset) < 0 || (size_t)(offset) >= (buffer_size) ? 0 : (buffer_size) - (size_t)(offset))
int buffer_size
Size of circular buffer.
Definition grep.c:68

Safe buffer size calculation for snprintf.

Casts offset to size_t to avoid sign conversion warnings when subtracting from buffer_size. Returns 0 if offset is negative or >= buffer_size (prevents underflow).

Definition at line 516 of file common.h.

516#define SAFE_BUFFER_SIZE(buffer_size, offset) \
517 ((offset) < 0 || (size_t)(offset) >= (buffer_size) ? 0 : (buffer_size) - (size_t)(offset))

◆ SAFE_CALLOC

#define SAFE_CALLOC ( count,
size,
cast )

#include <include/ascii-chat/common.h>

Value:
({ \
cast _ptr = (cast)ALLOC_CALLOC((count), (size)); \
if (!_ptr) { \
FATAL(ERROR_MEMORY, "Memory allocation failed: %zu elements x %zu bytes", (size_t)(count), (size_t)(size)); \
} \
_ptr; \
})
#define ALLOC_CALLOC(count, size)
Definition common.h:254
@ ERROR_MEMORY
Definition error_codes.h:51

Definition at line 275 of file common.h.

275#define SAFE_CALLOC(count, size, cast) \
276 ({ \
277 cast _ptr = (cast)ALLOC_CALLOC((count), (size)); \
278 if (!_ptr) { \
279 FATAL(ERROR_MEMORY, "Memory allocation failed: %zu elements x %zu bytes", (size_t)(count), (size_t)(size)); \
280 } \
281 _ptr; \
282 })

Referenced by acip_async_tcp_transport_create(), acip_outbound_create(), acip_security_init_options(), acip_tcp_transport_create(), acip_websocket_runtime_create(), ascii_create_grid(), ascii_render(), ascii_stabilizer_prepare(), asciichat_instr_runtime_get(), audio_processor_create(), audio_recording_create_channels(), client_audio_pipeline_create(), client_connection_create(), crypto_session_create(), digital_rain_init(), discovery_session_create(), face_follow_image_process(), ffmpeg_encoder_create_scaled(), fps_counter_create(), h265_client_context_create(), h265_decoder_create(), h265_server_context_create(), http2_connection_create(), http2_connection_submit_response(), http_renderer_init(), http_renderer_process(), http_renderer_submit(), http_response_retain(), http_server_http3_create(), http_server_init(), levenshtein_n(), mcp_request_parse(), mcp_server_main(), mixer_add_source(), mutex_stack_get_all_threads(), nat_upnp_open_protocol(), network_server_create(), options_get_enum_entries(), options_json_parse_value(), peer_crypto_create(), platform_event_listen(), platform_event_loop_create(), platform_event_loop_work(), platform_event_stream_work(), quic_connection_matches_cid(), quic_connection_submit_datagram(), quic_endpoint_open(), quic_udp_endpoint_create(), render_file_create(), render_progress_create(), render_progress_frame(), ringbuffer_create(), session_audio_create(), session_av_state_create(), session_capture_create(), session_consensus_create(), session_display_create(), session_host_create(), session_log_buffer_create(), session_network_capture_create(), session_participant_create(), session_pipeline_create(), simple_frame_swap_create(), spectral_create(), stats_runtime_peer_open(), stats_sampler_create(), stats_scope_create(), term_renderer_create(), terminal_fd_reader_create(), terminal_fd_writer_create(), test_pattern_create(), ui_password_prompt_present(), ui_session_create(), video_encoder_create(), webrtc_create_datachannel(), and webrtc_create_peer_connection().

◆ SAFE_CALLOC_DEFER_FREE

#define SAFE_CALLOC_DEFER_FREE ( name,
count,
size,
cast )

#include <include/ascii-chat/common.h>

Value:
cast name = SAFE_CALLOC(count, size, cast); \
defer(SAFE_FREE(name))
#define SAFE_FREE(ptr)
Definition common.h:377
#define SAFE_CALLOC(count, size, cast)
Definition common.h:275

Definition at line 389 of file common.h.

389#define SAFE_CALLOC_DEFER_FREE(name, count, size, cast) \
390 cast name = SAFE_CALLOC(count, size, cast); \
391 defer(SAFE_FREE(name))

Referenced by framebuffer_create(), framebuffer_create_multi(), levenshtein(), packet_queue_create_config(), video_frame_buffer_create(), and webrtc_create_peer_connection().

◆ SAFE_CALLOC_SIMD

#define SAFE_CALLOC_SIMD ( count,
size,
cast )

#include <include/ascii-chat/common.h>

Value:
({ \
size_t total_size = (count) * (size); \
cast _ptr = SAFE_MALLOC_SIMD(total_size, cast); \
memset(_ptr, 0, total_size); \
_ptr; \
})
#define SAFE_MALLOC_SIMD(size, cast)
Definition common.h:365

Definition at line 368 of file common.h.

368#define SAFE_CALLOC_SIMD(count, size, cast) \
369 ({ \
370 size_t total_size = (count) * (size); \
371 cast _ptr = SAFE_MALLOC_SIMD(total_size, cast); \
372 memset(_ptr, 0, total_size); \
373 _ptr; \
374 })

◆ SAFE_FCLOSE

#define SAFE_FCLOSE ( fp)

#include <include/ascii-chat/common.h>

Value:
do { \
if ((fp) != NULL) { \
fclose(fp); \
(fp) = NULL; \
} \
} while (0)

Definition at line 395 of file common.h.

395#define SAFE_FCLOSE(fp) \
396 do { \
397 if ((fp) != NULL) { \
398 fclose(fp); \
399 (fp) = NULL; \
400 } \
401 } while (0)

Referenced by add_known_host(), check_known_host_no_identity(), check_known_host_with_key(), config_create_default(), parse_keys_from_file(), parse_public_key(), remove_known_host(), and update_check_load_cache().

◆ SAFE_FREE

#define SAFE_FREE ( ptr)

#include <include/ascii-chat/common.h>

Value:
do { \
if ((ptr) != NULL) { \
ALLOC_FREE((void *)(ptr)); \
(ptr) = NULL; \
} \
} while (0)

Definition at line 377 of file common.h.

377#define SAFE_FREE(ptr) \
378 do { \
379 if ((ptr) != NULL) { \
380 ALLOC_FREE((void *)(ptr)); \
381 (ptr) = NULL; \
382 } \
383 } while (0)

Referenced by acds_identity_default_path(), acds_server_shutdown(), acds_strings_destroy(), acip_async_tcp_transport_create(), acip_outbound_create(), acip_outbound_destroy(), acip_render_settings_capabilities(), acip_security_cleanup(), acip_settings_request(), acip_settings_send(), acip_tcp_transport_create(), acip_transport_destroy(), acip_websocket_client_transport_create(), acip_websocket_runtime_create(), acip_websocket_runtime_destroy(), add_known_host(), ascii_convert(), ascii_convert_with_buffers_stabilized(), ascii_create_grid(), ascii_render(), ascii_stabilizer_prepare(), ascii_stabilizer_reset(), ascii_write(), asciichat_instr_runtime_destroy(), asciichat_instr_runtime_get(), asciichat_mdns_destroy(), asciichat_mdns_init(), audio_destroy(), audio_free_device_list(), audio_init(), audio_processor_create(), audio_processor_destroy(), audio_recording_destroy(), audio_visualization_render_fft(), audio_visualization_render_waveform(), buffer_domain_create(), check_known_host_no_identity(), check_known_host_with_key(), client_audio_pipeline_create(), client_audio_pipeline_destroy(), client_audio_render_thread(), client_connection_destroy(), client_settings_receive(), client_settings_values(), client_video_render_thread(), colorscheme_cleanup_compiled(), completions_collect_all_modes_unique(), completions_generate_fish(), completions_generate_powershell(), completions_generate_zsh(), config_create_default(), config_load_and_apply(), config_schema_build_from_configs(), config_schema_destroy(), consensus_coordinator_create(), consensus_coordinator_destroy(), consensus_election_choose_hosts(), consensus_metrics_collection_add(), consensus_metrics_collection_destroy(), consensus_state_destroy(), consensus_topology_create(), consensus_topology_destroy(), create_mixed_ascii_frame_for_client(), crypto_handshake_server_start(), crypto_regex_match_known_hosts(), crypto_regex_match_public_key(), crypto_session_create(), crypto_session_destroy(), detect_client_utf8_support(), detect_default_ssh_key(), digital_rain_destroy(), digital_rain_init(), digital_rain_render_at(), discover_session_parallel(), discovery_keys_get_cache_path(), discovery_mdns_destroy(), discovery_session_create(), discovery_session_destroy(), display_height(), display_width(), ducking_destroy(), ducking_init(), face_follow_image_destroy(), fetch_github_gpg_keys(), fetch_github_ssh_keys(), fetch_gitlab_gpg_keys(), fetch_gitlab_ssh_keys(), ffmpeg_decoder_create_stdin(), ffmpeg_decoder_create_with_request_options(), ffmpeg_decoder_destroy(), ffmpeg_encoder_create_scaled(), format_message(), fps_counter_destroy(), frame_buffer_append(), frame_buffer_create(), frame_buffer_destroy(), frame_buffer_flush(), frame_buffer_printf(), framebuffer_destroy(), get_discovery_database_dir(), get_known_hosts_path(), get_log_dir(), gpg_get_public_key(), gpg_homedir_destroy(), grep_destroy(), grep_init(), grep_restore_patterns(), grep_save_patterns(), grep_should_output(), h265_client_context_create(), h265_client_context_destroy(), h265_client_init_media_source(), h265_decoder_destroy(), h265_encoder_destroy(), h265_server_context_destroy(), handle_audio_batch_packet(), handle_audio_opus_batch_packet(), handle_audio_packet(), handle_image_frame_h265_packet(), handle_image_frame_packet(), http2_connection_create(), http2_connection_destroy(), http2_connection_submit_response(), http_render_result_destroy(), http_renderer_destroy(), http_renderer_init(), http_renderer_process(), http_renderer_process_result_destroy(), http_renderer_reap(), http_renderer_submit(), http_response_finish(), http_response_release(), http_response_retain(), http_server_destroy(), http_server_dispatch_http3(), http_server_http3_destroy(), http_server_init(), https_get(), initial_options(), keyboard_help_toggle_terminal(), known_hosts_destroy(), layout_print_two_column_row(), levenshtein_n(), log_mmap_write(), log_net_message(), log_search_filter_buffer(), manpage_content_free_environment(), manpage_content_free_examples(), manpage_content_free_options(), manpage_content_free_positional(), manpage_content_free_usage(), manpage_content_generate_environment_with_manual(), manpage_content_generate_examples(), manpage_content_generate_options(), manpage_merger_free_content(), manpage_parser_free_sections(), manpage_resources_destroy(), mcp_request_destroy(), mcp_server_main(), mcp_stdio_run(), media_source_create_interruptible(), media_source_destroy(), memory_backend_create(), mirror_convert_frame(), mirror_free_string(), mirror_render_audio_visualization(), mixer_add_source(), mixer_create_channels(), mixer_destroy(), mixer_remove_source(), mutex_stack_free_all_threads(), mutex_stack_get_all_threads(), nat_upnp_close(), nat_upnp_open_protocol(), network_server_create(), network_server_destroy(), openpgp_base64_decode(), openpgp_parse_armored_pubkey(), openpgp_parse_armored_seckey(), options_apply_patch(), options_init(), options_json_parse_value(), options_state_destroy(), opus_codec_create_decoder_channels(), opus_codec_create_encoder_channels(), opus_codec_destroy(), packet_queue_destroy(), packet_send_error(), packet_send_remote_log(), parse_gpg_key_binary(), parse_gpg_keys_from_response(), parse_keys_from_file(), parse_log_file(), parse_private_key(), parse_public_key(), parse_public_keys(), parse_ssh_ed25519_line(), parse_ssh_keys_from_response(), parse_ssh_private_key(), path_validate_user_path(), peer_crypto_destroy(), peer_crypto_output_pop(), platform_event_listen(), platform_event_loop_create(), platform_event_loop_destroy(), platform_event_loop_work(), platform_event_stream_close(), platform_event_stream_work(), platform_event_stream_write(), quic_connection_destroy(), quic_connection_matches_cid(), quic_endpoint_destroy(), quic_endpoint_open(), quic_release(), quic_tls_destroy(), quic_transport_destroy_unclaimed_on_lane(), quic_udp_connect(), quic_udp_endpoint_create(), quic_udp_endpoint_destroy(), quic_udp_remove(), quic_worker_stop(), read_password_from_stdin(), remove_known_host(), render_file_create(), render_file_destroy(), render_progress_create(), render_progress_destroy(), render_progress_frame(), ringbuffer_destroy(), sdp_session_destroy(), session_audio_create(), session_audio_destroy(), session_av_state_destroy(), session_capture_create(), session_capture_destroy(), session_consensus_create(), session_consensus_destroy(), session_display_destroy(), session_display_encode_frame(), session_display_release_ascii(), session_display_render_frame(), session_display_write_ascii_frame(), session_entry_destroy(), session_host_create(), session_host_destroy(), session_log_buffer_destroy(), session_network_capture_create(), session_participant_create(), session_participant_destroy(), session_participant_receive_settings(), session_participant_request_settings(), session_pipeline_create(), session_pipeline_destroy(), session_protocol_dispatch(), session_settings_from_options(), simd_caches_destroy_all(), simple_frame_swap_destroy(), spectral_destroy(), ssh_agent_sign(), stats_runtime_peer_close(), stats_runtime_peer_open(), stats_sampler_create(), stats_sampler_destroy(), stats_scope_create(), stats_scope_destroy(), term_renderer_create(), term_renderer_destroy(), term_renderer_feed(), terminal_fd_reader_destroy(), terminal_fd_reader_next(), terminal_fd_writer_destroy(), terminal_screen_compose(), terminal_screen_render(), test_pattern_destroy(), test_pattern_resize(), thread_pool_create(), thread_pool_create_with_workers(), thread_pool_destroy(), thread_pool_spawn(), thread_pool_stop_all(), timer_start(), timer_stop(), timer_system_destroy(), ui_notice_present(), ui_notice_present_first_use(), ui_password_prompt_present(), ui_prompt_present_kind(), ui_session_destroy(), ui_session_help_free(), update_check_load_cache(), update_check_perform(), update_check_save_cache(), url_parse(), url_parts_destroy(), utf8_palette_create(), utf8_palette_destroy(), validate_options_and_report(), validate_ssh_key_file(), video_frame_buffer_destroy(), wav_writer_close(), wav_writer_open(), webrtc_close_peer_connection(), webrtc_create_peer_connection(), webrtc_datachannel_destroy(), webrtc_peer_connection_destroy(), webrtc_peer_manager_create(), webrtc_peer_manager_destroy(), webrtc_peer_manager_handle_sdp(), and zalgo_apply().

◆ SAFE_GETENV

◆ SAFE_MALLOC

#define SAFE_MALLOC ( size,
cast )

#include <include/ascii-chat/common.h>

Value:
({ \
cast _ptr = (cast)ALLOC_MALLOC(size); \
if (!_ptr) { \
FATAL(ERROR_MEMORY, "Memory allocation failed: %zu bytes", (size_t)(size)); \
} \
_ptr; \
})
#define ALLOC_MALLOC(size)
Definition common.h:253

Definition at line 265 of file common.h.

265#define SAFE_MALLOC(size, cast) \
266 ({ \
267 cast _ptr = (cast)ALLOC_MALLOC(size); \
268 if (!_ptr) { \
269 FATAL(ERROR_MEMORY, "Memory allocation failed: %zu bytes", (size_t)(size)); \
270 } \
271 _ptr; \
272 })

Referenced by acip_render_settings_capabilities(), acip_settings_request(), acip_tcp_transport_create(), add_known_host(), ansi_strip_escapes(), ascii_create_grid(), ascii_pad_frame_height(), ascii_pad_frame_width(), ascii_write(), asciichat_mdns_init(), asciichat_pcre2_extract_group(), asciichat_pcre2_extract_named_group(), audio_init(), audio_visualization_render_fft(), audio_visualization_render_waveform(), client_audio_render_thread(), client_settings_receive(), client_settings_values(), colorscheme_compile_scheme(), config_create_default(), config_load_and_apply(), config_schema_build_from_configs(), consensus_coordinator_create(), consensus_election_choose_hosts(), consensus_metrics_collection_add(), consensus_metrics_collection_create(), consensus_state_create(), consensus_topology_create(), crypto_handshake_server_start(), digital_rain_render_at(), discover_session_parallel(), discovery_mdns_query(), ducking_init(), expand_path(), ffmpeg_decoder_create_stdin(), ffmpeg_decoder_create_with_request_options(), format_message(), frame_buffer_append(), frame_buffer_create(), frame_buffer_flush(), frame_buffer_printf(), get_known_hosts_path(), get_log_dir(), get_modes_by_group(), get_utf8_palette_cache(), grep_highlight_colored_copy(), grep_init(), grep_should_output(), h265_client_context_create(), h265_client_init_media_source(), handle_audio_batch_packet(), handle_audio_opus_batch_packet(), handle_audio_packet(), handle_image_frame_h265_packet(), http2_connection_submit_response(), http_render_result_add_text_frame(), http_renderer_process(), http_renderer_render_file(), http_response_finish(), http_response_retain(), initial_options(), log_search_filter_buffer(), manpage_content_generate_environment(), manpage_content_generate_environment_with_manual(), manpage_content_generate_examples(), manpage_content_generate_options(), manpage_content_generate_positional(), manpage_content_generate_usage(), manpage_merger_generate_synopsis(), manpage_merger_generate_usage(), manpage_merger_merge_environment(), manpage_merger_merge_options(), manpage_merger_merge_positional(), mcp_stdio_run(), media_source_create_interruptible(), memory_backend_create(), mirror_convert_frame(), mixer_add_source(), mixer_create_channels(), mutex_stack_get_all_threads(), openpgp_base64_decode(), options_apply_patch(), options_get_enum_values(), options_registry_get_binary_options(), options_registry_get_for_display(), options_registry_get_for_mode(), options_state_init(), options_state_set(), opus_codec_create_decoder_channels(), opus_codec_create_encoder_channels(), packet_send_error(), packet_send_remote_log(), parse_gpg_key_binary(), parse_gpg_keys_from_response(), parse_public_keys(), parse_ssh_keys_from_response(), path_validate_user_path(), platform_event_stream_write(), rainbow_render_ansi_at(), read_password_from_stdin(), render_file_create(), sdp_generate_answer(), sdp_generate_offer(), sdp_parse(), session_capture_create(), session_display_write_ascii_frame(), session_network_capture_create(), session_participant_receive_settings(), session_participant_request_settings(), session_protocol_dispatch(), session_settings_from_options(), simple_frame_swap_create(), ssh_agent_sign(), term_renderer_create(), term_renderer_feed(), terminal_fd_reader_create(), terminal_fd_reader_next(), terminal_screen_compose(), terminal_screen_render(), test_pattern_rgba(), thread_pool_create(), thread_pool_create_with_workers(), thread_pool_queue_work(), thread_pool_spawn(), timer_start(), ui_notice_present(), ui_notice_present_first_use(), ui_prompt_present_kind(), ui_session_context_help_render(), ui_session_help_render(), utf8_palette_create(), video_encoder_create(), visualization_encode(), wav_writer_open(), webrtc_create_peer_connection(), webrtc_peer_manager_create(), webrtc_peer_manager_handle_sdp(), and zalgo_apply().

◆ SAFE_MALLOC_ALIGNED

#define SAFE_MALLOC_ALIGNED ( size,
alignment,
cast )

#include <include/ascii-chat/common.h>

Value:
({ \
size_t aligned_size = (((size) + (alignment) - 1) / (alignment)) * (alignment); \
cast _ptr = (cast)aligned_alloc((alignment), aligned_size); \
if (!_ptr) { \
FATAL(ERROR_MEMORY, "Aligned memory allocation failed: %zu bytes, %zu alignment", aligned_size, \
(size_t)(alignment)); \
} \
TRACK_ALIGNED_ALLOC(_ptr, aligned_size, __FILE__, __LINE__); \
_ptr; \
})

Definition at line 350 of file common.h.

350#define SAFE_MALLOC_ALIGNED(size, alignment, cast) \
351 ({ \
352 size_t aligned_size = (((size) + (alignment) - 1) / (alignment)) * (alignment); \
353 cast _ptr = (cast)aligned_alloc((alignment), aligned_size); \
354 if (!_ptr) { \
355 FATAL(ERROR_MEMORY, "Aligned memory allocation failed: %zu bytes, %zu alignment", aligned_size, \
356 (size_t)(alignment)); \
357 } \
358 TRACK_ALIGNED_ALLOC(_ptr, aligned_size, __FILE__, __LINE__); \
359 _ptr; \
360 })

◆ SAFE_MALLOC_DEFER_FREE

#define SAFE_MALLOC_DEFER_FREE ( name,
size,
cast )

#include <include/ascii-chat/common.h>

Value:
cast name = SAFE_MALLOC(size, cast); \
defer(SAFE_FREE(name))
#define SAFE_MALLOC(size, cast)
Definition common.h:265

Definition at line 386 of file common.h.

386#define SAFE_MALLOC_DEFER_FREE(name, size, cast) \
387 cast name = SAFE_MALLOC(size, cast); \
388 defer(SAFE_FREE(name))

Referenced by crypto_handshake_client_key_exchange(), crypto_handshake_server_auth_challenge(), gpg_homedir_create(), https_get(), levenshtein(), openpgp_base64_decode(), parse_keys_from_file(), parse_private_key(), parse_public_key(), session_protocol_update_settings(), video_frame_buffer_create(), and zalgo_apply().

◆ SAFE_MALLOC_SIMD

#define SAFE_MALLOC_SIMD ( size,
cast )

#include <include/ascii-chat/common.h>

Value:
SAFE_MALLOC_ALIGNED(size, 16, cast)
#define SAFE_MALLOC_ALIGNED(size, alignment, cast)
Definition common.h:350

Definition at line 365 of file common.h.

◆ SAFE_MEMCPY

◆ SAFE_MEMMOVE

#define SAFE_MEMMOVE ( dest,
dest_size,
src,
count )

#include <include/ascii-chat/common.h>

Value:
platform_memmove((dest), (dest_size), (src), (count))
asciichat_error_t platform_memmove(void *dest, size_t dest_size, const void *src, size_t count)
Platform-safe memmove wrapper.

Definition at line 485 of file common.h.

◆ SAFE_MEMSET

#define SAFE_MEMSET ( dest,
dest_size,
ch,
count )

◆ SAFE_REALLOC

#define SAFE_REALLOC ( ptr,
size,
cast )

#include <include/ascii-chat/common.h>

Value:
({ \
void *tmp_ptr = ALLOC_REALLOC((ptr), (size)); \
if (!tmp_ptr) { \
FATAL(ERROR_MEMORY, "Memory reallocation failed: %zu bytes", (size_t)(size)); \
} \
(cast)(tmp_ptr); \
})
#define ALLOC_REALLOC(ptr, size)
Definition common.h:255

Definition at line 285 of file common.h.

285#define SAFE_REALLOC(ptr, size, cast) \
286 ({ \
287 void *tmp_ptr = ALLOC_REALLOC((ptr), (size)); \
288 if (!tmp_ptr) { \
289 FATAL(ERROR_MEMORY, "Memory reallocation failed: %zu bytes", (size_t)(size)); \
290 } \
291 (cast)(tmp_ptr); \
292 })

Referenced by completions_collect_all_modes_unique(), consensus_state_add_metrics(), grep_init(), http_response_write(), https_get(), manpage_content_generate_environment(), manpage_content_generate_environment_with_manual(), manpage_content_generate_examples(), manpage_content_generate_options(), manpage_content_generate_positional(), manpage_content_generate_usage(), manpage_merger_generate_usage(), ob_reserve(), remove_known_host(), and session_display_write_ascii_frame().

◆ safe_size_mul

#define safe_size_mul   bytes_safe_size_mul

◆ SAFE_SNPRINTF

◆ SAFE_SSCANF

#define SAFE_SSCANF ( str,
format,
... )

#include <include/ascii-chat/common.h>

Value:
sscanf(str, format, __VA_ARGS__)

Definition at line 455 of file common.h.

Referenced by parse_hex_color().

◆ SAFE_STRCPY

#define SAFE_STRCPY ( dest,
dest_size,
src )

#include <include/ascii-chat/common.h>

Value:
platform_strcpy((dest), (dest_size), (src))
asciichat_error_t platform_strcpy(char *dest, size_t dest_size, const char *src)
Platform-safe strcpy wrapper.

Definition at line 486 of file common.h.

Referenced by h265_client_init_media_source(), log_named_format_or_original(), main(), mixer_add_source(), and video_frame_buffer_create().

◆ SAFE_STRDUP

#define SAFE_STRDUP ( dst,
src )

#include <include/ascii-chat/common.h>

Value:
do { \
if (src) { \
size_t _len = strlen(src) + 1; \
(dst) = SAFE_MALLOC(_len, char *); \
if (dst) { \
SAFE_MEMCPY((dst), _len, (src), _len); \
} else { \
SET_ERRNO(ERROR_MEMORY, "String duplication failed for: %s", (src)); \
} \
} else { \
(dst) = NULL; \
} \
} while (0)

Definition at line 433 of file common.h.

433#define SAFE_STRDUP(dst, src) \
434 do { \
435 if (src) { \
436 size_t _len = strlen(src) + 1; \
437 (dst) = SAFE_MALLOC(_len, char *); \
438 if (dst) { \
439 SAFE_MEMCPY((dst), _len, (src), _len); \
440 } else { \
441 SET_ERRNO(ERROR_MEMORY, "String duplication failed for: %s", (src)); \
442 } \
443 } else { \
444 (dst) = NULL; \
445 } \
446 } while (0)

Referenced by detect_client_utf8_support(), and url_parse().

◆ SAFE_STRERROR

#define SAFE_STRERROR ( errnum)

#include <include/ascii-chat/common.h>

Value:
const char * platform_strerror(int errnum)
Get human-readable error message for a system error code.

Definition at line 480 of file common.h.

Referenced by acip_tcp_transport_create(), gpg_sign_with_key(), gpg_verify_signature_with_binary(), and packet_send().

◆ SAFE_STRNCPY

#define SAFE_STRNCPY ( dst,
src,
size )

#include <include/ascii-chat/common.h>

Value:
do { \
size_t _safe_strncpy_size = (size); \
if (_safe_strncpy_size > 0) { \
(void)platform_strncpy((dst), _safe_strncpy_size, (src), _safe_strncpy_size - 1); \
} \
} while (0)

Definition at line 423 of file common.h.

423#define SAFE_STRNCPY(dst, src, size) \
424 do { \
425 size_t _safe_strncpy_size = (size); \
426 if (_safe_strncpy_size > 0) { \
427 (void)platform_strncpy((dst), _safe_strncpy_size, (src), _safe_strncpy_size - 1); \
428 } \
429 } while (0)

Referenced by acds_client_config_init_defaults(), acds_identity_save(), acds_protocol_create(), acds_protocol_enter(), acds_protocol_join(), acds_protocol_lookup(), acds_protocol_receive(), acds_session_create(), acds_session_join(), acip_render_settings_capabilities(), acip_render_settings_options(), acip_render_settings_prepare(), acip_security_init_options(), asciichat_instr_log_line(), asciichat_mdns_advertise(), asciichat_mdns_query(), build_github_gpg_url(), build_gitlab_gpg_url(), client_audio_render_thread(), client_configure_crypto_options(), client_crypto_init(), client_main(), client_set_server_address(), client_video_render_thread(), colorscheme_compile_scheme(), colorscheme_load_from_file(), config_create_default(), config_schema_build_from_configs(), connection_endpoint_resolve(), crypto_handshake_init_with_password(), database_session_join(), database_session_leave(), detect_client_utf8_support(), disconnect_client_for_bad_data(), discovery_config_init_defaults(), discovery_main(), discovery_session_create(), env_pop_prompt_response(), extract_gpg_key_comment(), extract_ip_from_address(), format_gpg_key_display(), format_ip_with_port(), get_utf8_palette_cache(), gpg_get_public_key(), grep_highlight_colored(), handle_client_join_packet(), http_render_result_add_file_frame(), http_renderer_process(), is_valid_ipv4(), is_valid_ipv6(), layout_print_wrapped_description(), log_init(), log_mmap_init(), log_recolor_plain_entry(), log_search_get_match_info(), log_search_init(), main(), mcp_dispatch(), mcp_request_parse(), mcp_server_main(), mirror_convert_frame(), nat_upnp_get_endpoint(), nat_upnp_open_protocol(), negotiate_determine_result(), network_connection_prepare_security(), options_collect_identity_keys(), options_json_parse_value(), options_t_new(), parse_address_with_optional_port(), parse_gpg_keys_from_response(), parse_ip_with_port(), parse_log_file(), parse_palette_chars(), parse_palette_chars_option(), path_validate_user_path(), render_file_create(), sdp_generate_answer(), sdp_parse(), send_error_packet_message(), server_connection_set_ip(), session_host_add_client(), session_host_add_memory_participant(), session_host_create(), session_host_find_client(), session_participant_connect(), session_participant_create(), session_protocol_build_capabilities(), session_settings_from_values(), session_settings_to_options(), splash_set_discovery_session(), splash_set_update_notification(), TerminalRendererBinding::TerminalRendererBinding(), thread_pool_create(), thread_pool_create_with_workers(), thread_pool_spawn(), time_pretty(), timer_start(), ui_session_loading(), ui_status_gather(), ui_status_render_header(), update_check_load_cache(), update_check_perform(), utf8_palette_create(), and webrtc_turn_servers_parse().

◆ THREAD_CREATE_OR_RETURN

#define THREAD_CREATE_OR_RETURN ( thread,
func,
arg )

#include <include/ascii-chat/common.h>

Value:
do { \
if (platform_thread_create(&(thread), (func), (arg)) != 0) { \
log_error("Failed to create thread: %s", #func); \
return -1; \
} \
} while (0)

Create a thread or log error and return.

Parameters
threadPointer to thread_t variable
funcThread function (should match void* (*)(void*) signature)
argThread argument

Handles common pattern: create thread, log error if failed, then return -1. Example usage:

THREAD_CREATE_OR_RETURN(thread, thread_func, arg); // Thread created successfully, continue

Definition at line 537 of file common.h.

537#define THREAD_CREATE_OR_RETURN(thread, func, arg) \
538 do { \
539 if (platform_thread_create(&(thread), (func), (arg)) != 0) { \
540 log_error("Failed to create thread: %s", #func); \
541 return -1; \
542 } \
543 } while (0)

◆ TRACK_ALIGNED_ALLOC

#define TRACK_ALIGNED_ALLOC ( ptr,
size,
file,
line )

#include <include/ascii-chat/common.h>

Value:
((void)0)

Definition at line 304 of file common.h.

◆ UNTRACKED_FREE

#define UNTRACKED_FREE ( ptr)

#include <include/ascii-chat/common.h>

Value:
do { \
if ((ptr) != NULL) { \
free((void *)(ptr)); \
(ptr) = NULL; \
} \
} while (0)

Definition at line 414 of file common.h.

414#define UNTRACKED_FREE(ptr) \
415 do { \
416 if ((ptr) != NULL) { \
417 free((void *)(ptr)); \
418 (ptr) = NULL; \
419 } \
420 } while (0)

Referenced by debug_sync_check_cond_deadlocks(), named_registry_for_each(), named_update_name(), and ui_sync_stop().

◆ UNTRACKED_MALLOC

#define UNTRACKED_MALLOC ( size,
cast )

#include <include/ascii-chat/common.h>

Value:
({ \
cast _ptr = (cast)malloc(size); \
if (!_ptr) { \
FATAL(ERROR_MEMORY, "Memory allocation failed: %zu bytes", (size_t)(size)); \
} \
_ptr; \
})

Definition at line 405 of file common.h.

405#define UNTRACKED_MALLOC(size, cast) \
406 ({ \
407 cast _ptr = (cast)malloc(size); \
408 if (!_ptr) { \
409 FATAL(ERROR_MEMORY, "Memory allocation failed: %zu bytes", (size_t)(size)); \
410 } \
411 _ptr; \
412 })

Referenced by debug_sync_check_cond_deadlocks(), and named_registry_for_each().

◆ write_u16_unaligned

#define write_u16_unaligned   bytes_write_u16_unaligned

#include <include/ascii-chat/common.h>

Definition at line 501 of file common.h.

◆ write_u32_unaligned

#define write_u32_unaligned   bytes_write_u32_unaligned

#include <include/ascii-chat/common.h>

Definition at line 502 of file common.h.

Typedef Documentation

◆ uint16_t

typedef unsigned short uint16_t

#include <include/ascii-chat/common.h>

Definition at line 61 of file common.h.

◆ uint32_t

typedef unsigned int uint32_t

#include <include/ascii-chat/common.h>

Definition at line 62 of file common.h.

◆ uint64_t

typedef unsigned long long uint64_t

#include <include/ascii-chat/common.h>

Definition at line 63 of file common.h.

◆ uint8_t

typedef unsigned char uint8_t

#include <include/ascii-chat/common.h>

Definition at line 60 of file common.h.

Function Documentation

◆ asciichat_fatal_with_context()

void asciichat_fatal_with_context ( asciichat_error_t code,
const char * file,
int line,
const char * function,
const char * format,
... )

#include <include/ascii-chat/common.h>

Definition at line 884 of file asciichat_errno.c.

885 {
886 // This path must also work when an allocator or a diagnostic itself failed.
887 bool previous = g_recording;
888 g_recording = true;
889 char message[ASCIICHAT_ERRNO_MESSAGE_MAX];
890 va_list args;
891 va_start(args, format);
892 vsnprintf(message, sizeof(message), format ? format : "", args);
893 va_end(args);
894 NOTICE(FATAL, "FATAL ERROR", "%s", asciichat_error_format(message, code));
895 log_error("Fatal: %s (at %s:%d in %s)", asciichat_error_format(message, code), file ? file : "?", line,
896 function ? function : "?");
898 g_recording = previous;
899#ifdef EMSCRIPTEN_BUILD
900 SET_ERRNO(code, "%s", message);
901#else
902 exit(code);
903#endif
904}
const char * asciichat_error_format(const char *message, asciichat_error_t code)
void errno_print_stacks(void)
#define ASCIICHAT_ERRNO_MESSAGE_MAX
#define SET_ERRNO(code,...)
#define NOTICE(severity, title,...)
Definition notice.h:68

References args, ASCIICHAT_ERRNO_MESSAGE_MAX, asciichat_error_format(), errno_print_stacks(), FATAL, log_error, NOTICE, and SET_ERRNO.

◆ asciichat_shared_destroy()

void asciichat_shared_destroy ( void )

#include <include/ascii-chat/common.h>

Clean up shared library subsystems.

Performs cleanup of all subsystems initialized by asciichat_shared_init(). All cleanup functions are idempotent and safe to call multiple times.

Applications should typically register this with atexit(): asciichat_shared_init(log_file, is_client); atexit(asciichat_shared_destroy);

Note
This function is safe to call even if init failed or wasn't called.
Cleanup order is the reverse of initialization order.
Library code never calls atexit() - only application code should.

Clean up shared library subsystems.

Performs comprehensive cleanup of all subsystems initialized by asciichat_shared_init(). All cleanup functions are idempotent (safe to call multiple times), so this can be called explicitly and also via atexit() without issues.

Cleanup order is carefully chosen to be the reverse of initialization, ensuring dependencies are respected (e.g., timer cleanup before memory reporting, memory reporting before errno cleanup).

Note
This function is safe to call even if init failed or wasn't called.
All subsystem cleanup functions must remain idempotent.

Definition at line 217 of file common.c.

217 {
218 // Guard against double cleanup (can be called explicitly + via atexit)
219 static bool shutdown_done = false;
220 if (shutdown_done) {
221 return;
222 }
223 shutdown_done = true;
224
225 // Stop diagnostic readers before destroying symbols or synchronization state.
226 debug_sync_cleanup_thread();
229
235
236 // Cleanup in reverse order of initialization (LIFO)
237 // This ensures dependencies are properly handled
238
239 // 0. Stop background threads first (before any cleanup that might use them)
240 // Terminal resize detection thread (Windows only, checks if active)
241 terminal_stop_resize_detection();
242
243#ifndef NDEBUG
244
245 // Clean up all remaining mutex stacks before memory report
247
248 // Clean up current thread's allocations
249 debug_sync_final_cleanup();
250
251 // Atomic debug cleanup
252 debug_atomic_shutdown();
253#endif
254 debug_sync_destroy();
257
258 // 1. Terminal screen - cleanup frame buffer
260
261 // 2. SIMD caches - cleanup CPU-specific caches
263
264 // 3. Discovery service strings cache - cleanup session string cache
266
267 // 4. Logging - in correct order (end first, then begin)
270
271 // 5. Known hosts - cleanup authentication state
273
274 // 6. Options state - cleanup RCU-based options
276
277 // 7. buffer domain - cleanup global buffer domain
279
280 // 8. Platform cleanup - restores terminal, cleans up platform resources
281 // (includes symbol cache cleanup on Windows)
283
284 // 9. Keyboard - restore terminal settings (redundant with platform_destroy but safe)
286
287 // Workers have stopped; restore argv/environment before releasing title storage.
289
290 // 10. Timer system - cleanup timers (may still log!)
292
293 // 11. Error context cleanup
295
296 // 12. Logging cleanup - free log format buffers and system state
297 log_destroy();
300
301 // 13. Mutex stack cleanup - must be before memory report so stacks are freed
302#ifndef NDEBUG
304 // Final cleanup: free the main thread's debug allocations
305 debug_sync_final_cleanup();
306#endif
307
308 // 14. Memory stats (debug builds only) - runs with colors still available
309 // Note: debug_memory_report() is also called manually during shutdown in server_main()
310 // The function is safe to call multiple times with polling-based locking
311#if defined(USE_MIMALLOC_DEBUG) && !defined(NDEBUG)
312 print_mimalloc_stats();
313#endif
314
315#if defined(DEBUG_MEMORY) && !defined(NDEBUG)
316 debug_memory_report(GET_OPTION(color));
317#endif
318
319 // 15. Color cleanup - free compiled ANSI strings (AFTER memory report)
322
323 // 16. Clean up binary path cache explicitly
324 // Note: This is also called by platform_destroy() via atexit(), but it's idempotent
325 platform_cleanup_binary_path_cache();
326
327 // 17. Clean up RCU-based options state
329
330 // 18. Clean up errno context (allocated strings, backtrace symbols)
332
333#ifndef NDEBUG
334 // 19. Named registry - cleanup all registered thread names and debug entries
336#endif
337
338 // 21. timer resolution restore
339 platform_restore_timer_resolution(); // Restore timer resolution (no-op on POSIX)
340
341 // 22. Clean up SIMD caches
343
344 // 23. Clean up symbol cache
345 // This must be called BEFORE log_destroy() as symbol_cache_destroy() uses log_debug()
346 // Safe to call even if atexit() runs - it's idempotent (checks g_symbol_cache_initialized)
347 // Also called via platform_destroy() atexit handler, but explicit call ensures proper ordering
349
350 // 24. Clean up global buffer domain (explicitly, as atexit may not run on Ctrl-C)
351 // Note: This is also registered with atexit(), but calling it explicitly is safe (idempotent)
352 // Safe to call even if atexit() runs - it checks the default domain and sets it to NULL
354
355#ifndef NDEBUG
356 // 25. Symbol cache cleanup
358#endif
359 // No more shutdown diagnostics may scroll pending terminal errors away.
361}
void sanitizer_log_destroy(void)
Definition asan.c:52
void errno_shutdown(void)
void errno_destroy(void)
void buffer_system_cleanup(void)
Definition buffer.c:428
void colorscheme_destroy(void)
Shutdown the color system.
void acds_strings_destroy(void)
Cleanup function for session string cache Called by asciichat_shared_destroy() during library cleanup...
void debug_errno_destroy(void)
Definition errno.c:125
void debug_errno_cleanup_thread(void)
Definition errno.c:110
void ui_error_popup_flush(void)
void known_hosts_destroy(void)
Cleanup function to free cached known_hosts path.
void named_destroy(void)
Destroy the named object registry.
void log_shutdown_end(void)
End shutdown phase - restore previous logging settings.
Definition log.c:2018
void log_destroy(void)
Destroy the logging system and close log file.
Definition log.c:667
void log_cleanup_colors(void)
Clean up compiled color scheme.
Definition log.c:2034
void log_shutdown_begin(void)
Begin shutdown phase - disable console logging but keep file logging.
Definition log.c:2007
void log_system_destroy(void)
Shutdown the logging system internal state (system-level cleanup).
Definition log.c:729
void timer_system_destroy(void)
Cleanup the timing system.
Definition time.c:177
#define GET_OPTION(field)
Safely get a specific option field (lock-free read).
Definition options.h:1336
void platform_destroy(void)
Cleanup platform-specific subsystems.
void keyboard_destroy(void)
Cleanup keyboard input system and restore terminal.
void symbol_cache_destroy(void)
Clean up the symbol cache and free all resources.
asciichat_error_t platform_restore_timer_resolution(void)
Restore default timer precision.
void platform_process_title_destroy(void)
Restore Unix argument storage and release title allocations.
void simd_caches_destroy_all(void)
Destroy all SIMD caches (palette and other caches).
void debug_stats_cleanup_thread(void)
void debug_stats_destroy(void)
void mutex_stack_cleanup(void)
Cleanup mutex stack system.
Definition mutex.c:980
void options_state_destroy(void)
Shutdown RCU options system.
Definition rcu.c:476
void stats_runtime_stop(void)
Definition runtime.c:639
void terminal_screen_cleanup(void)
Clean up terminal screen resources.
void ui_controller_shutdown(void)
void ui_input_shutdown(void)
Definition tui/input.c:565

References acds_strings_destroy(), buffer_system_cleanup(), colorscheme_destroy(), debug_errno_cleanup_thread(), debug_errno_destroy(), debug_stats_cleanup_thread(), debug_stats_destroy(), errno_destroy(), errno_shutdown(), GET_OPTION, keyboard_destroy(), known_hosts_destroy(), log_cleanup_colors(), log_destroy(), log_shutdown_begin(), log_shutdown_end(), log_system_destroy(), mutex_stack_cleanup(), named_destroy(), options_state_destroy(), platform_destroy(), platform_process_title_destroy(), platform_restore_timer_resolution(), sanitizer_log_destroy(), simd_caches_destroy_all(), stats_runtime_stop(), symbol_cache_destroy(), terminal_screen_cleanup(), timer_system_destroy(), ui_controller_shutdown(), ui_error_popup_flush(), and ui_input_shutdown().

Referenced by client_main(), and main().

◆ asciichat_shared_init()

asciichat_error_t asciichat_shared_init ( const char * log_file,
bool is_client,
bool quiet_startup )

#include <include/ascii-chat/common.h>

Initialize common subsystems shared by client and server.

This function performs initialization that is common to both client and server modes:

  • Platform initialization (Winsock, etc.)
  • Logging setup with default filename
  • Palette configuration
  • buffer domain initialization
  • Cleanup registration (errno, known_hosts, platform, buffer domain)
  • Mimalloc debug registration (if enabled)

Note: Memory debugging setup is handled separately by each mode due to different requirements (client has snapshot mode, server doesn't).

Call this BEFORE options_init() so that options parsing can use properly configured logging with colors. This initializes timer system, logging, and platform subsystems.

Parameters
log_fileLog filename to use (e.g., "client.log" or "ascii-chat.log")
is_clienttrue for client mode (routes all logs to stderr), false for server mode
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 131 of file common.c.

131 {
132 // Initialize shared subsystems BEFORE options_init()
133 // This allows options_init() to use properly configured logging with colors
134 //
135 // NOTE: This function is called BEFORE options_init(), so we can't use GET_OPTION()
136 // Palette config and quiet mode will be applied after options_init() is called
137
138 // Only register initialization tracking once
139 if (!g_shared_initialized) {
140 // 1. TIMER SYSTEM - Initialize first so timing is available for everything else
141 if (!timer_system_init()) {
142 FATAL(ERROR_PLATFORM_INIT, "Failed to initialize timer system");
143 }
144
145 // KEYBOARD SYSTEM must be initialized BEFORE logging since keyboard_init() calls log_info()
146 // But we need to initialize logging AFTER timer_system_init() and BEFORE keyboard_init()
147 // So we move keyboard_init() to AFTER log_init()
148
149#ifndef NDEBUG
150 if (named_init() != ASCIICHAT_OK) {
151 return SET_ERRNO(ERROR_PLATFORM_INIT, "Failed to initialize named.");
152 }
153 debug_memory_ensure_init();
155#endif
156
157 // 2. LOGGING - Initialize system state first, then user-level logging
158 // Initialize logging system internal state (terminal caps, colors)
160
161 // Initialize with provided log file
162 // Force stderr for client-like modes when stdout is piped to keep stdout clean
163 bool force_stderr = is_client && terminal_is_piped_output();
164
165 if (quiet_startup) {
167 }
168
169 // Use LOG_DEBUG by default; will be reconfigured after options_init()
171 log_init(log_file, LOG_DEBUG, force_stderr, false /* don't use_mmap */);
172
173 // 2. KEYBOARD SYSTEM - Initialize keyboard input AFTER logging (may fail if stdin/tty not available)
174 // Failure is not fatal - keyboard_read_nonblocking() safely handles uninitialized state
175 if (terminal_is_stdin_tty()) {
177 }
178
179 // 3. PLATFORM - Initialize platform-specific functionality (Winsock, etc)
180 if (platform_init() != ASCIICHAT_OK) {
181 FATAL(ERROR_PLATFORM_INIT, "Failed to initialize platform");
182 }
183 if (socket_init() != 0) {
184 FATAL(ERROR_PLATFORM_INIT, "Failed to initialize sockets");
185 }
186
187 // 4. buffer domain - Initialize global shared buffer domain
189
190 // Mark that we've initialized (prevents re-registration of subsystems)
191 g_shared_initialized = true;
192 }
193
194 // NOTE: This library function does NOT register atexit() handlers.
195 // Library code should not own the process lifecycle. The application
196 // is responsible for calling atexit(asciichat_shared_destroy) if it
197 // wants automatic cleanup on normal exit.
198
199 return ASCIICHAT_OK;
200}
void sanitizer_log_init(const char *filename)
Definition asan.c:49
void buffer_system_init(void)
Definition buffer.c:400
asciichat_error_t named_init(void)
Initialize the named object registry.
@ ERROR_PLATFORM_INIT
Definition error_codes.h:55
void log_system_init(void)
Initialize the logging system internal state (system-level init).
Definition log.c:712
void log_init(const char *filename, log_level_t level, bool force_stderr, bool use_mmap)
Initialize the logging system.
Definition log.c:569
#define log_file(...)
File-only logging - writes to log file only, no stderr output.
Definition log/log.h:693
void log_set_terminal_output(bool enabled)
Control stderr output to terminal.
Definition log.c:746
bool timer_system_init(void)
Initialize the timing system.
Definition time.c:155
asciichat_error_t keyboard_init(void)
Initialize keyboard input system.
asciichat_error_t symbol_cache_init(void)
Initialize the symbol cache.
asciichat_error_t platform_init(void)
Initialize platform-specific subsystems.
#define LOG_DEBUG
Definition types.h:39

References ASCIICHAT_OK, buffer_system_init(), ERROR_PLATFORM_INIT, FATAL, keyboard_init(), LOG_DEBUG, log_file, log_init(), log_set_terminal_output(), log_system_init(), named_init(), platform_init(), sanitizer_log_init(), SET_ERRNO, symbol_cache_init(), and timer_system_init().

Referenced by main().

◆ fps_frame_ns()

void fps_frame_ns ( fps_t * tracker,
uint64_t current_time_ns,
const char * context )

#include <include/ascii-chat/util/fps.h>

Track a frame and detect lag conditions (nanosecond version - PRIMARY).

Call this function when a frame is processed. Automatically detects when frames arrive late and generates periodic FPS reports every report_interval_ns. This is the primary API that all code should use going forward.

Parameters
trackerFPS tracker state
current_time_nsTimestamp of this frame in nanoseconds (from time_get_ns())
contextOptional context string for lag logging (e.g., "ASCII frame received")

Example usage:

fps_t tracker;
fps_init(&tracker, 60, "RENDER");
// In your frame loop
uint64_t now = time_get_ns();
fps_frame_ns(&tracker, now, "frame rendered");
void fps_frame_ns(fps_t *tracker, uint64_t current_time_ns, const char *context)
Track a frame and detect lag conditions (nanosecond version - PRIMARY).
Definition fps.c:52

Definition at line 52 of file fps.c.

52 {
53 if (!tracker) {
54 return;
55 }
56
57 // Initialize on first frame
58 if (tracker->last_fps_report_ns == 0) {
59 tracker->last_fps_report_ns = current_time_ns;
60 tracker->last_frame_time_ns = current_time_ns;
61 }
62
63 tracker->frame_count++;
64
65 // Calculate time since last frame in nanoseconds
66 uint64_t frame_interval_ns = time_elapsed_ns(tracker->last_frame_time_ns, current_time_ns);
67 tracker->last_frame_time_ns = current_time_ns;
68
69 // Expected frame interval in nanoseconds
70 // For 60 FPS: 1 second / 60 = 16,666,666 ns per frame
71 uint64_t expected_interval_ns = NS_PER_SEC_INT / (uint64_t)tracker->expected_fps;
72 uint64_t lag_threshold_ns = expected_interval_ns + (expected_interval_ns / 2); // 50% over expected
73
74 // Log error if frame arrived too late (only after first frame)
75 if (tracker->frame_count > 1 && frame_interval_ns > lag_threshold_ns) {
76 const char *context_str = context ? context : "Frame";
77
78 // Convert to milliseconds for display (but calculations stay in nanoseconds)
79 double late_ms = time_ns_to_us(frame_interval_ns - expected_interval_ns) / 1000.0;
80 double expected_ms = time_ns_to_us(expected_interval_ns) / 1000.0;
81 double actual_ms = time_ns_to_us(frame_interval_ns) / 1000.0;
82 double actual_fps = 1e9 / (double)frame_interval_ns;
83
84 log_lag_event(tracker->tracker_name, context_str, late_ms, expected_ms, actual_ms, actual_fps);
85 }
86
87 // Report FPS every report_interval_ns
88 uint64_t elapsed_ns = time_elapsed_ns(tracker->last_fps_report_ns, current_time_ns);
89
90 if (elapsed_ns >= tracker->report_interval_ns) {
91 double elapsed_seconds = time_ns_to_s(elapsed_ns);
92 double actual_fps = (double)tracker->frame_count / elapsed_seconds;
93 log_fps_report(tracker->tracker_name, actual_fps, tracker->frame_count, elapsed_seconds);
94
95 // Reset counters for next interval
96 tracker->frame_count = 0;
97 tracker->last_fps_report_ns = current_time_ns;
98 }
99}
#define NS_PER_SEC_INT
Definition time.h:169
uint64_t time_elapsed_ns(uint64_t start_ns, uint64_t end_ns)
Calculate elapsed time with wraparound safety.
Definition time.c:123
const char * tracker_name
Definition fps.h:59
uint64_t frame_count
Definition fps.h:54
uint64_t report_interval_ns
Definition fps.h:58
uint64_t last_frame_time_ns
Definition fps.h:56
int expected_fps
Definition fps.h:57
uint64_t last_fps_report_ns
Definition fps.h:55

References fps_t::expected_fps, fps_t::frame_count, fps_t::last_fps_report_ns, fps_t::last_frame_time_ns, NS_PER_SEC_INT, fps_t::report_interval_ns, time_elapsed_ns(), and fps_t::tracker_name.

Referenced by client_audio_render_thread(), and client_video_render_thread().

◆ fps_init()

void fps_init ( fps_t * tracker,
int expected_fps,
const char * name )

#include <include/ascii-chat/util/fps.h>

Initialize FPS tracker.

Sets up the tracker with expected FPS and default reporting interval (10 seconds). Should be called once before using the tracker.

Parameters
trackerPointer to uninitialized fps_t (should be zero-initialized)
expected_fpsExpected frame rate in FPS (e.g., 60, 30, 20)
nameDisplay name for logging (e.g., "CLIENT", "WEBCAM", "AUDIO", "KEEPALIVE")

Definition at line 32 of file fps.c.

32 {
33 // Default report interval: 1 second
34 fps_init_with_interval(tracker, expected_fps, name, 1 * NS_PER_SEC_INT);
35}
void fps_init_with_interval(fps_t *tracker, int expected_fps, const char *name, uint64_t report_interval_ns)
Initialize FPS tracker with custom report interval.
Definition fps.c:37

References fps_init_with_interval(), and NS_PER_SEC_INT.

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

◆ fps_init_with_interval()

void fps_init_with_interval ( fps_t * tracker,
int expected_fps,
const char * name,
uint64_t report_interval_ns )

#include <include/ascii-chat/util/fps.h>

Initialize FPS tracker with custom report interval.

Sets up the tracker with expected FPS and custom reporting interval in nanoseconds. Useful for different threads that may need different reporting frequencies.

Parameters
trackerPointer to uninitialized fps_t (should be zero-initialized)
expected_fpsExpected frame rate in FPS
nameDisplay name for logging
report_interval_nsCustom report interval in nanoseconds (e.g., 10000000000 = 10 seconds)

Definition at line 37 of file fps.c.

37 {
38 if (!tracker) {
39 return;
40 }
41
42 tracker->frame_count = 0;
43 tracker->expected_fps = expected_fps > 0 ? expected_fps : 60;
44 tracker->tracker_name = name ? name : "FPS";
45 tracker->report_interval_ns = report_interval_ns;
46
47 // Initialize timestamps to zero (will be set on first frame)
48 tracker->last_fps_report_ns = 0;
49 tracker->last_frame_time_ns = 0;
50}

References fps_t::expected_fps, fps_t::frame_count, fps_t::last_fps_report_ns, fps_t::last_frame_time_ns, fps_t::report_interval_ns, and fps_t::tracker_name.

Referenced by fps_init().

Variable Documentation

◆ g_argc

int g_argc
extern

#include <include/ascii-chat/common.h>

Global argc for early argument inspection (e.g., –color flag detection) Set by main() for access from lib/platform/terminal.c during early execution.

Definition at line 61 of file common.c.

Referenced by main().

◆ g_argv

char** g_argv
extern

#include <include/ascii-chat/common.h>

Global argv for early argument inspection (e.g., –color flag detection) Set by main() for access from lib/platform/terminal.c during early execution.

Definition at line 62 of file common.c.

Referenced by main().

◆ g_color_flag_passed

bool g_color_flag_passed
extern

#include <include/ascii-chat/common.h>

Was –color explicitly passed in command-line arguments? Set by options_init() before RCU is initialized, used by terminal_should_color_output().

Definition at line 65 of file common.c.

Referenced by colored_string(), and main().

◆ g_color_flag_value

bool g_color_flag_value
extern

#include <include/ascii-chat/common.h>

Value of –color flag (true if –color was in argv) Set by options_init() before RCU is initialized, used by terminal_should_color_output().

Definition at line 66 of file common.c.

Referenced by colored_string(), and main().