mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
[wasm] add no thread variant for freestanding environment
This implementation does nothing around preemptive context switching because there is no native thread.
This commit is contained in:
parent
d6d52a7d04
commit
420622b5a7
Notes:
git
2022-01-19 11:19:40 +09:00
5 changed files with 306 additions and 1 deletions
|
@ -37,6 +37,12 @@ typedef pthread_t rb_nativethread_id_t;
|
|||
typedef pthread_mutex_t rb_nativethread_lock_t;
|
||||
typedef pthread_cond_t rb_nativethread_cond_t;
|
||||
|
||||
#elif defined(__wasi__) // no-thread platforms
|
||||
|
||||
typedef struct rb_nativethread_id_t *rb_nativethread_id_t;
|
||||
typedef struct rb_nativethread_lock_t *rb_nativethread_lock_t;
|
||||
typedef struct rb_nativethread_cond_t *rb_nativethread_cond_t;
|
||||
|
||||
#elif defined(__DOXYGEN__)
|
||||
|
||||
/** Opaque type that holds an ID of a native thread. */
|
||||
|
|
2
thread.c
2
thread.c
|
@ -340,7 +340,7 @@ rb_thread_s_debug_set(VALUE self, VALUE val)
|
|||
# define PRI_THREAD_ID "p"
|
||||
#endif
|
||||
|
||||
NOINLINE(static int thread_start_func_2(rb_thread_t *th, VALUE *stack_start));
|
||||
MAYBE_UNUSED(NOINLINE(static int thread_start_func_2(rb_thread_t *th, VALUE *stack_start)));
|
||||
void ruby_sigchld_handler(rb_vm_t *); /* signal.c */
|
||||
|
||||
static void
|
||||
|
|
278
thread_none.c
Normal file
278
thread_none.c
Normal file
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
A thread interface implementation without any system thread.
|
||||
|
||||
Assumption:
|
||||
* There is a only single thread in the ruby process
|
||||
* No signal happens targeting the ruby process
|
||||
|
||||
Note:
|
||||
* No thread switching in the VM
|
||||
* No timer thread because thread switching won't happen
|
||||
* No mutex guard because the VM won't be racy
|
||||
*/
|
||||
|
||||
#ifdef THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#define DEBUG_OUT() (void)(0);
|
||||
|
||||
#define TIME_QUANTUM_MSEC (100)
|
||||
#define TIME_QUANTUM_USEC (TIME_QUANTUM_MSEC * 1000)
|
||||
#define TIME_QUANTUM_NSEC (TIME_QUANTUM_USEC * 1000)
|
||||
|
||||
// Do nothing for GVL
|
||||
static void
|
||||
gvl_acquire(rb_global_vm_lock_t *gvl, rb_thread_t *th)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gvl_release(rb_global_vm_lock_t *gvl)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gvl_yield(rb_global_vm_lock_t *gvl, rb_thread_t *th)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
rb_gvl_init(rb_global_vm_lock_t *gvl)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gvl_destroy(rb_global_vm_lock_t *gvl)
|
||||
{
|
||||
}
|
||||
|
||||
// Do nothing for mutex guard
|
||||
void
|
||||
rb_native_mutex_lock(rb_nativethread_lock_t *lock)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
rb_native_mutex_unlock(rb_nativethread_lock_t *lock)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
rb_native_mutex_trylock(rb_nativethread_lock_t *lock)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
rb_native_mutex_initialize(rb_nativethread_lock_t *lock)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
rb_native_mutex_destroy(rb_nativethread_lock_t *lock)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
rb_native_cond_initialize(rb_nativethread_cond_t *cond)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
rb_native_cond_destroy(rb_nativethread_cond_t *cond)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
rb_native_cond_signal(rb_nativethread_cond_t *cond)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
rb_native_cond_broadcast(rb_nativethread_cond_t *cond)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
rb_native_cond_wait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
rb_native_cond_timedwait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex, unsigned long msec)
|
||||
{
|
||||
}
|
||||
|
||||
// The only one thread in process
|
||||
static rb_thread_t *ruby_native_thread;
|
||||
|
||||
rb_thread_t *
|
||||
ruby_thread_from_native(void)
|
||||
{
|
||||
return ruby_native_thread;
|
||||
}
|
||||
|
||||
int
|
||||
ruby_thread_set_native(rb_thread_t *th)
|
||||
{
|
||||
if (th && th->ec) {
|
||||
rb_ractor_set_current_ec(th->ractor, th->ec);
|
||||
}
|
||||
ruby_native_thread = th;
|
||||
return 1; // always succeed
|
||||
}
|
||||
|
||||
void
|
||||
Init_native_thread(rb_thread_t *th)
|
||||
{
|
||||
// no TLS setup and no thread id setup
|
||||
ruby_thread_set_native(th);
|
||||
fill_thread_id_str(th);
|
||||
}
|
||||
|
||||
static void
|
||||
native_thread_destroy(rb_thread_t *th)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ruby_init_stack(volatile VALUE *addr)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
native_thread_init_stack(rb_thread_t *th)
|
||||
{
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
static int
|
||||
native_thread_create(rb_thread_t *th)
|
||||
{
|
||||
th->status = THREAD_KILLED;
|
||||
rb_ractor_living_threads_remove(th->ractor, th);
|
||||
rb_notimplement();
|
||||
}
|
||||
|
||||
// Do nothing for handling ubf because no other thread doesn't exist and unblock anything
|
||||
#define register_ubf_list(th) (void)(th)
|
||||
#define unregister_ubf_list(th) (void)(th)
|
||||
#define ubf_select 0
|
||||
|
||||
inline static void
|
||||
ubf_wakeup_all_threads(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
inline static int
|
||||
ubf_threads_empty(void)
|
||||
{
|
||||
return 1; // true
|
||||
}
|
||||
|
||||
inline static void
|
||||
ubf_list_atfork()
|
||||
{
|
||||
}
|
||||
|
||||
inline static void
|
||||
ubf_timer_disarm(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// No timer thread because thread switching won't happen
|
||||
#define TIMER_THREAD_CREATED_P() (1)
|
||||
inline static void
|
||||
rb_thread_create_timer_thread(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
rb_thread_wakeup_timer_thread(int sig)
|
||||
{
|
||||
}
|
||||
|
||||
inline static int
|
||||
native_stop_timer_thread(void)
|
||||
{
|
||||
return 1; // success
|
||||
}
|
||||
|
||||
inline static void
|
||||
native_reset_timer_thread(void)
|
||||
{
|
||||
}
|
||||
|
||||
// Do nothing for thread naming
|
||||
inline static void
|
||||
native_set_thread_name(rb_thread_t *th)
|
||||
{
|
||||
}
|
||||
|
||||
inline static void
|
||||
native_set_another_thread_name(rb_nativethread_id_t thread_id, VALUE name)
|
||||
{
|
||||
}
|
||||
|
||||
// Don't expose native thread id for now to keep system's thread API agnostic
|
||||
#define USE_NATIVE_THREAD_NATIVE_THREAD_ID 0
|
||||
|
||||
// No reserved fd for piping threads
|
||||
int
|
||||
rb_reserved_fd_p(int fd)
|
||||
{
|
||||
return 0; // not reserved
|
||||
}
|
||||
|
||||
// Don't expose native thread info for now to keep system's thread API agnostic
|
||||
rb_nativethread_id_t
|
||||
rb_nativethread_self(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Do nothing for sigwait things because of no signal assumption
|
||||
// Q(katei): is this correct description?
|
||||
int
|
||||
rb_sigwait_fd_get(const rb_thread_t *th)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
NORETURN(void rb_sigwait_fd_put(rb_thread_t *, int));
|
||||
void
|
||||
rb_sigwait_fd_put(rb_thread_t *th, int fd)
|
||||
{
|
||||
rb_bug("not implemented, should not be called rb_sigwait_fd_put");
|
||||
}
|
||||
|
||||
NORETURN(void rb_sigwait_sleep(const rb_thread_t *, int, const rb_hrtime_t *));
|
||||
void
|
||||
rb_sigwait_sleep(const rb_thread_t *th, int sigwait_fd, const rb_hrtime_t *rel)
|
||||
{
|
||||
rb_bug("not implemented, should not be called rb_sigwait_sleep");
|
||||
}
|
||||
|
||||
static void
|
||||
native_sleep(rb_thread_t *th, rb_hrtime_t *rel)
|
||||
{
|
||||
// No signal assumption allows the use of uninterruptible sleep
|
||||
struct timespec ts;
|
||||
(void)clock_nanosleep(CLOCK_REALTIME, 0, rb_hrtime2timespec(&ts, rel), NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
native_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout, rb_thread_t *th)
|
||||
{
|
||||
return rb_fd_select(n, readfds, writefds, exceptfds, timeout);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_thread_start_unblock_thread(void)
|
||||
{
|
||||
return Qfalse;
|
||||
}
|
||||
#endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */
|
17
thread_none.h
Normal file
17
thread_none.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef RUBY_THREAD_NONE_H
|
||||
#define RUBY_THREAD_NONE_H
|
||||
|
||||
#define RB_NATIVETHREAD_LOCK_INIT (void)(0)
|
||||
#define RB_NATIVETHREAD_COND_INIT (void)(0)
|
||||
|
||||
// no-thread impl doesn't use TLS but define this to avoid using tls key
|
||||
// based implementation in vm.c
|
||||
#define RB_THREAD_LOCAL_SPECIFIER
|
||||
|
||||
typedef struct native_thread_data_struct {} native_thread_data_t;
|
||||
|
||||
typedef struct rb_global_vm_lock_struct {} rb_global_vm_lock_t;
|
||||
|
||||
RUBY_EXTERN struct rb_execution_context_struct *ruby_current_ec;
|
||||
|
||||
#endif /* RUBY_THREAD_NONE_H */
|
|
@ -8,6 +8,9 @@ AC_ARG_WITH(thread,
|
|||
[mingw*], [
|
||||
THREAD_MODEL=win32
|
||||
],
|
||||
[wasi*], [
|
||||
THREAD_MODEL=none
|
||||
],
|
||||
[
|
||||
AS_IF([test "$rb_with_pthread" = "yes"], [
|
||||
THREAD_MODEL=pthread
|
||||
|
@ -19,6 +22,7 @@ AC_ARG_WITH(thread,
|
|||
AS_CASE(["$THREAD_MODEL"],
|
||||
[pthread], [AC_CHECK_HEADERS(pthread.h)],
|
||||
[win32], [],
|
||||
[none], [],
|
||||
[""], [AC_MSG_ERROR(thread model is missing)],
|
||||
[AC_MSG_ERROR(unknown thread model $THREAD_MODEL)])
|
||||
|
||||
|
|
Loading…
Reference in a new issue