54 #undef _FORTIFY_SOURCE
55 #undef __USE_FORTIFY_LEVEL
56 #define __USE_FORTIFY_LEVEL 0
65 #ifndef USE_NATIVE_THREAD_PRIORITY
66 #define USE_NATIVE_THREAD_PRIORITY 0
67 #define RUBY_THREAD_PRIORITY_MAX 3
68 #define RUBY_THREAD_PRIORITY_MIN -3
72 #define THREAD_DEBUG 0
86 #define eKillSignal INT2FIX(0)
87 #define eTerminateSignal INT2FIX(1)
90 #define closed_stream_error GET_VM()->special_exceptions[ruby_error_closed_stream]
100 #define THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
113 #define RB_GC_SAVE_MACHINE_CONTEXT(th) \
115 rb_gc_save_machine_context(th); \
116 SET_MACHINE_STACK_END(&(th)->machine_stack_end); \
119 #define GVL_UNLOCK_BEGIN() do { \
120 rb_thread_t *_th_stored = GET_THREAD(); \
121 RB_GC_SAVE_MACHINE_CONTEXT(_th_stored); \
122 gvl_release(_th_stored->vm);
124 #define GVL_UNLOCK_END() \
125 gvl_acquire(_th_stored->vm, _th_stored); \
126 rb_thread_set_current(_th_stored); \
129 #define blocking_region_begin(th, region, func, arg) \
131 (region)->prev_status = (th)->status; \
132 set_unblock_function((th), (func), (arg), &(region)->oldubf); \
133 (th)->blocking_region_buffer = (region); \
134 (th)->status = THREAD_STOPPED; \
135 thread_debug("enter blocking region (%p)\n", (void *)(th)); \
136 RB_GC_SAVE_MACHINE_CONTEXT(th); \
137 gvl_release((th)->vm); \
140 #define BLOCKING_REGION(exec, ubf, ubfarg) do { \
141 rb_thread_t *__th = GET_THREAD(); \
142 struct rb_blocking_region_buffer __region; \
143 blocking_region_begin(__th, &__region, (ubf), (ubfarg)); \
145 blocking_region_end(__th, &__region); \
146 RUBY_VM_CHECK_INTS(); \
150 #ifdef HAVE_VA_ARGS_MACRO
151 void rb_thread_debug(
const char *file,
int line,
const char *fmt, ...);
152 #define thread_debug(fmt, ...) rb_thread_debug(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
153 #define POSITION_FORMAT "%s:%d:"
154 #define POSITION_ARGS ,file, line
156 void rb_thread_debug(
const char *fmt, ...);
157 #define thread_debug rb_thread_debug
158 #define POSITION_FORMAT
159 #define POSITION_ARGS
162 # if THREAD_DEBUG < 0
163 static int rb_thread_debug_enabled;
174 rb_thread_s_debug(
void)
176 return INT2NUM(rb_thread_debug_enabled);
190 rb_thread_debug_enabled =
RTEST(val) ?
NUM2INT(val) : 0;
194 # define rb_thread_debug_enabled THREAD_DEBUG
197 #define thread_debug if(0)printf
201 #define thread_start_func_2(th, st, rst) thread_start_func_2(th, st)
204 VALUE *register_stack_start));
210 #define DEBUG_OUT() \
211 WaitForSingleObject(&debug_mutex, INFINITE); \
212 printf(POSITION_FORMAT"%p - %s" POSITION_ARGS, GetCurrentThreadId(), buf); \
214 ReleaseMutex(&debug_mutex);
216 #elif defined(HAVE_PTHREAD_H)
219 #define DEBUG_OUT() \
220 pthread_mutex_lock(&debug_mutex); \
221 printf(POSITION_FORMAT"%#"PRIxVALUE" - %s" POSITION_ARGS, (VALUE)pthread_self(), buf); \
223 pthread_mutex_unlock(&debug_mutex);
226 #error "unsupported thread type"
230 static int debug_mutex_initialized = 1;
235 #ifdef HAVE_VA_ARGS_MACRO
236 const char *file,
int line,
238 const char *fmt, ...)
243 if (!rb_thread_debug_enabled)
return;
245 if (debug_mutex_initialized == 1) {
246 debug_mutex_initialized = 0;
247 native_mutex_initialize(&debug_mutex);
268 native_mutex_unlock(lock);
274 native_mutex_destroy(lock);
326 if (th != main_thread) {
333 thread_debug(
"terminate_i: main thread (%p)\n", (
void *)th);
365 if (err)
rb_bug(
"invalid keeping_mutexes: %s", err);
376 rb_bug(
"rb_thread_terminate_all: called by child thread (%p, %p)",
383 thread_debug(
"rb_thread_terminate_all (main thread: %p)\n", (
void *)th);
406 th->machine_register_stack_start = th->machine_register_stack_end = 0;
427 native_thread_destroy(th);
435 native_thread_init_stack(th);
447 # ifdef USE_SIGALTSTACK
450 rb_register_sigaltstack(th);
453 ruby_thread_set_native(th);
457 th->machine_register_stack_start = register_stack_start;
461 gvl_acquire(th->
vm, th);
463 thread_debug(
"thread start (get lock): %p\n", (
void *)th);
520 rb_bug(
"thread_start_func_2: locking_mutex must not be set (%p:%"PRIxVALUE")",
532 if (join_th == main_th) errinfo =
Qnil;
534 switch (join_th->
status) {
569 "can't start a new thread (frozen ThreadGroup)");
587 err = native_thread_create(th);
603 if (
GET_VM()->inhibit_thread_creation)
665 #define DELAY_INFTY 1E30
760 return target_th->
self;
850 time.
tv_usec = (int)((d - (
int)d) * 1e6);
875 }
while (th->
status == status);
882 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
885 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
910 native_sleep(th, &tv);
944 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
947 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
1040 gvl_yield(th->
vm, th);
1062 gvl_acquire(th->
vm, th);
1064 thread_debug(
"leave blocking region (%p)\n", (
void *)th);
1065 remove_signal_thread_list(th);
1085 int saved_errno =
errno;
1090 errno = saved_errno;
1136 int saved_errno = 0;
1146 saved_errno =
errno;
1148 errno = saved_errno;
1158 int saved_errno = 0;
1163 saved_errno =
errno;
1166 errno = saved_errno;
1227 fprintf(stderr,
"[BUG] rb_thread_call_with_gvl() is called by non-ruby thread\n");
1235 rb_bug(
"rb_thread_call_with_gvl: called by a thread which has GVL.");
1296 int timer_interrupt = interrupt & 0x01;
1297 int finalizer_interrupt = interrupt & 0x04;
1325 if (finalizer_interrupt) {
1329 if (timer_interrupt) {
1330 unsigned long limits_us = 250 * 1000;
1364 rb_bug(
"deprecated function rb_gc_mark_threads is called");
1416 #if defined(POSIX_SIGNAL) && defined(SIGSEGV) && defined(HAVE_SIGALTSTACK)
1417 #define USE_SIGALTSTACK
1424 #ifdef USE_SIGALTSTACK
1452 #define THREAD_IO_WAITING_P(th) ( \
1453 ((th)->status == THREAD_STOPPED || \
1454 (th)->status == THREAD_STOPPED_FOREVER) && \
1455 (th)->blocking_region_buffer && \
1456 (th)->unblock.func == ubf_select && \
1686 "stopping only thread\n\tnote: use sleep to stop forever");
2047 str =
rb_sprintf(
"#<%s:%p %s>", cname, (
void *)thread, status);
2279 #if USE_NATIVE_THREAD_PRIORITY
2281 native_thread_apply_priority(th);
2297 #if defined(NFDBITS) && defined(HAVE_RB_FD_INIT)
2330 fds->fdset =
ALLOC(fd_set);
2331 FD_ZERO(fds->fdset);
2337 size_t size = howmany(
rb_fd_max(src), NFDBITS) *
sizeof(fd_mask);
2339 if (size <
sizeof(fd_set))
2340 size =
sizeof(fd_set);
2341 dst->maxfd = src->maxfd;
2343 memcpy(dst->fdset, src->fdset, size);
2349 if (fds->fdset)
xfree(fds->fdset);
2358 MEMZERO(fds->fdset, fd_mask, howmany(fds->maxfd, NFDBITS));
2364 size_t m = howmany(n + 1, NFDBITS) *
sizeof(fd_mask);
2365 size_t o = howmany(fds->maxfd, NFDBITS) *
sizeof(fd_mask);
2367 if (m <
sizeof(fd_set)) m =
sizeof(fd_set);
2368 if (o <
sizeof(fd_set)) o =
sizeof(fd_set);
2371 fds->fdset =
xrealloc(fds->fdset, m);
2372 memset((
char *)fds->fdset + o, 0, m - o);
2374 if (n >= fds->maxfd) fds->maxfd = n + 1;
2387 if (n >= fds->maxfd)
return;
2394 if (n >= fds->maxfd)
return 0;
2395 return FD_ISSET(n, fds->fdset) != 0;
2401 size_t size = howmany(max, NFDBITS) *
sizeof(fd_mask);
2403 if (size <
sizeof(fd_set)) size =
sizeof(fd_set);
2405 dst->fdset =
xrealloc(dst->fdset, size);
2406 memcpy(dst->fdset, src, size);
2412 size_t size = howmany(
rb_fd_max(src), NFDBITS) *
sizeof(fd_mask);
2414 if (size >
sizeof(fd_set)) {
2417 memcpy(dst,
rb_fd_ptr(src),
sizeof(fd_set));
2423 size_t size = howmany(
rb_fd_max(src), NFDBITS) *
sizeof(fd_mask);
2425 if (size <
sizeof(fd_set))
2426 size =
sizeof(fd_set);
2427 dst->maxfd = src->maxfd;
2428 dst->fdset =
xrealloc(dst->fdset, size);
2429 memcpy(dst->fdset, src->fdset, size);
2448 return select(n, r, w, e, timeout);
2456 #define FD_ZERO(f) rb_fd_zero(f)
2457 #define FD_SET(i, f) rb_fd_set((i), (f))
2458 #define FD_CLR(i, f) rb_fd_clr((i), (f))
2459 #define FD_ISSET(i, f) rb_fd_isset((i), (f))
2461 #elif defined(_WIN32)
2467 set->fdset =
ALLOC(fd_set);
2468 FD_ZERO(set->fdset);
2485 if (max >
FD_SETSIZE || max > dst->fd_count) {
2489 memcpy(dst->fd_array, src->fdset->fd_array, max);
2490 dst->fd_count =
max;
2507 for (i = 0; i < set->fdset->fd_count; i++) {
2508 if (set->fdset->fd_array[i] == s) {
2512 if (set->fdset->fd_count >= (
unsigned)set->capa) {
2514 set->fdset =
xrealloc(set->fdset,
sizeof(
unsigned int) +
sizeof(SOCKET) * set->capa);
2516 set->fdset->fd_array[set->fdset->fd_count++] = s;
2524 #define FD_ZERO(f) rb_fd_zero(f)
2525 #define FD_SET(i, f) rb_fd_set((i), (f))
2526 #define FD_CLR(i, f) rb_fd_clr((i), (f))
2527 #define FD_ISSET(i, f) rb_fd_isset((i), (f))
2530 #define rb_fd_rcopy(d, s) (*(d) = *(s))
2533 #if defined(__CYGWIN__)
2570 # if defined(__CYGWIN__)
2575 # if defined(__CYGWIN__)
2577 limit = (double)start_time.
tv_sec + (
double)start_time.
tv_usec*1e-6;
2581 limit += (double)timeout->
tv_sec+(
double)timeout->
tv_usec*1e-6;
2582 wait_rest = *timeout;
2583 timeout = &wait_rest;
2596 #if defined(__CYGWIN__)
2602 wait_100ms.
tv_usec = 100 * 1000;
2605 wait = (timeout == 0 || cmp_tv(&wait_100ms, timeout) < 0) ? &wait_100ms : timeout;
2609 if (result < 0) lerrno =
errno;
2610 if (result != 0)
break;
2621 subtract_tv(&elapsed, &start_time);
2623 if (!subtract_tv(timeout, &elapsed)) {
2627 if (cmp_tv(&wait_100ms, timeout) > 0) wait = timeout;
2629 }
while (__th->interrupt_flag == 0);
2631 }
while (result == 0 && !finish);
2633 #elif defined(_WIN32)
2637 result = native_fd_select(n, read, write, except, timeout, th);
2638 if (result < 0) lerrno =
errno;
2643 result =
rb_fd_select(n, read, write, except, timeout);
2644 if (result < 0) lerrno =
errno;
2666 wait_rest.
tv_sec = (
unsigned int)d;
2667 wait_rest.
tv_usec = (int)((d-(
double)wait_rest.
tv_sec)*1e6);
2694 thread_debug(
"rb_thread_wait_fd_rw(%d, %s)\n", fd, read ?
"read" :
"write");
2700 while (result <= 0) {
2708 thread_debug(
"rb_thread_wait_fd_rw(%d, %s): done\n", fd, read ?
"read" :
"write");
2772 if (!read && !write && !except) {
2790 return do_select(max, read, write, except, timeout);
2798 #if defined(HAVE_POLL) && defined(linux)
2805 #define POLLIN_SET (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP | POLLERR)
2806 #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
2807 #define POLLEX_SET (POLLPRI)
2809 #define TIMET_MAX (~(time_t)0 <= 0 ? (time_t)((~(unsigned_time_t)0) >> 1) : (time_t)(~(unsigned_time_t)0))
2810 #define TIMET_MIN (~(time_t)0 <= 0 ? (time_t)(((unsigned_time_t)1) << (sizeof(time_t) * CHAR_BIT - 1)) : (time_t)0)
2814 int ppoll(
struct pollfd *fds, nfds_t nfds,
2815 const struct timespec *ts,
const sigset_t *sigmask)
2826 tmp2 = ts->
tv_nsec / (1000 * 1000);
2830 timeout_ms = tmp + tmp2;
2835 return poll(fds, nfds, timeout_ms);
2860 fds.events = (short)events;
2865 result = ppoll(&fds, 1, timeout,
NULL);
2866 if (result < 0) lerrno =
errno;
2891 if (fds.revents & POLLNVAL) {
2901 if (fds.revents & POLLIN_SET)
2903 if (fds.revents & POLLOUT_SET)
2905 if (fds.revents & POLLEX_SET)
2990 #ifdef USE_CONSERVATIVE_STACK_END
2995 *stack_end_p = &stack_end;
3004 th->machine_register_stack_end = rb_ia64_bsp();
3036 if (vm->prove_profile.enable) {
3039 if (vm->during_gc) {
3049 if (timer_thread_id && native_stop_timer_thread(close_anyway)) {
3050 native_reset_timer_thread();
3057 native_reset_timer_thread();
3064 rb_thread_create_timer_thread();
3085 if (
RTEST(coverages)) {
3158 return ptr ?
sizeof(
struct thgroup) : 0;
3337 "can't move from the enclosed thread group");
3370 #define GetMutexPtr(obj, tobj) \
3371 TypedData_Get_Struct((obj), rb_mutex_t, &mutex_data_type, (tobj))
3373 #define mutex_mark NULL
3383 if (err)
rb_bug(
"%s", err);
3385 native_mutex_destroy(&mutex->
lock);
3386 native_cond_destroy(&mutex->
cond);
3420 native_mutex_initialize(&mutex->
lock);
3421 native_cond_initialize(&mutex->
cond, RB_CONDATTR_CLOCK_MONOTONIC);
3483 native_mutex_lock(&mutex->
lock);
3484 if (mutex->
th == 0) {
3490 native_mutex_unlock(&mutex->
lock);
3498 int interrupted = 0;
3521 timeout_rel.
tv_nsec = timeout_ms * 1000 * 1000;
3522 timeout = native_cond_timeout(&mutex->
cond, timeout_rel);
3523 err = native_cond_timedwait(&mutex->
cond, &mutex->
lock, &timeout);
3526 native_cond_wait(&mutex->
cond, &mutex->
lock);
3539 native_mutex_lock(&mutex->
lock);
3541 native_cond_broadcast(&mutex->
cond);
3542 native_mutex_unlock(&mutex->
lock);
3572 while (mutex->
th != th) {
3582 native_mutex_lock(&mutex->
lock);
3596 interrupted =
lock_func(th, mutex, timeout_ms);
3597 native_mutex_unlock(&mutex->
lock);
3600 if (patrol_thread == th)
3601 patrol_thread =
NULL;
3606 if (mutex->
th && interrupted == 2) {
3610 th->
status = prev_status;
3630 native_mutex_lock(&mutex->
lock);
3632 if (mutex->
th == 0) {
3633 err =
"Attempt to unlock a mutex which is not locked";
3635 else if (mutex->
th != th) {
3636 err =
"Attempt to unlock a mutex which is locked by another thread";
3641 native_cond_signal(&mutex->
cond);
3644 native_mutex_unlock(&mutex->
lock);
3648 if (th_mutex == mutex) {
3655 if (tmp_mutex == mutex) {
3659 th_mutex = tmp_mutex;
3705 if (mutex->
th == th)
3744 if (!
NIL_P(timeout)) {
3749 if (
NIL_P(timeout)) {
3755 end = time(0) - beg;
3811 #define GetBarrierPtr(obj) ((VALUE)rb_check_typeddata((obj), &barrier_data_type))
3827 if (!mutex)
return Qfalse;
3891 #if SIZEOF_LONG == SIZEOF_VOIDP
3892 #define OBJ_ID_EQL(obj_id, other) ((obj_id) == (other))
3893 #elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
3894 #define OBJ_ID_EQL(obj_id, other) (RB_TYPE_P((obj_id), T_BIGNUM) ? \
3895 rb_big_eql((obj_id), (other)) : ((obj_id) == (other)))
3901 if (paired_obj_id) {
3936 VALUE other_paired_obj = pair_list;
3959 if (pair_list ==
Qundef) {
4027 if (outer && !outermost) {
4039 if (result == p.list) {
4086 #define RUBY_EVENT_REMOVED 0x1000000
4112 hook->
flag = events;
4182 for (; hook; hook = hook->
next) {
4187 if (flag & hook->
flag) {
4188 (*hook->
func)(flag, hook->
data,
self,
id, klass);
4225 th->
tracing &= ~EVENT_RUNNING_VM;
4265 if (func == 0 || hook->
func == func) {
4560 if (p->
klass != 0) {
4571 klass =
RBASIC(klass)->klass;
4574 klass =
rb_iv_get(klass,
"__attached__");
4578 argv[0] = eventname;
4583 argv[5] = klass ? klass :
Qnil;
4613 volatile int raised;
4614 volatile int outer_state;
4617 if (running == ev && !always) {
4625 outer_state = th->
state;
4630 result = (*func)(
arg, running);
4645 th->
state = outer_state;
4690 #define rb_intern(str) rb_intern_const(str)
4707 #if THREAD_DEBUG < 0
4763 recursive_key =
rb_intern(
"__recursive_key__");
4777 gvl_acquire(th->
vm, th);
4782 rb_thread_create_timer_thread();
4785 (void)native_mutex_trylock;
4810 native_mutex_lock(&mutex->
lock);
4814 native_mutex_unlock(&mutex->
lock);
4820 #ifdef DEBUG_DEADLOCK_CHECK
4833 native_mutex_lock(&mutex->
lock);
4835 native_mutex_unlock(&mutex->
lock);
4851 if (patrol_thread && patrol_thread !=
GET_THREAD())
return;
4859 #ifdef DEBUG_DEADLOCK_CHECK
4872 if (coverage &&
RBASIC(coverage)->klass == 0) {
4888 return GET_VM()->coverages;
4894 GET_VM()->coverages = coverages;
static int vm_living_thread_num(rb_vm_t *vm)
struct timeval rb_time_interval(VALUE num)
void rb_gc_finalize_deferred(void)
void rb_threadptr_unlock_all_locking_mutexes(rb_thread_t *th)
#define RUBY_EVENT_SWITCH
void rb_thread_add_event_hook(VALUE thval, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
static VALUE thgroup_enclose(VALUE group)
#define GetBarrierPtr(obj)
unsigned long running_time_us
VALUE rb_barrier_wait(VALUE self)
static VALUE thgroup_add(VALUE group, VALUE thread)
static int check_deadlock_i(st_data_t key, st_data_t val, int *found)
VALUE rb_mutex_sleep(VALUE self, VALUE timeout)
int ruby_thread_has_gvl_p(void)
struct rb_mutex_struct * next_mutex
void ruby_thread_stack_overflow(rb_thread_t *th)
#define RUBY_EVENT_C_RETURN
void rb_bug(const char *fmt,...)
static VALUE rb_thread_priority(VALUE thread)
int gettimeofday(struct timeval *, struct timezone *)
static int lock_func(rb_thread_t *th, rb_mutex_t *mutex, int timeout_ms)
static const char * rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t volatile *th)
VALUE rb_obj_id(VALUE obj)
VALUE rb_thread_backtrace(VALUE thval)
static void thread_cleanup_func_before_exec(void *th_ptr)
struct rb_thread_struct * running_thread
VALUE rb_thread_call_without_gvl(rb_blocking_function_t *func, void *data1, rb_unblock_function_t *ubf, void *data2)
VALUE rb_make_exception(int argc, VALUE *argv)
static int rb_threadptr_remove_event_hook(rb_thread_t *th, rb_event_hook_func_t func)
#define RUBY_EVENT_RETURN
#define RUBY_VM_SET_INTERRUPT(th)
static VALUE rb_thread_abort_exc_set(VALUE thread, VALUE val)
void rb_thread_lock_unlock(rb_thread_lock_t *lock)
static void rb_mutex_abandon_all(rb_mutex_t *mutexes)
struct rb_blocking_region_buffer * rb_thread_blocking_region_begin(void)
VALUE rb_exec_recursive_outer(VALUE(*func)(VALUE, VALUE, int), VALUE obj, VALUE arg)
static int max(int a, int b)
VALUE(* func)(VALUE, VALUE, int)
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
static VALUE thgroup_enclosed_p(VALUE group)
int rb_thread_check_trap_pending(void)
int ruby_cleanup(volatile int ex)
#define RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)
VALUE rb_thread_list(void)
#define GetProcPtr(obj, ptr)
static VALUE thread_join_sleep(VALUE arg)
rb_thread_lock_t interrupt_lock
#define FLUSH_REGISTER_WINDOWS
VALUE rb_exec_recursive(VALUE(*func)(VALUE, VALUE, int), VALUE obj, VALUE arg)
pthread_mutex_t rb_thread_lock_t
if(len<=MAX_WORD_LENGTH &&len >=MIN_WORD_LENGTH)
static int terminate_atfork_before_exec_i(st_data_t key, st_data_t val, st_data_t current_th)
void rb_thread_blocking_region_end(struct rb_blocking_region_buffer *region)
void rb_unblock_function_t(void *)
static VALUE recursive_list_access(void)
#define ATOMIC_EXCHANGE(var, val)
rb_unblock_function_t * func
static VALUE thread_suppress_tracing(rb_thread_t *th, int ev, VALUE(*func)(VALUE, int), VALUE arg, int always, int pop_p)
static void update_coverage(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
static int remove_defered_event_hook(rb_event_hook_t **root)
static VALUE thread_s_new(int argc, VALUE *argv, VALUE klass)
void rb_error_frozen(const char *what)
VALUE rb_proc_call_with_block(VALUE, int argc, VALUE *argv, VALUE)
#define TypedData_Wrap_Struct(klass, data_type, sval)
#define TypedData_Get_Struct(obj, type, data_type, sval)
static VALUE mutex_initialize(VALUE self)
static void rb_mutex_abandon_keeping_mutexes(rb_thread_t *th)
void rb_threadptr_signal_raise(rb_thread_t *th, int sig)
struct rb_thread_struct volatile * th
static struct timeval double2timeval(double d)
ID rb_frame_this_func(void)
SOCKET rb_w32_get_osfhandle(int)
VALUE rb_thread_stop(void)
#define TH_JUMP_TAG(th, st)
static VALUE mutex_alloc(VALUE klass)
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
VALUE rb_catch_obj(VALUE, VALUE(*)(ANYARGS), VALUE)
static const rb_data_type_t mutex_data_type
VALUE rb_ary_push(VALUE ary, VALUE item)
void rb_thread_wait_for(struct timeval time)
static rb_event_hook_t * search_live_hook(rb_event_hook_t *hook)
st_table * living_threads
void rb_signal_exec(rb_thread_t *th, int sig)
void rb_gc_save_machine_context(rb_thread_t *th)
static VALUE INT2NUM(int v)
struct rb_thread_struct * join_list_head
static VALUE rb_thread_safe_level(VALUE thread)
static VALUE rb_thread_aset(VALUE self, VALUE id, VALUE val)
static void call_trace_func(rb_event_flag_t, VALUE data, VALUE self, ID id, VALUE klass)
#define RSTRING_PTR(string)
VALUE rb_thread_current(void)
#define OBJ_ID_EQL(obj_id, other)
void rb_raise(VALUE exc, const char *fmt,...)
VALUE rb_thread_alloc(VALUE klass)
static VALUE rb_mutex_sleep_forever(VALUE time)
static VALUE rb_thread_abort_exc(VALUE thread)
static void blocking_region_end(rb_thread_t *th, struct rb_blocking_region_buffer *region)
static void clear_coverage(void)
static const char * get_event_name(rb_event_flag_t event)
int rb_thread_alone(void)
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
VALUE rb_obj_is_kind_of(VALUE, VALUE)
VALUE rb_thread_local_aref(VALUE thread, ID id)
#define RARRAY_LEN(ARRAY)
VALUE rb_barrier_release(VALUE self)
static size_t thgroup_memsize(const void *ptr)
static void rb_mutex_abandon_locking_mutex(rb_thread_t *th)
static void set_threads_event_flags(int flag)
void rb_gc_mark(VALUE ptr)
void(* rb_event_hook_func_t)(rb_event_flag_t, VALUE data, VALUE, ID, VALUE klass)
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
static size_t mutex_memsize(const void *ptr)
static volatile int system_working
static VALUE thread_join(rb_thread_t *target_th, double delay)
#define THREAD_IO_WAITING_P(th)
static VALUE remove_from_join_list(VALUE arg)
rb_event_flag_t event_flags
VALUE rb_thread_kill(VALUE thread)
VALUE rb_mutex_locked_p(VALUE self)
static int rb_threadptr_dead(rb_thread_t *th)
static void thread_reset_event_flags(rb_thread_t *th)
void rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t flag, VALUE self, ID id, VALUE klass, int pop_p)
static VALUE rb_thread_alive_p(VALUE thread)
VALUE rb_exec_recursive_paired(VALUE(*func)(VALUE, VALUE, int), VALUE obj, VALUE paired_obj, VALUE arg)
#define rb_fd_rcopy(d, s)
static VALUE rb_thread_backtrace_m(VALUE thval)
static VALUE exec_recursive_i(VALUE tag, struct exec_recursive_params *p)
void rb_thread_start_timer_thread(void)
static rb_fdset_t * init_set_fd(int fd, rb_fdset_t *fds)
const char * rb_obj_classname(VALUE)
static void sleep_wait_for_interrupt(rb_thread_t *th, double sleepsec)
static VALUE rb_thread_stop_p(VALUE thread)
static void thread_cleanup_func(void *th_ptr, int atfork)
static double timeofday(void)
int ruby_native_thread_p(void)
rb_thread_t * patrol_thread
static VALUE rb_thread_s_abort_exc_set(VALUE self, VALUE val)
#define rb_fd_isset(n, f)
VALUE(* first_func)(ANYARGS)
VALUE rb_thread_wakeup(VALUE thread)
static VALUE rb_thread_s_main(VALUE klass)
void rb_exc_raise(VALUE mesg)
static void rb_thread_wait_fd_rw(int fd, int read)
static void rb_thread_schedule_limits(unsigned long limits_us)
void rb_reset_random_seed(void)
int rb_thread_fd_writable(int fd)
VALUE rb_binding_new(void)
static VALUE thgroup_s_alloc(VALUE klass)
static int thread_list_i(st_data_t key, st_data_t val, void *data)
#define MEMZERO(p, type, n)
#define closed_stream_error
static int clear_trace_func_i(st_data_t key, st_data_t val, st_data_t flag)
#define RUBY_VM_CHECK_INTS()
#define RUBY_THREAD_PRIORITY_MAX
static VALUE rb_thread_priority_set(VALUE thread, VALUE prio)
static int do_select(int n, rb_fdset_t *read, rb_fdset_t *write, rb_fdset_t *except, struct timeval *timeout)
static void sleep_for_polling(rb_thread_t *th)
int rb_thread_method_id_and_class(rb_thread_t *th, ID *idp, VALUE *klassp)
int rb_block_given_p(void)
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
static void sleep_forever(rb_thread_t *th, int nodeadlock)
struct rb_event_hook_struct * next
RUBY_EXTERN VALUE rb_cObject
static VALUE rb_thread_inspect(VALUE thread)
static VALUE rb_threadptr_raise(rb_thread_t *, int, VALUE *)
VALUE rb_mutex_trylock(VALUE self)
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
void * blocking_region_buffer
static VALUE exec_recursive(VALUE(*func)(VALUE, VALUE, int), VALUE obj, VALUE pairid, VALUE arg, int outer)
static VALUE thread_create_core(VALUE thval, VALUE args, VALUE(*fn)(ANYARGS))
static rb_event_hook_t * alloc_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
VALUE rb_iv_get(VALUE, const char *)
rb_event_hook_t * event_hooks
static VALUE thread_exec_event_hooks(VALUE args, int running)
void rb_thread_stop_timer_thread(int close_anyway)
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
static void rb_threadptr_ready(rb_thread_t *th)
void rb_define_const(VALUE, const char *, VALUE)
void rb_thread_atfork_before_exec(void)
void rb_threadptr_check_signal(rb_thread_t *mth)
rb_event_hook_t * event_hooks
int thread_abort_on_exception
void ruby_thread_init_stack(rb_thread_t *th)
VALUE rb_proc_location(VALUE self)
static VALUE rb_thread_exit(void)
void rb_thread_check_ints(void)
void rb_thread_fd_close(int fd)
static VALUE coverage(const char *f, int n)
VALUE rb_vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, int argc, const VALUE *argv, const rb_block_t *blockptr)
unsigned int rb_event_flag_t
VALUE rb_obj_alloc(VALUE)
#define RUBY_EVENT_C_CALL
void rb_thread_atfork(void)
VALUE * machine_stack_start
#define GVL_UNLOCK_BEGIN()
static const rb_data_type_t thgroup_data_type
VALUE rb_thread_create(VALUE(*fn)(ANYARGS), void *arg)
void rb_throw_obj(VALUE tag, VALUE value)
static VALUE thread_s_current(VALUE klass)
static int running_vm_event_hooks(st_data_t key, st_data_t val, st_data_t data)
static VALUE set_trace_func(VALUE obj, VALUE trace)
void rb_thread_polling(void)
static int set_threads_event_flags_i(st_data_t key, st_data_t val, st_data_t flag)
#define GetMutexPtr(obj, tobj)
int rb_thread_select(int max, fd_set *read, fd_set *write, fd_set *except, struct timeval *timeout)
rb_event_hook_func_t func
struct rb_unblock_callback oldubf
SSL_METHOD *(* func)(void)
static void sleep_timeval(rb_thread_t *th, struct timeval time)
#define rb_thread_set_current(th)
#define RUBY_EVENT_REMOVED
static int thgroup_list_i(st_data_t key, st_data_t val, st_data_t data)
VALUE rb_obj_is_proc(VALUE)
VALUE special_exceptions[ruby_special_error_count]
struct rb_mutex_struct * keeping_mutexes
VALUE rb_sprintf(const char *format,...)
int rb_get_next_signal(void)
VALUE rb_hash_delete(VALUE hash, VALUE key)
static VALUE thread_set_trace_func_m(VALUE obj, VALUE trace)
int rb_thread_fd_select(int max, rb_fdset_t *read, rb_fdset_t *write, rb_fdset_t *except, struct timeval *timeout)
#define rb_fd_copy(d, s, n)
static int thread_fd_close_i(st_data_t key, st_data_t val, st_data_t data)
int rb_threadptr_reset_raised(rb_thread_t *th)
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
unsigned char buf[MIME_BUF_SIZE]
#define RUBY_VM_SET_TIMER_INTERRUPT(th)
static VALUE thread_initialize(VALUE thread, VALUE args)
static void rb_check_deadlock(rb_vm_t *vm)
void rb_thread_sleep_forever(void)
VALUE rb_exc_new2(VALUE etype, const char *s)
static VALUE barrier_alloc(VALUE klass)
#define SAVE_ROOT_JMPBUF(th, stmt)
RUBY_EXTERN VALUE rb_cThread
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
#define UNINITIALIZED_VAR(x)
const char * rb_class2name(VALUE)
struct rb_thread_struct * main_thread
static int clear_coverage_i(st_data_t key, st_data_t val, st_data_t dummy)
void rb_gc_set_stack_end(VALUE **stack_end_p)
#define RARRAY_PTR(ARRAY)
void rb_thread_schedule(void)
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
VALUE rb_exec_recursive_paired_outer(VALUE(*func)(VALUE, VALUE, int), VALUE obj, VALUE paired_obj, VALUE arg)
static VALUE thread_value(VALUE self)
static void reset_unblock_function(rb_thread_t *th, const struct rb_unblock_callback *old)
rb_atomic_t interrupt_flag
static void timer_thread_function(void *)
void rb_thread_wait_fd(int fd)
VALUE rb_blocking_function_t(void *)
void rb_sys_fail(const char *mesg)
VALUE rb_thread_main(void)
VALUE rb_barrier_new(void)
enum rb_thread_status status
static void st_delete_wrap(st_table *table, st_data_t key)
void rb_thread_sleep(int sec)
static VALUE thread_add_trace_func_m(VALUE obj, VALUE trace)
static VALUE thread_s_pass(VALUE klass)
static VALUE thread_join_m(int argc, VALUE *argv, VALUE self)
#define EXEC_EVENT_HOOK(th, flag, self, id, klass)
#define thread_start_func_2(th, st, rst)
VALUE rb_mRubyVMFrozenCore
int inhibit_thread_creation
static void rb_thread_sleep_deadly(void)
enum rb_thread_status prev_status
static VALUE mutex_sleep(int argc, VALUE *argv, VALUE self)
VALUE * machine_stack_end
void rb_thread_recycle_stack_release(VALUE *)
void rb_thread_terminate_all(void)
void rb_reset_coverages(void)
void rb_clear_trace_func(void)
VALUE rb_hash_lookup2(VALUE hash, VALUE key, VALUE def)
void rb_thread_execute_interrupts(VALUE thval)
void rb_thread_lock_destroy(rb_thread_lock_t *lock)
static VALUE thgroup_list(VALUE group)
struct rb_thread_struct * join_list_next
VALUE rb_exc_new3(VALUE etype, VALUE str)
static int remove_event_hook(rb_event_hook_t **root, rb_event_hook_func_t func)
VALUE rb_block_proc(void)
#define RUBY_THREAD_PRIORITY_MIN
VALUE rb_thread_group(VALUE thread)
struct rb_unblock_callback unblock
static VALUE rb_thread_aref(VALUE thread, VALUE id)
VALUE rb_hash_aref(VALUE hash, VALUE key)
#define rb_fd_select(n, rfds, wfds, efds, timeout)
#define RB_GC_SAVE_MACHINE_CONTEXT(th)
void rb_thread_reset_timer_thread(void)
static VALUE rb_thread_status(VALUE thread)
int rb_signal_buff_size(void)
static const char * thread_status_name(enum rb_thread_status status)
static const unsigned char ev[]
struct rb_encoding_entry * list
static void recursive_push(VALUE list, VALUE obj, VALUE paired_obj)
static VALUE thread_start(VALUE klass, VALUE args)
int rb_remove_event_hook(rb_event_hook_func_t func)
#define TypedData_Make_Struct(klass, type, data_type, sval)
void rb_gc_mark_threads(void)
static VALUE rb_mutex_wait_for(VALUE time)
#define GetThreadPtr(obj, ptr)
static unsigned int hash(const char *str, unsigned int len)
static VALUE thread_raise_m(int argc, VALUE *argv, VALUE self)
static void thread_add_trace_func(rb_thread_t *th, VALUE trace)
#define rb_fd_resize(n, f)
static int defer_remove_event_hook(rb_event_hook_t *hook, rb_event_hook_func_t func)
static void rb_threadptr_add_event_hook(rb_thread_t *th, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
#define RUBY_EVENT_COVERAGE
RUBY_EXTERN VALUE rb_eIOError
VALUE rb_thread_io_blocking_region(rb_blocking_function_t *func, void *data1, int fd)
#define StringValuePtr(v)
union select_args::@70 as
#define rb_fd_init_copy(d, s)
static rb_thread_t * vm_event_hooks_running_thread(rb_vm_t *vm)
static int terminate_i(st_data_t key, st_data_t val, rb_thread_t *main_thread)
#define RUBY_VM_INTERRUPTED(th)
static VALUE rb_thread_s_abort_exc(void)
VALUE rb_thread_local_aset(VALUE thread, ID id, VALUE val)
static void recursive_pop(VALUE list, VALUE obj, VALUE paired_obj)
void rb_vm_gvl_destroy(rb_vm_t *vm)
void st_clear(st_table *)
#define BLOCKING_REGION(exec, ubf, ubfarg)
static void barrier_mark(void *ptr)
static void mutex_locked(rb_thread_t *th, VALUE self)
#define RUBY_TYPED_DEFAULT_FREE
static void rb_threadptr_execute_interrupts_common(rb_thread_t *)
NOINLINE(static int thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_start))
static VALUE rb_thread_keys(VALUE self)
int rb_thread_remove_event_hook(VALUE thval, rb_event_hook_func_t func)
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
static void getclockofday(struct timeval *tp)
static const rb_data_type_t barrier_data_type
static VALUE select_single_cleanup(VALUE ptr)
VALUE rb_vm_make_jump_tag_but_local_jump(int state, VALUE val)
static VALUE select_single(VALUE ptr)
struct rb_mutex_struct rb_mutex_t
VALUE rb_get_coverages(void)
void rb_threadptr_execute_interrupts(rb_thread_t *th)
static int exec_event_hooks(const rb_event_hook_t *hook, rb_event_flag_t flag, VALUE self, ID id, VALUE klass)
static rb_thread_t * thval2thread_t(VALUE thval)
static VALUE call_trace_proc(VALUE args, int tracing)
static int thread_keys_i(ID key, VALUE value, VALUE ary)
#define GET_THROWOBJ_STATE(obj)
#define blocking_region_begin(th, region, func, arg)
void rb_threadptr_interrupt(rb_thread_t *th)
VALUE rb_thread_wakeup_alive(VALUE thread)
VALUE rb_thread_blocking_region(rb_blocking_function_t *func, void *data1, rb_unblock_function_t *ubf, void *data2)
void rb_obj_call_init(VALUE obj, int argc, VALUE *argv)
static void mutex_free(void *ptr)
VALUE rb_mutex_unlock(VALUE self)
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
VALUE ruby_suppress_tracing(VALUE(*func)(VALUE, int), VALUE arg, int always)
VALUE rb_str_new2(const char *)
VALUE rb_barrier_destroy(VALUE self)
#define GET_THROWOBJ_VAL(obj)
void rb_set_coverages(VALUE coverages)
static VALUE rb_thread_key_p(VALUE self, VALUE key)
VALUE rb_obj_is_mutex(VALUE obj)
static VALUE rb_thread_s_kill(VALUE obj, VALUE th)
static VALUE recursive_check(VALUE list, VALUE obj_id, VALUE paired_obj_id)
static void set_unblock_function(rb_thread_t *th, rb_unblock_function_t *func, void *arg, struct rb_unblock_callback *old)
VALUE rb_thread_run(VALUE thread)
void rb_threadptr_signal_exit(rb_thread_t *th)
static void lock_interrupt(void *ptr)
static void rb_thread_atfork_internal(int(*atfork)(st_data_t, st_data_t, st_data_t))
int rb_thread_interrupted(VALUE thval)
struct timeval rb_time_timeval(VALUE)
VALUE rb_mutex_lock(VALUE self)
int rb_threadptr_set_raised(rb_thread_t *th)
static int terminate_atfork_i(st_data_t key, st_data_t val, st_data_t current_th)