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

🚨 Custom error code system with formatted messages, thread-local storage, and errno mapping More...

Go to the source code of this file.

Macros

#define MAX_THREAD_ERRORS   64
 

Functions

void log_labeled (const char *label, log_color_t color, const char *message,...)
 
void asciichat_set_errno (asciichat_error_t code, const char *file, int line, const char *function, const char *context_message)
 
void asciichat_set_errno_with_message (asciichat_error_t code, const char *file, int line, const char *function, const char *format,...)
 
void asciichat_set_errno_with_system_error (asciichat_error_t code, const char *file, int line, const char *function, int sys_errno)
 
void asciichat_set_errno_with_system_error_and_message (asciichat_error_t code, const char *file, int line, const char *function, int sys_errno, const char *format,...)
 
void asciichat_set_errno_with_wsa_error (asciichat_error_t code, const char *file, int line, const char *function, int wsa_error)
 
bool asciichat_has_wsa_error (void)
 
bool asciichat_has_errno (asciichat_error_context_t *context)
 
void asciichat_clear_errno (void)
 
asciichat_error_t asciichat_get_errno (void)
 
void asciichat_fatal_with_context (asciichat_error_t code, const char *file, int line, const char *function, const char *format,...)
 
void asciichat_print_error_context (const asciichat_error_context_t *context)
 
void asciichat_error_stats_init (void)
 
void asciichat_error_stats_record (asciichat_error_t code)
 
void asciichat_error_stats_print (void)
 
void asciichat_error_stats_reset (void)
 
asciichat_error_stats_t asciichat_error_stats_get (void)
 
asciichat_error_t asciichat_get_thread_error (int thread_id)
 
void asciichat_set_thread_error (int thread_id, asciichat_error_t code)
 
void asciichat_clear_thread_error (int thread_id)
 
void asciichat_errno_suppress (bool suppress)
 
void asciichat_errno_destroy (void)
 

Variables

__thread asciichat_error_context_t asciichat_errno_context
 
__thread asciichat_error_t asciichat_errno = ASCIICHAT_OK
 

Detailed Description

🚨 Custom error code system with formatted messages, thread-local storage, and errno mapping

Definition in file asciichat_errno.c.

Macro Definition Documentation

◆ MAX_THREAD_ERRORS

#define MAX_THREAD_ERRORS   64

Definition at line 62 of file asciichat_errno.c.

Function Documentation

◆ asciichat_clear_errno()

void asciichat_clear_errno ( void  )

Definition at line 236 of file asciichat_errno.c.

236 {
237 if (asciichat_errno_context.context_message) {
238 SAFE_FREE(asciichat_errno_context.context_message);
239 asciichat_errno_context.context_message = NULL;
240 }
241
242 if (asciichat_errno_context.backtrace_symbols != NULL) {
244 asciichat_errno_context.backtrace_symbols = NULL;
245 }
246
248 asciichat_errno_context.code = ASCIICHAT_OK;
249 asciichat_errno_context.system_errno = 0;
250 asciichat_errno_context.has_system_error = false;
251 asciichat_errno_context.has_wsa_error = false;
252 asciichat_errno_context.wsa_error = 0;
253
254 /* Clear platform-specific error state */
256}
__thread asciichat_error_context_t asciichat_errno_context
void platform_clear_error_state(void)
Definition util.c:67
void platform_backtrace_symbols_destroy(char **symbols)
Definition util.c:26

References asciichat_errno_context, platform_backtrace_symbols_destroy(), and platform_clear_error_state().

◆ asciichat_clear_thread_error()

void asciichat_clear_thread_error ( int  thread_id)

Definition at line 484 of file asciichat_errno.c.

484 {
485 for (int i = 0; i < MAX_THREAD_ERRORS; i++) {
486 if (thread_errors[i].valid && thread_errors[i].thread_id == thread_id) {
487 thread_errors[i].valid = false;
488 break;
489 }
490 }
491}
#define MAX_THREAD_ERRORS
bool valid
int thread_id

