Lime Parser Generator 0.1.0
Runtime-extensible LALR(1) parser with SIMD tokenization and LLVM JIT
Loading...
Searching...
No Matches
lime_threads.h
1/*
2** lime_threads.h -- minimal pthread shim for Windows portability.
3**
4** On POSIX (Linux, macOS, FreeBSD, Solaris, etc.) this header
5** is just a passthrough to <pthread.h>; existing code that uses
6** pthread_rwlock_t / pthread_mutex_t / pthread_t compiles
7** unchanged.
8**
9** On Windows / MSVC, where <pthread.h> is not in the platform
10** SDK, this header provides the pthread API surface Lime
11** actually uses, implemented on top of Win32 SRWLock,
12** CRITICAL_SECTION, and the classic thread API. The mapping
13** is pragmatic, not faithful: error returns are 0 on success
14** (not POSIX EBUSY/EINVAL details) since Lime's call sites
15** only check `!= 0` to decide whether to abort.
16**
17** Subset implemented (= what Lime needs as of v0.2.x):
18**
19** pthread_rwlock_t -> SRWLOCK
20** pthread_rwlock_init -> InitializeSRWLock + 0
21** pthread_rwlock_destroy -> 0 (SRWLOCK has no destructor)
22** pthread_rwlock_rdlock -> AcquireSRWLockShared
23** pthread_rwlock_wrlock -> AcquireSRWLockExclusive
24** pthread_rwlock_unlock -> ReleaseSRWLockShared (read)
25** or ReleaseSRWLockExclusive (write)
26** -- callers MUST pair lock/unlock by hand on Windows
27** because SRWLOCK is two distinct release paths. Lime
28** wraps with two thin macros: LIME_RWLOCK_RDUNLOCK and
29** LIME_RWLOCK_WRUNLOCK. POSIX users use the same
30** macros (which expand to plain pthread_rwlock_unlock)
31** for source-compatibility.
32**
33** pthread_mutex_t -> CRITICAL_SECTION
34** pthread_mutex_init -> InitializeCriticalSection + 0
35** pthread_mutex_destroy -> DeleteCriticalSection + 0
36** pthread_mutex_lock -> EnterCriticalSection + 0
37** pthread_mutex_unlock -> LeaveCriticalSection + 0
38**
39** pthread_t -> HANDLE
40** pthread_attr_t -> int (unused)
41** pthread_attr_init -> 0
42** pthread_attr_setdetachstate -> 0
43** pthread_attr_destroy -> 0
44** pthread_create -> _beginthreadex (then closes the
45** handle if detached)
46** pthread_detach -> CloseHandle + 0
47** PTHREAD_CREATE_DETACHED -> 1
48*/
49#ifndef LIME_THREADS_H
50#define LIME_THREADS_H
51
52#if !defined(_WIN32)
53
54/* POSIX passthrough: include the real <pthread.h>. The
55** preceding #ifndef LIME_THREADS_H guard makes this safe; the
56** earlier sed sweep that converted Lime-source `#include
57** <pthread.h>` to `#include "lime_threads.h"` would have
58** loop-included this very header, but the system pthread
59** include below is intentional and breaks the recursion. */
60#include <pthread.h>
61
62/* On POSIX the rd/wr unlock macros expand to the same
63** pthread_rwlock_unlock to keep call sites identical between
64** platforms. */
65#define LIME_RWLOCK_RDUNLOCK(lock_ptr) pthread_rwlock_unlock(lock_ptr)
66#define LIME_RWLOCK_WRUNLOCK(lock_ptr) pthread_rwlock_unlock(lock_ptr)
67
68#else /* _WIN32 */
69
70#include <windows.h>
71#include <process.h>
72
73typedef SRWLOCK pthread_rwlock_t;
74/* mutex on Windows: implemented over SRWLOCK in exclusive mode
75** rather than CRITICAL_SECTION, so we can supply a
76** PTHREAD_MUTEX_INITIALIZER for static-initialised mutexes
77** (CRITICAL_SECTION has no static initializer; it requires a
78** runtime InitializeCriticalSection call). All Lime mutex
79** uses are non-recursive single-process locks; SRWLOCK in
80** exclusive mode is a faithful substitute. */
81typedef SRWLOCK pthread_mutex_t;
82typedef HANDLE pthread_t;
83typedef int pthread_attr_t;
84typedef int pthread_rwlockattr_t;
85typedef int pthread_mutexattr_t;
86
87#define PTHREAD_CREATE_DETACHED 1
88#define PTHREAD_CREATE_JOINABLE 0
89
90/* Static-initialiser parity with POSIX <pthread.h>. SRWLOCK_INIT
91** is the documented zero-value SRWLOCK initialiser. */
92#define PTHREAD_MUTEX_INITIALIZER SRWLOCK_INIT
93#define PTHREAD_RWLOCK_INITIALIZER SRWLOCK_INIT
94
95/* --- rwlock --- */
96static __inline int pthread_rwlock_init(pthread_rwlock_t *lock,
97 const pthread_rwlockattr_t *a) {
98 (void)a;
99 InitializeSRWLock(lock);
100 return 0;
101}
102static __inline int pthread_rwlock_destroy(pthread_rwlock_t *lock) {
103 (void)lock;
104 return 0;
105}
106static __inline int pthread_rwlock_rdlock(pthread_rwlock_t *lock) {
107 AcquireSRWLockShared(lock);
108 return 0;
109}
110static __inline int pthread_rwlock_wrlock(pthread_rwlock_t *lock) {
111 AcquireSRWLockExclusive(lock);
112 return 0;
113}
114/* Generic unlock is ambiguous on SRWLOCK -- use the
115** LIME_RWLOCK_RDUNLOCK / LIME_RWLOCK_WRUNLOCK macros instead. */
116#define LIME_RWLOCK_RDUNLOCK(lock_ptr) ReleaseSRWLockShared(lock_ptr)
117#define LIME_RWLOCK_WRUNLOCK(lock_ptr) ReleaseSRWLockExclusive(lock_ptr)
118/* For source compatibility with code that uses pthread_rwlock_unlock
119** generically: assume exclusive (write) lock since that's the
120** stricter invariant; the rd-locked branch must use
121** LIME_RWLOCK_RDUNLOCK explicitly. Lime's own code is being
122** updated to use the LIME_* macros directly. */
123static __inline int pthread_rwlock_unlock(pthread_rwlock_t *lock) {
124 /* SRWLOCK has no "release whatever you held" operation.
125 ** Calling this on an SRWLOCK is wrong; we ABI-stub it as
126 ** unlock-exclusive which matches the most common Lime
127 ** call site (a write-locked path). Read-locked paths in
128 ** Lime have been audited and converted to LIME_RWLOCK_RDUNLOCK. */
129 ReleaseSRWLockExclusive(lock);
130 return 0;
131}
132
133/* --- mutex (over SRWLOCK in exclusive mode) --- */
134static __inline int pthread_mutex_init(pthread_mutex_t *m,
135 const pthread_mutexattr_t *a) {
136 (void)a;
137 InitializeSRWLock(m);
138 return 0;
139}
140static __inline int pthread_mutex_destroy(pthread_mutex_t *m) {
141 (void)m;
142 return 0;
143}
144static __inline int pthread_mutex_lock(pthread_mutex_t *m) {
145 AcquireSRWLockExclusive(m);
146 return 0;
147}
148static __inline int pthread_mutex_unlock(pthread_mutex_t *m) {
149 ReleaseSRWLockExclusive(m);
150 return 0;
151}
152
153/* --- condition variable (over Win32 CONDITION_VARIABLE) ---
154** v1.2.0 addition: lsp_diagnostics_async needs cond_wait/signal
155** pairs to gate its worker queue. Win32 CONDITION_VARIABLE pairs
156** with either an SRWLOCK or a CRITICAL_SECTION. Lime's mutex shim
157** above is SRWLOCK-backed so we use SleepConditionVariableSRW with
158** the CONDITION_VARIABLE_LOCKMODE_EXCLUSIVE flag (the default for
159** mutex-style usage). */
160typedef CONDITION_VARIABLE pthread_cond_t;
161typedef int pthread_condattr_t;
162
163static __inline int pthread_cond_init(pthread_cond_t *c,
164 const pthread_condattr_t *attr) {
165 (void)attr;
166 InitializeConditionVariable(c);
167 return 0;
168}
169static __inline int pthread_cond_destroy(pthread_cond_t *c) {
170 /* CONDITION_VARIABLE has no destructor on Win32. */
171 (void)c;
172 return 0;
173}
174static __inline int pthread_cond_wait(pthread_cond_t *c,
175 pthread_mutex_t *m) {
176 /* CONDITION_VARIABLE_LOCKMODE_EXCLUSIVE = 0 is the default for
177 ** SRWLOCK-backed exclusive-mode usage, which matches our mutex
178 ** shim. */
179 SleepConditionVariableSRW(c, m, INFINITE, 0);
180 return 0;
181}
182static __inline int pthread_cond_signal(pthread_cond_t *c) {
183 WakeConditionVariable(c);
184 return 0;
185}
186static __inline int pthread_cond_broadcast(pthread_cond_t *c) {
187 WakeAllConditionVariable(c);
188 return 0;
189}
190
191/* --- thread --- */
192static __inline int pthread_attr_init(pthread_attr_t *a) {
193 *a = PTHREAD_CREATE_JOINABLE;
194 return 0;
195}
196static __inline int pthread_attr_destroy(pthread_attr_t *a) {
197 (void)a;
198 return 0;
199}
200static __inline int pthread_attr_setdetachstate(pthread_attr_t *a, int s) {
201 *a = s;
202 return 0;
203}
204typedef unsigned (__stdcall *lime_thread_fn)(void *);
205static __inline int pthread_create(pthread_t *t,
206 const pthread_attr_t *attr,
207 void *(*start)(void *),
208 void *arg) {
209 /* Win32's _beginthreadex expects unsigned (__stdcall *)(void *)
210 ** but POSIX expects void *(*)(void *). We pun the function
211 ** pointer via a void * cast -- callers ignore the return
212 ** value of start_routine (Lime never inspects pthread_join
213 ** return values), so the ABI mismatch on the return type
214 ** is not observed. */
215 HANDLE h = (HANDLE)_beginthreadex(NULL, 0,
216 (lime_thread_fn)(void *)start,
217 arg, 0, NULL);
218 if (h == NULL) return 1;
219 *t = h;
220 if (attr != NULL && *attr == PTHREAD_CREATE_DETACHED) {
221 CloseHandle(h);
222 }
223 return 0;
224}
225static __inline int pthread_detach(pthread_t t) {
226 CloseHandle(t);
227 return 0;
228}
229static __inline int pthread_join(pthread_t t, void **rv) {
230 WaitForSingleObject(t, INFINITE);
231 if (rv != NULL) *rv = NULL;
232 CloseHandle(t);
233 return 0;
234}
235
236#endif /* _WIN32 */
237
238#endif /* LIME_THREADS_H */