Ruby 4.1.0dev (2026-09-07 revision b57404b461ba8bf34e802d86b0db78388216e182)
thread_none.c (b57404b461ba8bf34e802d86b0db78388216e182)
1/*
2 A thread interface implementation without any system thread.
3
4 Assumption:
5 * There is a only single thread in the ruby process
6 * No signal happens targeting the ruby process
7
8 Note:
9 * No thread switching in the VM
10 * No timer thread because thread switching won't happen
11 * No mutex guard because the VM won't be racy
12*/
13
14#ifdef THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
15
16#include <time.h>
17
18#if defined(__wasm__) && !defined(__EMSCRIPTEN__)
19# include "wasm/machine.h"
20#endif
21
22// Do nothing for GVL
23static void
24thread_sched_to_running(struct rb_thread_sched *sched, rb_thread_t *th)
25{
26}
27
28static void
29thread_sched_to_waiting(struct rb_thread_sched *sched, rb_thread_t *th, bool yield_immediately)
30{
31}
32
33#define thread_sched_to_dead(a,b) thread_sched_to_waiting(a,b,true)
34
35static void
36thread_sched_yield(struct rb_thread_sched *sched, rb_thread_t *th)
37{
38}
39
40void
41rb_thread_sched_init(struct rb_thread_sched *sched, bool atfork)
42{
43}
44
45void
46rb_thread_sched_destroy(struct rb_thread_sched *sched)
47{
48}
49
50// Do nothing for mutex guard
51void
52rb_native_mutex_lock(rb_nativethread_lock_t *lock)
53{
54}
55
56void
57rb_native_mutex_unlock(rb_nativethread_lock_t *lock)
58{
59}
60
61int
62rb_native_mutex_trylock(rb_nativethread_lock_t *lock)
63{
64 return 0;
65}
66
67void
68rb_native_mutex_initialize(rb_nativethread_lock_t *lock)
69{
70}
71
72void
73rb_native_mutex_destroy(rb_nativethread_lock_t *lock)
74{
75}
76
77void
78rb_native_cond_initialize(rb_nativethread_cond_t *cond)
79{
80}
81
82void
83rb_native_cond_destroy(rb_nativethread_cond_t *cond)
84{
85}
86
87void
88rb_native_cond_signal(rb_nativethread_cond_t *cond)
89{
90}
91
92void
93rb_native_cond_broadcast(rb_nativethread_cond_t *cond)
94{
95}
96
97void
98rb_native_cond_wait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex)
99{
100}
101
102void
103rb_native_cond_timedwait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex, unsigned long msec)
104{
105}
106
107// The only one thread in process
108static rb_thread_t *ruby_native_thread;
109
111ruby_thread_from_native(void)
112{
113 return ruby_native_thread;
114}
115
116int
117ruby_thread_set_native(rb_thread_t *th)
118{
119 if (th && th->ec) {
120 rb_ractor_set_current_ec(th->ractor, th->ec);
121 }
122 ruby_native_thread = th;
123 return 1; // always succeed
124}
125
126void
127Init_native_thread(rb_thread_t *main_th)
128{
129 // no TLS setup and no thread id setup
130 ruby_thread_set_native(main_th);
131}
132
133void
134ruby_mn_threads_params(void)
135{
136}
137
138static void
139native_thread_destroy_atfork(struct rb_native_thread *nt)
140{
141 /* no-op */
142}
143
144static int
145native_thread_init_stack(rb_thread_t *th, void *local_in_parent_frame)
146{
147#if defined(__wasm__) && !defined(__EMSCRIPTEN__)
148 th->ec->machine.stack_start = (VALUE *)rb_wasm_stack_get_base();
149#endif
150 return 0; // success
151}
152
153static int
154native_thread_create(rb_thread_t *th)
155{
156 th->status = THREAD_KILLED;
157 rb_ractor_living_threads_remove(th->ractor, th);
158 rb_notimplement();
159}
160
161// Do nothing for handling ubf because no other thread doesn't exist and unblock anything
162#define register_ubf_list(th) (void)(th)
163#define unregister_ubf_list(th) (void)(th)
164#define ubf_select 0
165
166inline static void
167ubf_wakeup_all_threads(void)
168{
169 return;
170}
171
172inline static int
173ubf_threads_empty(void)
174{
175 return 1; // true
176}
177
178inline static void
179ubf_list_atfork()
180{
181}
182
183inline static void
184ubf_timer_disarm(void)
185{
186}
187
188
189// No timer thread because thread switching won't happen
190#define TIMER_THREAD_CREATED_P() (1)
191inline static void
192rb_thread_create_timer_thread(void)
193{
194}
195
196void
197rb_thread_wakeup_timer_thread(int sig)
198{
199}
200
201inline static int
202native_stop_timer_thread(void)
203{
204 return 1; // success
205}
206
207inline static void
208native_reset_timer_thread(void)
209{
210}
211
212// Do nothing for thread naming
213inline static void
214native_set_thread_name(rb_thread_t *th)
215{
216}
217
218inline static void
219native_set_another_thread_name(rb_nativethread_id_t thread_id, VALUE name)
220{
221}
222
223// Don't expose native thread id for now to keep system's thread API agnostic
224#define USE_NATIVE_THREAD_NATIVE_THREAD_ID 0
225
226// No reserved fd for piping threads
227int
228rb_reserved_fd_p(int fd)
229{
230 return 0; // not reserved
231}
232
233// Don't expose native thread info for now to keep system's thread API agnostic
234rb_nativethread_id_t
236{
237 return NULL;
238}
239
240// Do nothing for sigwait things because of no signal assumption
241// Q(katei): is this correct description?
242int
243rb_sigwait_fd_get(const rb_thread_t *th)
244{
245 return -1;
246}
247
248NORETURN(void rb_sigwait_fd_put(rb_thread_t *, int));
249void
250rb_sigwait_fd_put(rb_thread_t *th, int fd)
251{
252 rb_bug("not implemented, should not be called rb_sigwait_fd_put");
253}
254
255NORETURN(void rb_sigwait_sleep(const rb_thread_t *, int, const rb_hrtime_t *));
256void
257rb_sigwait_sleep(const rb_thread_t *th, int sigwait_fd, const rb_hrtime_t *rel)
258{
259 rb_bug("not implemented, should not be called rb_sigwait_sleep");
260}
261
262static void
263native_sleep(rb_thread_t *th, rb_hrtime_t *rel)
264{
265 // No signal assumption allows the use of uninterruptible sleep
266 struct timespec ts;
267 (void)clock_nanosleep(CLOCK_REALTIME, 0, rb_hrtime2timespec(&ts, rel), NULL);
268}
269
270static int
271native_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout, rb_thread_t *th)
272{
273 return rb_fd_select(n, readfds, writefds, exceptfds, timeout);
274}
275
276static bool
277th_has_dedicated_nt(const rb_thread_t *th)
278{
279 return true;
280}
281
282void
283rb_add_running_thread(rb_thread_t *th)
284{
285 // do nothing
286}
287
288void
289rb_del_running_thread(rb_thread_t *th)
290{
291 // do nothing
292}
293
294void
295rb_threadptr_sched_free(rb_thread_t *th)
296{
297 // do nothing
298}
299
300void
301rb_ractor_sched_barrier_start(rb_vm_t *vm, rb_ractor_t *cr)
302{
303 // do nothing
304}
305
306void
307rb_ractor_sched_barrier_join(rb_vm_t *vm, rb_ractor_t *cr)
308{
309 // do nothing
310}
311
312void
313rb_ractor_sched_barrier_end(rb_vm_t *vm, rb_ractor_t *cr)
314{
315 // do nothing
316}
317
318void
319rb_ractor_sched_wait(rb_execution_context_t *ec, rb_ractor_t *cr, rb_unblock_function_t *ubf, void *ptr)
320{
321 // nothing can wake this: with no threads there is nobody to send
322 rb_bug("unreachable");
323}
324
325void
326rb_ractor_sched_wakeup(rb_ractor_t *r, rb_thread_t *th)
327{
328 // do nothing
329}
330
331
332
333bool
335{
336 return false;
337}
338
339void *
340rb_thread_prevent_fork(void *(*func)(void *), void *data)
341{
342 return func(data);
343}
344
345void
346rb_thread_malloc_stack_set(rb_thread_t *th, void *stack, size_t stack_size)
347{
348 // no-op
349}
350
351bool
352rb_thread_event_hooks_registered_p(void)
353{
354 return false; // hooks are not implemented on this platform
355}
356
357#endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */
358
359void
360rb_thread_sched_winding_begin(rb_vm_t *vm)
361{
362 // nothing to count: rb_thread_sched_wait_winding below never waits
363 (void)vm;
364}
365
366void
367rb_thread_sched_winding_end(rb_vm_t *vm)
368{
369 (void)vm;
370}
371
372void
373rb_thread_sched_wait_winding(rb_vm_t *vm)
374{
375 // no coroutine (M:N) threads on this implementation: nothing winds down
376 // after leaving the living set (see thread_pthread.c)
377 (void)vm;
378}
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_unblock_function_t(void *)
This is the type of UBFs.
Definition thread.h:336
bool rb_thread_lock_native_thread(void)
Declare the current Ruby thread should acquire a dedicated native thread on M:N thread scheduler.
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
rb_nativethread_id_t rb_nativethread_self(void)
Queries the ID of the native thread that is calling this function.
void rb_native_mutex_lock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_lock.
void rb_native_cond_initialize(rb_nativethread_cond_t *cond)
Fills the passed condition variable with an initial value.
int rb_native_mutex_trylock(rb_nativethread_lock_t *lock)
Identical to rb_native_mutex_lock(), except it doesn't block in case rb_native_mutex_lock() would.
void rb_native_cond_broadcast(rb_nativethread_cond_t *cond)
Signals a condition variable.
void rb_native_mutex_initialize(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_initialize.
void rb_native_mutex_unlock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_unlock.
void rb_native_mutex_destroy(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_destroy.
void rb_native_cond_destroy(rb_nativethread_cond_t *cond)
Destroys the passed condition variable.
void rb_native_cond_signal(rb_nativethread_cond_t *cond)
Signals a condition variable.
void rb_native_cond_wait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex)
Waits for the passed condition variable to be signalled.
void rb_native_cond_timedwait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex, unsigned long msec)
Identical to rb_native_cond_wait(), except it additionally takes timeout in msec resolution.
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40