References MAX_THREAD_ERRORS, thread_id, and valid.

◆ asciichat_errno_destroy()

void asciichat_errno_destroy ( void  )

Definition at line 502 of file asciichat_errno.c.

502 {
503 if (asciichat_errno_context.backtrace_symbols != NULL) {
505 asciichat_errno_context.backtrace_symbols = NULL;
506 }
507
508 if (asciichat_errno_context.context_message != NULL) {
509 SAFE_FREE(asciichat_errno_context.context_message);
510 }
511
512 // Reset the context to a clean state
514 asciichat_errno_context.code = ASCIICHAT_OK;
515
516 // Suppress any further error context allocation to prevent cleanup-phase leaks
517 // This prevents other atexit() functions from allocating new contexts after we've cleaned up
518 g_suppress_error_context = true;
519}

References asciichat_errno_context, and platform_backtrace_symbols_destroy().

Referenced by asciichat_shared_destroy(), client_audio_render_thread(), client_receive_thread(), client_send_thread_func(), client_video_render_thread(), server_main(), and stats_logger_thread().

◆ asciichat_errno_suppress()

void asciichat_errno_suppress ( bool  suppress)

Definition at line 498 of file asciichat_errno.c.

498 {
499 g_suppress_error_context = suppress;
500}

◆ asciichat_error_stats_get()

asciichat_error_stats_t asciichat_error_stats_get ( void  )

Definition at line 436 of file asciichat_errno.c.

436 {
437 static_mutex_lock(&g_error_stats_mutex);
438
439 if (!stats_initialized) {
440 memset(&error_stats, 0, sizeof(error_stats));
441 stats_initialized = true;
442 }
443
444 asciichat_error_stats_t result = error_stats;
445 static_mutex_unlock(&g_error_stats_mutex);
446
447 return result;
448}

◆ asciichat_error_stats_init()

void asciichat_error_stats_init ( void  )

Definition at line 365 of file asciichat_errno.c.

365 {
366 static_mutex_lock(&g_error_stats_mutex);
367
368 if (!stats_initialized) {
369 memset(&error_stats, 0, sizeof(error_stats));
370 stats_initialized = true;
371 }
372
373 static_mutex_unlock(&g_error_stats_mutex);
374}

◆ asciichat_error_stats_print()

void asciichat_error_stats_print ( void  )

Definition at line 394 of file asciichat_errno.c.

394 {
395 static_mutex_lock(&g_error_stats_mutex);
396
397 if (!stats_initialized || error_stats.total_errors == 0) {
398 static_mutex_unlock(&g_error_stats_mutex);
399 log_plain("No errors recorded.\n");
400 return;
401 }
402
403 // Copy stats to local variable to minimize lock hold time
404 asciichat_error_stats_t local_stats = error_stats;
405 static_mutex_unlock(&g_error_stats_mutex);
406
407 log_plain("\n=== ascii-chat Error Statistics ===\n");
408 log_plain("Total errors: %llu\n", (unsigned long long)local_stats.total_errors);
409
410 if (local_stats.last_error_time > 0) {
411 time_t sec = (time_t)(local_stats.last_error_time / NS_PER_MS_INT);
412 struct tm tm_info;
413 if (platform_localtime(&sec, &tm_info) == ASCIICHAT_OK) {
414 char time_str[64];
415 strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &tm_info);
416 log_plain("Last error: %s (code %d)\n", time_str, (int)local_stats.last_error_code);
417 }
418 }
419
420 log_plain("\nError breakdown:\n");
421 for (int i = 0; i < 256; i++) {
422 if (local_stats.error_counts[i] > 0) {
423 log_plain(" %3d (%s): %llu\n", i, asciichat_error_string((asciichat_error_t)i),
424 (unsigned long long)local_stats.error_counts[i]);
425 }
426 }
427 log_plain("\n");
428}
asciichat_error_t platform_localtime(const time_t *timer, struct tm *result)
Definition util.c:48

