00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 #undef _FORTIFY_SOURCE
00055 #undef __USE_FORTIFY_LEVEL
00056 #define __USE_FORTIFY_LEVEL 0
00057
00058
00059
00060 #include "eval_intern.h"
00061 #include "gc.h"
00062 #include "timev.h"
00063 #include "ruby/io.h"
00064 #include "ruby/thread.h"
00065 #include "internal.h"
00066
00067 #ifndef USE_NATIVE_THREAD_PRIORITY
00068 #define USE_NATIVE_THREAD_PRIORITY 0
00069 #define RUBY_THREAD_PRIORITY_MAX 3
00070 #define RUBY_THREAD_PRIORITY_MIN -3
00071 #endif
00072
00073 #ifndef THREAD_DEBUG
00074 #define THREAD_DEBUG 0
00075 #endif
00076
00077 VALUE rb_cMutex;
00078 VALUE rb_cThreadShield;
00079
00080 static VALUE sym_immediate;
00081 static VALUE sym_on_blocking;
00082 static VALUE sym_never;
00083 static ID id_locals;
00084
00085 static void sleep_timeval(rb_thread_t *th, struct timeval time, int spurious_check);
00086 static void sleep_wait_for_interrupt(rb_thread_t *th, double sleepsec, int spurious_check);
00087 static void sleep_forever(rb_thread_t *th, int nodeadlock, int spurious_check);
00088 static double timeofday(void);
00089 static int rb_threadptr_dead(rb_thread_t *th);
00090 static void rb_check_deadlock(rb_vm_t *vm);
00091 static int rb_threadptr_pending_interrupt_empty_p(rb_thread_t *th);
00092
00093 #define eKillSignal INT2FIX(0)
00094 #define eTerminateSignal INT2FIX(1)
00095 static volatile int system_working = 1;
00096
00097 #define closed_stream_error GET_VM()->special_exceptions[ruby_error_closed_stream]
00098
00099 inline static void
00100 st_delete_wrap(st_table *table, st_data_t key)
00101 {
00102 st_delete(table, &key, 0);
00103 }
00104
00105
00106
00107 #define THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
00108
00109 struct rb_blocking_region_buffer {
00110 enum rb_thread_status prev_status;
00111 struct rb_unblock_callback oldubf;
00112 };
00113
00114 static int set_unblock_function(rb_thread_t *th, rb_unblock_function_t *func, void *arg,
00115 struct rb_unblock_callback *old, int fail_if_interrupted);
00116 static void reset_unblock_function(rb_thread_t *th, const struct rb_unblock_callback *old);
00117
00118 static inline int blocking_region_begin(rb_thread_t *th, struct rb_blocking_region_buffer *region,
00119 rb_unblock_function_t *ubf, void *arg, int fail_if_interrupted);
00120 static inline void blocking_region_end(rb_thread_t *th, struct rb_blocking_region_buffer *region);
00121
00122 #ifdef __ia64
00123 #define RB_GC_SAVE_MACHINE_REGISTER_STACK(th) \
00124 do{(th)->machine.register_stack_end = rb_ia64_bsp();}while(0)
00125 #else
00126 #define RB_GC_SAVE_MACHINE_REGISTER_STACK(th)
00127 #endif
00128 #define RB_GC_SAVE_MACHINE_CONTEXT(th) \
00129 do { \
00130 FLUSH_REGISTER_WINDOWS; \
00131 RB_GC_SAVE_MACHINE_REGISTER_STACK(th); \
00132 setjmp((th)->machine.regs); \
00133 SET_MACHINE_STACK_END(&(th)->machine.stack_end); \
00134 } while (0)
00135
00136 #define GVL_UNLOCK_BEGIN() do { \
00137 rb_thread_t *_th_stored = GET_THREAD(); \
00138 RB_GC_SAVE_MACHINE_CONTEXT(_th_stored); \
00139 gvl_release(_th_stored->vm);
00140
00141 #define GVL_UNLOCK_END() \
00142 gvl_acquire(_th_stored->vm, _th_stored); \
00143 rb_thread_set_current(_th_stored); \
00144 } while(0)
00145
00146 #ifdef __GNUC__
00147 #define only_if_constant(expr, notconst) (__builtin_constant_p(expr) ? (expr) : (notconst))
00148 #else
00149 #define only_if_constant(expr, notconst) notconst
00150 #endif
00151 #define BLOCKING_REGION(exec, ubf, ubfarg, fail_if_interrupted) do { \
00152 rb_thread_t *__th = GET_THREAD(); \
00153 struct rb_blocking_region_buffer __region; \
00154 if (blocking_region_begin(__th, &__region, (ubf), (ubfarg), fail_if_interrupted) || \
00155 \
00156 !only_if_constant(fail_if_interrupted, TRUE)) { \
00157 exec; \
00158 blocking_region_end(__th, &__region); \
00159 }; \
00160 } while(0)
00161
00162 #if THREAD_DEBUG
00163 #ifdef HAVE_VA_ARGS_MACRO
00164 void rb_thread_debug(const char *file, int line, const char *fmt, ...);
00165 #define thread_debug(fmt, ...) rb_thread_debug(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
00166 #define POSITION_FORMAT "%s:%d:"
00167 #define POSITION_ARGS ,file, line
00168 #else
00169 void rb_thread_debug(const char *fmt, ...);
00170 #define thread_debug rb_thread_debug
00171 #define POSITION_FORMAT
00172 #define POSITION_ARGS
00173 #endif
00174
00175 # if THREAD_DEBUG < 0
00176 static int rb_thread_debug_enabled;
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186 static VALUE
00187 rb_thread_s_debug(void)
00188 {
00189 return INT2NUM(rb_thread_debug_enabled);
00190 }
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200 static VALUE
00201 rb_thread_s_debug_set(VALUE self, VALUE val)
00202 {
00203 rb_thread_debug_enabled = RTEST(val) ? NUM2INT(val) : 0;
00204 return val;
00205 }
00206 # else
00207 # define rb_thread_debug_enabled THREAD_DEBUG
00208 # endif
00209 #else
00210 #define thread_debug if(0)printf
00211 #endif
00212
00213 #ifndef __ia64
00214 #define thread_start_func_2(th, st, rst) thread_start_func_2(th, st)
00215 #endif
00216 NOINLINE(static int thread_start_func_2(rb_thread_t *th, VALUE *stack_start,
00217 VALUE *register_stack_start));
00218 static void timer_thread_function(void *);
00219
00220 #if defined(_WIN32)
00221 #include "thread_win32.c"
00222
00223 #define DEBUG_OUT() \
00224 WaitForSingleObject(&debug_mutex, INFINITE); \
00225 printf(POSITION_FORMAT"%p - %s" POSITION_ARGS, GetCurrentThreadId(), buf); \
00226 fflush(stdout); \
00227 ReleaseMutex(&debug_mutex);
00228
00229 #elif defined(HAVE_PTHREAD_H)
00230 #include "thread_pthread.c"
00231
00232 #define DEBUG_OUT() \
00233 pthread_mutex_lock(&debug_mutex); \
00234 printf(POSITION_FORMAT"%#"PRIxVALUE" - %s" POSITION_ARGS, (VALUE)pthread_self(), buf); \
00235 fflush(stdout); \
00236 pthread_mutex_unlock(&debug_mutex);
00237
00238 #else
00239 #error "unsupported thread type"
00240 #endif
00241
00242 #if THREAD_DEBUG
00243 static int debug_mutex_initialized = 1;
00244 static rb_nativethread_lock_t debug_mutex;
00245
00246 void
00247 rb_thread_debug(
00248 #ifdef HAVE_VA_ARGS_MACRO
00249 const char *file, int line,
00250 #endif
00251 const char *fmt, ...)
00252 {
00253 va_list args;
00254 char buf[BUFSIZ];
00255
00256 if (!rb_thread_debug_enabled) return;
00257
00258 if (debug_mutex_initialized == 1) {
00259 debug_mutex_initialized = 0;
00260 native_mutex_initialize(&debug_mutex);
00261 }
00262
00263 va_start(args, fmt);
00264 vsnprintf(buf, BUFSIZ, fmt, args);
00265 va_end(args);
00266
00267 DEBUG_OUT();
00268 }
00269 #endif
00270
00271 void
00272 rb_vm_gvl_destroy(rb_vm_t *vm)
00273 {
00274 gvl_release(vm);
00275 gvl_destroy(vm);
00276 native_mutex_destroy(&vm->thread_destruct_lock);
00277 }
00278
00279 void
00280 rb_nativethread_lock_initialize(rb_nativethread_lock_t *lock)
00281 {
00282 native_mutex_initialize(lock);
00283 }
00284
00285 void
00286 rb_nativethread_lock_destroy(rb_nativethread_lock_t *lock)
00287 {
00288 native_mutex_destroy(lock);
00289 }
00290
00291 void
00292 rb_nativethread_lock_lock(rb_nativethread_lock_t *lock)
00293 {
00294 native_mutex_lock(lock);
00295 }
00296
00297 void
00298 rb_nativethread_lock_unlock(rb_nativethread_lock_t *lock)
00299 {
00300 native_mutex_unlock(lock);
00301 }
00302
00303 static int
00304 set_unblock_function(rb_thread_t *th, rb_unblock_function_t *func, void *arg,
00305 struct rb_unblock_callback *old, int fail_if_interrupted)
00306 {
00307 check_ints:
00308 if (fail_if_interrupted) {
00309 if (RUBY_VM_INTERRUPTED_ANY(th)) {
00310 return FALSE;
00311 }
00312 }
00313 else {
00314 RUBY_VM_CHECK_INTS(th);
00315 }
00316
00317 native_mutex_lock(&th->interrupt_lock);
00318 if (RUBY_VM_INTERRUPTED_ANY(th)) {
00319 native_mutex_unlock(&th->interrupt_lock);
00320 goto check_ints;
00321 }
00322 else {
00323 if (old) *old = th->unblock;
00324 th->unblock.func = func;
00325 th->unblock.arg = arg;
00326 }
00327 native_mutex_unlock(&th->interrupt_lock);
00328
00329 return TRUE;
00330 }
00331
00332 static void
00333 reset_unblock_function(rb_thread_t *th, const struct rb_unblock_callback *old)
00334 {
00335 native_mutex_lock(&th->interrupt_lock);
00336 th->unblock = *old;
00337 native_mutex_unlock(&th->interrupt_lock);
00338 }
00339
00340 static void
00341 rb_threadptr_interrupt_common(rb_thread_t *th, int trap)
00342 {
00343 native_mutex_lock(&th->interrupt_lock);
00344 if (trap)
00345 RUBY_VM_SET_TRAP_INTERRUPT(th);
00346 else
00347 RUBY_VM_SET_INTERRUPT(th);
00348 if (th->unblock.func) {
00349 (th->unblock.func)(th->unblock.arg);
00350 }
00351 else {
00352
00353 }
00354 native_cond_signal(&th->interrupt_cond);
00355 native_mutex_unlock(&th->interrupt_lock);
00356 }
00357
00358 void
00359 rb_threadptr_interrupt(rb_thread_t *th)
00360 {
00361 rb_threadptr_interrupt_common(th, 0);
00362 }
00363
00364 void
00365 rb_threadptr_trap_interrupt(rb_thread_t *th)
00366 {
00367 rb_threadptr_interrupt_common(th, 1);
00368 }
00369
00370 static int
00371 terminate_i(st_data_t key, st_data_t val, rb_thread_t *main_thread)
00372 {
00373 VALUE thval = key;
00374 rb_thread_t *th;
00375 GetThreadPtr(thval, th);
00376
00377 if (th != main_thread) {
00378 thread_debug("terminate_i: %p\n", (void *)th);
00379 rb_threadptr_pending_interrupt_enque(th, eTerminateSignal);
00380 rb_threadptr_interrupt(th);
00381 }
00382 else {
00383 thread_debug("terminate_i: main thread (%p)\n", (void *)th);
00384 }
00385 return ST_CONTINUE;
00386 }
00387
00388 typedef struct rb_mutex_struct
00389 {
00390 rb_nativethread_lock_t lock;
00391 rb_nativethread_cond_t cond;
00392 struct rb_thread_struct volatile *th;
00393 struct rb_mutex_struct *next_mutex;
00394 int cond_waiting;
00395 int allow_trap;
00396 } rb_mutex_t;
00397
00398 static void rb_mutex_abandon_all(rb_mutex_t *mutexes);
00399 static void rb_mutex_abandon_keeping_mutexes(rb_thread_t *th);
00400 static void rb_mutex_abandon_locking_mutex(rb_thread_t *th);
00401 static const char* rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t volatile *th);
00402
00403 void
00404 rb_threadptr_unlock_all_locking_mutexes(rb_thread_t *th)
00405 {
00406 const char *err;
00407 rb_mutex_t *mutex;
00408 rb_mutex_t *mutexes = th->keeping_mutexes;
00409
00410 while (mutexes) {
00411 mutex = mutexes;
00412
00413
00414 mutexes = mutex->next_mutex;
00415 err = rb_mutex_unlock_th(mutex, th);
00416 if (err) rb_bug("invalid keeping_mutexes: %s", err);
00417 }
00418 }
00419
00420 void
00421 rb_thread_terminate_all(void)
00422 {
00423 rb_thread_t *th = GET_THREAD();
00424 rb_vm_t *vm = th->vm;
00425
00426 if (vm->main_thread != th) {
00427 rb_bug("rb_thread_terminate_all: called by child thread (%p, %p)",
00428 (void *)vm->main_thread, (void *)th);
00429 }
00430
00431
00432 rb_threadptr_unlock_all_locking_mutexes(th);
00433
00434 retry:
00435 thread_debug("rb_thread_terminate_all (main thread: %p)\n", (void *)th);
00436 st_foreach(vm->living_threads, terminate_i, (st_data_t)th);
00437
00438 while (!rb_thread_alone()) {
00439 int state;
00440
00441 TH_PUSH_TAG(th);
00442 if ((state = TH_EXEC_TAG()) == 0) {
00443
00444
00445
00446
00447 native_sleep(th, 0);
00448 RUBY_VM_CHECK_INTS_BLOCKING(th);
00449 }
00450 TH_POP_TAG();
00451
00452
00453
00454
00455
00456
00457 if (state) {
00458 goto retry;
00459 }
00460 }
00461 }
00462
00463 static void
00464 thread_cleanup_func_before_exec(void *th_ptr)
00465 {
00466 rb_thread_t *th = th_ptr;
00467 th->status = THREAD_KILLED;
00468 th->machine.stack_start = th->machine.stack_end = 0;
00469 #ifdef __ia64
00470 th->machine.register_stack_start = th->machine.register_stack_end = 0;
00471 #endif
00472 }
00473
00474 static void
00475 thread_cleanup_func(void *th_ptr, int atfork)
00476 {
00477 rb_thread_t *th = th_ptr;
00478
00479 th->locking_mutex = Qfalse;
00480 thread_cleanup_func_before_exec(th_ptr);
00481
00482
00483
00484
00485
00486
00487 if (atfork)
00488 return;
00489
00490 native_mutex_destroy(&th->interrupt_lock);
00491 native_thread_destroy(th);
00492 }
00493
00494 static VALUE rb_threadptr_raise(rb_thread_t *, int, VALUE *);
00495
00496 void
00497 ruby_thread_init_stack(rb_thread_t *th)
00498 {
00499 native_thread_init_stack(th);
00500 }
00501
00502 static int
00503 thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_start)
00504 {
00505 int state;
00506 VALUE args = th->first_args;
00507 rb_proc_t *proc;
00508 rb_thread_list_t *join_list;
00509 rb_thread_t *main_th;
00510 VALUE errinfo = Qnil;
00511 # ifdef USE_SIGALTSTACK
00512 void rb_register_sigaltstack(rb_thread_t *th);
00513
00514 rb_register_sigaltstack(th);
00515 # endif
00516
00517 if (th == th->vm->main_thread)
00518 rb_bug("thread_start_func_2 must not be used for main thread");
00519
00520 ruby_thread_set_native(th);
00521
00522 th->machine.stack_start = stack_start;
00523 #ifdef __ia64
00524 th->machine.register_stack_start = register_stack_start;
00525 #endif
00526 thread_debug("thread start: %p\n", (void *)th);
00527
00528 gvl_acquire(th->vm, th);
00529 {
00530 thread_debug("thread start (get lock): %p\n", (void *)th);
00531 rb_thread_set_current(th);
00532
00533 TH_PUSH_TAG(th);
00534 if ((state = EXEC_TAG()) == 0) {
00535 SAVE_ROOT_JMPBUF(th, {
00536 if (!th->first_func) {
00537 GetProcPtr(th->first_proc, proc);
00538 th->errinfo = Qnil;
00539 th->root_lep = rb_vm_ep_local_ep(proc->block.ep);
00540 th->root_svar = Qnil;
00541 EXEC_EVENT_HOOK(th, RUBY_EVENT_THREAD_BEGIN, th->self, 0, 0, Qundef);
00542 th->value = rb_vm_invoke_proc(th, proc, (int)RARRAY_LEN(args), RARRAY_CONST_PTR(args), 0);
00543 EXEC_EVENT_HOOK(th, RUBY_EVENT_THREAD_END, th->self, 0, 0, Qundef);
00544 }
00545 else {
00546 th->value = (*th->first_func)((void *)args);
00547 }
00548 });
00549 }
00550 else {
00551 errinfo = th->errinfo;
00552 if (state == TAG_FATAL) {
00553
00554 }
00555 else if (rb_obj_is_kind_of(errinfo, rb_eSystemExit)) {
00556
00557 }
00558 else if (th->vm->thread_abort_on_exception ||
00559 th->abort_on_exception || RTEST(ruby_debug)) {
00560
00561 }
00562 else {
00563 errinfo = Qnil;
00564 }
00565 th->value = Qnil;
00566 }
00567
00568 th->status = THREAD_KILLED;
00569 thread_debug("thread end: %p\n", (void *)th);
00570
00571 main_th = th->vm->main_thread;
00572 if (main_th == th) {
00573 ruby_stop(0);
00574 }
00575 if (RB_TYPE_P(errinfo, T_OBJECT)) {
00576
00577 rb_threadptr_raise(main_th, 1, &errinfo);
00578 }
00579 TH_POP_TAG();
00580
00581
00582 if (th->locking_mutex != Qfalse) {
00583 rb_bug("thread_start_func_2: locking_mutex must not be set (%p:%"PRIxVALUE")",
00584 (void *)th, th->locking_mutex);
00585 }
00586
00587
00588 st_delete_wrap(th->vm->living_threads, th->self);
00589 if (rb_thread_alone()) {
00590
00591 rb_threadptr_interrupt(main_th);
00592 }
00593
00594
00595 join_list = th->join_list;
00596 while (join_list) {
00597 rb_threadptr_interrupt(join_list->th);
00598 switch (join_list->th->status) {
00599 case THREAD_STOPPED: case THREAD_STOPPED_FOREVER:
00600 join_list->th->status = THREAD_RUNNABLE;
00601 default: break;
00602 }
00603 join_list = join_list->next;
00604 }
00605
00606 rb_threadptr_unlock_all_locking_mutexes(th);
00607 rb_check_deadlock(th->vm);
00608
00609 if (!th->root_fiber) {
00610 rb_thread_recycle_stack_release(th->stack);
00611 th->stack = 0;
00612 }
00613 }
00614 native_mutex_lock(&th->vm->thread_destruct_lock);
00615
00616 th->vm->running_thread = NULL;
00617 native_mutex_unlock(&th->vm->thread_destruct_lock);
00618 thread_cleanup_func(th, FALSE);
00619 gvl_release(th->vm);
00620
00621 return 0;
00622 }
00623
00624 static VALUE
00625 thread_create_core(VALUE thval, VALUE args, VALUE (*fn)(ANYARGS))
00626 {
00627 rb_thread_t *th, *current_th = GET_THREAD();
00628 int err;
00629
00630 if (OBJ_FROZEN(GET_THREAD()->thgroup)) {
00631 rb_raise(rb_eThreadError,
00632 "can't start a new thread (frozen ThreadGroup)");
00633 }
00634 GetThreadPtr(thval, th);
00635
00636
00637 th->first_func = fn;
00638 th->first_proc = fn ? Qfalse : rb_block_proc();
00639 th->first_args = args;
00640
00641 th->priority = current_th->priority;
00642 th->thgroup = current_th->thgroup;
00643
00644 th->pending_interrupt_queue = rb_ary_tmp_new(0);
00645 th->pending_interrupt_queue_checked = 0;
00646 th->pending_interrupt_mask_stack = rb_ary_dup(current_th->pending_interrupt_mask_stack);
00647 RBASIC_CLEAR_CLASS(th->pending_interrupt_mask_stack);
00648
00649 th->interrupt_mask = 0;
00650
00651 native_mutex_initialize(&th->interrupt_lock);
00652 native_cond_initialize(&th->interrupt_cond, RB_CONDATTR_CLOCK_MONOTONIC);
00653
00654
00655 err = native_thread_create(th);
00656 if (err) {
00657 th->status = THREAD_KILLED;
00658 rb_raise(rb_eThreadError, "can't create Thread: %s", strerror(err));
00659 }
00660 st_insert(th->vm->living_threads, thval, (st_data_t) th->thread_id);
00661 return thval;
00662 }
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684 static VALUE
00685 thread_s_new(int argc, VALUE *argv, VALUE klass)
00686 {
00687 rb_thread_t *th;
00688 VALUE thread = rb_thread_alloc(klass);
00689
00690 if (GET_VM()->main_thread->status == THREAD_KILLED)
00691 rb_raise(rb_eThreadError, "can't alloc thread");
00692
00693 rb_obj_call_init(thread, argc, argv);
00694 GetThreadPtr(thread, th);
00695 if (!th->first_args) {
00696 rb_raise(rb_eThreadError, "uninitialized thread - check `%s#initialize'",
00697 rb_class2name(klass));
00698 }
00699 return thread;
00700 }
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712 static VALUE
00713 thread_start(VALUE klass, VALUE args)
00714 {
00715 return thread_create_core(rb_thread_alloc(klass), args, 0);
00716 }
00717
00718
00719 static VALUE
00720 thread_initialize(VALUE thread, VALUE args)
00721 {
00722 rb_thread_t *th;
00723 if (!rb_block_given_p()) {
00724 rb_raise(rb_eThreadError, "must be called with a block");
00725 }
00726 GetThreadPtr(thread, th);
00727 if (th->first_args) {
00728 VALUE proc = th->first_proc, line, loc;
00729 const char *file;
00730 if (!proc || !RTEST(loc = rb_proc_location(proc))) {
00731 rb_raise(rb_eThreadError, "already initialized thread");
00732 }
00733 file = RSTRING_PTR(RARRAY_AREF(loc, 0));
00734 if (NIL_P(line = RARRAY_AREF(loc, 1))) {
00735 rb_raise(rb_eThreadError, "already initialized thread - %s",
00736 file);
00737 }
00738 rb_raise(rb_eThreadError, "already initialized thread - %s:%d",
00739 file, NUM2INT(line));
00740 }
00741 return thread_create_core(thread, args, 0);
00742 }
00743
00744 VALUE
00745 rb_thread_create(VALUE (*fn)(ANYARGS), void *arg)
00746 {
00747 return thread_create_core(rb_thread_alloc(rb_cThread), (VALUE)arg, fn);
00748 }
00749
00750
00751
00752 #define DELAY_INFTY 1E30
00753
00754 struct join_arg {
00755 rb_thread_t *target, *waiting;
00756 double limit;
00757 int forever;
00758 };
00759
00760 static VALUE
00761 remove_from_join_list(VALUE arg)
00762 {
00763 struct join_arg *p = (struct join_arg *)arg;
00764 rb_thread_t *target_th = p->target, *th = p->waiting;
00765
00766 if (target_th->status != THREAD_KILLED) {
00767 rb_thread_list_t **p = &target_th->join_list;
00768
00769 while (*p) {
00770 if ((*p)->th == th) {
00771 *p = (*p)->next;
00772 break;
00773 }
00774 p = &(*p)->next;
00775 }
00776 }
00777
00778 return Qnil;
00779 }
00780
00781 static VALUE
00782 thread_join_sleep(VALUE arg)
00783 {
00784 struct join_arg *p = (struct join_arg *)arg;
00785 rb_thread_t *target_th = p->target, *th = p->waiting;
00786 double now, limit = p->limit;
00787
00788 while (target_th->status != THREAD_KILLED) {
00789 if (p->forever) {
00790 sleep_forever(th, 1, 0);
00791 }
00792 else {
00793 now = timeofday();
00794 if (now > limit) {
00795 thread_debug("thread_join: timeout (thid: %p)\n",
00796 (void *)target_th->thread_id);
00797 return Qfalse;
00798 }
00799 sleep_wait_for_interrupt(th, limit - now, 0);
00800 }
00801 thread_debug("thread_join: interrupted (thid: %p)\n",
00802 (void *)target_th->thread_id);
00803 }
00804 return Qtrue;
00805 }
00806
00807 static VALUE
00808 thread_join(rb_thread_t *target_th, double delay)
00809 {
00810 rb_thread_t *th = GET_THREAD();
00811 struct join_arg arg;
00812
00813 if (th == target_th) {
00814 rb_raise(rb_eThreadError, "Target thread must not be current thread");
00815 }
00816 if (GET_VM()->main_thread == target_th) {
00817 rb_raise(rb_eThreadError, "Target thread must not be main thread");
00818 }
00819
00820 arg.target = target_th;
00821 arg.waiting = th;
00822 arg.limit = timeofday() + delay;
00823 arg.forever = delay == DELAY_INFTY;
00824
00825 thread_debug("thread_join (thid: %p)\n", (void *)target_th->thread_id);
00826
00827 if (target_th->status != THREAD_KILLED) {
00828 rb_thread_list_t list;
00829 list.next = target_th->join_list;
00830 list.th = th;
00831 target_th->join_list = &list;
00832 if (!rb_ensure(thread_join_sleep, (VALUE)&arg,
00833 remove_from_join_list, (VALUE)&arg)) {
00834 return Qnil;
00835 }
00836 }
00837
00838 thread_debug("thread_join: success (thid: %p)\n",
00839 (void *)target_th->thread_id);
00840
00841 if (target_th->errinfo != Qnil) {
00842 VALUE err = target_th->errinfo;
00843
00844 if (FIXNUM_P(err)) {
00845
00846 }
00847 else if (RB_TYPE_P(target_th->errinfo, T_NODE)) {
00848 rb_exc_raise(rb_vm_make_jump_tag_but_local_jump(
00849 GET_THROWOBJ_STATE(err), GET_THROWOBJ_VAL(err)));
00850 }
00851 else {
00852
00853 rb_exc_raise(err);
00854 }
00855 }
00856 return target_th->self;
00857 }
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898 static VALUE
00899 thread_join_m(int argc, VALUE *argv, VALUE self)
00900 {
00901 rb_thread_t *target_th;
00902 double delay = DELAY_INFTY;
00903 VALUE limit;
00904
00905 GetThreadPtr(self, target_th);
00906
00907 rb_scan_args(argc, argv, "01", &limit);
00908 if (!NIL_P(limit)) {
00909 delay = rb_num2dbl(limit);
00910 }
00911
00912 return thread_join(target_th, delay);
00913 }
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925 static VALUE
00926 thread_value(VALUE self)
00927 {
00928 rb_thread_t *th;
00929 GetThreadPtr(self, th);
00930 thread_join(th, DELAY_INFTY);
00931 return th->value;
00932 }
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951 #if SIGNEDNESS_OF_TIME_T < 0
00952 # define TIMEVAL_SEC_MAX SIGNED_INTEGER_MAX(TYPEOF_TIMEVAL_TV_SEC)
00953 # define TIMEVAL_SEC_MIN SIGNED_INTEGER_MIN(TYPEOF_TIMEVAL_TV_SEC)
00954 #elif SIGNEDNESS_OF_TIME_T > 0
00955 # define TIMEVAL_SEC_MAX ((TYPEOF_TIMEVAL_TV_SEC)(~(unsigned_time_t)0))
00956 # define TIMEVAL_SEC_MIN ((TYPEOF_TIMEVAL_TV_SEC)0)
00957 #endif
00958
00959 static struct timeval
00960 double2timeval(double d)
00961 {
00962
00963 const double TIMEVAL_SEC_MAX_PLUS_ONE = (2*(double)(TIMEVAL_SEC_MAX/2+1));
00964
00965 struct timeval time;
00966
00967 if (TIMEVAL_SEC_MAX_PLUS_ONE <= d) {
00968 time.tv_sec = TIMEVAL_SEC_MAX;
00969 time.tv_usec = 999999;
00970 }
00971 else if (d <= TIMEVAL_SEC_MIN) {
00972 time.tv_sec = TIMEVAL_SEC_MIN;
00973 time.tv_usec = 0;
00974 }
00975 else {
00976 time.tv_sec = (TYPEOF_TIMEVAL_TV_SEC)d;
00977 time.tv_usec = (int)((d - (time_t)d) * 1e6);
00978 if (time.tv_usec < 0) {
00979 time.tv_usec += (int)1e6;
00980 time.tv_sec -= 1;
00981 }
00982 }
00983 return time;
00984 }
00985
00986 static void
00987 sleep_forever(rb_thread_t *th, int deadlockable, int spurious_check)
00988 {
00989 enum rb_thread_status prev_status = th->status;
00990 enum rb_thread_status status = deadlockable ? THREAD_STOPPED_FOREVER : THREAD_STOPPED;
00991
00992 th->status = status;
00993 RUBY_VM_CHECK_INTS_BLOCKING(th);
00994 while (th->status == status) {
00995 if (deadlockable) {
00996 th->vm->sleeper++;
00997 rb_check_deadlock(th->vm);
00998 }
00999 native_sleep(th, 0);
01000 if (deadlockable) {
01001 th->vm->sleeper--;
01002 }
01003 RUBY_VM_CHECK_INTS_BLOCKING(th);
01004 if (!spurious_check)
01005 break;
01006 }
01007 th->status = prev_status;
01008 }
01009
01010 static void
01011 getclockofday(struct timeval *tp)
01012 {
01013 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
01014 struct timespec ts;
01015
01016 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
01017 tp->tv_sec = ts.tv_sec;
01018 tp->tv_usec = ts.tv_nsec / 1000;
01019 } else
01020 #endif
01021 {
01022 gettimeofday(tp, NULL);
01023 }
01024 }
01025
01026 static void
01027 sleep_timeval(rb_thread_t *th, struct timeval tv, int spurious_check)
01028 {
01029 struct timeval to, tvn;
01030 enum rb_thread_status prev_status = th->status;
01031
01032 getclockofday(&to);
01033 if (TIMEVAL_SEC_MAX - tv.tv_sec < to.tv_sec)
01034 to.tv_sec = TIMEVAL_SEC_MAX;
01035 else
01036 to.tv_sec += tv.tv_sec;
01037 if ((to.tv_usec += tv.tv_usec) >= 1000000) {
01038 if (to.tv_sec == TIMEVAL_SEC_MAX)
01039 to.tv_usec = 999999;
01040 else {
01041 to.tv_sec++;
01042 to.tv_usec -= 1000000;
01043 }
01044 }
01045
01046 th->status = THREAD_STOPPED;
01047 RUBY_VM_CHECK_INTS_BLOCKING(th);
01048 while (th->status == THREAD_STOPPED) {
01049 native_sleep(th, &tv);
01050 RUBY_VM_CHECK_INTS_BLOCKING(th);
01051 getclockofday(&tvn);
01052 if (to.tv_sec < tvn.tv_sec) break;
01053 if (to.tv_sec == tvn.tv_sec && to.tv_usec <= tvn.tv_usec) break;
01054 thread_debug("sleep_timeval: %"PRI_TIMET_PREFIX"d.%.6ld > %"PRI_TIMET_PREFIX"d.%.6ld\n",
01055 (time_t)to.tv_sec, (long)to.tv_usec,
01056 (time_t)tvn.tv_sec, (long)tvn.tv_usec);
01057 tv.tv_sec = to.tv_sec - tvn.tv_sec;
01058 if ((tv.tv_usec = to.tv_usec - tvn.tv_usec) < 0) {
01059 --tv.tv_sec;
01060 tv.tv_usec += 1000000;
01061 }
01062 if (!spurious_check)
01063 break;
01064 }
01065 th->status = prev_status;
01066 }
01067
01068 void
01069 rb_thread_sleep_forever(void)
01070 {
01071 thread_debug("rb_thread_sleep_forever\n");
01072 sleep_forever(GET_THREAD(), 0, 1);
01073 }
01074
01075 void
01076 rb_thread_sleep_deadly(void)
01077 {
01078 thread_debug("rb_thread_sleep_deadly\n");
01079 sleep_forever(GET_THREAD(), 1, 1);
01080 }
01081
01082 static double
01083 timeofday(void)
01084 {
01085 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
01086 struct timespec tp;
01087
01088 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
01089 return (double)tp.tv_sec + (double)tp.tv_nsec * 1e-9;
01090 } else
01091 #endif
01092 {
01093 struct timeval tv;
01094 gettimeofday(&tv, NULL);
01095 return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6;
01096 }
01097 }
01098
01099 static void
01100 sleep_wait_for_interrupt(rb_thread_t *th, double sleepsec, int spurious_check)
01101 {
01102 sleep_timeval(th, double2timeval(sleepsec), spurious_check);
01103 }
01104
01105 static void
01106 sleep_for_polling(rb_thread_t *th)
01107 {
01108 struct timeval time;
01109 time.tv_sec = 0;
01110 time.tv_usec = 100 * 1000;
01111 sleep_timeval(th, time, 1);
01112 }
01113
01114 void
01115 rb_thread_wait_for(struct timeval time)
01116 {
01117 rb_thread_t *th = GET_THREAD();
01118 sleep_timeval(th, time, 1);
01119 }
01120
01121 void
01122 rb_thread_polling(void)
01123 {
01124 if (!rb_thread_alone()) {
01125 rb_thread_t *th = GET_THREAD();
01126 RUBY_VM_CHECK_INTS_BLOCKING(th);
01127 sleep_for_polling(th);
01128 }
01129 }
01130
01131
01132
01133
01134
01135
01136
01137
01138 void
01139 rb_thread_check_ints(void)
01140 {
01141 RUBY_VM_CHECK_INTS_BLOCKING(GET_THREAD());
01142 }
01143
01144
01145
01146
01147
01148 int
01149 rb_thread_check_trap_pending(void)
01150 {
01151 return rb_signal_buff_size() != 0;
01152 }
01153
01154
01155 int
01156 rb_thread_interrupted(VALUE thval)
01157 {
01158 rb_thread_t *th;
01159 GetThreadPtr(thval, th);
01160 return (int)RUBY_VM_INTERRUPTED(th);
01161 }
01162
01163 void
01164 rb_thread_sleep(int sec)
01165 {
01166 rb_thread_wait_for(rb_time_timeval(INT2FIX(sec)));
01167 }
01168
01169 static void
01170 rb_thread_schedule_limits(unsigned long limits_us)
01171 {
01172 thread_debug("rb_thread_schedule\n");
01173 if (!rb_thread_alone()) {
01174 rb_thread_t *th = GET_THREAD();
01175
01176 if (th->running_time_us >= limits_us) {
01177 thread_debug("rb_thread_schedule/switch start\n");
01178 RB_GC_SAVE_MACHINE_CONTEXT(th);
01179 gvl_yield(th->vm, th);
01180 rb_thread_set_current(th);
01181 thread_debug("rb_thread_schedule/switch done\n");
01182 }
01183 }
01184 }
01185
01186 void
01187 rb_thread_schedule(void)
01188 {
01189 rb_thread_t *cur_th = GET_THREAD();
01190 rb_thread_schedule_limits(0);
01191
01192 if (UNLIKELY(RUBY_VM_INTERRUPTED_ANY(cur_th))) {
01193 rb_threadptr_execute_interrupts(cur_th, 0);
01194 }
01195 }
01196
01197
01198
01199 static inline int
01200 blocking_region_begin(rb_thread_t *th, struct rb_blocking_region_buffer *region,
01201 rb_unblock_function_t *ubf, void *arg, int fail_if_interrupted)
01202 {
01203 region->prev_status = th->status;
01204 if (set_unblock_function(th, ubf, arg, ®ion->oldubf, fail_if_interrupted)) {
01205 th->blocking_region_buffer = region;
01206 th->status = THREAD_STOPPED;
01207 thread_debug("enter blocking region (%p)\n", (void *)th);
01208 RB_GC_SAVE_MACHINE_CONTEXT(th);
01209 gvl_release(th->vm);
01210 return TRUE;
01211 }
01212 else {
01213 return FALSE;
01214 }
01215 }
01216
01217 static inline void
01218 blocking_region_end(rb_thread_t *th, struct rb_blocking_region_buffer *region)
01219 {
01220 gvl_acquire(th->vm, th);
01221 rb_thread_set_current(th);
01222 thread_debug("leave blocking region (%p)\n", (void *)th);
01223 remove_signal_thread_list(th);
01224 th->blocking_region_buffer = 0;
01225 reset_unblock_function(th, ®ion->oldubf);
01226 if (th->status == THREAD_STOPPED) {
01227 th->status = region->prev_status;
01228 }
01229 }
01230
01231 struct rb_blocking_region_buffer *
01232 rb_thread_blocking_region_begin(void)
01233 {
01234 rb_thread_t *th = GET_THREAD();
01235 struct rb_blocking_region_buffer *region = ALLOC(struct rb_blocking_region_buffer);
01236 blocking_region_begin(th, region, ubf_select, th, FALSE);
01237 return region;
01238 }
01239
01240 void
01241 rb_thread_blocking_region_end(struct rb_blocking_region_buffer *region)
01242 {
01243 int saved_errno = errno;
01244 rb_thread_t *th = ruby_thread_from_native();
01245 blocking_region_end(th, region);
01246 xfree(region);
01247 RUBY_VM_CHECK_INTS_BLOCKING(th);
01248 errno = saved_errno;
01249 }
01250
01251 static void *
01252 call_without_gvl(void *(*func)(void *), void *data1,
01253 rb_unblock_function_t *ubf, void *data2, int fail_if_interrupted)
01254 {
01255 void *val = 0;
01256
01257 rb_thread_t *th = GET_THREAD();
01258 int saved_errno = 0;
01259
01260 th->waiting_fd = -1;
01261 if (ubf == RUBY_UBF_IO || ubf == RUBY_UBF_PROCESS) {
01262 ubf = ubf_select;
01263 data2 = th;
01264 }
01265
01266 BLOCKING_REGION({
01267 val = func(data1);
01268 saved_errno = errno;
01269 }, ubf, data2, fail_if_interrupted);
01270
01271 if (!fail_if_interrupted) {
01272 RUBY_VM_CHECK_INTS_BLOCKING(th);
01273 }
01274
01275 errno = saved_errno;
01276
01277 return val;
01278 }
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365 void *
01366 rb_thread_call_without_gvl2(void *(*func)(void *), void *data1,
01367 rb_unblock_function_t *ubf, void *data2)
01368 {
01369 return call_without_gvl(func, data1, ubf, data2, TRUE);
01370 }
01371
01372 void *
01373 rb_thread_call_without_gvl(void *(*func)(void *data), void *data1,
01374 rb_unblock_function_t *ubf, void *data2)
01375 {
01376 return call_without_gvl(func, data1, ubf, data2, FALSE);
01377 }
01378
01379 VALUE
01380 rb_thread_io_blocking_region(rb_blocking_function_t *func, void *data1, int fd)
01381 {
01382 VALUE val = Qundef;
01383 rb_thread_t *th = GET_THREAD();
01384 int saved_errno = 0;
01385 int state;
01386
01387 th->waiting_fd = fd;
01388
01389 TH_PUSH_TAG(th);
01390 if ((state = EXEC_TAG()) == 0) {
01391 BLOCKING_REGION({
01392 val = func(data1);
01393 saved_errno = errno;
01394 }, ubf_select, th, FALSE);
01395 }
01396 TH_POP_TAG();
01397
01398
01399 th->waiting_fd = -1;
01400
01401 if (state) {
01402 JUMP_TAG(state);
01403 }
01404
01405 RUBY_VM_CHECK_INTS_BLOCKING(th);
01406
01407 errno = saved_errno;
01408
01409 return val;
01410 }
01411
01412 VALUE
01413 rb_thread_blocking_region(
01414 rb_blocking_function_t *func, void *data1,
01415 rb_unblock_function_t *ubf, void *data2)
01416 {
01417 void *(*f)(void*) = (void *(*)(void*))func;
01418 return (VALUE)rb_thread_call_without_gvl(f, data1, ubf, data2);
01419 }
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447
01448
01449 void *
01450 rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
01451 {
01452 rb_thread_t *th = ruby_thread_from_native();
01453 struct rb_blocking_region_buffer *brb;
01454 struct rb_unblock_callback prev_unblock;
01455 void *r;
01456
01457 if (th == 0) {
01458
01459
01460
01461
01462
01463 fprintf(stderr, "[BUG] rb_thread_call_with_gvl() is called by non-ruby thread\n");
01464 exit(EXIT_FAILURE);
01465 }
01466
01467 brb = (struct rb_blocking_region_buffer *)th->blocking_region_buffer;
01468 prev_unblock = th->unblock;
01469
01470 if (brb == 0) {
01471 rb_bug("rb_thread_call_with_gvl: called by a thread which has GVL.");
01472 }
01473
01474 blocking_region_end(th, brb);
01475
01476 r = (*func)(data1);
01477
01478 blocking_region_begin(th, brb, prev_unblock.func, prev_unblock.arg, FALSE);
01479 return r;
01480 }
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491 int
01492 ruby_thread_has_gvl_p(void)
01493 {
01494 rb_thread_t *th = ruby_thread_from_native();
01495
01496 if (th && th->blocking_region_buffer == 0) {
01497 return 1;
01498 }
01499 else {
01500 return 0;
01501 }
01502 }
01503
01504
01505
01506
01507
01508
01509
01510
01511
01512 static VALUE
01513 thread_s_pass(VALUE klass)
01514 {
01515 rb_thread_schedule();
01516 return Qnil;
01517 }
01518
01519
01520
01521
01522
01523
01524
01525
01526
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537 void
01538 rb_threadptr_pending_interrupt_clear(rb_thread_t *th)
01539 {
01540 rb_ary_clear(th->pending_interrupt_queue);
01541 }
01542
01543 void
01544 rb_threadptr_pending_interrupt_enque(rb_thread_t *th, VALUE v)
01545 {
01546 rb_ary_push(th->pending_interrupt_queue, v);
01547 th->pending_interrupt_queue_checked = 0;
01548 }
01549
01550 enum handle_interrupt_timing {
01551 INTERRUPT_NONE,
01552 INTERRUPT_IMMEDIATE,
01553 INTERRUPT_ON_BLOCKING,
01554 INTERRUPT_NEVER
01555 };
01556
01557 static enum handle_interrupt_timing
01558 rb_threadptr_pending_interrupt_check_mask(rb_thread_t *th, VALUE err)
01559 {
01560 VALUE mask;
01561 long mask_stack_len = RARRAY_LEN(th->pending_interrupt_mask_stack);
01562 const VALUE *mask_stack = RARRAY_CONST_PTR(th->pending_interrupt_mask_stack);
01563 VALUE ancestors = rb_mod_ancestors(err);
01564 long ancestors_len = RARRAY_LEN(ancestors);
01565 const VALUE *ancestors_ptr = RARRAY_CONST_PTR(ancestors);
01566 int i, j;
01567
01568 for (i=0; i<mask_stack_len; i++) {
01569 mask = mask_stack[mask_stack_len-(i+1)];
01570
01571 for (j=0; j<ancestors_len; j++) {
01572 VALUE klass = ancestors_ptr[j];
01573 VALUE sym;
01574
01575
01576 if ((sym = rb_hash_aref(mask, klass)) != Qnil) {
01577 if (sym == sym_immediate) {
01578 return INTERRUPT_IMMEDIATE;
01579 }
01580 else if (sym == sym_on_blocking) {
01581 return INTERRUPT_ON_BLOCKING;
01582 }
01583 else if (sym == sym_never) {
01584 return INTERRUPT_NEVER;
01585 }
01586 else {
01587 rb_raise(rb_eThreadError, "unknown mask signature");
01588 }
01589 }
01590 }
01591
01592 }
01593 return INTERRUPT_NONE;
01594 }
01595
01596 static int
01597 rb_threadptr_pending_interrupt_empty_p(rb_thread_t *th)
01598 {
01599 return RARRAY_LEN(th->pending_interrupt_queue) == 0;
01600 }
01601
01602 static int
01603 rb_threadptr_pending_interrupt_include_p(rb_thread_t *th, VALUE err)
01604 {
01605 int i;
01606 for (i=0; i<RARRAY_LEN(th->pending_interrupt_queue); i++) {
01607 VALUE e = RARRAY_AREF(th->pending_interrupt_queue, i);
01608 if (rb_class_inherited_p(e, err)) {
01609 return TRUE;
01610 }
01611 }
01612 return FALSE;
01613 }
01614
01615 static VALUE
01616 rb_threadptr_pending_interrupt_deque(rb_thread_t *th, enum handle_interrupt_timing timing)
01617 {
01618 #if 1
01619 int i;
01620
01621 for (i=0; i<RARRAY_LEN(th->pending_interrupt_queue); i++) {
01622 VALUE err = RARRAY_AREF(th->pending_interrupt_queue, i);
01623
01624 enum handle_interrupt_timing mask_timing = rb_threadptr_pending_interrupt_check_mask(th, CLASS_OF(err));
01625
01626 switch (mask_timing) {
01627 case INTERRUPT_ON_BLOCKING:
01628 if (timing != INTERRUPT_ON_BLOCKING) {
01629 break;
01630 }
01631
01632 case INTERRUPT_NONE:
01633 case INTERRUPT_IMMEDIATE:
01634 rb_ary_delete_at(th->pending_interrupt_queue, i);
01635 return err;
01636 case INTERRUPT_NEVER:
01637 break;
01638 }
01639 }
01640
01641 th->pending_interrupt_queue_checked = 1;
01642 return Qundef;
01643 #else
01644 VALUE err = rb_ary_shift(th->pending_interrupt_queue);
01645 if (rb_threadptr_pending_interrupt_empty_p(th)) {
01646 th->pending_interrupt_queue_checked = 1;
01647 }
01648 return err;
01649 #endif
01650 }
01651
01652 int
01653 rb_threadptr_pending_interrupt_active_p(rb_thread_t *th)
01654 {
01655
01656
01657
01658
01659
01660 if (th->pending_interrupt_queue_checked) {
01661 return 0;
01662 }
01663
01664 if (rb_threadptr_pending_interrupt_empty_p(th)) {
01665 return 0;
01666 }
01667
01668 return 1;
01669 }
01670
01671 static int
01672 handle_interrupt_arg_check_i(VALUE key, VALUE val)
01673 {
01674 if (val != sym_immediate && val != sym_on_blocking && val != sym_never) {
01675 rb_raise(rb_eArgError, "unknown mask signature");
01676 }
01677
01678 return ST_CONTINUE;
01679 }
01680
01681
01682
01683
01684
01685
01686
01687
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787 static VALUE
01788 rb_thread_s_handle_interrupt(VALUE self, VALUE mask_arg)
01789 {
01790 VALUE mask;
01791 rb_thread_t *th = GET_THREAD();
01792 VALUE r = Qnil;
01793 int state;
01794
01795 if (!rb_block_given_p()) {
01796 rb_raise(rb_eArgError, "block is needed.");
01797 }
01798
01799 mask = rb_convert_type(mask_arg, T_HASH, "Hash", "to_hash");
01800 rb_hash_foreach(mask, handle_interrupt_arg_check_i, 0);
01801 rb_ary_push(th->pending_interrupt_mask_stack, mask);
01802 if (!rb_threadptr_pending_interrupt_empty_p(th)) {
01803 th->pending_interrupt_queue_checked = 0;
01804 RUBY_VM_SET_INTERRUPT(th);
01805 }
01806
01807 TH_PUSH_TAG(th);
01808 if ((state = EXEC_TAG()) == 0) {
01809 r = rb_yield(Qnil);
01810 }
01811 TH_POP_TAG();
01812
01813 rb_ary_pop(th->pending_interrupt_mask_stack);
01814 if (!rb_threadptr_pending_interrupt_empty_p(th)) {
01815 th->pending_interrupt_queue_checked = 0;
01816 RUBY_VM_SET_INTERRUPT(th);
01817 }
01818
01819 RUBY_VM_CHECK_INTS(th);
01820
01821 if (state) {
01822 JUMP_TAG(state);
01823 }
01824
01825 return r;
01826 }
01827
01828
01829
01830
01831
01832
01833
01834
01835
01836
01837
01838 static VALUE
01839 rb_thread_pending_interrupt_p(int argc, VALUE *argv, VALUE target_thread)
01840 {
01841 rb_thread_t *target_th;
01842
01843 GetThreadPtr(target_thread, target_th);
01844
01845 if (rb_threadptr_pending_interrupt_empty_p(target_th)) {
01846 return Qfalse;
01847 }
01848 else {
01849 if (argc == 1) {
01850 VALUE err;
01851 rb_scan_args(argc, argv, "01", &err);
01852 if (!rb_obj_is_kind_of(err, rb_cModule)) {
01853 rb_raise(rb_eTypeError, "class or module required for rescue clause");
01854 }
01855 if (rb_threadptr_pending_interrupt_include_p(target_th, err)) {
01856 return Qtrue;
01857 }
01858 else {
01859 return Qfalse;
01860 }
01861 }
01862 return Qtrue;
01863 }
01864 }
01865
01866
01867
01868
01869
01870
01871
01872
01873
01874
01875
01876
01877
01878
01879
01880
01881
01882
01883
01884
01885
01886
01887
01888
01889
01890
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900
01901
01902
01903
01904
01905
01906
01907
01908
01909
01910
01911
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923 static VALUE
01924 rb_thread_s_pending_interrupt_p(int argc, VALUE *argv, VALUE self)
01925 {
01926 return rb_thread_pending_interrupt_p(argc, argv, GET_THREAD()->self);
01927 }
01928
01929 static void
01930 rb_threadptr_to_kill(rb_thread_t *th)
01931 {
01932 rb_threadptr_pending_interrupt_clear(th);
01933 th->status = THREAD_RUNNABLE;
01934 th->to_kill = 1;
01935 th->errinfo = INT2FIX(TAG_FATAL);
01936 TH_JUMP_TAG(th, TAG_FATAL);
01937 }
01938
01939 static inline rb_atomic_t
01940 threadptr_get_interrupts(rb_thread_t *th)
01941 {
01942 rb_atomic_t interrupt;
01943 rb_atomic_t old;
01944
01945 do {
01946 interrupt = th->interrupt_flag;
01947 old = ATOMIC_CAS(th->interrupt_flag, interrupt, interrupt & th->interrupt_mask);
01948 } while (old != interrupt);
01949 return interrupt & (rb_atomic_t)~th->interrupt_mask;
01950 }
01951
01952 void
01953 rb_threadptr_execute_interrupts(rb_thread_t *th, int blocking_timing)
01954 {
01955 rb_atomic_t interrupt;
01956 int postponed_job_interrupt = 0;
01957
01958 if (th->raised_flag) return;
01959
01960 while ((interrupt = threadptr_get_interrupts(th)) != 0) {
01961 int sig;
01962 int timer_interrupt;
01963 int pending_interrupt;
01964 int trap_interrupt;
01965
01966 timer_interrupt = interrupt & TIMER_INTERRUPT_MASK;
01967 pending_interrupt = interrupt & PENDING_INTERRUPT_MASK;
01968 postponed_job_interrupt = interrupt & POSTPONED_JOB_INTERRUPT_MASK;
01969 trap_interrupt = interrupt & TRAP_INTERRUPT_MASK;
01970
01971 if (postponed_job_interrupt) {
01972 rb_postponed_job_flush(th->vm);
01973 }
01974
01975
01976 if (trap_interrupt && (th == th->vm->main_thread)) {
01977 enum rb_thread_status prev_status = th->status;
01978 th->status = THREAD_RUNNABLE;
01979 while ((sig = rb_get_next_signal()) != 0) {
01980 rb_signal_exec(th, sig);
01981 }
01982 th->status = prev_status;
01983 }
01984
01985
01986 if (pending_interrupt && rb_threadptr_pending_interrupt_active_p(th)) {
01987 VALUE err = rb_threadptr_pending_interrupt_deque(th, blocking_timing ? INTERRUPT_ON_BLOCKING : INTERRUPT_NONE);
01988 thread_debug("rb_thread_execute_interrupts: %"PRIdVALUE"\n", err);
01989
01990 if (err == Qundef) {
01991
01992 }
01993 else if (err == eKillSignal ||
01994 err == eTerminateSignal ||
01995 err == INT2FIX(TAG_FATAL) ) {
01996 rb_threadptr_to_kill(th);
01997 }
01998 else {
01999
02000 if (th->status == THREAD_STOPPED ||
02001 th->status == THREAD_STOPPED_FOREVER)
02002 th->status = THREAD_RUNNABLE;
02003 rb_exc_raise(err);
02004 }
02005 }
02006
02007 if (timer_interrupt) {
02008 unsigned long limits_us = TIME_QUANTUM_USEC;
02009
02010 if (th->priority > 0)
02011 limits_us <<= th->priority;
02012 else
02013 limits_us >>= -th->priority;
02014
02015 if (th->status == THREAD_RUNNABLE)
02016 th->running_time_us += TIME_QUANTUM_USEC;
02017
02018 EXEC_EVENT_HOOK(th, RUBY_INTERNAL_EVENT_SWITCH, th->cfp->self, 0, 0, Qundef);
02019
02020 rb_thread_schedule_limits(limits_us);
02021 }
02022 }
02023 }
02024
02025 void
02026 rb_thread_execute_interrupts(VALUE thval)
02027 {
02028 rb_thread_t *th;
02029 GetThreadPtr(thval, th);
02030 rb_threadptr_execute_interrupts(th, 1);
02031 }
02032
02033 static void
02034 rb_threadptr_ready(rb_thread_t *th)
02035 {
02036 rb_threadptr_interrupt(th);
02037 }
02038
02039 static VALUE
02040 rb_threadptr_raise(rb_thread_t *th, int argc, VALUE *argv)
02041 {
02042 VALUE exc;
02043
02044 if (rb_threadptr_dead(th)) {
02045 return Qnil;
02046 }
02047
02048 if (argc == 0) {
02049 exc = rb_exc_new(rb_eRuntimeError, 0, 0);
02050 }
02051 else {
02052 exc = rb_make_exception(argc, argv);
02053 }
02054 rb_threadptr_pending_interrupt_enque(th, exc);
02055 rb_threadptr_interrupt(th);
02056 return Qnil;
02057 }
02058
02059 void
02060 rb_threadptr_signal_raise(rb_thread_t *th, int sig)
02061 {
02062 VALUE argv[2];
02063
02064 argv[0] = rb_eSignal;
02065 argv[1] = INT2FIX(sig);
02066 rb_threadptr_raise(th->vm->main_thread, 2, argv);
02067 }
02068
02069 void
02070 rb_threadptr_signal_exit(rb_thread_t *th)
02071 {
02072 VALUE argv[2];
02073
02074 argv[0] = rb_eSystemExit;
02075 argv[1] = rb_str_new2("exit");
02076 rb_threadptr_raise(th->vm->main_thread, 2, argv);
02077 }
02078
02079 #if defined(POSIX_SIGNAL) && defined(SIGSEGV) && defined(HAVE_SIGALTSTACK)
02080 #define USE_SIGALTSTACK
02081 #endif
02082
02083 void
02084 ruby_thread_stack_overflow(rb_thread_t *th)
02085 {
02086 th->raised_flag = 0;
02087 #ifdef USE_SIGALTSTACK
02088 rb_exc_raise(sysstack_error);
02089 #else
02090 th->errinfo = sysstack_error;
02091 TH_JUMP_TAG(th, TAG_RAISE);
02092 #endif
02093 }
02094
02095 int
02096 rb_threadptr_set_raised(rb_thread_t *th)
02097 {
02098 if (th->raised_flag & RAISED_EXCEPTION) {
02099 return 1;
02100 }
02101 th->raised_flag |= RAISED_EXCEPTION;
02102 return 0;
02103 }
02104
02105 int
02106 rb_threadptr_reset_raised(rb_thread_t *th)
02107 {
02108 if (!(th->raised_flag & RAISED_EXCEPTION)) {
02109 return 0;
02110 }
02111 th->raised_flag &= ~RAISED_EXCEPTION;
02112 return 1;
02113 }
02114
02115 static int
02116 thread_fd_close_i(st_data_t key, st_data_t val, st_data_t data)
02117 {
02118 int fd = (int)data;
02119 rb_thread_t *th;
02120 GetThreadPtr((VALUE)key, th);
02121
02122 if (th->waiting_fd == fd) {
02123 VALUE err = th->vm->special_exceptions[ruby_error_closed_stream];
02124 rb_threadptr_pending_interrupt_enque(th, err);
02125 rb_threadptr_interrupt(th);
02126 }
02127 return ST_CONTINUE;
02128 }
02129
02130 void
02131 rb_thread_fd_close(int fd)
02132 {
02133 st_foreach(GET_THREAD()->vm->living_threads, thread_fd_close_i, (st_index_t)fd);
02134 }
02135
02136
02137
02138
02139
02140
02141
02142
02143
02144
02145
02146
02147
02148
02149
02150
02151
02152
02153
02154
02155
02156
02157 static VALUE
02158 thread_raise_m(int argc, VALUE *argv, VALUE self)
02159 {
02160 rb_thread_t *target_th;
02161 rb_thread_t *th = GET_THREAD();
02162 GetThreadPtr(self, target_th);
02163 rb_threadptr_raise(target_th, argc, argv);
02164
02165
02166 if (th == target_th) {
02167 RUBY_VM_CHECK_INTS(th);
02168 }
02169 return Qnil;
02170 }
02171
02172
02173
02174
02175
02176
02177
02178
02179
02180
02181
02182
02183
02184
02185
02186 VALUE
02187 rb_thread_kill(VALUE thread)
02188 {
02189 rb_thread_t *th;
02190
02191 GetThreadPtr(thread, th);
02192
02193 if (th->to_kill || th->status == THREAD_KILLED) {
02194 return thread;
02195 }
02196 if (th == th->vm->main_thread) {
02197 rb_exit(EXIT_SUCCESS);
02198 }
02199
02200 thread_debug("rb_thread_kill: %p (%p)\n", (void *)th, (void *)th->thread_id);
02201
02202 if (th == GET_THREAD()) {
02203
02204 rb_threadptr_to_kill(th);
02205 }
02206 else {
02207 rb_threadptr_pending_interrupt_enque(th, eKillSignal);
02208 rb_threadptr_interrupt(th);
02209 }
02210 return thread;
02211 }
02212
02213
02214
02215
02216
02217
02218
02219
02220
02221
02222
02223
02224
02225
02226
02227
02228 static VALUE
02229 rb_thread_s_kill(VALUE obj, VALUE th)
02230 {
02231 return rb_thread_kill(th);
02232 }
02233
02234
02235
02236
02237
02238
02239
02240
02241
02242
02243
02244
02245
02246
02247 static VALUE
02248 rb_thread_exit(void)
02249 {
02250 rb_thread_t *th = GET_THREAD();
02251 return rb_thread_kill(th->self);
02252 }
02253
02254
02255
02256
02257
02258
02259
02260
02261
02262
02263
02264
02265
02266
02267
02268
02269
02270
02271 VALUE
02272 rb_thread_wakeup(VALUE thread)
02273 {
02274 if (!RTEST(rb_thread_wakeup_alive(thread))) {
02275 rb_raise(rb_eThreadError, "killed thread");
02276 }
02277 return thread;
02278 }
02279
02280 VALUE
02281 rb_thread_wakeup_alive(VALUE thread)
02282 {
02283 rb_thread_t *th;
02284 GetThreadPtr(thread, th);
02285
02286 if (th->status == THREAD_KILLED) {
02287 return Qnil;
02288 }
02289 rb_threadptr_ready(th);
02290 if (th->status == THREAD_STOPPED || th->status == THREAD_STOPPED_FOREVER)
02291 th->status = THREAD_RUNNABLE;
02292 return thread;
02293 }
02294
02295
02296
02297
02298
02299
02300
02301
02302
02303
02304
02305
02306
02307
02308
02309
02310
02311
02312
02313
02314
02315
02316
02317 VALUE
02318 rb_thread_run(VALUE thread)
02319 {
02320 rb_thread_wakeup(thread);
02321 rb_thread_schedule();
02322 return thread;
02323 }
02324
02325
02326
02327
02328
02329
02330
02331
02332
02333
02334
02335
02336
02337
02338
02339
02340
02341 VALUE
02342 rb_thread_stop(void)
02343 {
02344 if (rb_thread_alone()) {
02345 rb_raise(rb_eThreadError,
02346 "stopping only thread\n\tnote: use sleep to stop forever");
02347 }
02348 rb_thread_sleep_deadly();
02349 return Qnil;
02350 }
02351
02352 static int
02353 thread_list_i(st_data_t key, st_data_t val, void *data)
02354 {
02355 VALUE ary = (VALUE)data;
02356 rb_thread_t *th;
02357 GetThreadPtr((VALUE)key, th);
02358
02359 switch (th->status) {
02360 case THREAD_RUNNABLE:
02361 case THREAD_STOPPED:
02362 case THREAD_STOPPED_FOREVER:
02363 rb_ary_push(ary, th->self);
02364 default:
02365 break;
02366 }
02367 return ST_CONTINUE;
02368 }
02369
02370
02371
02372
02373
02374
02375
02376
02377
02378
02379
02380
02381
02382
02383
02384
02385
02386
02387
02388
02389
02390
02391
02392 VALUE
02393 rb_thread_list(void)
02394 {
02395 VALUE ary = rb_ary_new();
02396 st_foreach(GET_THREAD()->vm->living_threads, thread_list_i, ary);
02397 return ary;
02398 }
02399
02400 VALUE
02401 rb_thread_current(void)
02402 {
02403 return GET_THREAD()->self;
02404 }
02405
02406
02407
02408
02409
02410
02411
02412
02413
02414
02415 static VALUE
02416 thread_s_current(VALUE klass)
02417 {
02418 return rb_thread_current();
02419 }
02420
02421 VALUE
02422 rb_thread_main(void)
02423 {
02424 return GET_THREAD()->vm->main_thread->self;
02425 }
02426
02427
02428
02429
02430
02431
02432
02433
02434 static VALUE
02435 rb_thread_s_main(VALUE klass)
02436 {
02437 return rb_thread_main();
02438 }
02439
02440
02441
02442
02443
02444
02445
02446
02447
02448
02449
02450
02451
02452
02453
02454
02455
02456
02457
02458
02459
02460
02461 static VALUE
02462 rb_thread_s_abort_exc(void)
02463 {
02464 return GET_THREAD()->vm->thread_abort_on_exception ? Qtrue : Qfalse;
02465 }
02466
02467
02468
02469
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489
02490
02491
02492
02493
02494
02495
02496
02497 static VALUE
02498 rb_thread_s_abort_exc_set(VALUE self, VALUE val)
02499 {
02500 GET_THREAD()->vm->thread_abort_on_exception = RTEST(val);
02501 return val;
02502 }
02503
02504
02505
02506
02507
02508
02509
02510
02511
02512
02513
02514
02515
02516
02517
02518
02519
02520 static VALUE
02521 rb_thread_abort_exc(VALUE thread)
02522 {
02523 rb_thread_t *th;
02524 GetThreadPtr(thread, th);
02525 return th->abort_on_exception ? Qtrue : Qfalse;
02526 }
02527
02528
02529
02530
02531
02532
02533
02534
02535
02536
02537
02538
02539
02540
02541
02542
02543
02544 static VALUE
02545 rb_thread_abort_exc_set(VALUE thread, VALUE val)
02546 {
02547 rb_thread_t *th;
02548
02549 GetThreadPtr(thread, th);
02550 th->abort_on_exception = RTEST(val);
02551 return val;
02552 }
02553
02554
02555
02556
02557
02558
02559
02560
02561
02562
02563
02564
02565 VALUE
02566 rb_thread_group(VALUE thread)
02567 {
02568 rb_thread_t *th;
02569 VALUE group;
02570 GetThreadPtr(thread, th);
02571 group = th->thgroup;
02572
02573 if (!group) {
02574 group = Qnil;
02575 }
02576 return group;
02577 }
02578
02579 static const char *
02580 thread_status_name(rb_thread_t *th)
02581 {
02582 switch (th->status) {
02583 case THREAD_RUNNABLE:
02584 if (th->to_kill)
02585 return "aborting";
02586 else
02587 return "run";
02588 case THREAD_STOPPED:
02589 case THREAD_STOPPED_FOREVER:
02590 return "sleep";
02591 case THREAD_KILLED:
02592 return "dead";
02593 default:
02594 return "unknown";
02595 }
02596 }
02597
02598 static int
02599 rb_threadptr_dead(rb_thread_t *th)
02600 {
02601 return th->status == THREAD_KILLED;
02602 }
02603
02604
02605
02606
02607
02608
02609
02610
02611
02612
02613
02614
02615
02616
02617
02618
02619
02620
02621
02622
02623
02624
02625
02626
02627
02628
02629
02630
02631
02632
02633
02634
02635
02636 static VALUE
02637 rb_thread_status(VALUE thread)
02638 {
02639 rb_thread_t *th;
02640 GetThreadPtr(thread, th);
02641
02642 if (rb_threadptr_dead(th)) {
02643 if (!NIL_P(th->errinfo) && !FIXNUM_P(th->errinfo)
02644 ) {
02645 return Qnil;
02646 }
02647 return Qfalse;
02648 }
02649 return rb_str_new2(thread_status_name(th));
02650 }
02651
02652
02653
02654
02655
02656
02657
02658
02659
02660
02661
02662
02663
02664
02665
02666
02667 static VALUE
02668 rb_thread_alive_p(VALUE thread)
02669 {
02670 rb_thread_t *th;
02671 GetThreadPtr(thread, th);
02672
02673 if (rb_threadptr_dead(th))
02674 return Qfalse;
02675 return Qtrue;
02676 }
02677
02678
02679
02680
02681
02682
02683
02684
02685
02686
02687
02688
02689
02690
02691
02692 static VALUE
02693 rb_thread_stop_p(VALUE thread)
02694 {
02695 rb_thread_t *th;
02696 GetThreadPtr(thread, th);
02697
02698 if (rb_threadptr_dead(th))
02699 return Qtrue;
02700 if (th->status == THREAD_STOPPED || th->status == THREAD_STOPPED_FOREVER)
02701 return Qtrue;
02702 return Qfalse;
02703 }
02704
02705
02706
02707
02708
02709
02710
02711
02712
02713
02714
02715
02716
02717 static VALUE
02718 rb_thread_safe_level(VALUE thread)
02719 {
02720 rb_thread_t *th;
02721 GetThreadPtr(thread, th);
02722
02723 return INT2NUM(th->safe_level);
02724 }
02725
02726
02727
02728
02729
02730
02731
02732
02733 static VALUE
02734 rb_thread_inspect(VALUE thread)
02735 {
02736 const char *cname = rb_obj_classname(thread);
02737 rb_thread_t *th;
02738 const char *status;
02739 VALUE str;
02740
02741 GetThreadPtr(thread, th);
02742 status = thread_status_name(th);
02743 str = rb_sprintf("#<%s:%p %s>", cname, (void *)thread, status);
02744 OBJ_INFECT(str, thread);
02745
02746 return str;
02747 }
02748
02749 static VALUE
02750 threadptr_local_aref(rb_thread_t *th, ID id)
02751 {
02752 st_data_t val;
02753
02754 if (th->local_storage && st_lookup(th->local_storage, id, &val)) {
02755 return (VALUE)val;
02756 }
02757 return Qnil;
02758 }
02759
02760 VALUE
02761 rb_thread_local_aref(VALUE thread, ID id)
02762 {
02763 rb_thread_t *th;
02764 GetThreadPtr(thread, th);
02765 return threadptr_local_aref(th, id);
02766 }
02767
02768
02769
02770
02771
02772
02773
02774
02775
02776
02777
02778
02779
02780
02781
02782
02783
02784
02785
02786
02787
02788
02789
02790
02791
02792
02793
02794
02795
02796
02797
02798
02799
02800
02801
02802
02803
02804
02805
02806
02807
02808
02809
02810
02811
02812
02813
02814
02815
02816
02817
02818
02819
02820
02821
02822
02823
02824
02825
02826
02827
02828 static VALUE
02829 rb_thread_aref(VALUE thread, VALUE key)
02830 {
02831 ID id = rb_check_id(&key);
02832 if (!id) return Qnil;
02833 return rb_thread_local_aref(thread, id);
02834 }
02835
02836 static VALUE
02837 threadptr_local_aset(rb_thread_t *th, ID id, VALUE val)
02838 {
02839 if (NIL_P(val)) {
02840 if (!th->local_storage) return Qnil;
02841 st_delete_wrap(th->local_storage, id);
02842 return Qnil;
02843 }
02844 else {
02845 if (!th->local_storage) {
02846 th->local_storage = st_init_numtable();
02847 }
02848 st_insert(th->local_storage, id, val);
02849 return val;
02850 }
02851 }
02852
02853 VALUE
02854 rb_thread_local_aset(VALUE thread, ID id, VALUE val)
02855 {
02856 rb_thread_t *th;
02857 GetThreadPtr(thread, th);
02858
02859 if (OBJ_FROZEN(thread)) {
02860 rb_error_frozen("thread locals");
02861 }
02862
02863 return threadptr_local_aset(th, id, val);
02864 }
02865
02866
02867
02868
02869
02870
02871
02872
02873
02874
02875
02876
02877
02878
02879 static VALUE
02880 rb_thread_aset(VALUE self, VALUE id, VALUE val)
02881 {
02882 return rb_thread_local_aset(self, rb_to_id(id), val);
02883 }
02884
02885
02886
02887
02888
02889
02890
02891
02892
02893
02894
02895
02896
02897
02898
02899
02900
02901
02902
02903
02904
02905
02906
02907
02908
02909
02910
02911
02912
02913 static VALUE
02914 rb_thread_variable_get(VALUE thread, VALUE key)
02915 {
02916 VALUE locals;
02917 ID id = rb_check_id(&key);
02918
02919 if (!id) return Qnil;
02920 locals = rb_ivar_get(thread, id_locals);
02921 return rb_hash_aref(locals, ID2SYM(id));
02922 }
02923
02924
02925
02926
02927
02928
02929
02930
02931
02932
02933 static VALUE
02934 rb_thread_variable_set(VALUE thread, VALUE id, VALUE val)
02935 {
02936 VALUE locals;
02937
02938 if (OBJ_FROZEN(thread)) {
02939 rb_error_frozen("thread locals");
02940 }
02941
02942 locals = rb_ivar_get(thread, id_locals);
02943 return rb_hash_aset(locals, ID2SYM(rb_to_id(id)), val);
02944 }
02945
02946
02947
02948
02949
02950
02951
02952
02953
02954
02955
02956
02957
02958
02959 static VALUE
02960 rb_thread_key_p(VALUE self, VALUE key)
02961 {
02962 rb_thread_t *th;
02963 ID id = rb_check_id(&key);
02964
02965 GetThreadPtr(self, th);
02966
02967 if (!id || !th->local_storage) {
02968 return Qfalse;
02969 }
02970 if (st_lookup(th->local_storage, id, 0)) {
02971 return Qtrue;
02972 }
02973 return Qfalse;
02974 }
02975
02976 static int
02977 thread_keys_i(ID key, VALUE value, VALUE ary)
02978 {
02979 rb_ary_push(ary, ID2SYM(key));
02980 return ST_CONTINUE;
02981 }
02982
02983 static int
02984 vm_living_thread_num(rb_vm_t *vm)
02985 {
02986 return (int)vm->living_threads->num_entries;
02987 }
02988
02989 int
02990 rb_thread_alone(void)
02991 {
02992 int num = 1;
02993 if (GET_THREAD()->vm->living_threads) {
02994 num = vm_living_thread_num(GET_THREAD()->vm);
02995 thread_debug("rb_thread_alone: %d\n", num);
02996 }
02997 return num == 1;
02998 }
02999
03000
03001
03002
03003
03004
03005
03006
03007
03008
03009
03010
03011
03012
03013
03014 static VALUE
03015 rb_thread_keys(VALUE self)
03016 {
03017 rb_thread_t *th;
03018 VALUE ary = rb_ary_new();
03019 GetThreadPtr(self, th);
03020
03021 if (th->local_storage) {
03022 st_foreach(th->local_storage, thread_keys_i, ary);
03023 }
03024 return ary;
03025 }
03026
03027 static int
03028 keys_i(VALUE key, VALUE value, VALUE ary)
03029 {
03030 rb_ary_push(ary, key);
03031 return ST_CONTINUE;
03032 }
03033
03034
03035
03036
03037
03038
03039
03040
03041
03042
03043
03044
03045
03046
03047
03048
03049
03050
03051 static VALUE
03052 rb_thread_variables(VALUE thread)
03053 {
03054 VALUE locals;
03055 VALUE ary;
03056
03057 locals = rb_ivar_get(thread, id_locals);
03058 ary = rb_ary_new();
03059 rb_hash_foreach(locals, keys_i, ary);
03060
03061 return ary;
03062 }
03063
03064
03065
03066
03067
03068
03069
03070
03071
03072
03073
03074
03075
03076
03077
03078
03079
03080 static VALUE
03081 rb_thread_variable_p(VALUE thread, VALUE key)
03082 {
03083 VALUE locals;
03084 ID id = rb_check_id(&key);
03085
03086 if (!id) return Qfalse;
03087
03088 locals = rb_ivar_get(thread, id_locals);
03089
03090 if (!RHASH(locals)->ntbl)
03091 return Qfalse;
03092
03093 if (st_lookup(RHASH(locals)->ntbl, ID2SYM(id), 0)) {
03094 return Qtrue;
03095 }
03096
03097 return Qfalse;
03098 }
03099
03100
03101
03102
03103
03104
03105
03106
03107
03108
03109
03110
03111
03112
03113
03114
03115 static VALUE
03116 rb_thread_priority(VALUE thread)
03117 {
03118 rb_thread_t *th;
03119 GetThreadPtr(thread, th);
03120 return INT2NUM(th->priority);
03121 }
03122
03123
03124
03125
03126
03127
03128
03129
03130
03131
03132
03133
03134
03135
03136
03137
03138
03139
03140
03141
03142
03143
03144
03145
03146
03147
03148
03149
03150 static VALUE
03151 rb_thread_priority_set(VALUE thread, VALUE prio)
03152 {
03153 rb_thread_t *th;
03154 int priority;
03155 GetThreadPtr(thread, th);
03156
03157
03158 #if USE_NATIVE_THREAD_PRIORITY
03159 th->priority = NUM2INT(prio);
03160 native_thread_apply_priority(th);
03161 #else
03162 priority = NUM2INT(prio);
03163 if (priority > RUBY_THREAD_PRIORITY_MAX) {
03164 priority = RUBY_THREAD_PRIORITY_MAX;
03165 }
03166 else if (priority < RUBY_THREAD_PRIORITY_MIN) {
03167 priority = RUBY_THREAD_PRIORITY_MIN;
03168 }
03169 th->priority = priority;
03170 #endif
03171 return INT2NUM(th->priority);
03172 }
03173
03174
03175
03176 #if defined(NFDBITS) && defined(HAVE_RB_FD_INIT)
03177
03178
03179
03180
03181
03182
03183
03184
03185
03186
03187
03188
03189
03190
03191
03192
03193
03194
03195
03196
03197
03198
03199
03200
03201
03202
03203
03204
03205
03206
03207
03208
03209 void
03210 rb_fd_init(rb_fdset_t *fds)
03211 {
03212 fds->maxfd = 0;
03213 fds->fdset = ALLOC(fd_set);
03214 FD_ZERO(fds->fdset);
03215 }
03216
03217 void
03218 rb_fd_init_copy(rb_fdset_t *dst, rb_fdset_t *src)
03219 {
03220 size_t size = howmany(rb_fd_max(src), NFDBITS) * sizeof(fd_mask);
03221
03222 if (size < sizeof(fd_set))
03223 size = sizeof(fd_set);
03224 dst->maxfd = src->maxfd;
03225 dst->fdset = xmalloc(size);
03226 memcpy(dst->fdset, src->fdset, size);
03227 }
03228
03229 void
03230 rb_fd_term(rb_fdset_t *fds)
03231 {
03232 if (fds->fdset) xfree(fds->fdset);
03233 fds->maxfd = 0;
03234 fds->fdset = 0;
03235 }
03236
03237 void
03238 rb_fd_zero(rb_fdset_t *fds)
03239 {
03240 if (fds->fdset)
03241 MEMZERO(fds->fdset, fd_mask, howmany(fds->maxfd, NFDBITS));
03242 }
03243
03244 static void
03245 rb_fd_resize(int n, rb_fdset_t *fds)
03246 {
03247 size_t m = howmany(n + 1, NFDBITS) * sizeof(fd_mask);
03248 size_t o = howmany(fds->maxfd, NFDBITS) * sizeof(fd_mask);
03249
03250 if (m < sizeof(fd_set)) m = sizeof(fd_set);
03251 if (o < sizeof(fd_set)) o = sizeof(fd_set);
03252
03253 if (m > o) {
03254 fds->fdset = xrealloc(fds->fdset, m);
03255 memset((char *)fds->fdset + o, 0, m - o);
03256 }
03257 if (n >= fds->maxfd) fds->maxfd = n + 1;
03258 }
03259
03260 void
03261 rb_fd_set(int n, rb_fdset_t *fds)
03262 {
03263 rb_fd_resize(n, fds);
03264 FD_SET(n, fds->fdset);
03265 }
03266
03267 void
03268 rb_fd_clr(int n, rb_fdset_t *fds)
03269 {
03270 if (n >= fds->maxfd) return;
03271 FD_CLR(n, fds->fdset);
03272 }
03273
03274 int
03275 rb_fd_isset(int n, const rb_fdset_t *fds)
03276 {
03277 if (n >= fds->maxfd) return 0;
03278 return FD_ISSET(n, fds->fdset) != 0;
03279 }
03280
03281 void
03282 rb_fd_copy(rb_fdset_t *dst, const fd_set *src, int max)
03283 {
03284 size_t size = howmany(max, NFDBITS) * sizeof(fd_mask);
03285
03286 if (size < sizeof(fd_set)) size = sizeof(fd_set);
03287 dst->maxfd = max;
03288 dst->fdset = xrealloc(dst->fdset, size);
03289 memcpy(dst->fdset, src, size);
03290 }
03291
03292 static void
03293 rb_fd_rcopy(fd_set *dst, rb_fdset_t *src)
03294 {
03295 size_t size = howmany(rb_fd_max(src), NFDBITS) * sizeof(fd_mask);
03296
03297 if (size > sizeof(fd_set)) {
03298 rb_raise(rb_eArgError, "too large fdsets");
03299 }
03300 memcpy(dst, rb_fd_ptr(src), sizeof(fd_set));
03301 }
03302
03303 void
03304 rb_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src)
03305 {
03306 size_t size = howmany(rb_fd_max(src), NFDBITS) * sizeof(fd_mask);
03307
03308 if (size < sizeof(fd_set))
03309 size = sizeof(fd_set);
03310 dst->maxfd = src->maxfd;
03311 dst->fdset = xrealloc(dst->fdset, size);
03312 memcpy(dst->fdset, src->fdset, size);
03313 }
03314
03315 #ifdef __native_client__
03316 int select(int nfds, fd_set *readfds, fd_set *writefds,
03317 fd_set *exceptfds, struct timeval *timeout);
03318 #endif
03319
03320 int
03321 rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout)
03322 {
03323 fd_set *r = NULL, *w = NULL, *e = NULL;
03324 if (readfds) {
03325 rb_fd_resize(n - 1, readfds);
03326 r = rb_fd_ptr(readfds);
03327 }
03328 if (writefds) {
03329 rb_fd_resize(n - 1, writefds);
03330 w = rb_fd_ptr(writefds);
03331 }
03332 if (exceptfds) {
03333 rb_fd_resize(n - 1, exceptfds);
03334 e = rb_fd_ptr(exceptfds);
03335 }
03336 return select(n, r, w, e, timeout);
03337 }
03338
03339 #undef FD_ZERO
03340 #undef FD_SET
03341 #undef FD_CLR
03342 #undef FD_ISSET
03343
03344 #define FD_ZERO(f) rb_fd_zero(f)
03345 #define FD_SET(i, f) rb_fd_set((i), (f))
03346 #define FD_CLR(i, f) rb_fd_clr((i), (f))
03347 #define FD_ISSET(i, f) rb_fd_isset((i), (f))
03348
03349 #elif defined(_WIN32)
03350
03351 void
03352 rb_fd_init(rb_fdset_t *set)
03353 {
03354 set->capa = FD_SETSIZE;
03355 set->fdset = ALLOC(fd_set);
03356 FD_ZERO(set->fdset);
03357 }
03358
03359 void
03360 rb_fd_init_copy(rb_fdset_t *dst, rb_fdset_t *src)
03361 {
03362 rb_fd_init(dst);
03363 rb_fd_dup(dst, src);
03364 }
03365
03366 static void
03367 rb_fd_rcopy(fd_set *dst, rb_fdset_t *src)
03368 {
03369 int max = rb_fd_max(src);
03370
03371
03372
03373 if (max > FD_SETSIZE || (UINT)max > dst->fd_count) {
03374 rb_raise(rb_eArgError, "too large fdsets");
03375 }
03376
03377 memcpy(dst->fd_array, src->fdset->fd_array, max);
03378 dst->fd_count = max;
03379 }
03380
03381 void
03382 rb_fd_term(rb_fdset_t *set)
03383 {
03384 xfree(set->fdset);
03385 set->fdset = NULL;
03386 set->capa = 0;
03387 }
03388
03389 void
03390 rb_fd_set(int fd, rb_fdset_t *set)
03391 {
03392 unsigned int i;
03393 SOCKET s = rb_w32_get_osfhandle(fd);
03394
03395 for (i = 0; i < set->fdset->fd_count; i++) {
03396 if (set->fdset->fd_array[i] == s) {
03397 return;
03398 }
03399 }
03400 if (set->fdset->fd_count >= (unsigned)set->capa) {
03401 set->capa = (set->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
03402 set->fdset = xrealloc(set->fdset, sizeof(unsigned int) + sizeof(SOCKET) * set->capa);
03403 }
03404 set->fdset->fd_array[set->fdset->fd_count++] = s;
03405 }
03406
03407 #undef FD_ZERO
03408 #undef FD_SET
03409 #undef FD_CLR
03410 #undef FD_ISSET
03411
03412 #define FD_ZERO(f) rb_fd_zero(f)
03413 #define FD_SET(i, f) rb_fd_set((i), (f))
03414 #define FD_CLR(i, f) rb_fd_clr((i), (f))
03415 #define FD_ISSET(i, f) rb_fd_isset((i), (f))
03416
03417 #else
03418 #define rb_fd_rcopy(d, s) (*(d) = *(s))
03419 #endif
03420
03421 static int
03422 do_select(int n, rb_fdset_t *read, rb_fdset_t *write, rb_fdset_t *except,
03423 struct timeval *timeout)
03424 {
03425 int UNINITIALIZED_VAR(result);
03426 int lerrno;
03427 rb_fdset_t UNINITIALIZED_VAR(orig_read);
03428 rb_fdset_t UNINITIALIZED_VAR(orig_write);
03429 rb_fdset_t UNINITIALIZED_VAR(orig_except);
03430 double limit = 0;
03431 struct timeval wait_rest;
03432 rb_thread_t *th = GET_THREAD();
03433
03434 if (timeout) {
03435 limit = timeofday();
03436 limit += (double)timeout->tv_sec+(double)timeout->tv_usec*1e-6;
03437 wait_rest = *timeout;
03438 timeout = &wait_rest;
03439 }
03440
03441 if (read)
03442 rb_fd_init_copy(&orig_read, read);
03443 if (write)
03444 rb_fd_init_copy(&orig_write, write);
03445 if (except)
03446 rb_fd_init_copy(&orig_except, except);
03447
03448 retry:
03449 lerrno = 0;
03450
03451 BLOCKING_REGION({
03452 result = native_fd_select(n, read, write, except, timeout, th);
03453 if (result < 0) lerrno = errno;
03454 }, ubf_select, th, FALSE);
03455
03456 RUBY_VM_CHECK_INTS_BLOCKING(th);
03457
03458 errno = lerrno;
03459
03460 if (result < 0) {
03461 switch (errno) {
03462 case EINTR:
03463 #ifdef ERESTART
03464 case ERESTART:
03465 #endif
03466 if (read)
03467 rb_fd_dup(read, &orig_read);
03468 if (write)
03469 rb_fd_dup(write, &orig_write);
03470 if (except)
03471 rb_fd_dup(except, &orig_except);
03472
03473 if (timeout) {
03474 double d = limit - timeofday();
03475
03476 wait_rest.tv_sec = (time_t)d;
03477 wait_rest.tv_usec = (int)((d-(double)wait_rest.tv_sec)*1e6);
03478 if (wait_rest.tv_sec < 0) wait_rest.tv_sec = 0;
03479 if (wait_rest.tv_usec < 0) wait_rest.tv_usec = 0;
03480 }
03481
03482 goto retry;
03483 default:
03484 break;
03485 }
03486 }
03487
03488 if (read)
03489 rb_fd_term(&orig_read);
03490 if (write)
03491 rb_fd_term(&orig_write);
03492 if (except)
03493 rb_fd_term(&orig_except);
03494
03495 return result;
03496 }
03497
03498 static void
03499 rb_thread_wait_fd_rw(int fd, int read)
03500 {
03501 int result = 0;
03502 int events = read ? RB_WAITFD_IN : RB_WAITFD_OUT;
03503
03504 thread_debug("rb_thread_wait_fd_rw(%d, %s)\n", fd, read ? "read" : "write");
03505
03506 if (fd < 0) {
03507 rb_raise(rb_eIOError, "closed stream");
03508 }
03509
03510 result = rb_wait_for_single_fd(fd, events, NULL);
03511 if (result < 0) {
03512 rb_sys_fail(0);
03513 }
03514
03515 thread_debug("rb_thread_wait_fd_rw(%d, %s): done\n", fd, read ? "read" : "write");
03516 }
03517
03518 void
03519 rb_thread_wait_fd(int fd)
03520 {
03521 rb_thread_wait_fd_rw(fd, 1);
03522 }
03523
03524 int
03525 rb_thread_fd_writable(int fd)
03526 {
03527 rb_thread_wait_fd_rw(fd, 0);
03528 return TRUE;
03529 }
03530
03531 int
03532 rb_thread_select(int max, fd_set * read, fd_set * write, fd_set * except,
03533 struct timeval *timeout)
03534 {
03535 rb_fdset_t fdsets[3];
03536 rb_fdset_t *rfds = NULL;
03537 rb_fdset_t *wfds = NULL;
03538 rb_fdset_t *efds = NULL;
03539 int retval;
03540
03541 if (read) {
03542 rfds = &fdsets[0];
03543 rb_fd_init(rfds);
03544 rb_fd_copy(rfds, read, max);
03545 }
03546 if (write) {
03547 wfds = &fdsets[1];
03548 rb_fd_init(wfds);
03549 rb_fd_copy(wfds, write, max);
03550 }
03551 if (except) {
03552 efds = &fdsets[2];
03553 rb_fd_init(efds);
03554 rb_fd_copy(efds, except, max);
03555 }
03556
03557 retval = rb_thread_fd_select(max, rfds, wfds, efds, timeout);
03558
03559 if (rfds) {
03560 rb_fd_rcopy(read, rfds);
03561 rb_fd_term(rfds);
03562 }
03563 if (wfds) {
03564 rb_fd_rcopy(write, wfds);
03565 rb_fd_term(wfds);
03566 }
03567 if (efds) {
03568 rb_fd_rcopy(except, efds);
03569 rb_fd_term(efds);
03570 }
03571
03572 return retval;
03573 }
03574
03575 int
03576 rb_thread_fd_select(int max, rb_fdset_t * read, rb_fdset_t * write, rb_fdset_t * except,
03577 struct timeval *timeout)
03578 {
03579 if (!read && !write && !except) {
03580 if (!timeout) {
03581 rb_thread_sleep_forever();
03582 return 0;
03583 }
03584 rb_thread_wait_for(*timeout);
03585 return 0;
03586 }
03587
03588 if (read) {
03589 rb_fd_resize(max - 1, read);
03590 }
03591 if (write) {
03592 rb_fd_resize(max - 1, write);
03593 }
03594 if (except) {
03595 rb_fd_resize(max - 1, except);
03596 }
03597 return do_select(max, read, write, except, timeout);
03598 }
03599
03600
03601
03602
03603
03604
03605 #if defined(HAVE_POLL) && defined(__linux__)
03606 # define USE_POLL
03607 #endif
03608
03609 #ifdef USE_POLL
03610
03611
03612 #define POLLIN_SET (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP | POLLERR)
03613 #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
03614 #define POLLEX_SET (POLLPRI)
03615
03616 #ifndef HAVE_PPOLL
03617
03618 int
03619 ppoll(struct pollfd *fds, nfds_t nfds,
03620 const struct timespec *ts, const sigset_t *sigmask)
03621 {
03622 int timeout_ms;
03623
03624 if (ts) {
03625 int tmp, tmp2;
03626
03627 if (ts->tv_sec > TIMET_MAX/1000)
03628 timeout_ms = -1;
03629 else {
03630 tmp = ts->tv_sec * 1000;
03631 tmp2 = ts->tv_nsec / (1000 * 1000);
03632 if (TIMET_MAX - tmp < tmp2)
03633 timeout_ms = -1;
03634 else
03635 timeout_ms = tmp + tmp2;
03636 }
03637 }
03638 else
03639 timeout_ms = -1;
03640
03641 return poll(fds, nfds, timeout_ms);
03642 }
03643 #endif
03644
03645
03646
03647
03648 int
03649 rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
03650 {
03651 struct pollfd fds;
03652 int result = 0, lerrno;
03653 double limit = 0;
03654 struct timespec ts;
03655 struct timespec *timeout = NULL;
03656 rb_thread_t *th = GET_THREAD();
03657
03658 if (tv) {
03659 ts.tv_sec = tv->tv_sec;
03660 ts.tv_nsec = tv->tv_usec * 1000;
03661 limit = timeofday();
03662 limit += (double)tv->tv_sec + (double)tv->tv_usec * 1e-6;
03663 timeout = &ts;
03664 }
03665
03666 fds.fd = fd;
03667 fds.events = (short)events;
03668
03669 retry:
03670 lerrno = 0;
03671 BLOCKING_REGION({
03672 result = ppoll(&fds, 1, timeout, NULL);
03673 if (result < 0) lerrno = errno;
03674 }, ubf_select, th, FALSE);
03675
03676 RUBY_VM_CHECK_INTS_BLOCKING(th);
03677
03678 if (result < 0) {
03679 errno = lerrno;
03680 switch (errno) {
03681 case EINTR:
03682 #ifdef ERESTART
03683 case ERESTART:
03684 #endif
03685 if (timeout) {
03686 double d = limit - timeofday();
03687
03688 ts.tv_sec = (long)d;
03689 ts.tv_nsec = (long)((d - (double)ts.tv_sec) * 1e9);
03690 if (ts.tv_sec < 0)
03691 ts.tv_sec = 0;
03692 if (ts.tv_nsec < 0)
03693 ts.tv_nsec = 0;
03694 }
03695 goto retry;
03696 }
03697 return -1;
03698 }
03699
03700 if (fds.revents & POLLNVAL) {
03701 errno = EBADF;
03702 return -1;
03703 }
03704
03705
03706
03707
03708
03709 result = 0;
03710 if (fds.revents & POLLIN_SET)
03711 result |= RB_WAITFD_IN;
03712 if (fds.revents & POLLOUT_SET)
03713 result |= RB_WAITFD_OUT;
03714 if (fds.revents & POLLEX_SET)
03715 result |= RB_WAITFD_PRI;
03716
03717 return result;
03718 }
03719 #else
03720 static rb_fdset_t *
03721 init_set_fd(int fd, rb_fdset_t *fds)
03722 {
03723 rb_fd_init(fds);
03724 rb_fd_set(fd, fds);
03725
03726 return fds;
03727 }
03728
03729 struct select_args {
03730 union {
03731 int fd;
03732 int error;
03733 } as;
03734 rb_fdset_t *read;
03735 rb_fdset_t *write;
03736 rb_fdset_t *except;
03737 struct timeval *tv;
03738 };
03739
03740 static VALUE
03741 select_single(VALUE ptr)
03742 {
03743 struct select_args *args = (struct select_args *)ptr;
03744 int r;
03745
03746 r = rb_thread_fd_select(args->as.fd + 1,
03747 args->read, args->write, args->except, args->tv);
03748 if (r == -1)
03749 args->as.error = errno;
03750 if (r > 0) {
03751 r = 0;
03752 if (args->read && rb_fd_isset(args->as.fd, args->read))
03753 r |= RB_WAITFD_IN;
03754 if (args->write && rb_fd_isset(args->as.fd, args->write))
03755 r |= RB_WAITFD_OUT;
03756 if (args->except && rb_fd_isset(args->as.fd, args->except))
03757 r |= RB_WAITFD_PRI;
03758 }
03759 return (VALUE)r;
03760 }
03761
03762 static VALUE
03763 select_single_cleanup(VALUE ptr)
03764 {
03765 struct select_args *args = (struct select_args *)ptr;
03766
03767 if (args->read) rb_fd_term(args->read);
03768 if (args->write) rb_fd_term(args->write);
03769 if (args->except) rb_fd_term(args->except);
03770
03771 return (VALUE)-1;
03772 }
03773
03774 int
03775 rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
03776 {
03777 rb_fdset_t rfds, wfds, efds;
03778 struct select_args args;
03779 int r;
03780 VALUE ptr = (VALUE)&args;
03781
03782 args.as.fd = fd;
03783 args.read = (events & RB_WAITFD_IN) ? init_set_fd(fd, &rfds) : NULL;
03784 args.write = (events & RB_WAITFD_OUT) ? init_set_fd(fd, &wfds) : NULL;
03785 args.except = (events & RB_WAITFD_PRI) ? init_set_fd(fd, &efds) : NULL;
03786 args.tv = tv;
03787
03788 r = (int)rb_ensure(select_single, ptr, select_single_cleanup, ptr);
03789 if (r == -1)
03790 errno = args.as.error;
03791
03792 return r;
03793 }
03794 #endif
03795
03796
03797
03798
03799
03800 #ifdef USE_CONSERVATIVE_STACK_END
03801 void
03802 rb_gc_set_stack_end(VALUE **stack_end_p)
03803 {
03804 VALUE stack_end;
03805 *stack_end_p = &stack_end;
03806 }
03807 #endif
03808
03809
03810
03811
03812
03813
03814 void
03815 rb_threadptr_check_signal(rb_thread_t *mth)
03816 {
03817
03818 if (rb_signal_buff_size() > 0) {
03819
03820 rb_threadptr_trap_interrupt(mth);
03821 }
03822 }
03823
03824 static void
03825 timer_thread_function(void *arg)
03826 {
03827 rb_vm_t *vm = GET_VM();
03828
03829
03830
03831
03832
03833
03834 native_mutex_lock(&vm->thread_destruct_lock);
03835
03836 if (vm->running_thread)
03837 RUBY_VM_SET_TIMER_INTERRUPT(vm->running_thread);
03838 native_mutex_unlock(&vm->thread_destruct_lock);
03839
03840
03841 rb_threadptr_check_signal(vm->main_thread);
03842
03843 #if 0
03844
03845 if (vm->prove_profile.enable) {
03846 rb_thread_t *th = vm->running_thread;
03847
03848 if (vm->during_gc) {
03849
03850 }
03851 }
03852 #endif
03853 }
03854
03855 void
03856 rb_thread_stop_timer_thread(int close_anyway)
03857 {
03858 if (timer_thread_id && native_stop_timer_thread(close_anyway)) {
03859 native_reset_timer_thread();
03860 }
03861 }
03862
03863 void
03864 rb_thread_reset_timer_thread(void)
03865 {
03866 native_reset_timer_thread();
03867 }
03868
03869 void
03870 rb_thread_start_timer_thread(void)
03871 {
03872 system_working = 1;
03873 rb_thread_create_timer_thread();
03874 }
03875
03876 static int
03877 clear_coverage_i(st_data_t key, st_data_t val, st_data_t dummy)
03878 {
03879 int i;
03880 VALUE lines = (VALUE)val;
03881
03882 for (i = 0; i < RARRAY_LEN(lines); i++) {
03883 if (RARRAY_AREF(lines, i) != Qnil) {
03884 RARRAY_ASET(lines, i, INT2FIX(0));
03885 }
03886 }
03887 return ST_CONTINUE;
03888 }
03889
03890 static void
03891 clear_coverage(void)
03892 {
03893 VALUE coverages = rb_get_coverages();
03894 if (RTEST(coverages)) {
03895 st_foreach(rb_hash_tbl_raw(coverages), clear_coverage_i, 0);
03896 }
03897 }
03898
03899 static void
03900 rb_thread_atfork_internal(int (*atfork)(st_data_t, st_data_t, st_data_t))
03901 {
03902 rb_thread_t *th = GET_THREAD();
03903 rb_vm_t *vm = th->vm;
03904 VALUE thval = th->self;
03905 vm->main_thread = th;
03906
03907 gvl_atfork(th->vm);
03908 st_foreach(vm->living_threads, atfork, (st_data_t)th);
03909 st_clear(vm->living_threads);
03910 st_insert(vm->living_threads, thval, (st_data_t)th->thread_id);
03911 vm->sleeper = 0;
03912 clear_coverage();
03913 }
03914
03915 static int
03916 terminate_atfork_i(st_data_t key, st_data_t val, st_data_t current_th)
03917 {
03918 VALUE thval = key;
03919 rb_thread_t *th;
03920 GetThreadPtr(thval, th);
03921
03922 if (th != (rb_thread_t *)current_th) {
03923 rb_mutex_abandon_keeping_mutexes(th);
03924 rb_mutex_abandon_locking_mutex(th);
03925 thread_cleanup_func(th, TRUE);
03926 }
03927 return ST_CONTINUE;
03928 }
03929
03930 void
03931 rb_thread_atfork(void)
03932 {
03933 rb_thread_atfork_internal(terminate_atfork_i);
03934 GET_THREAD()->join_list = NULL;
03935
03936
03937 rb_reset_random_seed();
03938 }
03939
03940 static int
03941 terminate_atfork_before_exec_i(st_data_t key, st_data_t val, st_data_t current_th)
03942 {
03943 VALUE thval = key;
03944 rb_thread_t *th;
03945 GetThreadPtr(thval, th);
03946
03947 if (th != (rb_thread_t *)current_th) {
03948 thread_cleanup_func_before_exec(th);
03949 }
03950 return ST_CONTINUE;
03951 }
03952
03953 void
03954 rb_thread_atfork_before_exec(void)
03955 {
03956 rb_thread_atfork_internal(terminate_atfork_before_exec_i);
03957 }
03958
03959 struct thgroup {
03960 int enclosed;
03961 VALUE group;
03962 };
03963
03964 static size_t
03965 thgroup_memsize(const void *ptr)
03966 {
03967 return ptr ? sizeof(struct thgroup) : 0;
03968 }
03969
03970 static const rb_data_type_t thgroup_data_type = {
03971 "thgroup",
03972 {NULL, RUBY_TYPED_DEFAULT_FREE, thgroup_memsize,},
03973 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
03974 };
03975
03976
03977
03978
03979
03980
03981
03982
03983
03984
03985
03986
03987
03988
03989
03990
03991
03992
03993
03994
03995 static VALUE
03996 thgroup_s_alloc(VALUE klass)
03997 {
03998 VALUE group;
03999 struct thgroup *data;
04000
04001 group = TypedData_Make_Struct(klass, struct thgroup, &thgroup_data_type, data);
04002 data->enclosed = 0;
04003 data->group = group;
04004
04005 return group;
04006 }
04007
04008 struct thgroup_list_params {
04009 VALUE ary;
04010 VALUE group;
04011 };
04012
04013 static int
04014 thgroup_list_i(st_data_t key, st_data_t val, st_data_t data)
04015 {
04016 VALUE thread = (VALUE)key;
04017 VALUE ary = ((struct thgroup_list_params *)data)->ary;
04018 VALUE group = ((struct thgroup_list_params *)data)->group;
04019 rb_thread_t *th;
04020 GetThreadPtr(thread, th);
04021
04022 if (th->thgroup == group) {
04023 rb_ary_push(ary, thread);
04024 }
04025 return ST_CONTINUE;
04026 }
04027
04028
04029
04030
04031
04032
04033
04034
04035
04036
04037 static VALUE
04038 thgroup_list(VALUE group)
04039 {
04040 VALUE ary = rb_ary_new();
04041 struct thgroup_list_params param;
04042
04043 param.ary = ary;
04044 param.group = group;
04045 st_foreach(GET_THREAD()->vm->living_threads, thgroup_list_i, (st_data_t) & param);
04046 return ary;
04047 }
04048
04049
04050
04051
04052
04053
04054
04055
04056
04057
04058
04059
04060
04061
04062
04063
04064
04065
04066 static VALUE
04067 thgroup_enclose(VALUE group)
04068 {
04069 struct thgroup *data;
04070
04071 TypedData_Get_Struct(group, struct thgroup, &thgroup_data_type, data);
04072 data->enclosed = 1;
04073
04074 return group;
04075 }
04076
04077
04078
04079
04080
04081
04082
04083
04084
04085 static VALUE
04086 thgroup_enclosed_p(VALUE group)
04087 {
04088 struct thgroup *data;
04089
04090 TypedData_Get_Struct(group, struct thgroup, &thgroup_data_type, data);
04091 if (data->enclosed)
04092 return Qtrue;
04093 return Qfalse;
04094 }
04095
04096
04097
04098
04099
04100
04101
04102
04103
04104
04105
04106
04107
04108
04109
04110
04111
04112
04113
04114
04115
04116
04117
04118
04119
04120
04121
04122
04123 static VALUE
04124 thgroup_add(VALUE group, VALUE thread)
04125 {
04126 rb_thread_t *th;
04127 struct thgroup *data;
04128
04129 GetThreadPtr(thread, th);
04130
04131 if (OBJ_FROZEN(group)) {
04132 rb_raise(rb_eThreadError, "can't move to the frozen thread group");
04133 }
04134 TypedData_Get_Struct(group, struct thgroup, &thgroup_data_type, data);
04135 if (data->enclosed) {
04136 rb_raise(rb_eThreadError, "can't move to the enclosed thread group");
04137 }
04138
04139 if (!th->thgroup) {
04140 return Qnil;
04141 }
04142
04143 if (OBJ_FROZEN(th->thgroup)) {
04144 rb_raise(rb_eThreadError, "can't move from the frozen thread group");
04145 }
04146 TypedData_Get_Struct(th->thgroup, struct thgroup, &thgroup_data_type, data);
04147 if (data->enclosed) {
04148 rb_raise(rb_eThreadError,
04149 "can't move from the enclosed thread group");
04150 }
04151
04152 th->thgroup = group;
04153 return group;
04154 }
04155
04156
04157
04158
04159
04160
04161
04162
04163
04164
04165
04166
04167
04168
04169
04170
04171
04172
04173
04174
04175
04176
04177
04178
04179
04180
04181
04182 #define GetMutexPtr(obj, tobj) \
04183 TypedData_Get_Struct((obj), rb_mutex_t, &mutex_data_type, (tobj))
04184
04185 #define mutex_mark NULL
04186
04187 static void
04188 mutex_free(void *ptr)
04189 {
04190 if (ptr) {
04191 rb_mutex_t *mutex = ptr;
04192 if (mutex->th) {
04193
04194 const char *err = rb_mutex_unlock_th(mutex, mutex->th);
04195 if (err) rb_bug("%s", err);
04196 }
04197 native_mutex_destroy(&mutex->lock);
04198 native_cond_destroy(&mutex->cond);
04199 }
04200 ruby_xfree(ptr);
04201 }
04202
04203 static size_t
04204 mutex_memsize(const void *ptr)
04205 {
04206 return ptr ? sizeof(rb_mutex_t) : 0;
04207 }
04208
04209 static const rb_data_type_t mutex_data_type = {
04210 "mutex",
04211 {mutex_mark, mutex_free, mutex_memsize,},
04212 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
04213 };
04214
04215 VALUE
04216 rb_obj_is_mutex(VALUE obj)
04217 {
04218 if (rb_typeddata_is_kind_of(obj, &mutex_data_type)) {
04219 return Qtrue;
04220 }
04221 else {
04222 return Qfalse;
04223 }
04224 }
04225
04226 static VALUE
04227 mutex_alloc(VALUE klass)
04228 {
04229 VALUE volatile obj;
04230 rb_mutex_t *mutex;
04231
04232 obj = TypedData_Make_Struct(klass, rb_mutex_t, &mutex_data_type, mutex);
04233 native_mutex_initialize(&mutex->lock);
04234 native_cond_initialize(&mutex->cond, RB_CONDATTR_CLOCK_MONOTONIC);
04235 return obj;
04236 }
04237
04238
04239
04240
04241
04242
04243
04244 static VALUE
04245 mutex_initialize(VALUE self)
04246 {
04247 return self;
04248 }
04249
04250 VALUE
04251 rb_mutex_new(void)
04252 {
04253 return mutex_alloc(rb_cMutex);
04254 }
04255
04256
04257
04258
04259
04260
04261
04262 VALUE
04263 rb_mutex_locked_p(VALUE self)
04264 {
04265 rb_mutex_t *mutex;
04266 GetMutexPtr(self, mutex);
04267 return mutex->th ? Qtrue : Qfalse;
04268 }
04269
04270 static void
04271 mutex_locked(rb_thread_t *th, VALUE self)
04272 {
04273 rb_mutex_t *mutex;
04274 GetMutexPtr(self, mutex);
04275
04276 if (th->keeping_mutexes) {
04277 mutex->next_mutex = th->keeping_mutexes;
04278 }
04279 th->keeping_mutexes = mutex;
04280 }
04281
04282
04283
04284
04285
04286
04287
04288
04289 VALUE
04290 rb_mutex_trylock(VALUE self)
04291 {
04292 rb_mutex_t *mutex;
04293 VALUE locked = Qfalse;
04294 GetMutexPtr(self, mutex);
04295
04296 native_mutex_lock(&mutex->lock);
04297 if (mutex->th == 0) {
04298 mutex->th = GET_THREAD();
04299 locked = Qtrue;
04300
04301 mutex_locked(GET_THREAD(), self);
04302 }
04303 native_mutex_unlock(&mutex->lock);
04304
04305 return locked;
04306 }
04307
04308 static int
04309 lock_func(rb_thread_t *th, rb_mutex_t *mutex, int timeout_ms)
04310 {
04311 int interrupted = 0;
04312 int err = 0;
04313
04314 mutex->cond_waiting++;
04315 for (;;) {
04316 if (!mutex->th) {
04317 mutex->th = th;
04318 break;
04319 }
04320 if (RUBY_VM_INTERRUPTED(th)) {
04321 interrupted = 1;
04322 break;
04323 }
04324 if (err == ETIMEDOUT) {
04325 interrupted = 2;
04326 break;
04327 }
04328
04329 if (timeout_ms) {
04330 struct timespec timeout_rel;
04331 struct timespec timeout;
04332
04333 timeout_rel.tv_sec = 0;
04334 timeout_rel.tv_nsec = timeout_ms * 1000 * 1000;
04335 timeout = native_cond_timeout(&mutex->cond, timeout_rel);
04336 err = native_cond_timedwait(&mutex->cond, &mutex->lock, &timeout);
04337 }
04338 else {
04339 native_cond_wait(&mutex->cond, &mutex->lock);
04340 err = 0;
04341 }
04342 }
04343 mutex->cond_waiting--;
04344
04345 return interrupted;
04346 }
04347
04348 static void
04349 lock_interrupt(void *ptr)
04350 {
04351 rb_mutex_t *mutex = (rb_mutex_t *)ptr;
04352 native_mutex_lock(&mutex->lock);
04353 if (mutex->cond_waiting > 0)
04354 native_cond_broadcast(&mutex->cond);
04355 native_mutex_unlock(&mutex->lock);
04356 }
04357
04358
04359
04360
04361
04362
04363 static const rb_thread_t *patrol_thread = NULL;
04364
04365
04366
04367
04368
04369
04370
04371
04372 VALUE
04373 rb_mutex_lock(VALUE self)
04374 {
04375 rb_thread_t *th = GET_THREAD();
04376 rb_mutex_t *mutex;
04377 GetMutexPtr(self, mutex);
04378
04379
04380 if (!mutex->allow_trap && th->interrupt_mask & TRAP_INTERRUPT_MASK) {
04381 rb_raise(rb_eThreadError, "can't be called from trap context");
04382 }
04383
04384 if (rb_mutex_trylock(self) == Qfalse) {
04385 if (mutex->th == GET_THREAD()) {
04386 rb_raise(rb_eThreadError, "deadlock; recursive locking");
04387 }
04388
04389 while (mutex->th != th) {
04390 int interrupted;
04391 enum rb_thread_status prev_status = th->status;
04392 volatile int timeout_ms = 0;
04393 struct rb_unblock_callback oldubf;
04394
04395 set_unblock_function(th, lock_interrupt, mutex, &oldubf, FALSE);
04396 th->status = THREAD_STOPPED_FOREVER;
04397 th->locking_mutex = self;
04398
04399 native_mutex_lock(&mutex->lock);
04400 th->vm->sleeper++;
04401
04402
04403
04404
04405
04406 if ((vm_living_thread_num(th->vm) == th->vm->sleeper) &&
04407 !patrol_thread) {
04408 timeout_ms = 100;
04409 patrol_thread = th;
04410 }
04411
04412 GVL_UNLOCK_BEGIN();
04413 interrupted = lock_func(th, mutex, (int)timeout_ms);
04414 native_mutex_unlock(&mutex->lock);
04415 GVL_UNLOCK_END();
04416
04417 if (patrol_thread == th)
04418 patrol_thread = NULL;
04419
04420 reset_unblock_function(th, &oldubf);
04421
04422 th->locking_mutex = Qfalse;
04423 if (mutex->th && interrupted == 2) {
04424 rb_check_deadlock(th->vm);
04425 }
04426 if (th->status == THREAD_STOPPED_FOREVER) {
04427 th->status = prev_status;
04428 }
04429 th->vm->sleeper--;
04430
04431 if (mutex->th == th) mutex_locked(th, self);
04432
04433 if (interrupted) {
04434 RUBY_VM_CHECK_INTS_BLOCKING(th);
04435 }
04436 }
04437 }
04438 return self;
04439 }
04440
04441
04442
04443
04444
04445
04446
04447
04448 VALUE
04449 rb_mutex_owned_p(VALUE self)
04450 {
04451 VALUE owned = Qfalse;
04452 rb_thread_t *th = GET_THREAD();
04453 rb_mutex_t *mutex;
04454
04455 GetMutexPtr(self, mutex);
04456
04457 if (mutex->th == th)
04458 owned = Qtrue;
04459
04460 return owned;
04461 }
04462
04463 static const char *
04464 rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t volatile *th)
04465 {
04466 const char *err = NULL;
04467
04468 native_mutex_lock(&mutex->lock);
04469
04470 if (mutex->th == 0) {
04471 err = "Attempt to unlock a mutex which is not locked";
04472 }
04473 else if (mutex->th != th) {
04474 err = "Attempt to unlock a mutex which is locked by another thread";
04475 }
04476 else {
04477 mutex->th = 0;
04478 if (mutex->cond_waiting > 0)
04479 native_cond_signal(&mutex->cond);
04480 }
04481
04482 native_mutex_unlock(&mutex->lock);
04483
04484 if (!err) {
04485 rb_mutex_t *volatile *th_mutex = &th->keeping_mutexes;
04486 while (*th_mutex != mutex) {
04487 th_mutex = &(*th_mutex)->next_mutex;
04488 }
04489 *th_mutex = mutex->next_mutex;
04490 mutex->next_mutex = NULL;
04491 }
04492
04493 return err;
04494 }
04495
04496
04497
04498
04499
04500
04501
04502
04503 VALUE
04504 rb_mutex_unlock(VALUE self)
04505 {
04506 const char *err;
04507 rb_mutex_t *mutex;
04508 GetMutexPtr(self, mutex);
04509
04510 err = rb_mutex_unlock_th(mutex, GET_THREAD());
04511 if (err) rb_raise(rb_eThreadError, "%s", err);
04512
04513 return self;
04514 }
04515
04516 static void
04517 rb_mutex_abandon_keeping_mutexes(rb_thread_t *th)
04518 {
04519 if (th->keeping_mutexes) {
04520 rb_mutex_abandon_all(th->keeping_mutexes);
04521 }
04522 th->keeping_mutexes = NULL;
04523 }
04524
04525 static void
04526 rb_mutex_abandon_locking_mutex(rb_thread_t *th)
04527 {
04528 rb_mutex_t *mutex;
04529
04530 if (!th->locking_mutex) return;
04531
04532 GetMutexPtr(th->locking_mutex, mutex);
04533 if (mutex->th == th)
04534 rb_mutex_abandon_all(mutex);
04535 th->locking_mutex = Qfalse;
04536 }
04537
04538 static void
04539 rb_mutex_abandon_all(rb_mutex_t *mutexes)
04540 {
04541 rb_mutex_t *mutex;
04542
04543 while (mutexes) {
04544 mutex = mutexes;
04545 mutexes = mutex->next_mutex;
04546 mutex->th = 0;
04547 mutex->next_mutex = 0;
04548 }
04549 }
04550
04551 static VALUE
04552 rb_mutex_sleep_forever(VALUE time)
04553 {
04554 sleep_forever(GET_THREAD(), 1, 0);
04555 return Qnil;
04556 }
04557
04558 static VALUE
04559 rb_mutex_wait_for(VALUE time)
04560 {
04561 struct timeval *t = (struct timeval *)time;
04562 sleep_timeval(GET_THREAD(), *t, 0);
04563 return Qnil;
04564 }
04565
04566 VALUE
04567 rb_mutex_sleep(VALUE self, VALUE timeout)
04568 {
04569 time_t beg, end;
04570 struct timeval t;
04571
04572 if (!NIL_P(timeout)) {
04573 t = rb_time_interval(timeout);
04574 }
04575 rb_mutex_unlock(self);
04576 beg = time(0);
04577 if (NIL_P(timeout)) {
04578 rb_ensure(rb_mutex_sleep_forever, Qnil, rb_mutex_lock, self);
04579 }
04580 else {
04581 rb_ensure(rb_mutex_wait_for, (VALUE)&t, rb_mutex_lock, self);
04582 }
04583 end = time(0) - beg;
04584 return INT2FIX(end);
04585 }
04586
04587
04588
04589
04590
04591
04592
04593
04594
04595
04596
04597
04598
04599
04600
04601 static VALUE
04602 mutex_sleep(int argc, VALUE *argv, VALUE self)
04603 {
04604 VALUE timeout;
04605
04606 rb_scan_args(argc, argv, "01", &timeout);
04607 return rb_mutex_sleep(self, timeout);
04608 }
04609
04610
04611
04612
04613
04614
04615
04616
04617
04618 VALUE
04619 rb_mutex_synchronize(VALUE mutex, VALUE (*func)(VALUE arg), VALUE arg)
04620 {
04621 rb_mutex_lock(mutex);
04622 return rb_ensure(func, arg, rb_mutex_unlock, mutex);
04623 }
04624
04625
04626
04627
04628
04629
04630
04631
04632 static VALUE
04633 rb_mutex_synchronize_m(VALUE self, VALUE args)
04634 {
04635 if (!rb_block_given_p()) {
04636 rb_raise(rb_eThreadError, "must be called with a block");
04637 }
04638
04639 return rb_mutex_synchronize(self, rb_yield, Qundef);
04640 }
04641
04642 void rb_mutex_allow_trap(VALUE self, int val)
04643 {
04644 rb_mutex_t *m;
04645 GetMutexPtr(self, m);
04646
04647 m->allow_trap = val;
04648 }
04649
04650
04651
04652
04653 static void
04654 thread_shield_mark(void *ptr)
04655 {
04656 rb_gc_mark((VALUE)ptr);
04657 }
04658
04659 static const rb_data_type_t thread_shield_data_type = {
04660 "thread_shield",
04661 {thread_shield_mark, 0, 0,},
04662 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
04663 };
04664
04665 static VALUE
04666 thread_shield_alloc(VALUE klass)
04667 {
04668 return TypedData_Wrap_Struct(klass, &thread_shield_data_type, (void *)mutex_alloc(0));
04669 }
04670
04671 #define GetThreadShieldPtr(obj) ((VALUE)rb_check_typeddata((obj), &thread_shield_data_type))
04672 #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)
04673 #define THREAD_SHIELD_WAITING_SHIFT (FL_USHIFT)
04674 #define rb_thread_shield_waiting(b) (int)((RBASIC(b)->flags&THREAD_SHIELD_WAITING_MASK)>>THREAD_SHIELD_WAITING_SHIFT)
04675
04676 static inline void
04677 rb_thread_shield_waiting_inc(VALUE b)
04678 {
04679 unsigned int w = rb_thread_shield_waiting(b);
04680 w++;
04681 if (w > (unsigned int)(THREAD_SHIELD_WAITING_MASK>>THREAD_SHIELD_WAITING_SHIFT))
04682 rb_raise(rb_eRuntimeError, "waiting count overflow");
04683 RBASIC(b)->flags &= ~THREAD_SHIELD_WAITING_MASK;
04684 RBASIC(b)->flags |= ((VALUE)w << THREAD_SHIELD_WAITING_SHIFT);
04685 }
04686
04687 static inline void
04688 rb_thread_shield_waiting_dec(VALUE b)
04689 {
04690 unsigned int w = rb_thread_shield_waiting(b);
04691 if (!w) rb_raise(rb_eRuntimeError, "waiting count underflow");
04692 w--;
04693 RBASIC(b)->flags &= ~THREAD_SHIELD_WAITING_MASK;
04694 RBASIC(b)->flags |= ((VALUE)w << THREAD_SHIELD_WAITING_SHIFT);
04695 }
04696
04697 VALUE
04698 rb_thread_shield_new(void)
04699 {
04700 VALUE thread_shield = thread_shield_alloc(rb_cThreadShield);
04701 rb_mutex_lock((VALUE)DATA_PTR(thread_shield));
04702 return thread_shield;
04703 }
04704
04705
04706
04707
04708
04709
04710
04711
04712
04713 VALUE
04714 rb_thread_shield_wait(VALUE self)
04715 {
04716 VALUE mutex = GetThreadShieldPtr(self);
04717 rb_mutex_t *m;
04718
04719 if (!mutex) return Qfalse;
04720 GetMutexPtr(mutex, m);
04721 if (m->th == GET_THREAD()) return Qnil;
04722 rb_thread_shield_waiting_inc(self);
04723 rb_mutex_lock(mutex);
04724 rb_thread_shield_waiting_dec(self);
04725 if (DATA_PTR(self)) return Qtrue;
04726 rb_mutex_unlock(mutex);
04727 return rb_thread_shield_waiting(self) > 0 ? Qnil : Qfalse;
04728 }
04729
04730
04731
04732
04733 VALUE
04734 rb_thread_shield_release(VALUE self)
04735 {
04736 VALUE mutex = GetThreadShieldPtr(self);
04737 rb_mutex_unlock(mutex);
04738 return rb_thread_shield_waiting(self) > 0 ? Qtrue : Qfalse;
04739 }
04740
04741
04742
04743
04744 VALUE
04745 rb_thread_shield_destroy(VALUE self)
04746 {
04747 VALUE mutex = GetThreadShieldPtr(self);
04748 DATA_PTR(self) = 0;
04749 rb_mutex_unlock(mutex);
04750 return rb_thread_shield_waiting(self) > 0 ? Qtrue : Qfalse;
04751 }
04752
04753
04754 static ID recursive_key;
04755
04756 extern const struct st_hash_type st_hashtype_num;
04757
04758 static VALUE
04759 ident_hash_new(void)
04760 {
04761 VALUE hash = rb_hash_new();
04762 rb_hash_tbl_raw(hash)->type = &st_hashtype_num;
04763 return hash;
04764 }
04765
04766
04767
04768
04769
04770
04771
04772 static VALUE
04773 recursive_list_access(void)
04774 {
04775 volatile VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
04776 VALUE sym = ID2SYM(rb_frame_this_func());
04777 VALUE list;
04778 if (NIL_P(hash) || !RB_TYPE_P(hash, T_HASH)) {
04779 hash = ident_hash_new();
04780 rb_thread_local_aset(rb_thread_current(), recursive_key, hash);
04781 list = Qnil;
04782 }
04783 else {
04784 list = rb_hash_aref(hash, sym);
04785 }
04786 if (NIL_P(list) || !RB_TYPE_P(list, T_HASH)) {
04787 list = ident_hash_new();
04788 rb_hash_aset(hash, sym, list);
04789 }
04790 return list;
04791 }
04792
04793 VALUE
04794 rb_threadptr_reset_recursive_data(rb_thread_t *th)
04795 {
04796 VALUE old = threadptr_local_aref(th, recursive_key);
04797 threadptr_local_aset(th, recursive_key, Qnil);
04798 return old;
04799 }
04800
04801 void
04802 rb_threadptr_restore_recursive_data(rb_thread_t *th, VALUE old)
04803 {
04804 threadptr_local_aset(th, recursive_key, old);
04805 }
04806
04807
04808
04809
04810
04811
04812
04813 static VALUE
04814 recursive_check(VALUE list, VALUE obj_id, VALUE paired_obj_id)
04815 {
04816 #if SIZEOF_LONG == SIZEOF_VOIDP
04817 #define OBJ_ID_EQL(obj_id, other) ((obj_id) == (other))
04818 #elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
04819 #define OBJ_ID_EQL(obj_id, other) (RB_TYPE_P((obj_id), T_BIGNUM) ? \
04820 rb_big_eql((obj_id), (other)) : ((obj_id) == (other)))
04821 #endif
04822
04823 VALUE pair_list = rb_hash_lookup2(list, obj_id, Qundef);
04824 if (pair_list == Qundef)
04825 return Qfalse;
04826 if (paired_obj_id) {
04827 if (!RB_TYPE_P(pair_list, T_HASH)) {
04828 if (!OBJ_ID_EQL(paired_obj_id, pair_list))
04829 return Qfalse;
04830 }
04831 else {
04832 if (NIL_P(rb_hash_lookup(pair_list, paired_obj_id)))
04833 return Qfalse;
04834 }
04835 }
04836 return Qtrue;
04837 }
04838
04839
04840
04841
04842
04843
04844
04845
04846
04847
04848 static void
04849 recursive_push(VALUE list, VALUE obj, VALUE paired_obj)
04850 {
04851 VALUE pair_list;
04852
04853 if (!paired_obj) {
04854 rb_hash_aset(list, obj, Qtrue);
04855 }
04856 else if ((pair_list = rb_hash_lookup2(list, obj, Qundef)) == Qundef) {
04857 rb_hash_aset(list, obj, paired_obj);
04858 }
04859 else {
04860 if (!RB_TYPE_P(pair_list, T_HASH)){
04861 VALUE other_paired_obj = pair_list;
04862 pair_list = rb_hash_new();
04863 rb_hash_aset(pair_list, other_paired_obj, Qtrue);
04864 rb_hash_aset(list, obj, pair_list);
04865 }
04866 rb_hash_aset(pair_list, paired_obj, Qtrue);
04867 }
04868 }
04869
04870
04871
04872
04873
04874
04875
04876
04877
04878 static void
04879 recursive_pop(VALUE list, VALUE obj, VALUE paired_obj)
04880 {
04881 if (paired_obj) {
04882 VALUE pair_list = rb_hash_lookup2(list, obj, Qundef);
04883 if (pair_list == Qundef) {
04884 VALUE symname = rb_inspect(ID2SYM(rb_frame_this_func()));
04885 VALUE thrname = rb_inspect(rb_thread_current());
04886 rb_raise(rb_eTypeError, "invalid inspect_tbl pair_list for %s in %s",
04887 StringValuePtr(symname), StringValuePtr(thrname));
04888 }
04889 if (RB_TYPE_P(pair_list, T_HASH)) {
04890 rb_hash_delete(pair_list, paired_obj);
04891 if (!RHASH_EMPTY_P(pair_list)) {
04892 return;
04893 }
04894 }
04895 }
04896 rb_hash_delete(list, obj);
04897 }
04898
04899 struct exec_recursive_params {
04900 VALUE (*func) (VALUE, VALUE, int);
04901 VALUE list;
04902 VALUE obj;
04903 VALUE objid;
04904 VALUE pairid;
04905 VALUE arg;
04906 };
04907
04908 static VALUE
04909 exec_recursive_i(RB_BLOCK_CALL_FUNC_ARGLIST(tag, data))
04910 {
04911 struct exec_recursive_params *p = (void *)data;
04912 return (*p->func)(p->obj, p->arg, FALSE);
04913 }
04914
04915
04916
04917
04918
04919
04920
04921
04922
04923
04924
04925
04926 static VALUE
04927 exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE pairid, VALUE arg, int outer)
04928 {
04929 VALUE result = Qundef;
04930 struct exec_recursive_params p;
04931 int outermost;
04932 p.list = recursive_list_access();
04933 p.objid = rb_obj_id(obj);
04934 p.obj = obj;
04935 p.pairid = pairid;
04936 p.arg = arg;
04937 outermost = outer && !recursive_check(p.list, ID2SYM(recursive_key), 0);
04938
04939 if (recursive_check(p.list, p.objid, pairid)) {
04940 if (outer && !outermost) {
04941 rb_throw_obj(p.list, p.list);
04942 }
04943 return (*func)(obj, arg, TRUE);
04944 }
04945 else {
04946 int state;
04947
04948 p.func = func;
04949
04950 if (outermost) {
04951 recursive_push(p.list, ID2SYM(recursive_key), 0);
04952 recursive_push(p.list, p.objid, p.pairid);
04953 result = rb_catch_protect(p.list, exec_recursive_i, (VALUE)&p, &state);
04954 recursive_pop(p.list, p.objid, p.pairid);
04955 recursive_pop(p.list, ID2SYM(recursive_key), 0);
04956 if (state) JUMP_TAG(state);
04957 if (result == p.list) {
04958 result = (*func)(obj, arg, TRUE);
04959 }
04960 }
04961 else {
04962 recursive_push(p.list, p.objid, p.pairid);
04963 PUSH_TAG();
04964 if ((state = EXEC_TAG()) == 0) {
04965 result = (*func)(obj, arg, FALSE);
04966 }
04967 POP_TAG();
04968 recursive_pop(p.list, p.objid, p.pairid);
04969 if (state) JUMP_TAG(state);
04970 }
04971 }
04972 *(volatile struct exec_recursive_params *)&p;
04973 return result;
04974 }
04975
04976
04977
04978
04979
04980
04981 VALUE
04982 rb_exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
04983 {
04984 return exec_recursive(func, obj, 0, arg, 0);
04985 }
04986
04987
04988
04989
04990
04991
04992 VALUE
04993 rb_exec_recursive_paired(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE paired_obj, VALUE arg)
04994 {
04995 return exec_recursive(func, obj, rb_obj_id(paired_obj), arg, 0);
04996 }
04997
04998
04999
05000
05001
05002
05003
05004 VALUE
05005 rb_exec_recursive_outer(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
05006 {
05007 return exec_recursive(func, obj, 0, arg, 1);
05008 }
05009
05010
05011
05012
05013
05014
05015
05016 VALUE
05017 rb_exec_recursive_paired_outer(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE paired_obj, VALUE arg)
05018 {
05019 return exec_recursive(func, obj, rb_obj_id(paired_obj), arg, 1);
05020 }
05021
05022
05023
05024
05025
05026
05027
05028
05029
05030 static VALUE
05031 rb_thread_backtrace_m(int argc, VALUE *argv, VALUE thval)
05032 {
05033 return rb_vm_thread_backtrace(argc, argv, thval);
05034 }
05035
05036
05037
05038
05039
05040
05041
05042
05043
05044
05045
05046
05047 static VALUE
05048 rb_thread_backtrace_locations_m(int argc, VALUE *argv, VALUE thval)
05049 {
05050 return rb_vm_thread_backtrace_locations(argc, argv, thval);
05051 }
05052
05053
05054
05055
05056
05057
05058
05059
05060
05061
05062
05063
05064
05065
05066
05067
05068 void
05069 Init_Thread(void)
05070 {
05071 #undef rb_intern
05072 #define rb_intern(str) rb_intern_const(str)
05073
05074 VALUE cThGroup;
05075 rb_thread_t *th = GET_THREAD();
05076
05077 sym_never = ID2SYM(rb_intern("never"));
05078 sym_immediate = ID2SYM(rb_intern("immediate"));
05079 sym_on_blocking = ID2SYM(rb_intern("on_blocking"));
05080 id_locals = rb_intern("locals");
05081
05082 rb_define_singleton_method(rb_cThread, "new", thread_s_new, -1);
05083 rb_define_singleton_method(rb_cThread, "start", thread_start, -2);
05084 rb_define_singleton_method(rb_cThread, "fork", thread_start, -2);
05085 rb_define_singleton_method(rb_cThread, "main", rb_thread_s_main, 0);
05086 rb_define_singleton_method(rb_cThread, "current", thread_s_current, 0);
05087 rb_define_singleton_method(rb_cThread, "stop", rb_thread_stop, 0);
05088 rb_define_singleton_method(rb_cThread, "kill", rb_thread_s_kill, 1);
05089 rb_define_singleton_method(rb_cThread, "exit", rb_thread_exit, 0);
05090 rb_define_singleton_method(rb_cThread, "pass", thread_s_pass, 0);
05091 rb_define_singleton_method(rb_cThread, "list", rb_thread_list, 0);
05092 rb_define_singleton_method(rb_cThread, "abort_on_exception", rb_thread_s_abort_exc, 0);
05093 rb_define_singleton_method(rb_cThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1);
05094 #if THREAD_DEBUG < 0
05095 rb_define_singleton_method(rb_cThread, "DEBUG", rb_thread_s_debug, 0);
05096 rb_define_singleton_method(rb_cThread, "DEBUG=", rb_thread_s_debug_set, 1);
05097 #endif
05098 rb_define_singleton_method(rb_cThread, "handle_interrupt", rb_thread_s_handle_interrupt, 1);
05099 rb_define_singleton_method(rb_cThread, "pending_interrupt?", rb_thread_s_pending_interrupt_p, -1);
05100 rb_define_method(rb_cThread, "pending_interrupt?", rb_thread_pending_interrupt_p, -1);
05101
05102 rb_define_method(rb_cThread, "initialize", thread_initialize, -2);
05103 rb_define_method(rb_cThread, "raise", thread_raise_m, -1);
05104 rb_define_method(rb_cThread, "join", thread_join_m, -1);
05105 rb_define_method(rb_cThread, "value", thread_value, 0);
05106 rb_define_method(rb_cThread, "kill", rb_thread_kill, 0);
05107 rb_define_method(rb_cThread, "terminate", rb_thread_kill, 0);
05108 rb_define_method(rb_cThread, "exit", rb_thread_kill, 0);
05109 rb_define_method(rb_cThread, "run", rb_thread_run, 0);
05110 rb_define_method(rb_cThread, "wakeup", rb_thread_wakeup, 0);
05111 rb_define_method(rb_cThread, "[]", rb_thread_aref, 1);
05112 rb_define_method(rb_cThread, "[]=", rb_thread_aset, 2);
05113 rb_define_method(rb_cThread, "key?", rb_thread_key_p, 1);
05114 rb_define_method(rb_cThread, "keys", rb_thread_keys, 0);
05115 rb_define_method(rb_cThread, "priority", rb_thread_priority, 0);
05116 rb_define_method(rb_cThread, "priority=", rb_thread_priority_set, 1);
05117 rb_define_method(rb_cThread, "status", rb_thread_status, 0);
05118 rb_define_method(rb_cThread, "thread_variable_get", rb_thread_variable_get, 1);
05119 rb_define_method(rb_cThread, "thread_variable_set", rb_thread_variable_set, 2);
05120 rb_define_method(rb_cThread, "thread_variables", rb_thread_variables, 0);
05121 rb_define_method(rb_cThread, "thread_variable?", rb_thread_variable_p, 1);
05122 rb_define_method(rb_cThread, "alive?", rb_thread_alive_p, 0);
05123 rb_define_method(rb_cThread, "stop?", rb_thread_stop_p, 0);
05124 rb_define_method(rb_cThread, "abort_on_exception", rb_thread_abort_exc, 0);
05125 rb_define_method(rb_cThread, "abort_on_exception=", rb_thread_abort_exc_set, 1);
05126 rb_define_method(rb_cThread, "safe_level", rb_thread_safe_level, 0);
05127 rb_define_method(rb_cThread, "group", rb_thread_group, 0);
05128 rb_define_method(rb_cThread, "backtrace", rb_thread_backtrace_m, -1);
05129 rb_define_method(rb_cThread, "backtrace_locations", rb_thread_backtrace_locations_m, -1);
05130
05131 rb_define_method(rb_cThread, "inspect", rb_thread_inspect, 0);
05132
05133 closed_stream_error = rb_exc_new2(rb_eIOError, "stream closed");
05134 OBJ_TAINT(closed_stream_error);
05135 OBJ_FREEZE(closed_stream_error);
05136
05137 cThGroup = rb_define_class("ThreadGroup", rb_cObject);
05138 rb_define_alloc_func(cThGroup, thgroup_s_alloc);
05139 rb_define_method(cThGroup, "list", thgroup_list, 0);
05140 rb_define_method(cThGroup, "enclose", thgroup_enclose, 0);
05141 rb_define_method(cThGroup, "enclosed?", thgroup_enclosed_p, 0);
05142 rb_define_method(cThGroup, "add", thgroup_add, 1);
05143
05144 {
05145 th->thgroup = th->vm->thgroup_default = rb_obj_alloc(cThGroup);
05146 rb_define_const(cThGroup, "Default", th->thgroup);
05147 }
05148
05149 rb_cMutex = rb_define_class("Mutex", rb_cObject);
05150 rb_define_alloc_func(rb_cMutex, mutex_alloc);
05151 rb_define_method(rb_cMutex, "initialize", mutex_initialize, 0);
05152 rb_define_method(rb_cMutex, "locked?", rb_mutex_locked_p, 0);
05153 rb_define_method(rb_cMutex, "try_lock", rb_mutex_trylock, 0);
05154 rb_define_method(rb_cMutex, "lock", rb_mutex_lock, 0);
05155 rb_define_method(rb_cMutex, "unlock", rb_mutex_unlock, 0);
05156 rb_define_method(rb_cMutex, "sleep", mutex_sleep, -1);
05157 rb_define_method(rb_cMutex, "synchronize", rb_mutex_synchronize_m, 0);
05158 rb_define_method(rb_cMutex, "owned?", rb_mutex_owned_p, 0);
05159
05160 recursive_key = rb_intern("__recursive_key__");
05161 rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError);
05162
05163
05164 {
05165
05166 {
05167
05168 gvl_init(th->vm);
05169 gvl_acquire(th->vm, th);
05170 native_mutex_initialize(&th->vm->thread_destruct_lock);
05171 native_mutex_initialize(&th->interrupt_lock);
05172 native_cond_initialize(&th->interrupt_cond,
05173 RB_CONDATTR_CLOCK_MONOTONIC);
05174
05175 th->pending_interrupt_queue = rb_ary_tmp_new(0);
05176 th->pending_interrupt_queue_checked = 0;
05177 th->pending_interrupt_mask_stack = rb_ary_tmp_new(0);
05178
05179 th->interrupt_mask = 0;
05180 }
05181 }
05182
05183 rb_thread_create_timer_thread();
05184
05185
05186 (void)native_mutex_trylock;
05187 }
05188
05189 int
05190 ruby_native_thread_p(void)
05191 {
05192 rb_thread_t *th = ruby_thread_from_native();
05193
05194 return th != 0;
05195 }
05196
05197 static int
05198 check_deadlock_i(st_data_t key, st_data_t val, int *found)
05199 {
05200 VALUE thval = key;
05201 rb_thread_t *th;
05202 GetThreadPtr(thval, th);
05203
05204 if (th->status != THREAD_STOPPED_FOREVER || RUBY_VM_INTERRUPTED(th)) {
05205 *found = 1;
05206 }
05207 else if (th->locking_mutex) {
05208 rb_mutex_t *mutex;
05209 GetMutexPtr(th->locking_mutex, mutex);
05210
05211 native_mutex_lock(&mutex->lock);
05212 if (mutex->th == th || (!mutex->th && mutex->cond_waiting)) {
05213 *found = 1;
05214 }
05215 native_mutex_unlock(&mutex->lock);
05216 }
05217
05218 return (*found) ? ST_STOP : ST_CONTINUE;
05219 }
05220
05221 #ifdef DEBUG_DEADLOCK_CHECK
05222 static int
05223 debug_i(st_data_t key, st_data_t val, int *found)
05224 {
05225 VALUE thval = key;
05226 rb_thread_t *th;
05227 GetThreadPtr(thval, th);
05228
05229 printf("th:%p %d %d", th, th->status, th->interrupt_flag);
05230 if (th->locking_mutex) {
05231 rb_mutex_t *mutex;
05232 GetMutexPtr(th->locking_mutex, mutex);
05233
05234 native_mutex_lock(&mutex->lock);
05235 printf(" %p %d\n", mutex->th, mutex->cond_waiting);
05236 native_mutex_unlock(&mutex->lock);
05237 }
05238 else
05239 puts("");
05240
05241 return ST_CONTINUE;
05242 }
05243 #endif
05244
05245 static void
05246 rb_check_deadlock(rb_vm_t *vm)
05247 {
05248 int found = 0;
05249
05250 if (vm_living_thread_num(vm) > vm->sleeper) return;
05251 if (vm_living_thread_num(vm) < vm->sleeper) rb_bug("sleeper must not be more than vm_living_thread_num(vm)");
05252 if (patrol_thread && patrol_thread != GET_THREAD()) return;
05253
05254 st_foreach(vm->living_threads, check_deadlock_i, (st_data_t)&found);
05255
05256 if (!found) {
05257 VALUE argv[2];
05258 argv[0] = rb_eFatal;
05259 argv[1] = rb_str_new2("No live threads left. Deadlock?");
05260 #ifdef DEBUG_DEADLOCK_CHECK
05261 printf("%d %d %p %p\n", vm->living_threads->num_entries, vm->sleeper, GET_THREAD(), vm->main_thread);
05262 st_foreach(vm->living_threads, debug_i, (st_data_t)0);
05263 #endif
05264 vm->sleeper--;
05265 rb_threadptr_raise(vm->main_thread, 2, argv);
05266 }
05267 }
05268
05269 static void
05270 update_coverage(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
05271 {
05272 VALUE coverage = GET_THREAD()->cfp->iseq->coverage;
05273 if (coverage && RBASIC(coverage)->klass == 0) {
05274 long line = rb_sourceline() - 1;
05275 long count;
05276 if (RARRAY_AREF(coverage, line) == Qnil) {
05277 return;
05278 }
05279 count = FIX2LONG(RARRAY_AREF(coverage, line)) + 1;
05280 if (POSFIXABLE(count)) {
05281 RARRAY_ASET(coverage, line, LONG2FIX(count));
05282 }
05283 }
05284 }
05285
05286 VALUE
05287 rb_get_coverages(void)
05288 {
05289 return GET_VM()->coverages;
05290 }
05291
05292 void
05293 rb_set_coverages(VALUE coverages)
05294 {
05295 GET_VM()->coverages = coverages;
05296 rb_add_event_hook(update_coverage, RUBY_EVENT_COVERAGE, Qnil);
05297 }
05298
05299 void
05300 rb_reset_coverages(void)
05301 {
05302 GET_VM()->coverages = Qfalse;
05303 rb_remove_event_hook(update_coverage);
05304 }
05305
05306 VALUE
05307 rb_uninterruptible(VALUE (*b_proc)(ANYARGS), VALUE data)
05308 {
05309 VALUE interrupt_mask = rb_hash_new();
05310 rb_thread_t *cur_th = GET_THREAD();
05311
05312 rb_hash_aset(interrupt_mask, rb_cObject, sym_never);
05313 rb_ary_push(cur_th->pending_interrupt_mask_stack, interrupt_mask);
05314
05315 return rb_ensure(b_proc, data, rb_ary_pop, cur_th->pending_interrupt_mask_stack);
05316 }
05317
05318 void
05319 ruby_kill(rb_pid_t pid, int sig)
05320 {
05321 int err;
05322 rb_thread_t *th = GET_THREAD();
05323
05324
05325
05326
05327
05328 {
05329 GVL_UNLOCK_BEGIN();
05330 native_mutex_lock(&th->interrupt_lock);
05331 err = kill(pid, sig);
05332 native_cond_wait(&th->interrupt_cond, &th->interrupt_lock);
05333 native_mutex_unlock(&th->interrupt_lock);
05334 GVL_UNLOCK_END();
05335 }
05336 if (err < 0) {
05337 rb_sys_fail(0);
05338 }
05339 }
05340