libxtc 0.4.0
Async concurrency for C: Tokio + Seastar + BEAM, in one library
Loading...
Searching...
No Matches
os_thread.h
1/*-
2 * Copyright (c) 2026, The XTC Project
3 * Use of this source code is governed by the ISC License.
4 *
5 * src/inc/os_thread.h
6 * Thread, TLS, mutex, rwlock, cond, sem abstractions.
7 * The pthreads implementation lives in src/os/os_*.c; a Win32
8 * implementation lands later behind the same surface.
9 * See M1_CLAIMS.md, T1-T7, L1-L5, Mu1-Mu6.
10 */
11
12#ifndef XTC_OS_THREAD_H
13#define XTC_OS_THREAD_H
14
15#include <stddef.h>
16#include <stdint.h>
17
18/*
19 * Thread-local storage-class specifier. GCC and clang spell it
20 * __thread; MSVC spells it __declspec(thread); C11 has _Thread_local.
21 * XTC_THREAD_LOCAL is the portable spelling used throughout the
22 * source. (Defined here because both xtc_int.h and loop_int.h
23 * include this header.)
24 */
25#if defined(_MSC_VER)
26# define XTC_THREAD_LOCAL __declspec(thread)
27#elif defined(__GNUC__) || defined(__clang__)
28# define XTC_THREAD_LOCAL __thread
29#else
30# define XTC_THREAD_LOCAL _Thread_local
31#endif
32
33/*
34 * Opaque handles. The full struct lives in the implementation file;
35 * callers see only an opaque pointer plus a sentinel-zero state.
36 *
37 * We reserve a small in-line "state" struct rather than allocating
38 * via __os_malloc -- initialisation must work before the allocator
39 * is initialised on some platforms.
40 */
41struct __os_thread { void *opaque; };
42/*
43 * Opaque storage with explicit alignment. pthread_mutex_t / cond_t /
44 * rwlock_t / sem_t carry stricter alignment requirements than `char`
45 * on some platforms (notably illumos / Solaris where uninitialized or
46 * misaligned storage causes pthread_mutex_init to return EINVAL).
47 * `_Alignas(long long)` gives us 8-byte alignment which covers every
48 * known pthread implementation. The rwlock buffer is 256 bytes:
49 * macOS's pthread_rwlock_t is ~200 (vs ~56 on glibc), so 128 was too
50 * small there.
51 */
52struct __os_mutex { _Alignas(long long) unsigned char storage[64]; };
53struct __os_rwlock { _Alignas(long long) unsigned char storage[256]; };
54struct __os_cond { _Alignas(long long) unsigned char storage[64]; };
55struct __os_sem { _Alignas(long long) unsigned char storage[64]; };
56
57typedef struct __os_thread __os_thread_t;
58typedef struct __os_mutex __os_mutex_t;
59typedef struct __os_rwlock __os_rwlock_t;
60typedef struct __os_cond __os_cond_t;
61typedef struct __os_sem __os_sem_t;
62typedef unsigned long __os_tls_key_t;
63
64typedef void *(*__os_thread_fn)(void *);
65typedef void (*__os_tls_dtor)(void *);
66
67/*
68 * --- Threads ---
69 *
70 * PUBLIC: int __os_thread_create __P((__os_thread_t *, __os_thread_fn, void *));
71 * PUBLIC: int __os_thread_join __P((__os_thread_t *, void **));
72 * PUBLIC: int __os_thread_detach __P((__os_thread_t *));
73 * PUBLIC: int __os_thread_self __P((__os_thread_t *));
74 * PUBLIC: void __os_thread_yield __P((void));
75 * PUBLIC: int __os_thread_setname __P((const char *));
76 * PUBLIC: void __os_thread_apply_default_qos __P((void));
77 * PUBLIC: int __os_thread_set_affinity __P((int));
78 */
79int __os_thread_create(__os_thread_t *thr, __os_thread_fn fn, void *arg);
80
81/* Create a raw pthread with all signals blocked (mask restored after),
82 * for the few call sites that hold a raw pthread_t rather than an
83 * __os_thread_t (the PSI slab thread, the deadlock detector). Keeps
84 * every runtime thread from inheriting a permissive signal mask.
85 * Declared with a pthread_t; callers already include <pthread.h>. */
86#include <pthread.h>
87int __os_pthread_create_masked(pthread_t *out, void *(*fn)(void *),
88 void *arg);
89int __os_thread_join(__os_thread_t *thr, void **retval);
90int __os_thread_detach(__os_thread_t *thr);
91int __os_thread_self(__os_thread_t *out);
92void __os_thread_yield(void);
93int __os_thread_setname(const char *name);
94void __os_thread_apply_default_qos(void);
95int __os_thread_set_affinity(int cpu);
96
97/*
98 * --- TLS ---
99 *
100 * PUBLIC: int __os_tls_create __P((__os_tls_key_t *, __os_tls_dtor));
101 * PUBLIC: int __os_tls_destroy __P((__os_tls_key_t));
102 * PUBLIC: int __os_tls_set __P((__os_tls_key_t, void *));
103 * PUBLIC: void *__os_tls_get __P((__os_tls_key_t));
104 */
105int __os_tls_create(__os_tls_key_t *key, __os_tls_dtor dtor);
106int __os_tls_destroy(__os_tls_key_t key);
107int __os_tls_set(__os_tls_key_t key, void *value);
108void *__os_tls_get(__os_tls_key_t key);
109
110/*
111 * --- Mutex ---
112 *
113 * PUBLIC: int __os_mutex_init __P((__os_mutex_t *));
114 * PUBLIC: int __os_mutex_destroy __P((__os_mutex_t *));
115 * PUBLIC: int __os_mutex_lock __P((__os_mutex_t *));
116 * PUBLIC: int __os_mutex_trylock __P((__os_mutex_t *));
117 * PUBLIC: int __os_mutex_unlock __P((__os_mutex_t *));
118 */
119int __os_mutex_init(__os_mutex_t *m);
120int __os_mutex_destroy(__os_mutex_t *m);
121int __os_mutex_lock(__os_mutex_t *m);
122int __os_mutex_trylock(__os_mutex_t *m);
123int __os_mutex_unlock(__os_mutex_t *m);
124
125/*
126 * --- RWLock ---
127 *
128 * PUBLIC: int __os_rwlock_init __P((__os_rwlock_t *));
129 * PUBLIC: int __os_rwlock_destroy __P((__os_rwlock_t *));
130 * PUBLIC: int __os_rwlock_rdlock __P((__os_rwlock_t *));
131 * PUBLIC: int __os_rwlock_wrlock __P((__os_rwlock_t *));
132 * PUBLIC: int __os_rwlock_unlock __P((__os_rwlock_t *));
133 */
134int __os_rwlock_init(__os_rwlock_t *r);
135int __os_rwlock_destroy(__os_rwlock_t *r);
136int __os_rwlock_rdlock(__os_rwlock_t *r);
137int __os_rwlock_wrlock(__os_rwlock_t *r);
138int __os_rwlock_unlock(__os_rwlock_t *r);
139
140/*
141 * --- Condition variable ---
142 *
143 * PUBLIC: int __os_cond_init __P((__os_cond_t *));
144 * PUBLIC: int __os_cond_destroy __P((__os_cond_t *));
145 * PUBLIC: int __os_cond_wait __P((__os_cond_t *, __os_mutex_t *));
146 * PUBLIC: int __os_cond_signal __P((__os_cond_t *));
147 * PUBLIC: int __os_cond_broadcast __P((__os_cond_t *));
148 */
149int __os_cond_init(__os_cond_t *c);
150int __os_cond_destroy(__os_cond_t *c);
151int __os_cond_wait(__os_cond_t *c, __os_mutex_t *m);
152int __os_cond_signal(__os_cond_t *c);
153int __os_cond_broadcast(__os_cond_t *c);
154
155/*
156 * --- Semaphore (counting; unnamed, in-process) ---
157 *
158 * PUBLIC: int __os_sem_init __P((__os_sem_t *, unsigned));
159 * PUBLIC: int __os_sem_destroy __P((__os_sem_t *));
160 * PUBLIC: int __os_sem_post __P((__os_sem_t *));
161 * PUBLIC: int __os_sem_wait __P((__os_sem_t *));
162 * PUBLIC: int __os_sem_trywait __P((__os_sem_t *));
163 */
164int __os_sem_init(__os_sem_t *s, unsigned initial);
165int __os_sem_destroy(__os_sem_t *s);
166int __os_sem_post(__os_sem_t *s);
167int __os_sem_wait(__os_sem_t *s);
168int __os_sem_trywait(__os_sem_t *s);
169
170#endif /* XTC_OS_THREAD_H */