References platform_localtime().

Referenced by server_main(), and stats_logger_thread().

◆ asciichat_error_stats_record()

void asciichat_error_stats_record ( asciichat_error_t  code)

Definition at line 376 of file asciichat_errno.c.

376 {
377 static_mutex_lock(&g_error_stats_mutex);
378
379 if (!stats_initialized) {
380 memset(&error_stats, 0, sizeof(error_stats));
381 stats_initialized = true;
382 }
383
384 if (code >= 0 && code < 256) {
385 error_stats.error_counts[code]++;
386 }
387 error_stats.total_errors++;
388 error_stats.last_error_time = time_ns_to_us(time_get_realtime_ns());
389 error_stats.last_error_code = code;
390
391 static_mutex_unlock(&g_error_stats_mutex);
392}
uint64_t time_get_realtime_ns(void)
Definition util/time.c:59

References time_get_realtime_ns().

Referenced by asciichat_set_errno().

◆ asciichat_error_stats_reset()

void asciichat_error_stats_reset ( void  )

Definition at line 430 of file asciichat_errno.c.

430 {
431 static_mutex_lock(&g_error_stats_mutex);
432 memset(&error_stats, 0, sizeof(error_stats));
433 static_mutex_unlock(&g_error_stats_mutex);
434}

◆ asciichat_fatal_with_context()

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

Definition at line 267 of file asciichat_errno.c.

268 {
269 (void)file;
270 (void)line;
271 (void)function;
272
273 // Print library error context if available
274 asciichat_error_context_t err_ctx;
275 if (HAS_ERRNO(&err_ctx)) {
276 log_labeled("\nasciichat_errno: libary code error context", LOG_COLOR_ERROR, "");
278 } else {
279 log_plain("WARNING: No error context found (asciichat_errno_context.code=%d)", asciichat_errno_context.code);
280 }
281
282 safe_fprintf(stderr, "\n");
283 log_labeled("FATAL ERROR", LOG_COLOR_FATAL, "exit code %d (%s)", (int)code, asciichat_error_string(code));
284#ifndef NDEBUG
285 const char *relative_file = extract_project_relative_path(file);
286 log_plain(" Location: %s:%d in %s()", relative_file, line, function);
287#endif
288
289 if (format) {
290 va_list args;
291 va_start(args, format);
292 char *formatted_message = format_message(format, args);
293 log_plain(" Error message: %s", formatted_message);
294 SAFE_FREE(formatted_message);
295 va_end(args);
296 }
297
298#ifndef NDEBUG
299 // Always print platform backtrace in debug/dev builds
300 void *buffer[32];
301 int size = platform_backtrace(buffer, 32);
302 if (size > 0) {
303 char **symbols = platform_backtrace_symbols(buffer, size);
304 if (symbols) {
305 platform_print_backtrace_symbols("\nFATAL BACKTRACE", symbols, size, 0, 0, skip_backtrace_frame);
307 }
308 }
309#endif
310
311 exit(code);
312}
void log_labeled(const char *label, log_color_t color, const char *message,...)
void asciichat_print_error_context(const asciichat_error_context_t *context)
char * format_message(const char *format, va_list args)
action_args_t args
const char * extract_project_relative_path(const char *file)
Definition path.c:410
int safe_fprintf(FILE *stream, const char *format,...)
Safe formatted output to file stream.
Definition system.c:480
void platform_print_backtrace_symbols(const char *label, char **symbols, int count, int skip_frames, int max_frames, backtrace_frame_filter_t filter)
Print pre-resolved backtrace symbols with colored terminal output and plain log file output.
Definition system.c:535
int platform_backtrace(void **buffer, int size)
Definition util.c:14
char ** platform_backtrace_symbols(void *const *buffer, int size)
Definition util.c:20

