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

Go to the source code of this file.

Functions

asciichat_error_t options_state_init (void)
 Initialize RCU options system.
asciichat_error_t options_state_set (const options_t *opts)
 Set options from a parsed options struct.
void options_state_destroy (void)
 Shutdown RCU options system.
const options_t * options_get (void)
 Get current options (lock-free read).
size_t options_retired_snapshot_count (void)
void options_cleanup_schema (void)
 Clean up schema resources.

Function Documentation

◆ options_cleanup_schema()

void options_cleanup_schema ( void )

Clean up schema resources.

Frees the dynamically allocated options schema array and all associated strings. Should be called at program shutdown after options_state_destroy(). Safe to call multiple times or if schema was never built.

Definition at line 507 of file rcu.c.

507 {
509}
void config_schema_destroy(void)
Clean up dynamically allocated schema resources.
Definition schema.c:469

References config_schema_destroy().

Referenced by main().

◆ options_retired_snapshot_count()

size_t options_retired_snapshot_count ( void )

Number of retired borrowed snapshots retained until shutdown.

Definition at line 322 of file rcu.c.

322 {
323 if (!lifecycle_is_initialized(&g_options_lifecycle))
324 return 0;
325 mutex_lock(&g_deferred_free_mutex);
326 size_t count = g_retired_count;
327 mutex_unlock(&g_deferred_free_mutex);
328 return count;
329}

◆ options_state_destroy()

void options_state_destroy ( void )

Shutdown RCU options system.

Frees the current options struct and cleans up resources. Should be called at program shutdown after all threads have exited.

Definition at line 476 of file rcu.c.

476 {
477 // Check if initialized using lifecycle
478 if (!lifecycle_is_initialized(&g_options_lifecycle)) {
479 return;
480 }
481
482 /* Shutdown lifecycle to mark as no longer initialized */
483 lifecycle_shutdown(&g_options_lifecycle);
484
485 // Get current options pointer
486 options_t *current = atomic_ptr_load(&g_options);
487
488 // Clear the atomic pointer (prevent further reads)
489 atomic_ptr_store(&g_options, NULL);
490
491 // Free current struct
492 SAFE_FREE(current);
493
494 // Free all deferred structs
495 deferred_free_all();
496
497 // Cleanup schema (frees all dynamically allocated config strings)
499
500 // Destroy dynamically created mutexes
501 mutex_destroy(&g_options_write_mutex);
502 mutex_destroy(&g_deferred_free_mutex);
503
504 log_debug("Options state shutdown complete");
505}
#define SAFE_FREE(ptr)
Definition common.h:377
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:595
struct options_state options_t
Immutable, RCU-published snapshot of the application's runtime configuration.

References config_schema_destroy(), log_debug, and SAFE_FREE.

Referenced by asciichat_shared_destroy(), main(), and mirror_cleanup().

◆ options_state_init()

asciichat_error_t options_state_init ( void )

Initialize RCU options system.

Must be called once at program startup before any threads access options. Allocates initial options struct and sets up atomic pointer.

Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 380 of file rcu.c.

