ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
common.c
Go to the documentation of this file.
1
9// Platform abstraction includes memory sizing functions
10#include <ascii-chat/common.h>
11#include <ascii-chat/platform/system.h>
12#include <ascii-chat/platform/init.h>
13#include <ascii-chat/platform/memory.h>
14#include <ascii-chat/log/logging.h>
15#include <ascii-chat/buffer_pool.h>
16#include <ascii-chat/video/palette.h>
17#include <ascii-chat/video/simd/common.h> // For simd_caches_destroy_all()
18#include <ascii-chat/video/webcam/webcam.h> // For webcam_destroy()
19#include <ascii-chat/options/colorscheme.h> // For colorscheme_destroy()
20#include <ascii-chat/util/time.h> // For timer_system_destroy()
21#include <ascii-chat/util/pcre2.h> // For asciichat_pcre2_cleanup_all()
22#include <ascii-chat/asciichat_errno.h>
23#include <ascii-chat/crypto/known_hosts.h>
24#include <ascii-chat/options/options.h>
25#include <ascii-chat/options/rcu.h> // For RCU-based options access
26#include <ascii-chat/discovery/strings.h> // For RCU-based options access
27#include <string.h>
28#include <stdatomic.h>
29#include <limits.h>
30#include <stdlib.h>
31
32#ifndef _WIN32
33#include <pthread.h> // For PTHREAD_MUTEX_INITIALIZER on POSIX
34#endif
35
36/* ============================================================================
37 * Global Variables for Early Argv Inspection
38 * ============================================================================
39 */
40
41// These globals are used by lib/platform/terminal.c to detect --color flag
42// during early execution phases (e.g., when --help is processed before
43// options are fully parsed and published to RCU)
44// ASCIICHAT_API is required for proper DLL export on Windows
45ASCIICHAT_API int g_argc = 0;
46ASCIICHAT_API char **g_argv = NULL;
47
48// Global flags for --color detection (set during options_init before RCU is ready)
49ASCIICHAT_API bool g_color_flag_passed = false; // Was --color explicitly passed in argv?
50ASCIICHAT_API bool g_color_flag_value = false; // What was the value of --color?
51
52/* ============================================================================
53 * Shutdown Check System Implementation
54 * ============================================================================
55 */
56
57// Use atomic for thread-safe access to shutdown callback
58#include <stdatomic.h>
59static _Atomic(shutdown_check_fn) g_shutdown_callback = NULL;
60
61void shutdown_register_callback(shutdown_check_fn callback) {
62 atomic_store(&g_shutdown_callback, callback);
63}
64
66 shutdown_check_fn callback = atomic_load(&g_shutdown_callback);
67 if (callback == NULL) {
68 return false; // No callback registered, assume not shutting down
69 }
70 return callback();
71}
72
73/* ============================================================================
74 * Shared Initialization Implementation
75 * ============================================================================
76 */
77
78#if defined(DEBUG_MEMORY) && !defined(USE_MIMALLOC_DEBUG) && !defined(NDEBUG)
79#include <ascii-chat/debug/memory.h>
80#elif defined(USE_MIMALLOC_DEBUG) && !defined(NDEBUG)
81static void print_mimalloc_stats(void);
82#endif
83
84// Guard to prevent multiple initialization of shared subsystems
85// (can happen if asciichat_shared_init() is called multiple times during startup)
86// But allow subsystem reinitialization for tests and other use cases
87static bool g_shared_initialized = false;
88
89#ifndef _WIN32
96static void asciichat_common_atfork_child(void) {
97 // Reset the shared initialization flag so asciichat_shared_init() will reinitialize subsystems
98 g_shared_initialized = false;
99}
100
104__attribute__((constructor)) static void register_common_fork_handlers(void) {
105 pthread_atfork(NULL, NULL, asciichat_common_atfork_child);
106}
107#endif
108
109asciichat_error_t asciichat_shared_init(const char *log_file, bool is_client) {
110 // Initialize shared subsystems BEFORE options_init()
111 // This allows options_init() to use properly configured logging with colors
112 //
113 // NOTE: This function is called BEFORE options_init(), so we can't use GET_OPTION()
114 // Palette config and quiet mode will be applied after options_init() is called
115
116 // Only register initialization tracking once
117 if (!g_shared_initialized) {
118 // 1. TIMER SYSTEM - Initialize first so timing is available for everything else
119 if (!timer_system_init()) {
120 FATAL(ERROR_PLATFORM_INIT, "Failed to initialize timer system");
121 }
122
123 // 2. LOGGING - Initialize with provided log file
124 // Force stderr for client-like modes when stdout is piped to keep stdout clean
125 bool force_stderr = is_client && terminal_is_piped_output();
126 // Use LOG_DEBUG by default; will be reconfigured after options_init()
127 log_init(log_file, LOG_DEBUG, force_stderr, false /* don't use_mmap */);
128
129 // 3. PLATFORM - Initialize platform-specific functionality (Winsock, etc)
130 if (platform_init() != ASCIICHAT_OK) {
131 FATAL(ERROR_PLATFORM_INIT, "Failed to initialize platform");
132 }
133
134 // 4. BUFFER POOL - Initialize global shared buffer pool
136
137 // Mark that we've initialized (prevents re-registration of subsystems)
138 g_shared_initialized = true;
139 }
140
141 // NOTE: This library function does NOT register atexit() handlers.
142 // Library code should not own the process lifecycle. The application
143 // is responsible for calling atexit(asciichat_shared_destroy) if it
144 // wants automatic cleanup on normal exit.
145
146 return ASCIICHAT_OK;
147}
148
165 // Guard against double cleanup (can be called explicitly + via atexit)
166 static bool shutdown_done = false;
167 if (shutdown_done) {
168 return;
169 }
170 shutdown_done = true;
171
172 // Cleanup in reverse order of initialization (LIFO)
173 // This ensures dependencies are properly handled
174
175 // 0. Stop background threads first (before any cleanup that might use them)
176 // Terminal resize detection thread (Windows only, checks if active)
177 extern void terminal_stop_resize_detection(void);
178 terminal_stop_resize_detection();
179
180#ifndef NDEBUG
181 // Lock debug thread - must join before any lock cleanup
182 extern void lock_debug_cleanup_thread(void);
184
185 // Lock debug system - set initialized=false so mutex_lock uses mutex_lock_impl directly
186 // This must happen after thread cleanup but before any subsystem that uses mutex_lock
187 extern void lock_debug_destroy(void);
189#endif
190
191 // 1. Webcam - cleanup resources
193
194 // 2. SIMD caches - cleanup CPU-specific caches
196
197 // 3. Discovery service strings cache - cleanup session string cache
199
200 // 4. Logging - in correct order (end first, then begin)
203
204 // 5. Known hosts - cleanup authentication state
206
207 // 6. Options state - cleanup RCU-based options
209
210 // 7. Buffer pool - cleanup global buffer pool
212
213 // 8. Platform cleanup - restores terminal, cleans up platform resources
214 // (includes symbol cache cleanup on Windows)
216
217 // 9. Keyboard - restore terminal settings (redundant with platform_destroy but safe)
218 extern void keyboard_destroy(void);
219 keyboard_destroy();
220
221 // 10. Timer system - cleanup timers (may still log!)
223
224 // 11. Error context cleanup
226
227 // 12. Logging cleanup - free log format buffers before memory report
228 log_destroy();
229
230 // 13. Memory stats (debug builds only) - runs with colors still available
231 // Note: PCRE2 singletons are ignored in the report (expected system allocations)
232 // Note: debug_memory_report() is also called manually during shutdown in server_main()
233 // The function is safe to call multiple times with polling-based locking
234#if defined(USE_MIMALLOC_DEBUG) && !defined(NDEBUG)
235 print_mimalloc_stats();
236#endif
237
238#if defined(DEBUG_MEMORY) && !defined(NDEBUG)
239 debug_memory_report();
240#endif
241
242 // 14. Color cleanup - free compiled ANSI strings (AFTER memory report)
245
246 // 15. PCRE2 - cleanup all regex singletons together
248}
249
250#if defined(USE_MIMALLOC_DEBUG) && !defined(NDEBUG)
251// Wrapper function for mi_stats_print to use with atexit()
252// mi_stats_print takes a parameter, but atexit requires void(void)
253static void print_mimalloc_stats(void) {
254 // Skip memory report if an action flag was passed (for clean action output)
255 // unless explicitly forced via ASCII_CHAT_MEMORY_DEBUG environment variable
256 if (has_action_flag() && !SAFE_GETENV("ASCII_CHAT_MEMORY_DEBUG")) {
257 return;
258 }
259 mi_stats_print(NULL); // NULL = print to stderr
260}
261#endif
void asciichat_errno_destroy(void)
void buffer_pool_cleanup_global(void)
void buffer_pool_init_global(void)
void colorscheme_destroy(void)
__attribute__((constructor))
Register fork handlers for common module.
Definition common.c:104
ASCIICHAT_API bool g_color_flag_value
Definition common.c:50
ASCIICHAT_API bool g_color_flag_passed
Definition common.c:49
ASCIICHAT_API char ** g_argv
Definition common.c:46
asciichat_error_t asciichat_shared_init(const char *log_file, bool is_client)
Definition common.c:109
ASCIICHAT_API int g_argc
Definition common.c:45
bool shutdown_is_requested(void)
Definition common.c:65
void asciichat_shared_destroy(void)
Clean up all shared library subsystems.
Definition common.c:164
void acds_strings_destroy(void)
Cleanup function for session string cache Called by asciichat_shared_destroy() during library cleanup...
void platform_destroy(void)
Definition init.c:15
asciichat_error_t platform_init(void)
Definition init.c:10
void known_hosts_destroy(void)
bool has_action_flag(void)
Check if an action flag was detected.
void lock_debug_cleanup_thread(void)
Definition lock.c:1371
void lock_debug_destroy(void)
Definition lock.c:1370
void log_shutdown_end(void)
void log_destroy(void)
void log_cleanup_colors(void)
Clean up compiled color scheme.
void log_shutdown_begin(void)
void log_init(const char *filename, log_level_t level, bool force_stderr, bool use_mmap)
void asciichat_pcre2_cleanup_all(void)
Free all PCRE2 singletons in the global registry.
Definition pcre2.c:197
bool terminal_is_piped_output(void)
void options_state_destroy(void)
Definition rcu.c:309
void timer_system_destroy(void)
Definition util/time.c:146
bool timer_system_init(void)
Definition util/time.c:125
void simd_caches_destroy_all(void)
void webcam_destroy(void)