References args, asciichat_errno_context, asciichat_print_error_context(), extract_project_relative_path(), format_message(), log_labeled(), platform_backtrace(), platform_backtrace_symbols(), platform_backtrace_symbols_destroy(), platform_print_backtrace_symbols(), and safe_fprintf().

◆ asciichat_get_errno()

asciichat_error_t asciichat_get_errno ( void  )

Definition at line 258 of file asciichat_errno.c.

258 {
259 return asciichat_errno_context.code;
260}

References asciichat_errno_context.

◆ asciichat_get_thread_error()

asciichat_error_t asciichat_get_thread_error ( int  thread_id)

Definition at line 455 of file asciichat_errno.c.

455 {
456 for (int i = 0; i < MAX_THREAD_ERRORS; i++) {
457 if (thread_errors[i].valid && thread_errors[i].thread_id == thread_id) {
458 return thread_errors[i].error_code;
459 }
460 }
461 return ASCIICHAT_OK;
462}

References MAX_THREAD_ERRORS, thread_id, and valid.

◆ asciichat_has_errno()

bool asciichat_has_errno ( asciichat_error_context_t *  context)

Definition at line 224 of file asciichat_errno.c.

224 {
225 if (asciichat_errno_context.code == ASCIICHAT_OK) {
226 return false;
227 }
228
229 if (context) {
230 *context = asciichat_errno_context;
231 }
232
233 return true;
234}

References asciichat_errno_context.

◆ asciichat_has_wsa_error()

bool asciichat_has_wsa_error ( void  )

Definition at line 215 of file asciichat_errno.c.

215 {
216 return asciichat_errno_context.has_wsa_error;
217}

References asciichat_errno_context.

◆ asciichat_print_error_context()

void asciichat_print_error_context ( const asciichat_error_context_t *  context)

Definition at line 319 of file asciichat_errno.c.

319 {
320 if (!context || context->code == ASCIICHAT_OK) {
321 return;
322 }
323
324 if (context->file && context->line && context->function) {
325 log_plain(" Location: %s:%d in %s()", extract_project_relative_path(context->file), context->line,
326 context->function);
327 } else {
328 log_plain(" Location: unknown (set by system code)");
329 }
330
331 if (context->context_message) {
332 safe_fprintf(stderr, " %s %s\n", colored_string(LOG_COLOR_WARN, "Context:"), context->context_message);
333 log_file(" Context: %s", context->context_message);
334 }
335
336 if (context->has_system_error) {
337 log_plain(" System error: %s (code: %d, meaning: %s)", SAFE_STRERROR(context->system_errno), context->system_errno,
338 SAFE_STRERROR(context->system_errno));
339 }
340
341 // Print timestamp
342 if (context->timestamp > 0) {
343 time_t sec = (time_t)(context->timestamp / NS_PER_MS_INT);
344 long usec = (long)(context->timestamp % NS_PER_MS_INT);
345 struct tm tm_info;
346 if (platform_localtime(&sec, &tm_info) == ASCIICHAT_OK) {
347 char time_str[64];
348 (void)strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &tm_info);
349 log_plain(" Timestamp: %s.%06ld", time_str, usec);
350 }
351 }
352
353 // Print stack trace from library error
354 if (context->stack_depth > 0 && context->backtrace_symbols) {
355 platform_print_backtrace_symbols("\nBacktrace from library error", context->backtrace_symbols, context->stack_depth,
356 0, 0, skip_backtrace_frame);
357 }
358}
const char * colored_string(log_color_t color, const char *text)

References colored_string(), extract_project_relative_path(), platform_localtime(), platform_print_backtrace_symbols(), and safe_fprintf().

Referenced by asciichat_fatal_with_context().

◆ asciichat_set_errno()

void asciichat_set_errno ( asciichat_error_t  code,
const char *  file,
int  line,
const char *  function,
const char *  context_message 
)

