ascii-chat 0.11.33
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)
 
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 492 of file rcu.c.

492 {
494}
void config_schema_destroy(void)
Clean up dynamically allocated schema resources.
Definition schema.c:454

References config_schema_destroy().

Referenced by main().

◆ 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 461 of file rcu.c.

461 {
462 // Check if initialized using lifecycle
463 if (!lifecycle_is_initialized(&g_options_lifecycle)) {
464 return;
465 }
466
467 /* Shutdown lifecycle to mark as no longer initialized */
468 lifecycle_shutdown(&g_options_lifecycle);
469
470 // Get current options pointer
471 options_t *current = atomic_ptr_load(&g_options);
472
473 // Clear the atomic pointer (prevent further reads)
474 atomic_ptr_store(&g_options, NULL);
475
476 // Free current struct
477 SAFE_FREE(current);
478
479 // Free all deferred structs
480 deferred_free_all();
481
482 // Cleanup schema (frees all dynamically allocated config strings)
484
485 // Destroy dynamically created mutexes
486 mutex_destroy(&g_options_write_mutex);
487 mutex_destroy(&g_deferred_free_mutex);
488
489 log_debug("Options state shutdown complete");
490}
void atomic_ptr_store(atomic_ptr_t *a, void *value)
Atomically store a pointer.
Definition atomic.c:280
void * atomic_ptr_load(atomic_ptr_t *a)
Atomically load a pointer.
Definition atomic.c:272
#define SAFE_FREE(ptr)
Definition common.h:376
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:548
int mutex_destroy(mutex_t *mutex)
Destroy a mutex.
Definition threading.c:22
bool lifecycle_is_initialized(const lifecycle_t *lc)
Definition lifecycle.c:155
bool lifecycle_shutdown(lifecycle_t *lc)
Definition lifecycle.c:108
Consolidated options structure.

References atomic_ptr_load(), atomic_ptr_store(), config_schema_destroy(), lifecycle_is_initialized(), lifecycle_shutdown(), log_debug, mutex_destroy(), and SAFE_FREE.

Referenced by asciichat_shared_destroy(), client_cleanup(), 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 370 of file rcu.c.

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

References ASCIICHAT_OK, atomic_ptr_load(), atomic_ptr_store(), ERROR_INVALID_STATE, ERROR_MEMORY, ERROR_THREAD, lifecycle_init(), lifecycle_is_initialized(), lifecycle_shutdown(), log_debug, log_dev, log_warn, mutex_destroy(), mutex_init(), 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 439 of file rcu.c.

439 {
440 if (!opts) {
441 return SET_ERRNO(ERROR_INVALID_PARAM, "opts is NULL");
442 }
443
444 // Check initialization state using lifecycle
445 if (!lifecycle_is_initialized(&g_options_lifecycle)) {
446 return SET_ERRNO(ERROR_INVALID_STATE, "Options state not initialized (call options_state_init first)");
447 }
448
449 // Get current struct (should be the initial zero-initialized one during startup)
450 options_t *current = atomic_ptr_load(&g_options);
451
452 // Copy provided options into current struct
453 // Note: No need for RCU update here since this is called during initialization
454 // before any reader threads exist
455 memcpy(current, opts, sizeof(options_t));
456
457 log_debug("Options state set from parsed struct");
458 return ASCIICHAT_OK;
459}
@ ERROR_INVALID_PARAM

References ASCIICHAT_OK, atomic_ptr_load(), ERROR_INVALID_PARAM, ERROR_INVALID_STATE, lifecycle_is_initialized(), log_debug, and SET_ERRNO.

Referenced by config_load_and_apply(), and options_init().