ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
lifecycle.h File Reference

Lock-free module lifecycle state machine using pure stdatomic. More...

Go to the source code of this file.

Data Structures

struct  lifecycle_t
 

Macros

#define LIFECYCLE_INIT
 Static initializer for module-global lifecycle variables (no sync primitive)
 
#define LIFECYCLE_INIT_MUTEX(m)
 Static initializer for lifecycle with mutex.
 
#define LIFECYCLE_INIT_RWLOCK(r)
 Static initializer for lifecycle with rwlock.
 

Enumerations

enum  lifecycle_state_t {
  LIFECYCLE_UNINITIALIZED = 0 , LIFECYCLE_INITIALIZING = 1 , LIFECYCLE_INITIALIZED = 2 , LIFECYCLE_DEAD = 3 ,
  LIFECYCLE_DESTROYING = 4
}
 
enum  lifecycle_sync_type_t { LIFECYCLE_SYNC_NONE = 0 , LIFECYCLE_SYNC_MUTEX = 1 , LIFECYCLE_SYNC_RWLOCK = 2 }
 

Functions

bool lifecycle_init (lifecycle_t *lc, const char *name)
 
bool lifecycle_init_once (lifecycle_t *lc)
 
void lifecycle_init_commit (lifecycle_t *lc)
 
void lifecycle_init_abort (lifecycle_t *lc)
 
bool lifecycle_shutdown (lifecycle_t *lc)
 
bool lifecycle_shutdown_forever (lifecycle_t *lc)
 
bool lifecycle_is_initialized (const lifecycle_t *lc)
 
bool lifecycle_is_dead (const lifecycle_t *lc)
 
bool lifecycle_reset (lifecycle_t *lc)
 
bool lifecycle_destroy_once (lifecycle_t *lc)
 
void lifecycle_destroy_commit (lifecycle_t *lc)
 

Detailed Description

Lock-free module lifecycle state machine using pure stdatomic.

Provides a standardized API for module-level init/shutdown synchronization across all modules. Uses a 4-state machine (UNINITIALIZED, INITIALIZING, INITIALIZED, DEAD) to coordinate concurrent initialization and permanent shutdown with zero mutex overhead.

Typical usage (concurrent init): static lifecycle_t g_module_lc = LIFECYCLE_INIT;