380 {
381 // RCU setters validate against the option registry, including when callers
382 // use the state API directly in tests or embedded integrations. Initialize
383 // the registry here so those callers observe the same metadata as the CLI.
385
386 // Detect fork: after fork(), child process must reinitialize
387 pid_t current_pid = platform_get_pid();
388 if ((lifecycle_is_initialized(&g_options_lifecycle) || g_init_pid != -1) && g_init_pid != current_pid) {
389 log_debug("Detected fork (parent PID %d, child PID %d) - resetting lifecycle", g_init_pid, current_pid);
390 /* Reset lifecycle to allow reinitialization after fork */
391 lifecycle_shutdown(&g_options_lifecycle);
392 g_init_pid = current_pid;
393 }
394
395 // Check if already initialized in this process using lifecycle
396 if (lifecycle_is_initialized(&g_options_lifecycle) && g_init_pid == current_pid &&
397 atomic_ptr_load(&g_options) != NULL) {
398 log_warn("Options state already initialized");
399 return ASCIICHAT_OK;
400 }
401 if (lifecycle_is_initialized(&g_options_lifecycle) && atomic_ptr_load(&g_options) == NULL) {
402 lifecycle_shutdown(&g_options_lifecycle);
403 }
404
405 /* Use lifecycle to serialize initialization */
406 if (!lifecycle_init(&g_options_lifecycle, "options")) {
407 /* Another thread is initializing or already initialized */
408 if (lifecycle_is_initialized(&g_options_lifecycle)) {
409 return ASCIICHAT_OK;
410 }
411 return SET_ERRNO(ERROR_INVALID_STATE, "Failed to acquire options initialization lock");
412 }
413
414 // Initialize write mutex
415 if (mutex_init(&g_options_write_mutex, "options_write") != 0) {
416 lifecycle_shutdown(&g_options_lifecycle);
417 return SET_ERRNO(ERROR_THREAD, "Failed to initialize options write mutex");
418 }
419
420 // Initialize deferred free mutex
421 if (mutex_init(&g_deferred_free_mutex, "deferred_free") != 0) {
422 mutex_destroy(&g_options_write_mutex);
423 lifecycle_shutdown(&g_options_lifecycle);
424 return SET_ERRNO(ERROR_THREAD, "Failed to initialize deferred free mutex");
425 }
426
427 // Allocate initial options struct (will be populated later by options_state_populate_from_globals)
428 options_t *initial_opts = SAFE_MALLOC(sizeof(options_t), options_t *);
429 if (!initial_opts) {
430 mutex_destroy(&g_options_write_mutex);
431 mutex_destroy(&g_deferred_free_mutex);
432 lifecycle_shutdown(&g_options_lifecycle);
433 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate initial options struct");
434 }
435
436 // Initialize all defaults using options_t_new()
437 *initial_opts = options_t_new();
438
439 // Publish initial struct (release semantics - make all fields visible to readers)
440 atomic_ptr_store(&g_options, initial_opts);
441
442 ++g_revision;
443 g_origin = OPTIONS_ORIGIN_CONFIG;
444 g_init_pid = current_pid; // Record PID to detect fork later
445 log_dev("Options state initialized with RCU pattern (PID %d)", current_pid);
446
447 return ASCIICHAT_OK;
448}
#define SET_ERRNO(code,...)
void registry_init_size(void)
Initialize registry size and metadata.
Definition core.c:108
#define SAFE_MALLOC(size, cast)
Definition common.h:265
@ ERROR_INVALID_STATE
@ ERROR_MEMORY
Definition error_codes.h:51
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_THREAD
#define log_warn(...)
Log a WARN message.
Definition log/log.h:621
#define log_dev(...)
Log a DEV message (most verbose, development only).
Definition log/log.h:581
options_t options_t_new(void)
Initialize options by parsing command-line arguments.
Definition options.c:547
pid_t platform_get_pid(void)
Get the current process ID.
@ OPTIONS_ORIGIN_CONFIG

References ASCIICHAT_OK, ERROR_INVALID_STATE, ERROR_MEMORY, ERROR_THREAD, log_debug, log_dev, log_warn, OPTIONS_ORIGIN_CONFIG, options_t_new(), platform_get_pid(), registry_init_size(), SAFE_MALLOC, and SET_ERRNO.

Referenced by __attribute__(), and options_init().

◆ options_state_set()

asciichat_error_t options_state_set ( const options_t * opts)

Set options from a parsed options struct.

Called by options_init() after parsing to publish the options struct to RCU. This atomically replaces the current options with the provided struct.

Parameters
optsPointer to options struct to publish (will be copied)
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 450 of file rcu.c.

450 {
451 if (!opts) {
452 return SET_ERRNO(ERROR_INVALID_PARAM, "opts is NULL");
453 }
454
455 // Check initialization state using lifecycle
456 if (!lifecycle_is_initialized(&g_options_lifecycle)) {
457 return SET_ERRNO(ERROR_INVALID_STATE, "Options state not initialized (call options_state_init first)");
458 }
459
460 mutex_lock(&g_options_write_mutex);
461 options_t *next = SAFE_MALLOC(sizeof(*next), options_t *);
462 *next = *opts;
463 options_t *previous = atomic_ptr_load(&g_options);
464 if (previous->flip_x_explicit && !next->flip_x_explicit)
465 next->flip_x = previous->flip_x;
466 next->flip_x_explicit |= previous->flip_x_explicit;
468 atomic_ptr_store(&g_options, next);
469 ++g_revision;
470 g_origin = OPTIONS_ORIGIN_CONFIG;
471 deferred_free_add(previous);
472 mutex_unlock(&g_options_write_mutex);
473 return ASCIICHAT_OK;
474}
@ ERROR_INVALID_PARAM
void options_resolve_flip_x(options_t *opts)
Definition options.c:2575
bool flip_x_explicit
User selected an orientation for this process lifetime.
Definition options.h:1104
bool flip_x
Effective horizontal orientation.
Definition options.h:1103

References ASCIICHAT_OK, ERROR_INVALID_PARAM, ERROR_INVALID_STATE, retired_options::next, OPTIONS_ORIGIN_CONFIG, options_resolve_flip_x(), SAFE_MALLOC, and SET_ERRNO.

Referenced by config_load_and_apply().