54 #undef _FORTIFY_SOURCE
55 #undef __USE_FORTIFY_LEVEL
56 #define __USE_FORTIFY_LEVEL 0
67 #ifndef USE_NATIVE_THREAD_PRIORITY
68 #define USE_NATIVE_THREAD_PRIORITY 0
69 #define RUBY_THREAD_PRIORITY_MAX 3
70 #define RUBY_THREAD_PRIORITY_MIN -3
74 #define THREAD_DEBUG 0
93 #define eKillSignal INT2FIX(0)
94 #define eTerminateSignal INT2FIX(1)
97 #define closed_stream_error GET_VM()->special_exceptions[ruby_error_closed_stream]
107 #define THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
123 #define RB_GC_SAVE_MACHINE_REGISTER_STACK(th) \
124 do{(th)->machine.register_stack_end = rb_ia64_bsp();}while(0)
126 #define RB_GC_SAVE_MACHINE_REGISTER_STACK(th)
128 #define RB_GC_SAVE_MACHINE_CONTEXT(th) \
130 FLUSH_REGISTER_WINDOWS; \
131 RB_GC_SAVE_MACHINE_REGISTER_STACK(th); \
132 setjmp((th)->machine.regs); \
133 SET_MACHINE_STACK_END(&(th)->machine.stack_end); \
136 #define GVL_UNLOCK_BEGIN() do { \
137 rb_thread_t *_th_stored = GET_THREAD(); \
138 RB_GC_SAVE_MACHINE_CONTEXT(_th_stored); \
139 gvl_release(_th_stored->vm);
141 #define GVL_UNLOCK_END() \
142 gvl_acquire(_th_stored->vm, _th_stored); \
143 rb_thread_set_current(_th_stored); \
147 #define only_if_constant(expr, notconst) (__builtin_constant_p(expr) ? (expr) : (notconst))
149 #define only_if_constant(expr, notconst) notconst
151 #define BLOCKING_REGION(exec, ubf, ubfarg, fail_if_interrupted) do { \
152 rb_thread_t *__th = GET_THREAD(); \
153 struct rb_blocking_region_buffer __region; \
154 if (blocking_region_begin(__th, &__region, (ubf), (ubfarg), fail_if_interrupted) || \
156 !only_if_constant(fail_if_interrupted, TRUE)) { \
158 blocking_region_end(__th, &__region); \
163 #ifdef HAVE_VA_ARGS_MACRO
164 void rb_thread_debug(
const char *file,
int line,
const char *fmt, ...);
165 #define thread_debug(fmt, ...) rb_thread_debug(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
166 #define POSITION_FORMAT "%s:%d:"
167 #define POSITION_ARGS ,file, line
169 void rb_thread_debug(
const char *fmt, ...);
170 #define thread_debug rb_thread_debug
171 #define POSITION_FORMAT
172 #define POSITION_ARGS
175 # if THREAD_DEBUG < 0
176 static int rb_thread_debug_enabled;
187 rb_thread_s_debug(
void)
189 return INT2NUM(rb_thread_debug_enabled);
203 rb_thread_debug_enabled =
RTEST(val) ?
NUM2INT(val) : 0;
207 # define rb_thread_debug_enabled THREAD_DEBUG
210 #define thread_debug if(0)printf
214 #define thread_start_func_2(th, st, rst) thread_start_func_2(th, st)
217 VALUE *register_stack_start));
223 #define DEBUG_OUT() \
224 WaitForSingleObject(&debug_mutex, INFINITE); \
225 printf(POSITION_FORMAT"%p - %s" POSITION_ARGS, GetCurrentThreadId(), buf); \
227 ReleaseMutex(&debug_mutex);
229 #elif defined(HAVE_PTHREAD_H)
232 #define DEBUG_OUT() \
233 pthread_mutex_lock(&debug_mutex); \
234 printf(POSITION_FORMAT"%#"PRIxVALUE" - %s" POSITION_ARGS, (VALUE)pthread_self(), buf); \
236 pthread_mutex_unlock(&debug_mutex);
239 #error "unsupported thread type"
243 static int debug_mutex_initialized = 1;
248 #ifdef HAVE_VA_ARGS_MACRO
249 const char *file,
int line,
251 const char *fmt, ...)
256 if (!rb_thread_debug_enabled)
return;
258 if (debug_mutex_initialized == 1) {
259 debug_mutex_initialized = 0;
260 native_mutex_initialize(&debug_mutex);
282 native_mutex_initialize(lock);
288 native_mutex_destroy(lock);
294 native_mutex_lock(lock);
300 native_mutex_unlock(lock);
308 if (fail_if_interrupted) {
377 if (th != main_thread) {
383 thread_debug(
"terminate_i: main thread (%p)\n", (
void *)th);
416 if (err)
rb_bug(
"invalid keeping_mutexes: %s", err);
427 rb_bug(
"rb_thread_terminate_all: called by child thread (%p, %p)",
435 thread_debug(
"rb_thread_terminate_all (main thread: %p)\n", (
void *)th);
470 th->
machine.register_stack_start = th->
machine.register_stack_end = 0;
491 native_thread_destroy(th);
499 native_thread_init_stack(th);
511 # ifdef USE_SIGALTSTACK
514 rb_register_sigaltstack(th);
518 rb_bug(
"thread_start_func_2 must not be used for main thread");
520 ruby_thread_set_native(th);
524 th->
machine.register_stack_start = register_stack_start;
528 gvl_acquire(th->
vm, th);
530 thread_debug(
"thread start (get lock): %p\n", (
void *)th);
583 rb_bug(
"thread_start_func_2: locking_mutex must not be set (%p:%"PRIxVALUE")",
603 join_list = join_list->
next;
632 "can't start a new thread (frozen ThreadGroup)");
652 native_cond_initialize(&th->
interrupt_cond, RB_CONDATTR_CLOCK_MONOTONIC);
655 err = native_thread_create(th);
752 #define DELAY_INFTY 1E30
770 if ((*p)->th == th) {
813 if (th == target_th) {
816 if (
GET_VM()->main_thread == target_th) {
856 return target_th->
self;
951 #if SIGNEDNESS_OF_TIME_T < 0
952 # define TIMEVAL_SEC_MAX SIGNED_INTEGER_MAX(TYPEOF_TIMEVAL_TV_SEC)
953 # define TIMEVAL_SEC_MIN SIGNED_INTEGER_MIN(TYPEOF_TIMEVAL_TV_SEC)
954 #elif SIGNEDNESS_OF_TIME_T > 0
955 # define TIMEVAL_SEC_MAX ((TYPEOF_TIMEVAL_TV_SEC)(~(unsigned_time_t)0))
956 # define TIMEVAL_SEC_MIN ((TYPEOF_TIMEVAL_TV_SEC)0)
963 const double TIMEVAL_SEC_MAX_PLUS_ONE = (2*(double)(TIMEVAL_SEC_MAX/2+1));
967 if (TIMEVAL_SEC_MAX_PLUS_ONE <= d) {
968 time.
tv_sec = TIMEVAL_SEC_MAX;
971 else if (d <= TIMEVAL_SEC_MIN) {
972 time.
tv_sec = TIMEVAL_SEC_MIN;
977 time.
tv_usec = (int)((d - (time_t)d) * 1e6);
994 while (th->
status == status) {
1004 if (!spurious_check)
1007 th->
status = prev_status;
1013 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
1034 to.
tv_sec = TIMEVAL_SEC_MAX;
1038 if (to.
tv_sec == TIMEVAL_SEC_MAX)
1049 native_sleep(th, &tv);
1062 if (!spurious_check)
1065 th->
status = prev_status;
1085 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
1179 gvl_yield(th->
vm, th);
1207 thread_debug(
"enter blocking region (%p)\n", (
void *)th);
1209 gvl_release(th->
vm);
1220 gvl_acquire(th->
vm, th);
1222 thread_debug(
"leave blocking region (%p)\n", (
void *)th);
1223 remove_signal_thread_list(th);
1243 int saved_errno =
errno;
1248 errno = saved_errno;
1258 int saved_errno = 0;
1268 saved_errno =
errno;
1269 }, ubf, data2, fail_if_interrupted);
1271 if (!fail_if_interrupted) {
1275 errno = saved_errno;
1384 int saved_errno = 0;
1393 saved_errno =
errno;
1394 }, ubf_select, th,
FALSE);
1407 errno = saved_errno;
1417 void *(*f)(
void*) = (
void *(*)(
void*))
func;
1463 fprintf(stderr,
"[BUG] rb_thread_call_with_gvl() is called by non-ruby thread\n");
1471 rb_bug(
"rb_thread_call_with_gvl: called by a thread which has GVL.");
1568 for (i=0; i<mask_stack_len; i++) {
1569 mask = mask_stack[mask_stack_len-(i+1)];
1571 for (j=0; j<ancestors_len; j++) {
1572 VALUE klass = ancestors_ptr[j];
1626 switch (mask_timing) {
1948 }
while (old != interrupt);
1956 int postponed_job_interrupt = 0;
1962 int timer_interrupt;
1963 int pending_interrupt;
1971 if (postponed_job_interrupt) {
2007 if (timer_interrupt) {
2008 unsigned long limits_us = TIME_QUANTUM_USEC;
2079 #if defined(POSIX_SIGNAL) && defined(SIGSEGV) && defined(HAVE_SIGALTSTACK)
2080 #define USE_SIGALTSTACK
2087 #ifdef USE_SIGALTSTACK
2166 if (th == target_th) {
2346 "stopping only thread\n\tnote: use sleep to stop forever");
2743 str =
rb_sprintf(
"#<%s:%p %s>", cname, (
void *)thread, status);
2832 if (!
id)
return Qnil;
2919 if (!
id)
return Qnil;
3090 if (!
RHASH(locals)->ntbl)
3158 #if USE_NATIVE_THREAD_PRIORITY
3160 native_thread_apply_priority(th);
3176 #if defined(NFDBITS) && defined(HAVE_RB_FD_INIT)
3213 fds->fdset =
ALLOC(fd_set);
3214 FD_ZERO(fds->fdset);
3220 size_t size = howmany(
rb_fd_max(src), NFDBITS) *
sizeof(fd_mask);
3222 if (size <
sizeof(fd_set))
3223 size =
sizeof(fd_set);
3224 dst->maxfd = src->maxfd;
3226 memcpy(dst->fdset, src->fdset, size);
3232 if (fds->fdset)
xfree(fds->fdset);
3241 MEMZERO(fds->fdset, fd_mask, howmany(fds->maxfd, NFDBITS));
3247 size_t m = howmany(n + 1, NFDBITS) *
sizeof(fd_mask);
3248 size_t o = howmany(fds->maxfd, NFDBITS) *
sizeof(fd_mask);
3250 if (m <
sizeof(fd_set)) m =
sizeof(fd_set);
3251 if (o <
sizeof(fd_set)) o =
sizeof(fd_set);
3254 fds->fdset =
xrealloc(fds->fdset, m);
3255 memset((
char *)fds->fdset + o, 0, m - o);
3257 if (n >= fds->maxfd) fds->maxfd = n + 1;
3270 if (n >= fds->maxfd)
return;
3277 if (n >= fds->maxfd)
return 0;
3278 return FD_ISSET(n, fds->fdset) != 0;
3284 size_t size = howmany(max, NFDBITS) *
sizeof(fd_mask);
3286 if (size <
sizeof(fd_set)) size =
sizeof(fd_set);
3288 dst->fdset =
xrealloc(dst->fdset, size);
3289 memcpy(dst->fdset, src, size);
3295 size_t size = howmany(
rb_fd_max(src), NFDBITS) *
sizeof(fd_mask);
3297 if (size >
sizeof(fd_set)) {
3300 memcpy(dst,
rb_fd_ptr(src),
sizeof(fd_set));
3306 size_t size = howmany(
rb_fd_max(src), NFDBITS) *
sizeof(fd_mask);
3308 if (size <
sizeof(fd_set))
3309 size =
sizeof(fd_set);
3310 dst->maxfd = src->maxfd;
3311 dst->fdset =
xrealloc(dst->fdset, size);
3312 memcpy(dst->fdset, src->fdset, size);
3315 #ifdef __native_client__
3316 int select(
int nfds, fd_set *readfds, fd_set *writefds,
3317 fd_set *exceptfds,
struct timeval *timeout);
3336 return select(n, r, w, e, timeout);
3344 #define FD_ZERO(f) rb_fd_zero(f)
3345 #define FD_SET(i, f) rb_fd_set((i), (f))
3346 #define FD_CLR(i, f) rb_fd_clr((i), (f))
3347 #define FD_ISSET(i, f) rb_fd_isset((i), (f))
3349 #elif defined(_WIN32)
3354 set->capa = FD_SETSIZE;
3355 set->fdset =
ALLOC(fd_set);
3356 FD_ZERO(set->fdset);
3373 if (max > FD_SETSIZE || (UINT)max > dst->fd_count) {
3377 memcpy(dst->fd_array, src->fdset->fd_array, max);
3378 dst->fd_count =
max;
3395 for (i = 0; i <
set->fdset->fd_count; i++) {
3396 if (set->fdset->fd_array[i] == s) {
3400 if (set->fdset->fd_count >= (
unsigned)set->capa) {
3401 set->capa = (
set->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
3402 set->fdset =
xrealloc(set->fdset,
sizeof(
unsigned int) +
sizeof(SOCKET) * set->capa);
3404 set->fdset->fd_array[
set->fdset->fd_count++] = s;
3412 #define FD_ZERO(f) rb_fd_zero(f)
3413 #define FD_SET(i, f) rb_fd_set((i), (f))
3414 #define FD_CLR(i, f) rb_fd_clr((i), (f))
3415 #define FD_ISSET(i, f) rb_fd_isset((i), (f))
3418 #define rb_fd_rcopy(d, s) (*(d) = *(s))
3436 limit += (double)timeout->
tv_sec+(
double)timeout->
tv_usec*1e-6;
3437 wait_rest = *timeout;
3438 timeout = &wait_rest;
3452 result = native_fd_select(n, read, write, except, timeout, th);
3454 }, ubf_select, th,
FALSE);
3476 wait_rest.
tv_sec = (time_t)d;
3477 wait_rest.
tv_usec = (int)((d-(
double)wait_rest.
tv_sec)*1e6);
3504 thread_debug(
"rb_thread_wait_fd_rw(%d, %s)\n", fd, read ?
"read" :
"write");
3515 thread_debug(
"rb_thread_wait_fd_rw(%d, %s): done\n", fd, read ?
"read" :
"write");
3579 if (!read && !write && !except) {
3597 return do_select(max, read, write, except, timeout);
3605 #if defined(HAVE_POLL) && defined(__linux__)
3612 #define POLLIN_SET (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP | POLLERR)
3613 #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
3614 #define POLLEX_SET (POLLPRI)
3619 ppoll(
struct pollfd *fds, nfds_t nfds,
3620 const struct timespec *ts,
const sigset_t *sigmask)
3627 if (ts->
tv_sec > TIMET_MAX/1000)
3631 tmp2 = ts->
tv_nsec / (1000 * 1000);
3632 if (TIMET_MAX - tmp < tmp2)
3635 timeout_ms = tmp + tmp2;
3641 return poll(fds, nfds, timeout_ms);
3667 fds.events = (short)events;
3672 result = ppoll(&fds, 1, timeout,
NULL);
3673 if (result < 0) lerrno =
errno;
3674 }, ubf_select, th,
FALSE);
3700 if (fds.revents & POLLNVAL) {
3710 if (fds.revents & POLLIN_SET)
3712 if (fds.revents & POLLOUT_SET)
3714 if (fds.revents & POLLEX_SET)
3800 #ifdef USE_CONSERVATIVE_STACK_END
3805 *stack_end_p = &stack_end;
3845 if (vm->prove_profile.enable) {
3848 if (vm->during_gc) {
3858 if (timer_thread_id && native_stop_timer_thread(close_anyway)) {
3859 native_reset_timer_thread();
3866 native_reset_timer_thread();
3873 rb_thread_create_timer_thread();
3894 if (
RTEST(coverages)) {
3967 return ptr ?
sizeof(
struct thgroup) : 0;
4149 "can't move from the enclosed thread group");
4182 #define GetMutexPtr(obj, tobj) \
4183 TypedData_Get_Struct((obj), rb_mutex_t, &mutex_data_type, (tobj))
4185 #define mutex_mark NULL
4195 if (err)
rb_bug(
"%s", err);
4197 native_mutex_destroy(&mutex->
lock);
4198 native_cond_destroy(&mutex->
cond);
4233 native_mutex_initialize(&mutex->
lock);
4234 native_cond_initialize(&mutex->
cond, RB_CONDATTR_CLOCK_MONOTONIC);
4296 native_mutex_lock(&mutex->
lock);
4297 if (mutex->
th == 0) {
4303 native_mutex_unlock(&mutex->
lock);
4311 int interrupted = 0;
4334 timeout_rel.
tv_nsec = timeout_ms * 1000 * 1000;
4335 timeout = native_cond_timeout(&mutex->
cond, timeout_rel);
4336 err = native_cond_timedwait(&mutex->
cond, &mutex->
lock, &timeout);
4339 native_cond_wait(&mutex->
cond, &mutex->
lock);
4352 native_mutex_lock(&mutex->
lock);
4354 native_cond_broadcast(&mutex->
cond);
4355 native_mutex_unlock(&mutex->
lock);
4389 while (mutex->
th != th) {
4392 volatile int timeout_ms = 0;
4399 native_mutex_lock(&mutex->
lock);
4413 interrupted =
lock_func(th, mutex, (
int)timeout_ms);
4414 native_mutex_unlock(&mutex->
lock);
4417 if (patrol_thread == th)
4418 patrol_thread =
NULL;
4423 if (mutex->
th && interrupted == 2) {
4427 th->
status = prev_status;
4457 if (mutex->
th == th)
4468 native_mutex_lock(&mutex->
lock);
4470 if (mutex->
th == 0) {
4471 err =
"Attempt to unlock a mutex which is not locked";
4473 else if (mutex->
th != th) {
4474 err =
"Attempt to unlock a mutex which is locked by another thread";
4479 native_cond_signal(&mutex->
cond);
4482 native_mutex_unlock(&mutex->
lock);
4486 while (*th_mutex != mutex) {
4533 if (mutex->
th == th)
4572 if (!
NIL_P(timeout)) {
4577 if (
NIL_P(timeout)) {
4583 end = time(0) - beg;
4671 #define GetThreadShieldPtr(obj) ((VALUE)rb_check_typeddata((obj), &thread_shield_data_type))
4672 #define THREAD_SHIELD_WAITING_MASK (FL_USER0|FL_USER1|FL_USER2|FL_USER3|FL_USER4|FL_USER5|FL_USER6|FL_USER7|FL_USER8|FL_USER9|FL_USER10|FL_USER11|FL_USER12|FL_USER13|FL_USER14|FL_USER15|FL_USER16|FL_USER17|FL_USER18|FL_USER19)
4673 #define THREAD_SHIELD_WAITING_SHIFT (FL_USHIFT)
4674 #define rb_thread_shield_waiting(b) (int)((RBASIC(b)->flags&THREAD_SHIELD_WAITING_MASK)>>THREAD_SHIELD_WAITING_SHIFT)
4702 return thread_shield;
4719 if (!mutex)
return Qfalse;
4816 #if SIZEOF_LONG == SIZEOF_VOIDP
4817 #define OBJ_ID_EQL(obj_id, other) ((obj_id) == (other))
4818 #elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
4819 #define OBJ_ID_EQL(obj_id, other) (RB_TYPE_P((obj_id), T_BIGNUM) ? \
4820 rb_big_eql((obj_id), (other)) : ((obj_id) == (other)))
4826 if (paired_obj_id) {
4861 VALUE other_paired_obj = pair_list;
4883 if (pair_list ==
Qundef) {
4940 if (outer && !outermost) {
4957 if (result == p.list) {
5072 #define rb_intern(str) rb_intern_const(str)
5094 #if THREAD_DEBUG < 0
5160 recursive_key =
rb_intern(
"__recursive_key__");
5169 gvl_acquire(th->
vm, th);
5173 RB_CONDATTR_CLOCK_MONOTONIC);
5183 rb_thread_create_timer_thread();
5186 (void)native_mutex_trylock;
5211 native_mutex_lock(&mutex->
lock);
5215 native_mutex_unlock(&mutex->
lock);
5221 #ifdef DEBUG_DEADLOCK_CHECK
5234 native_mutex_lock(&mutex->
lock);
5236 native_mutex_unlock(&mutex->
lock);
5252 if (patrol_thread && patrol_thread !=
GET_THREAD())
return;
5259 argv[1] =
rb_str_new2(
"No live threads left. Deadlock?");
5260 #ifdef DEBUG_DEADLOCK_CHECK
5273 if (coverage &&
RBASIC(coverage)->klass == 0) {
5289 return GET_VM()->coverages;
5295 GET_VM()->coverages = coverages;
5331 err =
kill(pid, sig);