Definition at line 112 of file asciichat_errno.c.

113 {
114 // Suppress error context allocation during cleanup to prevent leaks
115 if (g_suppress_error_context) {
116 return;
117 }
118
119 // Clear any existing context message
120 if (asciichat_errno_context.context_message) {
121 SAFE_FREE(asciichat_errno_context.context_message);
122 asciichat_errno_context.context_message = NULL;
123 }
124
125 // Set the error context
126 asciichat_errno_context.code = code;
127 asciichat_errno_context.file = file;
128 asciichat_errno_context.line = line;
129 asciichat_errno_context.function = function;
130 asciichat_errno_context.timestamp = time_ns_to_us(time_get_realtime_ns());
131 asciichat_errno_context.has_system_error = false;
132
133 // Set the simple error code variable
134 asciichat_errno = code;
135
136 // Copy context message if provided
137 if (context_message == NULL) {
138 log_error("context_message is NULL");
139 const char *fallback = "No context message (this is invalid - set a context message)";
140 size_t len = strlen(fallback) + 1;
141 asciichat_errno_context.context_message = SAFE_MALLOC(len, char *);
142 if (asciichat_errno_context.context_message) {
143 SAFE_STRNCPY(asciichat_errno_context.context_message, fallback, len);
144 } else {
145 log_error("SAFE_MALLOC failed for fallback context_message");
146 }
147 } else {
148 size_t len = strlen(context_message) + 1;
149 asciichat_errno_context.context_message = SAFE_MALLOC(len, char *);
150 if (asciichat_errno_context.context_message) {
151 SAFE_STRNCPY(asciichat_errno_context.context_message, context_message, len);
152 } else {
153 log_error("SAFE_MALLOC failed for context_message");
154 }
155 }
156
157 // Capture stack trace in debug builds
158 if (asciichat_errno_context.backtrace_symbols != NULL) {
160 asciichat_errno_context.backtrace_symbols = NULL;
161 }
162 capture_backtrace(asciichat_errno_context.backtrace, &asciichat_errno_context.backtrace_symbols,
163 &asciichat_errno_context.stack_depth);
164
165 // Record in statistics
167}
__thread asciichat_error_t asciichat_errno
void asciichat_error_stats_record(asciichat_error_t code)

References asciichat_errno, asciichat_errno_context, asciichat_error_stats_record(), platform_backtrace_symbols_destroy(), and time_get_realtime_ns().

Referenced by asciichat_set_errno_with_message(), asciichat_set_errno_with_system_error(), asciichat_set_errno_with_system_error_and_message(), and asciichat_set_errno_with_wsa_error().

◆ asciichat_set_errno_with_message()

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

Definition at line 169 of file asciichat_errno.c.

170 {
171 va_list args;
172 va_start(args, format);
173
174 char *context_message = format_message(format, args);
175 asciichat_set_errno(code, file, line, function, context_message);
176
177 if (context_message) {
178 SAFE_FREE(context_message);
179 }
180
181 va_end(args);
182}
void asciichat_set_errno(asciichat_error_t code, const char *file, int line, const char *function, const char *context_message)

References args, asciichat_set_errno(), and format_message().

◆ asciichat_set_errno_with_system_error()

void asciichat_set_errno_with_system_error ( asciichat_error_t  code,
const char *  file,
int  line,
const char *  function,
int  sys_errno 
)

Definition at line 184 of file asciichat_errno.c.

185 {
186 asciichat_set_errno(code, file, line, function, NULL);
187 asciichat_errno_context.system_errno = sys_errno;
188 asciichat_errno_context.has_system_error = true;
189}

References asciichat_errno_context, and asciichat_set_errno().

◆ asciichat_set_errno_with_system_error_and_message()

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

Definition at line 191 of file asciichat_errno.c.

