ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
include/ascii-chat/platform/init.h
Go to the documentation of this file.
1#pragma once
2
17#include "../platform/abstraction.h"
18
19// ============================================================================
20// Static Initialization Helpers
21// ============================================================================
22
23// Since Windows doesn't support static initialization of synchronization
24// primitives the same way POSIX does, we need a different approach.
25// We'll use a combination of static initialization and lazy initialization.
26
40typedef struct {
43#if PLATFORM_WINDOWS
45 volatile LONG initialized;
46#else
48 volatile int initialized;
49#endif
51
64typedef struct {
67#if PLATFORM_WINDOWS
69 volatile LONG initialized;
70#else
72 volatile int initialized;
73#endif
75
88typedef struct {
91#if PLATFORM_WINDOWS
93 volatile LONG initialized;
94#else
96 volatile int initialized;
97#endif
99
100// Initialization macros using designated initializers to avoid warnings
101// clang-format off
102#if PLATFORM_WINDOWS
103#define STATIC_MUTEX_INIT {.mutex = {0}, .initialized = 0}
104#define STATIC_RWLOCK_INIT {.lock = {0}, .initialized = 0}
105#define STATIC_COND_INIT {.cond = {0}, .initialized = 0}
106#else
107#define STATIC_MUTEX_INIT {.mutex.impl = PTHREAD_MUTEX_INITIALIZER, .mutex.name = NULL, .initialized = 1}
108#define STATIC_RWLOCK_INIT {.lock.impl = PTHREAD_RWLOCK_INITIALIZER, .lock.name = NULL, .initialized = 1}
109#define STATIC_COND_INIT {.cond.impl = PTHREAD_COND_INITIALIZER, .cond.name = NULL, .initialized = 1}
110#endif
111// clang-format on
112
113// Lazy initialization functions
114static inline void static_mutex_lock(static_mutex_t *m) {
115#if PLATFORM_WINDOWS
116 // Use InterlockedCompareExchange for thread-safe lazy init with proper synchronization
117 // Pattern: First thread sets flag to 1, initializes, then sets to 2
118 // Other threads spin until flag is 2 (fully initialized)
119 LONG prev = InterlockedCompareExchange(&m->initialized, 1, 0);
120 if (prev == 0) {
121 // We won the race - initialize the mutex
122 mutex_init(&m->mutex, "static_mutex");
123 // Memory barrier to ensure init is visible before flag update
124 MemoryBarrier();
125 InterlockedExchange(&m->initialized, 2);
126 } else if (prev == 1) {
127 // Another thread is initializing - spin until done
128 while (InterlockedCompareExchange(&m->initialized, 2, 2) != 2) {
129 YieldProcessor();
130 }
131 }
132 // prev == 2 means already initialized, proceed directly
133#else
134 // POSIX: Handle fork() by checking initialized flag atomically
135 // After fork(), child process must reinitialize the mutex
136 // Use atomic operations for thread-safe detection
137 if (__atomic_load_n(&m->initialized, __ATOMIC_ACQUIRE) == 0) {
138 // Mutex needs initialization (either never initialized or reset after fork)
139 mutex_init(&m->mutex, "static_mutex");
140 __atomic_store_n(&m->initialized, 1, __ATOMIC_RELEASE);
141 }
142#endif
143 mutex_lock(&m->mutex);
144}
145
146static inline void static_mutex_unlock(static_mutex_t *m) {
147 mutex_unlock(&m->mutex);
148}
149
150static inline void static_rwlock_rdlock(static_rwlock_t *l) {
151#if PLATFORM_WINDOWS
152 LONG prev = InterlockedCompareExchange(&l->initialized, 1, 0);
153 if (prev == 0) {
154 rwlock_init(&l->lock, "static_rwlock");
155 MemoryBarrier();
156 InterlockedExchange(&l->initialized, 2);
157 } else if (prev == 1) {
158 while (InterlockedCompareExchange(&l->initialized, 2, 2) != 2) {
159 YieldProcessor();
160 }
161 }
162#else
163 if (__atomic_load_n(&l->initialized, __ATOMIC_ACQUIRE) == 0) {
164 rwlock_init(&l->lock, "static_rwlock");
165 __atomic_store_n(&l->initialized, 1, __ATOMIC_RELEASE);
166 }
167#endif
168 rwlock_rdlock(&l->lock);
169}
170
171static inline void static_rwlock_wrlock(static_rwlock_t *l) {
172#if PLATFORM_WINDOWS
173 LONG prev = InterlockedCompareExchange(&l->initialized, 1, 0);
174 if (prev == 0) {
175 rwlock_init(&l->lock, "static_rwlock");
176 MemoryBarrier();
177 InterlockedExchange(&l->initialized, 2);
178 } else if (prev == 1) {
179 while (InterlockedCompareExchange(&l->initialized, 2, 2) != 2) {
180 YieldProcessor();
181 }
182 }
183#else
184 if (__atomic_load_n(&l->initialized, __ATOMIC_ACQUIRE) == 0) {
185 rwlock_init(&l->lock, "static_rwlock");
186 __atomic_store_n(&l->initialized, 1, __ATOMIC_RELEASE);
187 }
188#endif
189 rwlock_wrlock(&l->lock);
190}
191
192static inline void static_cond_wait(static_cond_t *c, static_mutex_t *m) {
193#if PLATFORM_WINDOWS
194 LONG prev = InterlockedCompareExchange(&c->initialized, 1, 0);
195 if (prev == 0) {
196 cond_init(&c->cond, "static_cond");
197 MemoryBarrier();
198 InterlockedExchange(&c->initialized, 2);
199 } else if (prev == 1) {
200 while (InterlockedCompareExchange(&c->initialized, 2, 2) != 2) {
201 YieldProcessor();
202 }
203 }
204 if (InterlockedCompareExchange(&m->initialized, 1, 0) == 0) {
205 mutex_init(&m->mutex, "static_mutex");
206 }
207#else
208 if (__atomic_load_n(&c->initialized, __ATOMIC_ACQUIRE) == 0) {
209 cond_init(&c->cond, "static_cond");
210 __atomic_store_n(&c->initialized, 1, __ATOMIC_RELEASE);
211 }
212 if (__atomic_load_n(&m->initialized, __ATOMIC_ACQUIRE) == 0) {
213 mutex_init(&m->mutex, "static_mutex");
214 __atomic_store_n(&m->initialized, 1, __ATOMIC_RELEASE);
215 }
216#endif
217 cond_wait(&c->cond, &m->mutex);
218}
219
220static inline void static_cond_timedwait(static_cond_t *c, static_mutex_t *m, int timeout_ms) {
221#if PLATFORM_WINDOWS
222 LONG prev = InterlockedCompareExchange(&c->initialized, 1, 0);
223 if (prev == 0) {
224 cond_init(&c->cond, "static_cond");
225 MemoryBarrier();
226 InterlockedExchange(&c->initialized, 2);
227 } else if (prev == 1) {
228 while (InterlockedCompareExchange(&c->initialized, 2, 2) != 2) {
229 YieldProcessor();
230 }
231 }
232 if (InterlockedCompareExchange(&m->initialized, 1, 0) == 0) {
233 mutex_init(&m->mutex, "static_mutex");
234 }
235#else
236 if (__atomic_load_n(&c->initialized, __ATOMIC_ACQUIRE) == 0) {
237 cond_init(&c->cond, "static_cond");
238 __atomic_store_n(&c->initialized, 1, __ATOMIC_RELEASE);
239 }
240 if (__atomic_load_n(&m->initialized, __ATOMIC_ACQUIRE) == 0) {
241 mutex_init(&m->mutex, "static_mutex");
242 __atomic_store_n(&m->initialized, 1, __ATOMIC_RELEASE);
243 }
244#endif
245 cond_timedwait(&c->cond, &m->mutex, timeout_ms);
246}
247
248static inline void static_cond_signal(static_cond_t *c) {
249#if PLATFORM_WINDOWS
250 LONG prev = InterlockedCompareExchange(&c->initialized, 1, 0);
251 if (prev == 0) {
252 cond_init(&c->cond, "static_cond");
253 MemoryBarrier();
254 InterlockedExchange(&c->initialized, 2);
255 } else if (prev == 1) {
256 while (InterlockedCompareExchange(&c->initialized, 2, 2) != 2) {
257 YieldProcessor();
258 }
259 }
260#else
261 if (__atomic_load_n(&c->initialized, __ATOMIC_ACQUIRE) == 0) {
262 cond_init(&c->cond, "static_cond");
263 __atomic_store_n(&c->initialized, 1, __ATOMIC_RELEASE);
264 }
265#endif
266 cond_signal(&c->cond);
267}
268
269static inline void static_cond_broadcast(static_cond_t *c) {
270#if PLATFORM_WINDOWS
271 LONG prev = InterlockedCompareExchange(&c->initialized, 1, 0);
272 if (prev == 0) {
273 cond_init(&c->cond, "static_cond");
274 MemoryBarrier();
275 InterlockedExchange(&c->initialized, 2);
276 } else if (prev == 1) {
277 while (InterlockedCompareExchange(&c->initialized, 2, 2) != 2) {
278 YieldProcessor();
279 }
280 }
281#else
282 if (__atomic_load_n(&c->initialized, __ATOMIC_ACQUIRE) == 0) {
283 cond_init(&c->cond, "static_cond");
284 __atomic_store_n(&c->initialized, 1, __ATOMIC_RELEASE);
285 }
286#endif
287 cond_broadcast(&c->cond);
288}
289
290// ============================================================================
291// Platform Initialization
292// ============================================================================
293
294// Call this once at program startup
296
297// Call this at program exit
298void platform_destroy(void);
299
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:49
#define cond_wait(cond, mutex)
Wait on a condition variable (with debug tracking in debug builds)
Definition cond.h:275
int rwlock_init(rwlock_t *rwlock, const char *name)
Initialize a read-write lock with a name.
Definition threading.c:65
#define mutex_lock(mutex)
Lock a mutex (with debug tracking in debug builds)
int cond_broadcast(cond_t *cond)
Broadcast to a condition variable (wake all waiting threads)
int mutex_init(mutex_t *mutex, const char *name)
Initialize a mutex with a name.
Definition threading.c:16
#define rwlock_rdlock(lock)
Acquire a read lock (with debug tracking in debug builds)
Definition rwlock.h:294
void platform_destroy(void)
Cleanup platform-specific subsystems.
int cond_signal(cond_t *cond)
Signal a condition variable (wake one waiting thread)
int cond_init(cond_t *cond, const char *name)
Initialize a condition variable with a name.
#define rwlock_wrlock(lock)
Acquire a write lock (with debug tracking in debug builds)
Definition rwlock.h:313
#define mutex_unlock(mutex)
Unlock a mutex (with debug tracking in debug builds)
#define cond_timedwait(cond, mutex, timeout_ns)
Wait on a condition variable with timeout (with debug tracking in debug builds)
Definition cond.h:300
asciichat_error_t platform_init(void)
Initialize platform-specific subsystems.
bool initialized
Definition mmap.c:38
Condition variable type (POSIX: pthread_cond_t with debug tracking)
Definition cond.h:63
Mutex type (POSIX: pthread_mutex_t with debug tracking)
Read-write lock type (POSIX: pthread_rwlock_t with debug tracking)
Definition rwlock.h:61
Static condition variable structure for global condition variables requiring static initialization.
volatile int initialized
Thread-safe initialization flag (POSIX: int for atomic operations)
cond_t cond
The actual condition variable.
Static mutex structure for global mutexes requiring static initialization.
volatile int initialized
Thread-safe initialization flag (POSIX: int for atomic operations)
mutex_t mutex
The actual mutex.
Static reader-writer lock structure for global rwlocks requiring static initialization.
rwlock_t lock
The actual reader-writer lock.
volatile int initialized
Thread-safe initialization flag (POSIX: int for atomic operations)