bool module_init(void) { if (!lifecycle_init_once(&g_module_lc)) return false; // do actual init work if (init_failed) { lifecycle_init_abort(&g_module_lc); // allow retry return false; } lifecycle_init_commit(&g_module_lc); // mark ready return true; }

Typical usage (non-concurrent, single-threaded startup): if (!lifecycle_init(&g_module_lc)) return false; // already initialized // do actual init work

Definition in file lifecycle.h.

Macro Definition Documentation

◆ LIFECYCLE_INIT

#define LIFECYCLE_INIT
Value:
{ \
.state = {.impl = LIFECYCLE_UNINITIALIZED}, .sync_type = LIFECYCLE_SYNC_NONE, .sync = {0} \
}
@ LIFECYCLE_SYNC_NONE
No sync primitive.
Definition lifecycle.h:49
@ LIFECYCLE_UNINITIALIZED
Not yet initialized (zero = default)
Definition lifecycle.h:41

Static initializer for module-global lifecycle variables (no sync primitive)

Definition at line 68 of file lifecycle.h.

69 { \
70 .state = {.impl = LIFECYCLE_UNINITIALIZED}, .sync_type = LIFECYCLE_SYNC_NONE, .sync = {0} \
71 }

◆ LIFECYCLE_INIT_MUTEX

#define LIFECYCLE_INIT_MUTEX (   m)
Value:
{ \
.state = {.impl = LIFECYCLE_UNINITIALIZED}, .sync_type = LIFECYCLE_SYNC_MUTEX, .sync = {.mutex = (m) } \
}
@ LIFECYCLE_SYNC_MUTEX
Contains mutex_t pointer.
Definition lifecycle.h:50

Static initializer for lifecycle with mutex.

Definition at line 74 of file lifecycle.h.

75 { \
76 .state = {.impl = LIFECYCLE_UNINITIALIZED}, .sync_type = LIFECYCLE_SYNC_MUTEX, .sync = {.mutex = (m) } \
77 }

◆ LIFECYCLE_INIT_RWLOCK

#define LIFECYCLE_INIT_RWLOCK (   r)
Value:
{ \
.state = {.impl = LIFECYCLE_UNINITIALIZED}, .sync_type = LIFECYCLE_SYNC_RWLOCK, .sync = {.rwlock = (r) } \
}
@ LIFECYCLE_SYNC_RWLOCK
Contains rwlock_t pointer.
Definition lifecycle.h:51

Static initializer for lifecycle with rwlock.

Definition at line 80 of file lifecycle.h.

81 { \
82 .state = {.impl = LIFECYCLE_UNINITIALIZED}, .sync_type = LIFECYCLE_SYNC_RWLOCK, .sync = {.rwlock = (r) } \
83 }

Enumeration Type Documentation

◆ lifecycle_state_t

Enumerator
LIFECYCLE_UNINITIALIZED 

Not yet initialized (zero = default)

LIFECYCLE_INITIALIZING 

init_once winner in progress; losers spin

LIFECYCLE_INITIALIZED 

Ready to use.

LIFECYCLE_DEAD 

Permanently shut down; no re-init.

LIFECYCLE_DESTROYING 

destroy_once winner in progress; losers skip

Definition at line 40 of file lifecycle.h.

40 {
44 LIFECYCLE_DEAD = 3,
lifecycle_state_t
Definition lifecycle.h:40
@ LIFECYCLE_DESTROYING
destroy_once winner in progress; losers skip
Definition lifecycle.h:45
@ LIFECYCLE_INITIALIZING
init_once winner in progress; losers spin
Definition lifecycle.h:42
@ LIFECYCLE_INITIALIZED
Ready to use.
Definition lifecycle.h:43
@ LIFECYCLE_DEAD
Permanently shut down; no re-init.
Definition lifecycle.h:44

◆ lifecycle_sync_type_t

Enumerator
LIFECYCLE_SYNC_NONE 

No sync primitive.

LIFECYCLE_SYNC_MUTEX 

Contains mutex_t pointer.

LIFECYCLE_SYNC_RWLOCK 

Contains rwlock_t pointer.

Definition at line 48 of file lifecycle.h.

Function Documentation

◆ lifecycle_destroy_commit()

void lifecycle_destroy_commit ( lifecycle_t *  lc)

Commit successful destruction: DESTROYING → UNINITIALIZED. Call this after lifecycle_destroy_once() returns true and destroy work completes.

Parameters
lclifecycle state

Returns the module to UNINITIALIZED state, allowing future re-initialization.

Definition at line 236 of file lifecycle.c.

236 {
237 if (lc == NULL) {
238 log_dev("[lifecycle] destroy_commit: NULL lifecycle pointer");
239 return;
240 }
241 log_dev("[lifecycle] destroy_commit: transitioning DESTROYING → UNINITIALIZED");
243}
void atomic_store_u64(atomic_t *a, uint64_t value)
Atomically store a uint64_t value.
Definition atomic.c:241
#define log_dev(...)
Log a DEV message (most verbose, development only)
Definition log/log.h:534
atomic_t state
lifecycle_state_t enum value
Definition lifecycle.h:59

References atomic_store_u64(), LIFECYCLE_UNINITIALIZED, log_dev, and lifecycle_t::state.

Referenced by audio_stop_thread().

◆ lifecycle_destroy_once()

bool lifecycle_destroy_once ( lifecycle_t *  lc)

Lock-free concurrent destruction: CAS INITIALIZED → DESTROYING.

Winner receives true and must complete the two-phase sequence:

  1. Do actual destroy work
  2. Call lifecycle_destroy_commit() on completion

Losing callers return false and should skip cleanup work. Once destruction begins, no further operations are possible until the winner completes.

Parameters
lclifecycle state
Returns
true if THIS caller won the destroy race and should do work
false if not INITIALIZED, already being destroyed, or in DEAD state

Safe for concurrent callers. Exactly one caller gets true (the CAS winner). Prevents double-join and other double-cleanup issues when multiple threads call cleanup functions concurrently.

Definition at line 193 of file lifecycle.c.

193 {
194 if (lc == NULL) {
195 log_dev("[lifecycle] destroy_once: NULL lifecycle pointer");
196 return false;
197 }
198
200 if (!atomic_cas_u64(&lc->state, &expected, LIFECYCLE_DESTROYING)) {
201 // If not initialized, nothing to destroy
202 if (expected == LIFECYCLE_UNINITIALIZED) {
203 log_dev("[lifecycle] destroy_once: already uninitialized, nothing to destroy");
204 return false;
205 }
206
207 // If dead, never allow destruction (already permanently shut down)
208 if (expected == LIFECYCLE_DEAD) {
209 log_dev("[lifecycle] destroy_once: module is dead, no destruction allowed");
210 return false;
211 }
212
213 // If already destroying, don't duplicate work (return false, let first destroyer finish)
214 if (expected == LIFECYCLE_DESTROYING) {
215 log_dev("[lifecycle] destroy_once: already destroying, skipping (first destroyer has priority)");
216 return false;
217 }
218
219 // If initializing, skip destruction (init may still be in progress)
220 if (expected == LIFECYCLE_INITIALIZING) {
221 log_dev("[lifecycle] destroy_once: still initializing, skipping destruction");
222 return false;
223 }
224
225 // Unexpected state
226 log_dev("[lifecycle] destroy_once: unexpected state: %d", expected);
227 return false;
228 }
229
230 // Winner: state is now LIFECYCLE_DESTROYING
231 // Caller must call lifecycle_destroy_commit()
232 log_dev("[lifecycle] destroy_once: won CAS, transitioned to DESTROYING");
233 return true;
234}
bool atomic_cas_u64(atomic_t *a, uint64_t *expected, uint64_t new_value)
Atomically compare-and-swap a uint64_t.
Definition atomic.c:264
unsigned long long uint64_t
Definition common.h:59

References atomic_cas_u64(), LIFECYCLE_DEAD, LIFECYCLE_DESTROYING, LIFECYCLE_INITIALIZED, LIFECYCLE_INITIALIZING, LIFECYCLE_UNINITIALIZED, log_dev, and lifecycle_t::state.

Referenced by audio_stop_thread().

◆ lifecycle_init()

bool lifecycle_init ( lifecycle_t *  lc,
const char *  name 
)

CAS-based initialization: UNINIT → INITIALIZED.

Parameters
lclifecycle state (may include sync_type and sync pointer)
namename tag for any sync primitive (for debugging), or NULL if no sync
Returns
true if THIS caller won the race and should do init work
false if already INITIALIZED, INITIALIZING, or DEAD

Suitable for single-threaded startup or contexts where the caller guarantees serialization. If lc->sync_type != SYNC_NONE, initializes the sync primitive.

Definition at line 26 of file lifecycle.c.

26 {
27 if (lc == NULL) {
28 lifecycle_log_dev("[lifecycle] init: NULL lifecycle pointer");
29 return false;
30 }
32 if (!atomic_cas_u64(&lc->state, &expected, LIFECYCLE_INITIALIZED)) {
33 lifecycle_log_dev("[lifecycle] init: %s already initialized (current state: %llu)", name ? name : "<unnamed>",
34 expected);
35 return false; // Already initialized or in INITIALIZING/DEAD state
36 }
37
38 /* Winner: initialize sync primitive if configured */
39 if (lc->sync_type == LIFECYCLE_SYNC_MUTEX && lc->sync.mutex != NULL) {
40 lifecycle_log_dev("[lifecycle] init: %s initializing mutex", name ? name : "<unnamed>");
41 mutex_init(lc->sync.mutex, name);
42 } else if (lc->sync_type == LIFECYCLE_SYNC_RWLOCK && lc->sync.rwlock != NULL) {
43 lifecycle_log_dev("[lifecycle] init: %s initializing rwlock", name ? name : "<unnamed>");
44 rwlock_init(lc->sync.rwlock, name);
45 } else {
46 lifecycle_log_dev("[lifecycle] init: %s initialized (no sync primitive)", name ? name : "<unnamed>");
47 }
48
49 return true;
50}
int rwlock_init(rwlock_t *rwlock, const char *name)
Initialize a read-write lock with a name.
Definition threading.c:65
int mutex_init(mutex_t *mutex, const char *name)
Initialize a mutex with a name.
Definition threading.c:16
#define lifecycle_log_dev(...)
Definition lifecycle.c:17
union lifecycle_t::@24 sync
rwlock_t * rwlock
Pointer to rwlock (if sync_type == LIFECYCLE_SYNC_RWLOCK)
Definition lifecycle.h:63
mutex_t * mutex
Pointer to mutex (if sync_type == LIFECYCLE_SYNC_MUTEX)
Definition lifecycle.h:62
lifecycle_sync_type_t sync_type
Type of sync primitive (if any)
Definition lifecycle.h:60

References atomic_cas_int(), atomic_cas_u64(), LIFECYCLE_INITIALIZED, lifecycle_log_dev, LIFECYCLE_SYNC_MUTEX, LIFECYCLE_SYNC_RWLOCK, LIFECYCLE_UNINITIALIZED, lifecycle_t::mutex, mutex_init(), lifecycle_t::rwlock, rwlock_init(), lifecycle_t::state, lifecycle_t::sync, and lifecycle_t::sync_type.

Referenced by ansi_fast_init_16color(), ansi_fast_init_256color(), asciichat_error_stats_get(), asciichat_error_stats_init(), asciichat_error_stats_record(), asciichat_pcre2_singleton_compile(), asciichat_pcre2_singleton_get_code(), audio_sender_init(), audio_stop_thread(), buffer_pool_init_global(), client_crypto_init(), colorscheme_init(), init_default_luminance_palette(), log_init(), log_search_init(), named_init(), options_state_init(), stats_init(), symbol_cache_init(), and timer_system_init().

◆ lifecycle_init_abort()

void lifecycle_init_abort ( lifecycle_t *  lc)

Abort failed initialization: INITIALIZING → UNINITIALIZED. Call this if lifecycle_init_once() returns true but init work fails.

Parameters
lclifecycle state

Allows the next caller to retry initialization. Wakes spinners.

Definition at line 99 of file lifecycle.c.

99 {
100 if (lc == NULL) {
101 lifecycle_log_dev("[lifecycle] init_abort: NULL lifecycle pointer");
102 return;
103 }
104 lifecycle_log_dev("[lifecycle] init_abort: transitioning INITIALIZING → UNINITIALIZED (retry allowed)");
106}

References atomic_store_int(), atomic_store_u64(), lifecycle_log_dev, LIFECYCLE_UNINITIALIZED, and lifecycle_t::state.

Referenced by audio_client_init(), and symbol_cache_init().

◆ lifecycle_init_commit()

void lifecycle_init_commit ( lifecycle_t *  lc)

Commit successful initialization: INITIALIZING → INITIALIZED. Call this after lifecycle_init_once() returns true and init work succeeds.

Parameters
lclifecycle state

Wakes all spinners waiting in lifecycle_init_once(). Must be called by the lifecycle_init_once() winner after successful init work.

Definition at line 90 of file lifecycle.c.

90 {
91 if (lc == NULL) {
92 lifecycle_log_dev("[lifecycle] init_commit: NULL lifecycle pointer");
93 return;
94 }
95 lifecycle_log_dev("[lifecycle] init_commit: transitioning INITIALIZING → INITIALIZED");
97}

References atomic_store_int(), atomic_store_u64(), LIFECYCLE_INITIALIZED, lifecycle_log_dev, and lifecycle_t::state.

Referenced by asciichat_instr_coverage_enabled(), asciichat_instr_runtime_get(), asciichat_pcre2_singleton_get_code(), audio_client_init(), log_search_init(), named_init(), splash_set_update_notification(), update_banner_has_update(), and update_banner_set_result().

◆ lifecycle_init_once()

bool lifecycle_init_once ( lifecycle_t *  lc)

Lock-free concurrent initialization: CAS UNINIT → INITIALIZING.

Winner receives true and must complete the two-phase sequence:

  1. Do actual init work
  2. Call lifecycle_init_commit() on success or lifecycle_init_abort() on failure

Losing callers spin on the transient INITIALIZING state until the winner commits, then return false without doing work.

Parameters
lclifecycle state
Returns
true if THIS caller won the init race and should do work
false if init already happened (or is in progress) or module is DEAD

Safe for concurrent callers. Exactly one caller gets true (the CAS winner). Other concurrent callers spin until the winner moves to INITIALIZED or DEAD.

Definition at line 52 of file lifecycle.c.

52 {
53 if (lc == NULL) {
54 lifecycle_log_dev("[lifecycle] init_once: NULL lifecycle pointer");
55 return false;
56 }
57
59 if (!atomic_cas_u64(&lc->state, &expected, LIFECYCLE_INITIALIZING)) {
60 // If already initialized, just return false (no work needed)
61 if (expected == LIFECYCLE_INITIALIZED) {
62 lifecycle_log_dev("[lifecycle] init_once: already initialized");
63 return false;
64 }
65
66 // If dead, never allow re-init
67 if (expected == LIFECYCLE_DEAD) {
68 lifecycle_log_dev("[lifecycle] init_once: module is dead, no re-init allowed");
69 return false;
70 }
71
72 // If initializing, don't spin (caller may be retrying or it may complete asynchronously)
73 // Just return false to indicate this thread doesn't need to do init work
74 if (expected == LIFECYCLE_INITIALIZING) {
75 lifecycle_log_dev("[lifecycle] init_once: already initializing, skipping (will resolve asynchronously)");
76 return false;
77 }
78
79 // Unexpected state
80 lifecycle_log_dev("[lifecycle] init_once: unexpected state: %d", expected);
81 return false;
82 }
83
84 // Winner: state is now LIFECYCLE_INITIALIZING
85 // Caller must call lifecycle_init_commit() or lifecycle_init_abort()
86 lifecycle_log_dev("[lifecycle] init_once: won CAS, transitioned to INITIALIZING");
87 return true;
88}

References atomic_cas_int(), atomic_cas_u64(), LIFECYCLE_DEAD, LIFECYCLE_INITIALIZED, LIFECYCLE_INITIALIZING, lifecycle_log_dev, LIFECYCLE_UNINITIALIZED, and lifecycle_t::state.

Referenced by asciichat_instr_coverage_enabled(), asciichat_instr_runtime_get(), audio_client_init(), log_search_init(), splash_set_update_notification(), update_banner_has_update(), and update_banner_set_result().

◆ lifecycle_is_dead()

bool lifecycle_is_dead ( const lifecycle_t *  lc)

Query: is module in DEAD state?

Parameters
lclifecycle state
Returns
true if state == LIFECYCLE_DEAD

Load-only, no side effects. Safe to call from any thread.

Definition at line 161 of file lifecycle.c.

161 {
162 if (lc == NULL)
163 return false;
164 return atomic_load_u64(&lc->state) == LIFECYCLE_DEAD;
165}
uint64_t atomic_load_u64(atomic_t *a)
Atomically load a uint64_t value.
Definition atomic.c:233

References atomic_load_u64(), LIFECYCLE_DEAD, and lifecycle_t::state.

◆ lifecycle_is_initialized()

bool lifecycle_is_initialized ( const lifecycle_t *  lc)

Query: is module in INITIALIZED state?

Parameters
lclifecycle state
Returns
true if state == LIFECYCLE_INITIALIZED

Load-only, no side effects. Safe to call from any thread.

Definition at line 155 of file lifecycle.c.

155 {
156 if (lc == NULL)
157 return false;
159}

References atomic_load_u64(), LIFECYCLE_INITIALIZED, and lifecycle_t::state.

Referenced by asciichat_error_stats_get(), asciichat_error_stats_print(), asciichat_error_stats_record(), asciichat_error_stats_reset(), asciichat_instr_coverage_enabled(), asciichat_instr_runtime_get(), asciichat_pcre2_singleton_get_code(), audio_client_init(), audio_sender_cleanup(), audio_sender_finalize(), audio_stop_thread(), client_crypto_handshake(), colorscheme_destroy(), colorscheme_get_active_scheme(), colorscheme_init(), colorscheme_set_active_scheme(), crypto_client_initiate_rekey(), crypto_client_is_ready(), crypto_client_process_rekey_request(), crypto_client_process_rekey_response(), crypto_client_send_rekey_complete(), crypto_client_send_rekey_response(), crypto_client_should_rekey(), log_file_msg(), log_init(), log_init_colors(), log_msg(), log_plain_msg(), log_plain_stderr_msg(), log_plain_stderr_nonewline_msg(), log_plain_stdout_msg(), log_server_stats(), log_terminal_msg(), named_describe(), named_get(), named_get_fd(), named_get_fd_format_spec(), named_get_format_spec(), named_get_packet_type(), named_get_packet_type_format_spec(), named_get_type(), named_init(), named_register(), named_register_fd(), named_register_fmt(), named_register_packet_type(), named_registry_for_each(), named_unregister(), options_state_destroy(), options_state_init(), options_state_set(), platform_is_binary_in_path(), simd_caches_destroy_all(), symbol_cache_insert(), symbol_cache_lookup(), symbol_cache_resolve_batch(), timer_is_initialized(), timer_start(), timer_stop(), timer_system_destroy(), timer_system_init(), and webrtc_create_peer_connection().

◆ lifecycle_reset()

bool lifecycle_reset ( lifecycle_t *  lc)

Reset initialized module: INITIALIZED → UNINITIALIZED.

Parameters
lclifecycle state (may include sync_type and sync pointer)
Returns
true if THIS caller should do reset work
false if not INITIALIZED or in DEAD state

Allows re-initialization after reset (like shutdown, but keeps sync primitives). If lc->sync_type != SYNC_NONE, destroys the sync primitive (will be recreated on next init). Used for modules that support reset/reinit cycles (e.g., client crypto reconnect).

Definition at line 167 of file lifecycle.c.

167 {
168 if (lc == NULL) {
169 log_dev("[lifecycle] reset: NULL lifecycle pointer");
170 return false;
171 }
172
174 if (!atomic_cas_u64(&lc->state, &expected, LIFECYCLE_UNINITIALIZED)) {
175 log_dev("[lifecycle] reset: not in INITIALIZED state (current: %d)", expected);
176 return false; // Not in INITIALIZED state
177 }
178
179 /* Winner: destroy sync primitive if configured (reset keeps same primitive) */
180 if (lc->sync_type == LIFECYCLE_SYNC_MUTEX && lc->sync.mutex != NULL) {
181 log_dev("[lifecycle] reset: destroying and resetting mutex");
183 } else if (lc->sync_type == LIFECYCLE_SYNC_RWLOCK && lc->sync.rwlock != NULL) {
184 log_dev("[lifecycle] reset: destroying and resetting rwlock");
186 } else {
187 log_dev("[lifecycle] reset: completed (no sync primitive, allows reinit)");
188 }
189
190 return true;
191}
int rwlock_destroy(rwlock_t *lock)
Destroy a read-write lock.
int mutex_destroy(mutex_t *mutex)
Destroy a mutex.
Definition threading.c:22

References atomic_cas_u64(), LIFECYCLE_INITIALIZED, LIFECYCLE_SYNC_MUTEX, LIFECYCLE_SYNC_RWLOCK, LIFECYCLE_UNINITIALIZED, log_dev, lifecycle_t::mutex, mutex_destroy(), lifecycle_t::rwlock, rwlock_destroy(), lifecycle_t::state, lifecycle_t::sync, and lifecycle_t::sync_type.

Referenced by client_crypto_init().

◆ lifecycle_shutdown()

bool lifecycle_shutdown ( lifecycle_t *  lc)

Regular shutdown: INITIALIZED → UNINITIALIZED.

Parameters
lclifecycle state (may include sync_type and sync pointer)
Returns
true if THIS caller should do shutdown work
false if already UNINITIALIZED or DEAD

Allows re-initialization after shutdown (unlike shutdown_forever). If lc->sync_type != SYNC_NONE, destroys the sync primitive.

Definition at line 108 of file lifecycle.c.

108 {
109 if (lc == NULL) {
110 lifecycle_log_dev("[lifecycle] shutdown: NULL lifecycle pointer");
111 return false;
112 }
114 if (!atomic_cas_u64(&lc->state, &expected, LIFECYCLE_UNINITIALIZED)) {
115 lifecycle_log_dev("[lifecycle] shutdown: not in INITIALIZED state (current: %d)", expected);
116 return false; // Not initialized or in unexpected state
117 }
118
119 /* Winner: destroy sync primitive if configured */
120 if (lc->sync_type == LIFECYCLE_SYNC_MUTEX && lc->sync.mutex != NULL) {
121 lifecycle_log_dev("[lifecycle] shutdown: destroying mutex");
123 } else if (lc->sync_type == LIFECYCLE_SYNC_RWLOCK && lc->sync.rwlock != NULL) {
124 lifecycle_log_dev("[lifecycle] shutdown: destroying rwlock");
126 } else {
127 lifecycle_log_dev("[lifecycle] shutdown: completed (no sync primitive)");
128 }
129
130 return true;
131}

References atomic_cas_u64(), atomic_store_int(), LIFECYCLE_INITIALIZED, lifecycle_log_dev, LIFECYCLE_SYNC_MUTEX, LIFECYCLE_SYNC_RWLOCK, LIFECYCLE_UNINITIALIZED, lifecycle_t::mutex, mutex_destroy(), lifecycle_t::rwlock, rwlock_destroy(), lifecycle_t::state, lifecycle_t::sync, and lifecycle_t::sync_type.

Referenced by acds_strings_destroy(), asciichat_instr_runtime_global_destroy(), asciichat_pcre2_cleanup_all(), audio_sender_finalize(), audio_terminate_portaudio_final(), buffer_pool_cleanup_global(), colorscheme_destroy(), crypto_client_cleanup(), lifecycle_shutdown_forever(), log_destroy(), log_search_destroy(), named_destroy(), named_init(), options_state_destroy(), options_state_init(), platform_cleanup_binary_path_cache(), simd_caches_destroy_all(), stats_cleanup(), symbol_cache_destroy(), and timer_system_destroy().

◆ lifecycle_shutdown_forever()

bool lifecycle_shutdown_forever ( lifecycle_t *  lc)

Permanent shutdown: any non-DEAD → DEAD.

Parameters
lclifecycle state
Returns
true if module was INITIALIZED and caller should do shutdown work
false if already DEAD

Once DEAD, future init/init_once calls always return false. Spins if called while init_once is in progress (INITIALIZING state). Used for modules that must never be re-initialized.

Definition at line 133 of file lifecycle.c.

133 {
134 if (lc == NULL) {
135 log_dev("[lifecycle] shutdown_forever: NULL lifecycle pointer");
136 return false;
137 }
138
139 uint64_t current;
140 do {
141 current = atomic_load_u64(&lc->state);
142 if (current == LIFECYCLE_DEAD) {
143 log_dev("[lifecycle] shutdown_forever: already DEAD");
144 return false;
145 }
146 if (current == LIFECYCLE_INITIALIZING) {
147 log_dev("[lifecycle] shutdown_forever: spinning on INITIALIZING");
148 }
149 } while (current == LIFECYCLE_INITIALIZING || !atomic_cas_u64(&lc->state, &current, LIFECYCLE_DEAD));
150
151 log_dev("[lifecycle] shutdown_forever: transitioned to DEAD (was in state: %d)", current);
152 return current == LIFECYCLE_INITIALIZED;
153}

References atomic_cas_u64(), atomic_load_u64(), LIFECYCLE_DEAD, LIFECYCLE_INITIALIZED, LIFECYCLE_INITIALIZING, lifecycle_shutdown(), log_dev, and lifecycle_t::state.