192 {
193 va_list args;
194 va_start(args, format);
195
196 char *context_message = format_message(format, args);
197 asciichat_set_errno(code, file, line, function, context_message);
198 asciichat_errno_context.system_errno = sys_errno;
199 asciichat_errno_context.has_system_error = true;
200
201 if (context_message) {
202 SAFE_FREE(context_message);
203 }
204
205 va_end(args);
206}

References args, asciichat_errno_context, asciichat_set_errno(), and format_message().

◆ asciichat_set_errno_with_wsa_error()

void asciichat_set_errno_with_wsa_error ( asciichat_error_t  code,
const char *  file,
int  line,
const char *  function,
int  wsa_error 
)

Definition at line 208 of file asciichat_errno.c.

209 {
210 asciichat_set_errno(code, file, line, function, NULL);
211 asciichat_errno_context.wsa_error = wsa_error;
212 asciichat_errno_context.has_wsa_error = true;
213}

References asciichat_errno_context, and asciichat_set_errno().

◆ asciichat_set_thread_error()

void asciichat_set_thread_error ( int  thread_id,
asciichat_error_t  code 
)

Definition at line 464 of file asciichat_errno.c.

464 {
465 // Find existing entry or empty slot
466 int slot = -1;
467 for (int i = 0; i < MAX_THREAD_ERRORS; i++) {
468 if (thread_errors[i].valid && thread_errors[i].thread_id == thread_id) {
469 slot = i;
470 break;
471 }
472 if (!thread_errors[i].valid && slot == -1) {
473 slot = i;
474 }
475 }
476
477 if (slot >= 0) {
478 thread_errors[slot].thread_id = thread_id;
479 thread_errors[slot].error_code = code;
480 thread_errors[slot].valid = true;
481 }
482}

References MAX_THREAD_ERRORS, thread_id, and valid.

◆ log_labeled()

void log_labeled ( const char *  label,
log_color_t  color,
const char *  message,
  ... 
)

Definition at line 94 of file asciichat_errno.c.

94 {
95 va_list args;
96 va_start(args, message);
97 char *formatted_message = format_message(message, args);
98 va_end(args);
99
100 safe_fprintf(stderr, "%s: %s\n", colored_string(color, label), formatted_message);
101
102 log_file("%s: %s", label, formatted_message);
103
104 SAFE_FREE(formatted_message);
105}

References args, colored_string(), format_message(), and safe_fprintf().

Referenced by asciichat_fatal_with_context().

Variable Documentation

◆ asciichat_errno

__thread asciichat_error_t asciichat_errno = ASCIICHAT_OK

Definition at line 43 of file asciichat_errno.c.

Referenced by accept_with_timeout(), and asciichat_set_errno().

◆ asciichat_errno_context

__thread asciichat_error_context_t asciichat_errno_context
Initial value:
= {.code = ASCIICHAT_OK,
.file = NULL,
.line = 0,
.function = NULL,
.context_message = NULL,
.timestamp = 0,
.system_errno = 0,
.backtrace = {0},
.backtrace_symbols = NULL,
.stack_depth = 0,
.has_system_error = false}

Definition at line 31 of file asciichat_errno.c.

31 {.code = ASCIICHAT_OK,
32 .file = NULL,
33 .line = 0,
34 .function = NULL,
35 .context_message = NULL,
36 .timestamp = 0,
37 .system_errno = 0,
38 .backtrace = {0},
39 .backtrace_symbols = NULL,
40 .stack_depth = 0,
41 .has_system_error = false};

Referenced by accept_with_timeout(), asciichat_clear_errno(), asciichat_errno_destroy(), asciichat_fatal_with_context(), asciichat_get_errno(), asciichat_has_errno(), asciichat_has_wsa_error(), asciichat_set_errno(), asciichat_set_errno_with_system_error(), asciichat_set_errno_with_system_error_and_message(), and asciichat_set_errno_with_wsa_error().

◆ error_code

◆ thread_id

◆ valid