Ruby 2.1.5p273(2014-11-13revision48405)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

thread.c
Go to the documentation of this file.
1 /**********************************************************************
2
3 thread.c -
4
5 $Author: nagachika $
6
7 Copyright (C) 2004-2007 Koichi Sasada
8
9 **********************************************************************/
10
11 /*
12 YARV Thread Design
13
14 model 1: Userlevel Thread
15 Same as traditional ruby thread.
16
17 model 2: Native Thread with Global VM lock
18 Using pthread (or Windows thread) and Ruby threads run concurrent.
19
20 model 3: Native Thread with fine grain lock
21 Using pthread and Ruby threads run concurrent or parallel.
22
23 ------------------------------------------------------------------------
24
25 model 2:
26 A thread has mutex (GVL: Global VM Lock or Giant VM Lock) can run.
27 When thread scheduling, running thread release GVL. If running thread
28 try blocking operation, this thread must release GVL and another
29 thread can continue this flow. After blocking operation, thread
30 must check interrupt (RUBY_VM_CHECK_INTS).
31
32 Every VM can run parallel.
33
34 Ruby threads are scheduled by OS thread scheduler.
35
36 ------------------------------------------------------------------------
37
38 model 3:
39 Every threads run concurrent or parallel and to access shared object
40 exclusive access control is needed. For example, to access String
41 object or Array object, fine grain lock must be locked every time.
42 */
43
44
45 /*
46 * FD_SET, FD_CLR and FD_ISSET have a small sanity check when using glibc
47 * 2.15 or later and set _FORTIFY_SOURCE > 0.
48 * However, the implementation is wrong. Even though Linux's select(2)
49 * supports large fd size (>FD_SETSIZE), it wrongly assumes fd is always
50 * less than FD_SETSIZE (i.e. 1024). And then when enabling HAVE_RB_FD_INIT,
51 * it doesn't work correctly and makes program abort. Therefore we need to
52 * disable FORTY_SOURCE until glibc fixes it.
53 */
54 #undef _FORTIFY_SOURCE
55 #undef __USE_FORTIFY_LEVEL
56 #define __USE_FORTIFY_LEVEL 0
57
58 /* for model 2 */
59
60 #include "eval_intern.h"
61 #include "gc.h"
62 #include "timev.h"
63 #include "ruby/io.h"
64 #include "ruby/thread.h"
65 #include "internal.h"
66
67 #ifndef USE_NATIVE_THREAD_PRIORITY
68 #define USE_NATIVE_THREAD_PRIORITY 0
69 #define RUBY_THREAD_PRIORITY_MAX 3
70 #define RUBY_THREAD_PRIORITY_MIN -3
71 #endif
72
73 #ifndef THREAD_DEBUG
74 #define THREAD_DEBUG 0
75 #endif
76
77 VALUE rb_cMutex;
78 VALUE rb_cThreadShield;
79
80 static VALUE sym_immediate;
81 static VALUE sym_on_blocking;
82 static VALUE sym_never;
83 static ID id_locals;
84
85 static void sleep_timeval(rb_thread_t *th, struct timeval time, int spurious_check);
86 static void sleep_wait_for_interrupt(rb_thread_t *th, double sleepsec, int spurious_check);
87 static void sleep_forever(rb_thread_t *th, int nodeadlock, int spurious_check);
88 static double timeofday(void);
89 static int rb_threadptr_dead(rb_thread_t *th);
90 static void rb_check_deadlock(rb_vm_t *vm);
91 static int rb_threadptr_pending_interrupt_empty_p(rb_thread_t *th);
92
93 #define eKillSignal INT2FIX(0)
94 #define eTerminateSignal INT2FIX(1)
95 static volatile int system_working = 1;
96
97 #define closed_stream_error GET_VM()->special_exceptions[ruby_error_closed_stream]
98
99 inline static void
100 st_delete_wrap(st_table *table, st_data_t key)
101 {
102 st_delete(table, &key, 0);
103 }
104
105 /********************************************************************************/
106
107 #define THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
108
109 struct rb_blocking_region_buffer {
110 enum rb_thread_status prev_status;
111 struct rb_unblock_callback oldubf;
112 };
113
114 static int set_unblock_function(rb_thread_t *th, rb_unblock_function_t *func, void *arg,
115 struct rb_unblock_callback *old, int fail_if_interrupted);
116 static void reset_unblock_function(rb_thread_t *th, const struct rb_unblock_callback *old);
117
118 static inline int blocking_region_begin(rb_thread_t *th, struct rb_blocking_region_buffer *region,
119 rb_unblock_function_t *ubf, void *arg, int fail_if_interrupted);
120 static inline void blocking_region_end(rb_thread_t *th, struct rb_blocking_region_buffer *region);
121
122 #ifdef __ia64
123 #define RB_GC_SAVE_MACHINE_REGISTER_STACK(th) \
124 do{(th)->machine.register_stack_end = rb_ia64_bsp();}while(0)
125 #else
126 #define RB_GC_SAVE_MACHINE_REGISTER_STACK(th)
127 #endif
128 #define RB_GC_SAVE_MACHINE_CONTEXT(th) \
129 do { \
130 FLUSH_REGISTER_WINDOWS; \
131 RB_GC_SAVE_MACHINE_REGISTER_STACK(th); \
132 setjmp((th)->machine.regs); \
133 SET_MACHINE_STACK_END(&(th)->machine.stack_end); \
134 } while (0)
135
136 #define GVL_UNLOCK_BEGIN() do { \
137 rb_thread_t *_th_stored = GET_THREAD(); \
138 RB_GC_SAVE_MACHINE_CONTEXT(_th_stored); \
139 gvl_release(_th_stored->vm);
140
141 #define GVL_UNLOCK_END() \
142 gvl_acquire(_th_stored->vm, _th_stored); \
143 rb_thread_set_current(_th_stored); \
144 } while(0)
145
146 #ifdef __GNUC__
147 #define only_if_constant(expr, notconst) (__builtin_constant_p(expr) ? (expr) : (notconst))
148 #else
149 #define only_if_constant(expr, notconst) notconst
150 #endif
151 #define BLOCKING_REGION(exec, ubf, ubfarg, fail_if_interrupted) do { \
152 rb_thread_t *__th = GET_THREAD(); \
153 struct rb_blocking_region_buffer __region; \
154 if (blocking_region_begin(__th, &__region, (ubf), (ubfarg), fail_if_interrupted) || \
155 /* always return true unless fail_if_interrupted */ \
156 !only_if_constant(fail_if_interrupted, TRUE)) { \
157 exec; \
158 blocking_region_end(__th, &__region); \
159 }; \
160 } while(0)
161
162 #if THREAD_DEBUG
163 #ifdef HAVE_VA_ARGS_MACRO
164 void rb_thread_debug(const char *file, int line, const char *fmt, ...);
165 #define thread_debug(fmt, ...) rb_thread_debug(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
166 #define POSITION_FORMAT "%s:%d:"
167 #define POSITION_ARGS ,file, line
168 #else
169 void rb_thread_debug(const char *fmt, ...);
170 #define thread_debug rb_thread_debug
171 #define POSITION_FORMAT
172 #define POSITION_ARGS
173 #endif
174
175 # if THREAD_DEBUG < 0
176 static int rb_thread_debug_enabled;
177
178 /*
179 * call-seq:
180 * Thread.DEBUG -> num
181 *
182 * Returns the thread debug level. Available only if compiled with
183 * THREAD_DEBUG=-1.
184 */
185
186 static VALUE
187 rb_thread_s_debug(void)
188 {
189 return INT2NUM(rb_thread_debug_enabled);
190 }
191
192 /*
193 * call-seq:
194 * Thread.DEBUG = num
195 *
196 * Sets the thread debug level. Available only if compiled with
197 * THREAD_DEBUG=-1.
198 */
199
200 static VALUE
201 rb_thread_s_debug_set(VALUE self, VALUE val)
202 {
203 rb_thread_debug_enabled = RTEST(val) ? NUM2INT(val) : 0;
204 return val;
205 }
206 # else
207 # define rb_thread_debug_enabled THREAD_DEBUG
208 # endif
209 #else
210 #define thread_debug if(0)printf
211 #endif
212
213 #ifndef __ia64
214 #define thread_start_func_2(th, st, rst) thread_start_func_2(th, st)
215 #endif
216 NOINLINE(static int thread_start_func_2(rb_thread_t *th, VALUE *stack_start,
217 VALUE *register_stack_start));
218 static void timer_thread_function(void *);
219
220 #if defined(_WIN32)
221 #include "thread_win32.c"
222
223 #define DEBUG_OUT() \
224 WaitForSingleObject(&debug_mutex, INFINITE); \
225 printf(POSITION_FORMAT"%p - %s" POSITION_ARGS, GetCurrentThreadId(), buf); \
226 fflush(stdout); \
227 ReleaseMutex(&debug_mutex);
228
229 #elif defined(HAVE_PTHREAD_H)
230 #include "thread_pthread.c"
231
232 #define DEBUG_OUT() \
233 pthread_mutex_lock(&debug_mutex); \
234 printf(POSITION_FORMAT"%#"PRIxVALUE" - %s" POSITION_ARGS, (VALUE)pthread_self(), buf); \
235 fflush(stdout); \
236 pthread_mutex_unlock(&debug_mutex);
237
238 #else
239 #error "unsupported thread type"
240 #endif
241
242 #if THREAD_DEBUG
243 static int debug_mutex_initialized = 1;
244 static rb_nativethread_lock_t debug_mutex;
245
246 void
247 rb_thread_debug(
248 #ifdef HAVE_VA_ARGS_MACRO
249 const char *file, int line,
250 #endif
251 const char *fmt, ...)
252 {
253 va_list args;
254 char buf[BUFSIZ];
255
256 if (!rb_thread_debug_enabled) return;
257
258 if (debug_mutex_initialized == 1) {
259 debug_mutex_initialized = 0;
260 native_mutex_initialize(&debug_mutex);
261 }
262
263 va_start(args, fmt);
264 vsnprintf(buf, BUFSIZ, fmt, args);
265 va_end(args);
266
267 DEBUG_OUT();
268 }
269 #endif
270
271 void
272 rb_vm_gvl_destroy(rb_vm_t *vm)
273 {
274 gvl_release(vm);
275 gvl_destroy(vm);
276 native_mutex_destroy(&vm->thread_destruct_lock);
277 }
278
279 void
280 rb_nativethread_lock_initialize(rb_nativethread_lock_t *lock)
281 {
282 native_mutex_initialize(lock);
283 }
284
285 void
286 rb_nativethread_lock_destroy(rb_nativethread_lock_t *lock)
287 {
288 native_mutex_destroy(lock);
289 }
290
291 void
292 rb_nativethread_lock_lock(rb_nativethread_lock_t *lock)
293 {
294 native_mutex_lock(lock);
295 }
296
297 void
298 rb_nativethread_lock_unlock(rb_nativethread_lock_t *lock)
299 {
300 native_mutex_unlock(lock);
301 }
302
303 static int
304 set_unblock_function(rb_thread_t *th, rb_unblock_function_t *func, void *arg,
305 struct rb_unblock_callback *old, int fail_if_interrupted)
306 {
307 check_ints:
308 if (fail_if_interrupted) {
309 if (RUBY_VM_INTERRUPTED_ANY(th)) {
310 return FALSE;
311 }
312 }
313 else {
314 RUBY_VM_CHECK_INTS(th);
315 }
316
317 native_mutex_lock(&th->interrupt_lock);
318 if (RUBY_VM_INTERRUPTED_ANY(th)) {
319 native_mutex_unlock(&th->interrupt_lock);
320 goto check_ints;
321 }
322 else {
323 if (old) *old = th->unblock;
324 th->unblock.func = func;
325 th->unblock.arg = arg;
326 }
327 native_mutex_unlock(&th->interrupt_lock);
328
329 return TRUE;
330 }
331
332 static void
333 reset_unblock_function(rb_thread_t *th, const struct rb_unblock_callback *old)
334 {
335 native_mutex_lock(&th->interrupt_lock);
336 th->unblock = *old;
337 native_mutex_unlock(&th->interrupt_lock);
338 }
339
340 static void
341 rb_threadptr_interrupt_common(rb_thread_t *th, int trap)
342 {
343 native_mutex_lock(&th->interrupt_lock);
344 if (trap)
345 RUBY_VM_SET_TRAP_INTERRUPT(th);
346 else
347 RUBY_VM_SET_INTERRUPT(th);
348 if (th->unblock.func) {
349 (th->unblock.func)(th->unblock.arg);
350 }
351 else {
352 /* none */
353 }
354 native_cond_signal(&th->interrupt_cond);
355 native_mutex_unlock(&th->interrupt_lock);
356 }
357
358 void
359 rb_threadptr_interrupt(rb_thread_t *th)
360 {
361 rb_threadptr_interrupt_common(th, 0);
362 }
363
364 void
365 rb_threadptr_trap_interrupt(rb_thread_t *th)
366 {
367 rb_threadptr_interrupt_common(th, 1);
368 }
369
370 static int
371 terminate_i(st_data_t key, st_data_t val, rb_thread_t *main_thread)
372 {
373 VALUE thval = key;
374 rb_thread_t *th;
375 GetThreadPtr(thval, th);
376
377 if (th != main_thread) {
378 thread_debug("terminate_i: %p\n", (void *)th);
379 rb_threadptr_pending_interrupt_enque(th, eTerminateSignal);
380 rb_threadptr_interrupt(th);
381 }
382 else {
383 thread_debug("terminate_i: main thread (%p)\n", (void *)th);
384 }
385 return ST_CONTINUE;
386 }
387
388 typedef struct rb_mutex_struct
389 {
390 rb_nativethread_lock_t lock;
391 rb_nativethread_cond_t cond;
392 struct rb_thread_struct volatile *th;
393 struct rb_mutex_struct *next_mutex;
394 int cond_waiting;
395 int allow_trap;
396 } rb_mutex_t;
397
398 static void rb_mutex_abandon_all(rb_mutex_t *mutexes);
399 static void rb_mutex_abandon_keeping_mutexes(rb_thread_t *th);
400 static void rb_mutex_abandon_locking_mutex(rb_thread_t *th);
401 static const char* rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t volatile *th);
402
403 void
404 rb_threadptr_unlock_all_locking_mutexes(rb_thread_t *th)
405 {
406 const char *err;
407 rb_mutex_t *mutex;
408 rb_mutex_t *mutexes = th->keeping_mutexes;
409
410 while (mutexes) {
411 mutex = mutexes;
412 /* rb_warn("mutex #<%p> remains to be locked by terminated thread",
413 mutexes); */
414 mutexes = mutex->next_mutex;
415 err = rb_mutex_unlock_th(mutex, th);
416 if (err) rb_bug("invalid keeping_mutexes: %s", err);
417 }
418 }
419
420 void
421 rb_thread_terminate_all(void)
422 {
423 rb_thread_t *th = GET_THREAD(); /* main thread */
424 rb_vm_t *vm = th->vm;
425
426 if (vm->main_thread != th) {
427 rb_bug("rb_thread_terminate_all: called by child thread (%p, %p)",
428 (void *)vm->main_thread, (void *)th);
429 }
430
431 /* unlock all locking mutexes */
432 rb_threadptr_unlock_all_locking_mutexes(th);
433
434 retry:
435 thread_debug("rb_thread_terminate_all (main thread: %p)\n", (void *)th);
436 st_foreach(vm->living_threads, terminate_i, (st_data_t)th);
437
438 while (!rb_thread_alone()) {
439 int state;
440
441 TH_PUSH_TAG(th);
442 if ((state = TH_EXEC_TAG()) == 0) {
443 /*
444 * Thread exiting routine in thread_start_func_2 notify
445 * me when the last sub-thread exit.
446 */
447 native_sleep(th, 0);
448 RUBY_VM_CHECK_INTS_BLOCKING(th);
449 }
450 TH_POP_TAG();
451
452 /*
453 * When caught an exception (e.g. Ctrl+C), let's broadcast
454 * kill request again to ensure killing all threads even
455 * if they are blocked on sleep, mutex, etc.
456 */
457 if (state) {
458 goto retry;
459 }
460 }
461 }
462
463 static void
464 thread_cleanup_func_before_exec(void *th_ptr)
465 {
466 rb_thread_t *th = th_ptr;
467 th->status = THREAD_KILLED;
468 th->machine.stack_start = th->machine.stack_end = 0;
469 #ifdef __ia64
470 th->machine.register_stack_start = th->machine.register_stack_end = 0;
471 #endif
472 }
473
474 static void
475 thread_cleanup_func(void *th_ptr, int atfork)
476 {
477 rb_thread_t *th = th_ptr;
478
479 th->locking_mutex = Qfalse;
480 thread_cleanup_func_before_exec(th_ptr);
481
482 /*
483 * Unfortunately, we can't release native threading resource at fork
484 * because libc may have unstable locking state therefore touching
485 * a threading resource may cause a deadlock.
486 */
487 if (atfork)
488 return;
489
490 native_mutex_destroy(&th->interrupt_lock);
491 native_thread_destroy(th);
492 }
493
494 static VALUE rb_threadptr_raise(rb_thread_t *, int, VALUE *);
495
496 void
497 ruby_thread_init_stack(rb_thread_t *th)
498 {
499 native_thread_init_stack(th);
500 }
501
502 static int
503 thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_start)
504 {
505 int state;
506 VALUE args = th->first_args;
507 rb_proc_t *proc;
508 rb_thread_list_t *join_list;
509 rb_thread_t *main_th;
510 VALUE errinfo = Qnil;
511 # ifdef USE_SIGALTSTACK
512 void rb_register_sigaltstack(rb_thread_t *th);
513
514 rb_register_sigaltstack(th);
515 # endif
516
517 if (th == th->vm->main_thread)
518 rb_bug("thread_start_func_2 must not be used for main thread");
519
520 ruby_thread_set_native(th);
521
522 th->machine.stack_start = stack_start;
523 #ifdef __ia64
524 th->machine.register_stack_start = register_stack_start;
525 #endif
526 thread_debug("thread start: %p\n", (void *)th);
527
528 gvl_acquire(th->vm, th);
529 {
530 thread_debug("thread start (get lock): %p\n", (void *)th);
531 rb_thread_set_current(th);
532
533 TH_PUSH_TAG(th);
534 if ((state = EXEC_TAG()) == 0) {
535 SAVE_ROOT_JMPBUF(th, {
536 if (!th->first_func) {
537 GetProcPtr(th->first_proc, proc);
538 th->errinfo = Qnil;
539 th->root_lep = rb_vm_ep_local_ep(proc->block.ep);
540 th->root_svar = Qnil;
541 EXEC_EVENT_HOOK(th, RUBY_EVENT_THREAD_BEGIN, th->self, 0, 0, Qundef);
542 th->value = rb_vm_invoke_proc(th, proc, (int)RARRAY_LEN(args), RARRAY_CONST_PTR(args), 0);
543 EXEC_EVENT_HOOK(th, RUBY_EVENT_THREAD_END, th->self, 0, 0, Qundef);
544 }
545 else {
546 th->value = (*th->first_func)((void *)args);
547 }
548 });
549 }
550 else {
551 errinfo = th->errinfo;
552 if (state == TAG_FATAL) {
553 /* fatal error within this thread, need to stop whole script */
554 }
555 else if (rb_obj_is_kind_of(errinfo, rb_eSystemExit)) {
556 /* exit on main_thread. */
557 }
558 else if (th->vm->thread_abort_on_exception ||
559 th->abort_on_exception || RTEST(ruby_debug)) {
560 /* exit on main_thread */
561 }
562 else {
563 errinfo = Qnil;
564 }
565 th->value = Qnil;
566 }
567
568 th->status = THREAD_KILLED;
569 thread_debug("thread end: %p\n", (void *)th);
570
571 main_th = th->vm->main_thread;
572 if (main_th == th) {
573 ruby_stop(0);
574 }
575 if (RB_TYPE_P(errinfo, T_OBJECT)) {
576 /* treat with normal error object */
577 rb_threadptr_raise(main_th, 1, &errinfo);
578 }
579 TH_POP_TAG();
580
581 /* locking_mutex must be Qfalse */
582 if (th->locking_mutex != Qfalse) {
583 rb_bug("thread_start_func_2: locking_mutex must not be set (%p:%"PRIxVALUE")",
584 (void *)th, th->locking_mutex);
585 }
586
587 /* delete self other than main thread from living_threads */
588 st_delete_wrap(th->vm->living_threads, th->self);
589 if (rb_thread_alone()) {
590 /* I'm last thread. wake up main thread from rb_thread_terminate_all */
591 rb_threadptr_interrupt(main_th);
592 }
593
594 /* wake up joining threads */
595 join_list = th->join_list;
596 while (join_list) {
597 rb_threadptr_interrupt(join_list->th);
598 switch (join_list->th->status) {
599 case THREAD_STOPPED: case THREAD_STOPPED_FOREVER:
600 join_list->th->status = THREAD_RUNNABLE;
601 default: break;
602 }
603 join_list = join_list->next;
604 }
605
606 rb_threadptr_unlock_all_locking_mutexes(th);
607 rb_check_deadlock(th->vm);
608
609 if (!th->root_fiber) {
610 rb_thread_recycle_stack_release(th->stack);
611 th->stack = 0;
612 }
613 }
614 native_mutex_lock(&th->vm->thread_destruct_lock);
615 /* make sure vm->running_thread never point me after this point.*/
616 th->vm->running_thread = NULL;
617 native_mutex_unlock(&th->vm->thread_destruct_lock);
618 thread_cleanup_func(th, FALSE);
619 gvl_release(th->vm);
620
621 return 0;
622 }
623
624 static VALUE
625 thread_create_core(VALUE thval, VALUE args, VALUE (*fn)(ANYARGS))
626 {
627 rb_thread_t *th, *current_th = GET_THREAD();
628 int err;
629
630 if (OBJ_FROZEN(GET_THREAD()->thgroup)) {
631 rb_raise(rb_eThreadError,
632 "can't start a new thread (frozen ThreadGroup)");
633 }
634 GetThreadPtr(thval, th);
635
636 /* setup thread environment */
637 th->first_func = fn;
638 th->first_proc = fn ? Qfalse : rb_block_proc();
639 th->first_args = args; /* GC: shouldn't put before above line */
640
641 th->priority = current_th->priority;
642 th->thgroup = current_th->thgroup;
643
644 th->pending_interrupt_queue = rb_ary_tmp_new(0);
645 th->pending_interrupt_queue_checked = 0;
646 th->pending_interrupt_mask_stack = rb_ary_dup(current_th->pending_interrupt_mask_stack);
647 RBASIC_CLEAR_CLASS(th->pending_interrupt_mask_stack);
648
649 th->interrupt_mask = 0;
650
651 native_mutex_initialize(&th->interrupt_lock);
652 native_cond_initialize(&th->interrupt_cond, RB_CONDATTR_CLOCK_MONOTONIC);
653
654 /* kick thread */
655 err = native_thread_create(th);
656 if (err) {
657 th->status = THREAD_KILLED;
658 rb_raise(rb_eThreadError, "can't create Thread: %s", strerror(err));
659 }
660 st_insert(th->vm->living_threads, thval, (st_data_t) th->thread_id);
661 return thval;
662 }
663
664 /*
665 * call-seq:
666 * Thread.new { ... } -> thread
667 * Thread.new(*args, &proc) -> thread
668 * Thread.new(*args) { |args| ... } -> thread
669 *
670 * Creates a new thread executing the given block.
671 *
672 * Any +args+ given to ::new will be passed to the block:
673 *
674 * arr = []
675 * a, b, c = 1, 2, 3
676 * Thread.new(a,b,c) { |d,e,f| arr << d << e << f }.join
677 * arr #=> [1, 2, 3]
678 *
679 * A ThreadError exception is raised if ::new is called without a block.
680 *
681 * If you're going to subclass Thread, be sure to call super in your
682 * +initialize+ method, otherwise a ThreadError will be raised.
683 */
684 static VALUE
685 thread_s_new(int argc, VALUE *argv, VALUE klass)
686 {
687 rb_thread_t *th;
688 VALUE thread = rb_thread_alloc(klass);
689
690 if (GET_VM()->main_thread->status == THREAD_KILLED)
691 rb_raise(rb_eThreadError, "can't alloc thread");
692
693 rb_obj_call_init(thread, argc, argv);
694 GetThreadPtr(thread, th);
695 if (!th->first_args) {
696 rb_raise(rb_eThreadError, "uninitialized thread - check `%s#initialize'",
697 rb_class2name(klass));
698 }
699 return thread;
700 }
701
702 /*
703 * call-seq:
704 * Thread.start([args]*) {|args| block } -> thread
705 * Thread.fork([args]*) {|args| block } -> thread
706 *
707 * Basically the same as ::new. However, if class Thread is subclassed, then
708 * calling +start+ in that subclass will not invoke the subclass's
709 * +initialize+ method.
710 */
711
712 static VALUE
713 thread_start(VALUE klass, VALUE args)
714 {
715 return thread_create_core(rb_thread_alloc(klass), args, 0);
716 }
717
718 /* :nodoc: */
719 static VALUE
720 thread_initialize(VALUE thread, VALUE args)
721 {
722 rb_thread_t *th;
723 if (!rb_block_given_p()) {
724 rb_raise(rb_eThreadError, "must be called with a block");
725 }
726 GetThreadPtr(thread, th);
727 if (th->first_args) {
728 VALUE proc = th->first_proc, line, loc;
729 const char *file;
730 if (!proc || !RTEST(loc = rb_proc_location(proc))) {
731 rb_raise(rb_eThreadError, "already initialized thread");
732 }
733 file = RSTRING_PTR(RARRAY_AREF(loc, 0));
734 if (NIL_P(line = RARRAY_AREF(loc, 1))) {
735 rb_raise(rb_eThreadError, "already initialized thread - %s",
736 file);
737 }
738 rb_raise(rb_eThreadError, "already initialized thread - %s:%d",
739 file, NUM2INT(line));
740 }
741 return thread_create_core(thread, args, 0);
742 }
743
744 VALUE
745 rb_thread_create(VALUE (*fn)(ANYARGS), void *arg)
746 {
747 return thread_create_core(rb_thread_alloc(rb_cThread), (VALUE)arg, fn);
748 }
749
750
751 /* +infty, for this purpose */
752 #define DELAY_INFTY 1E30
753
754 struct join_arg {
755 rb_thread_t *target, *waiting;
756 double limit;
757 int forever;
758 };
759
760 static VALUE
761 remove_from_join_list(VALUE arg)
762 {
763 struct join_arg *p = (struct join_arg *)arg;
764 rb_thread_t *target_th = p->target, *th = p->waiting;
765
766 if (target_th->status != THREAD_KILLED) {
767 rb_thread_list_t **p = &target_th->join_list;
768
769 while (*p) {
770 if ((*p)->th == th) {
771 *p = (*p)->next;
772 break;
773 }
774 p = &(*p)->next;
775 }
776 }
777
778 return Qnil;
779 }
780
781 static VALUE
782 thread_join_sleep(VALUE arg)
783 {
784 struct join_arg *p = (struct join_arg *)arg;
785 rb_thread_t *target_th = p->target, *th = p->waiting;
786 double now, limit = p->limit;
787
788 while (target_th->status != THREAD_KILLED) {
789 if (p->forever) {
790 sleep_forever(th, 1, 0);
791 }
792 else {
793 now = timeofday();
794 if (now > limit) {
795 thread_debug("thread_join: timeout (thid: %p)\n",
796 (void *)target_th->thread_id);
797 return Qfalse;
798 }
799 sleep_wait_for_interrupt(th, limit - now, 0);
800 }
801 thread_debug("thread_join: interrupted (thid: %p)\n",
802 (void *)target_th->thread_id);
803 }
804 return Qtrue;
805 }
806
807 static VALUE
808 thread_join(rb_thread_t *target_th, double delay)
809 {
810 rb_thread_t *th = GET_THREAD();
811 struct join_arg arg;
812
813 if (th == target_th) {
814 rb_raise(rb_eThreadError, "Target thread must not be current thread");
815 }
816 if (GET_VM()->main_thread == target_th) {
817 rb_raise(rb_eThreadError, "Target thread must not be main thread");
818 }
819
820 arg.target = target_th;
821 arg.waiting = th;
822 arg.limit = timeofday() + delay;
823 arg.forever = delay == DELAY_INFTY;
824
825 thread_debug("thread_join (thid: %p)\n", (void *)target_th->thread_id);
826
827 if (target_th->status != THREAD_KILLED) {
828 rb_thread_list_t list;
829 list.next = target_th->join_list;
830 list.th = th;
831 target_th->join_list = &list;
832 if (!rb_ensure(thread_join_sleep, (VALUE)&arg,
833 remove_from_join_list, (VALUE)&arg)) {
834 return Qnil;
835 }
836 }
837
838 thread_debug("thread_join: success (thid: %p)\n",
839 (void *)target_th->thread_id);
840
841 if (target_th->errinfo != Qnil) {
842 VALUE err = target_th->errinfo;
843
844 if (FIXNUM_P(err)) {
845 /* */
846 }
847 else if (RB_TYPE_P(target_th->errinfo, T_NODE)) {
848 rb_exc_raise(rb_vm_make_jump_tag_but_local_jump(
849 GET_THROWOBJ_STATE(err), GET_THROWOBJ_VAL(err)));
850 }
851 else {
852 /* normal exception */
853 rb_exc_raise(err);
854 }
855 }
856 return target_th->self;
857 }
858
859 /*
860 * call-seq:
861 * thr.join -> thr
862 * thr.join(limit) -> thr
863 *
864 * The calling thread will suspend execution and run this +thr+.
865 *
866 * Does not return until +thr+ exits or until the given +limit+ seconds have
867 * passed.
868 *
869 * If the time limit expires, +nil+ will be returned, otherwise +thr+ is
870 * returned.
871 *
872 * Any threads not joined will be killed when the main program exits.
873 *
874 * If +thr+ had previously raised an exception and the ::abort_on_exception or
875 * $DEBUG flags are not set, (so the exception has not yet been processed), it
876 * will be processed at this time.
877 *
878 * a = Thread.new { print "a"; sleep(10); print "b"; print "c" }
879 * x = Thread.new { print "x"; Thread.pass; print "y"; print "z" }
880 * x.join # Let thread x finish, thread a will be killed on exit.
881 * #=> "axyz"
882 *
883 * The following example illustrates the +limit+ parameter.
884 *
885 * y = Thread.new { 4.times { sleep 0.1; puts 'tick... ' }}
886 * puts "Waiting" until y.join(0.15)
887 *
888 * This will produce:
889 *
890 * tick...
891 * Waiting
892 * tick...
893 * Waiting
894 * tick...
895 * tick...
896 */
897
898 static VALUE
899 thread_join_m(int argc, VALUE *argv, VALUE self)
900 {
901 rb_thread_t *target_th;
902 double delay = DELAY_INFTY;
903 VALUE limit;
904
905 GetThreadPtr(self, target_th);
906
907 rb_scan_args(argc, argv, "01", &limit);
908 if (!NIL_P(limit)) {
909 delay = rb_num2dbl(limit);
910 }
911
912 return thread_join(target_th, delay);
913 }
914
915 /*
916 * call-seq:
917 * thr.value -> obj
918 *
919 * Waits for +thr+ to complete, using #join, and returns its value.
920 *
921 * a = Thread.new { 2 + 2 }
922 * a.value #=> 4
923 */
924
925 static VALUE
926 thread_value(VALUE self)
927 {
928 rb_thread_t *th;
929 GetThreadPtr(self, th);
930 thread_join(th, DELAY_INFTY);
931 return th->value;
932 }
933
934 /*
935 * Thread Scheduling
936 */
937
938 /*
939 * The type of tv_sec in struct timeval is time_t in POSIX.
940 * But several systems violate POSIX.
941 *
942 * OpenBSD 5.2 (amd64):
943 * time_t: int (signed 32bit integer)
944 * tv_sec: long (signed 64bit integer)
945 *
946 * MinGW-w64 (x64):
947 * time_t: long long (signed 64bit integer)
948 * tv_sec: long (signed 32bit integer)
949 */
950
951 #if SIGNEDNESS_OF_TIME_T < 0 /* signed */
952 # define TIMEVAL_SEC_MAX SIGNED_INTEGER_MAX(TYPEOF_TIMEVAL_TV_SEC)
953 # define TIMEVAL_SEC_MIN SIGNED_INTEGER_MIN(TYPEOF_TIMEVAL_TV_SEC)
954 #elif SIGNEDNESS_OF_TIME_T > 0 /* unsigned */
955 # define TIMEVAL_SEC_MAX ((TYPEOF_TIMEVAL_TV_SEC)(~(unsigned_time_t)0))
956 # define TIMEVAL_SEC_MIN ((TYPEOF_TIMEVAL_TV_SEC)0)
957 #endif
958
959 static struct timeval
960 double2timeval(double d)
961 {
962 /* assume timeval.tv_sec has same signedness as time_t */
963 const double TIMEVAL_SEC_MAX_PLUS_ONE = (2*(double)(TIMEVAL_SEC_MAX/2+1));
964
965 struct timeval time;
966
967 if (TIMEVAL_SEC_MAX_PLUS_ONE <= d) {
968 time.tv_sec = TIMEVAL_SEC_MAX;
969 time.tv_usec = 999999;
970 }
971 else if (d <= TIMEVAL_SEC_MIN) {
972 time.tv_sec = TIMEVAL_SEC_MIN;
973 time.tv_usec = 0;
974 }
975 else {
976 time.tv_sec = (TYPEOF_TIMEVAL_TV_SEC)d;
977 time.tv_usec = (int)((d - (time_t)d) * 1e6);
978 if (time.tv_usec < 0) {
979 time.tv_usec += (int)1e6;
980 time.tv_sec -= 1;
981 }
982 }
983 return time;
984 }
985
986 static void
987 sleep_forever(rb_thread_t *th, int deadlockable, int spurious_check)
988 {
989 enum rb_thread_status prev_status = th->status;
990 enum rb_thread_status status = deadlockable ? THREAD_STOPPED_FOREVER : THREAD_STOPPED;
991
992 th->status = status;
993 RUBY_VM_CHECK_INTS_BLOCKING(th);
994 while (th->status == status) {
995 if (deadlockable) {
996 th->vm->sleeper++;
997 rb_check_deadlock(th->vm);
998 }
999 native_sleep(th, 0);
1000 if (deadlockable) {
1001 th->vm->sleeper--;
1002 }
1003 RUBY_VM_CHECK_INTS_BLOCKING(th);
1004 if (!spurious_check)
1005 break;
1006 }
1007 th->status = prev_status;
1008 }
1009
1010 static void
1011 getclockofday(struct timeval *tp)
1012 {
1013 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
1014 struct timespec ts;
1015
1016 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
1017 tp->tv_sec = ts.tv_sec;
1018 tp->tv_usec = ts.tv_nsec / 1000;
1019 } else
1020 #endif
1021 {
1022 gettimeofday(tp, NULL);
1023 }
1024 }
1025
1026 static void
1027 sleep_timeval(rb_thread_t *th, struct timeval tv, int spurious_check)
1028 {
1029 struct timeval to, tvn;
1030 enum rb_thread_status prev_status = th->status;
1031
1032 getclockofday(&to);
1033 if (TIMEVAL_SEC_MAX - tv.tv_sec < to.tv_sec)
1034 to.tv_sec = TIMEVAL_SEC_MAX;
1035 else
1036 to.tv_sec += tv.tv_sec;
1037 if ((to.tv_usec += tv.tv_usec) >= 1000000) {
1038 if (to.tv_sec == TIMEVAL_SEC_MAX)
1039 to.tv_usec = 999999;
1040 else {
1041 to.tv_sec++;
1042 to.tv_usec -= 1000000;
1043 }
1044 }
1045
1046 th->status = THREAD_STOPPED;
1047 RUBY_VM_CHECK_INTS_BLOCKING(th);
1048 while (th->status == THREAD_STOPPED) {
1049 native_sleep(th, &tv);
1050 RUBY_VM_CHECK_INTS_BLOCKING(th);
1051 getclockofday(&tvn);
1052 if (to.tv_sec < tvn.tv_sec) break;
1053 if (to.tv_sec == tvn.tv_sec && to.tv_usec <= tvn.tv_usec) break;
1054 thread_debug("sleep_timeval: %"PRI_TIMET_PREFIX"d.%.6ld > %"PRI_TIMET_PREFIX"d.%.6ld\n",
1055 (time_t)to.tv_sec, (long)to.tv_usec,
1056 (time_t)tvn.tv_sec, (long)tvn.tv_usec);
1057 tv.tv_sec = to.tv_sec - tvn.tv_sec;
1058 if ((tv.tv_usec = to.tv_usec - tvn.tv_usec) < 0) {
1059 --tv.tv_sec;
1060 tv.tv_usec += 1000000;
1061 }
1062 if (!spurious_check)
1063 break;
1064 }
1065 th->status = prev_status;
1066 }
1067
1068 void
1069 rb_thread_sleep_forever(void)
1070 {
1071 thread_debug("rb_thread_sleep_forever\n");
1072 sleep_forever(GET_THREAD(), 0, 1);
1073 }
1074
1075 void
1076 rb_thread_sleep_deadly(void)
1077 {
1078 thread_debug("rb_thread_sleep_deadly\n");
1079 sleep_forever(GET_THREAD(), 1, 1);
1080 }
1081
1082 static double
1083 timeofday(void)
1084 {
1085 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
1086 struct timespec tp;
1087
1088 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
1089 return (double)tp.tv_sec + (double)tp.tv_nsec * 1e-9;
1090 } else
1091 #endif
1092 {
1093 struct timeval tv;
1094 gettimeofday(&tv, NULL);
1095 return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6;
1096 }
1097 }
1098
1099 static void
1100 sleep_wait_for_interrupt(rb_thread_t *th, double sleepsec, int spurious_check)
1101 {
1102 sleep_timeval(th, double2timeval(sleepsec), spurious_check);
1103 }
1104
1105 static void
1106 sleep_for_polling(rb_thread_t *th)
1107 {
1108 struct timeval time;
1109 time.tv_sec = 0;
1110 time.tv_usec = 100 * 1000; /* 0.1 sec */
1111 sleep_timeval(th, time, 1);
1112 }
1113
1114 void
1115 rb_thread_wait_for(struct timeval time)
1116 {
1117 rb_thread_t *th = GET_THREAD();
1118 sleep_timeval(th, time, 1);
1119 }
1120
1121 void
1122 rb_thread_polling(void)
1123 {
1124 if (!rb_thread_alone()) {
1125 rb_thread_t *th = GET_THREAD();
1126 RUBY_VM_CHECK_INTS_BLOCKING(th);
1127 sleep_for_polling(th);
1128 }
1129 }
1130
1131 /*
1132 * CAUTION: This function causes thread switching.
1133 * rb_thread_check_ints() check ruby's interrupts.
1134 * some interrupt needs thread switching/invoke handlers,
1135 * and so on.
1136 */
1137
1138 void
1139 rb_thread_check_ints(void)
1140 {
1141 RUBY_VM_CHECK_INTS_BLOCKING(GET_THREAD());
1142 }
1143
1144 /*
1145 * Hidden API for tcl/tk wrapper.
1146 * There is no guarantee to perpetuate it.
1147 */
1148 int
1149 rb_thread_check_trap_pending(void)
1150 {
1151 return rb_signal_buff_size() != 0;
1152 }
1153
1154 /* This function can be called in blocking region. */
1155 int
1156 rb_thread_interrupted(VALUE thval)
1157 {
1158 rb_thread_t *th;
1159 GetThreadPtr(thval, th);
1160 return (int)RUBY_VM_INTERRUPTED(th);
1161 }
1162
1163 void
1164 rb_thread_sleep(int sec)
1165 {
1166 rb_thread_wait_for(rb_time_timeval(INT2FIX(sec)));
1167 }
1168
1169 static void
1170 rb_thread_schedule_limits(unsigned long limits_us)
1171 {
1172 thread_debug("rb_thread_schedule\n");
1173 if (!rb_thread_alone()) {
1174 rb_thread_t *th = GET_THREAD();
1175
1176 if (th->running_time_us >= limits_us) {
1177 thread_debug("rb_thread_schedule/switch start\n");
1178 RB_GC_SAVE_MACHINE_CONTEXT(th);
1179 gvl_yield(th->vm, th);
1180 rb_thread_set_current(th);
1181 thread_debug("rb_thread_schedule/switch done\n");
1182 }
1183 }
1184 }
1185
1186 void
1187 rb_thread_schedule(void)
1188 {
1189 rb_thread_t *cur_th = GET_THREAD();
1190 rb_thread_schedule_limits(0);
1191
1192 if (UNLIKELY(RUBY_VM_INTERRUPTED_ANY(cur_th))) {
1193 rb_threadptr_execute_interrupts(cur_th, 0);
1194 }
1195 }
1196
1197 /* blocking region */
1198
1199 static inline int
1200 blocking_region_begin(rb_thread_t *th, struct rb_blocking_region_buffer *region,
1201 rb_unblock_function_t *ubf, void *arg, int fail_if_interrupted)
1202 {
1203 region->prev_status = th->status;
1204 if (set_unblock_function(th, ubf, arg, &region->oldubf, fail_if_interrupted)) {
1205 th->blocking_region_buffer = region;
1206 th->status = THREAD_STOPPED;
1207 thread_debug("enter blocking region (%p)\n", (void *)th);
1208 RB_GC_SAVE_MACHINE_CONTEXT(th);
1209 gvl_release(th->vm);
1210 return TRUE;
1211 }
1212 else {
1213 return FALSE;
1214 }
1215 }
1216
1217 static inline void
1218 blocking_region_end(rb_thread_t *th, struct rb_blocking_region_buffer *region)
1219 {
1220 gvl_acquire(th->vm, th);
1221 rb_thread_set_current(th);
1222 thread_debug("leave blocking region (%p)\n", (void *)th);
1223 remove_signal_thread_list(th);
1224 th->blocking_region_buffer = 0;
1225 reset_unblock_function(th, &region->oldubf);
1226 if (th->status == THREAD_STOPPED) {
1227 th->status = region->prev_status;
1228 }
1229 }
1230
1231 struct rb_blocking_region_buffer *
1232 rb_thread_blocking_region_begin(void)
1233 {
1234 rb_thread_t *th = GET_THREAD();
1235 struct rb_blocking_region_buffer *region = ALLOC(struct rb_blocking_region_buffer);
1236 blocking_region_begin(th, region, ubf_select, th, FALSE);
1237 return region;
1238 }
1239
1240 void
1241 rb_thread_blocking_region_end(struct rb_blocking_region_buffer *region)
1242 {
1243 int saved_errno = errno;
1244 rb_thread_t *th = ruby_thread_from_native();
1245 blocking_region_end(th, region);
1246 xfree(region);
1247 RUBY_VM_CHECK_INTS_BLOCKING(th);
1248 errno = saved_errno;
1249 }
1250
1251 static void *
1252 call_without_gvl(void *(*func)(void *), void *data1,
1253 rb_unblock_function_t *ubf, void *data2, int fail_if_interrupted)
1254 {
1255 void *val = 0;
1256
1257 rb_thread_t *th = GET_THREAD();
1258 int saved_errno = 0;
1259
1260 th->waiting_fd = -1;
1261 if (ubf == RUBY_UBF_IO || ubf == RUBY_UBF_PROCESS) {
1262 ubf = ubf_select;
1263 data2 = th;
1264 }
1265
1266 BLOCKING_REGION({
1267 val = func(data1);
1268 saved_errno = errno;
1269 }, ubf, data2, fail_if_interrupted);
1270
1271 if (!fail_if_interrupted) {
1272 RUBY_VM_CHECK_INTS_BLOCKING(th);
1273 }
1274
1275 errno = saved_errno;
1276
1277 return val;
1278 }
1279
1280 /*
1281 * rb_thread_call_without_gvl - permit concurrent/parallel execution.
1282 * rb_thread_call_without_gvl2 - permit concurrent/parallel execution
1283 * without interrupt process.
1284 *
1285 * rb_thread_call_without_gvl() does:
1286 * (1) Check interrupts.
1287 * (2) release GVL.
1288 * Other Ruby threads may run in parallel.
1289 * (3) call func with data1
1290 * (4) acquire GVL.
1291 * Other Ruby threads can not run in parallel any more.
1292 * (5) Check interrupts.
1293 *
1294 * rb_thread_call_without_gvl2() does:
1295 * (1) Check interrupt and return if interrupted.
1296 * (2) release GVL.
1297 * (3) call func with data1 and a pointer to the flags.
1298 * (4) acquire GVL.
1299 *
1300 * If another thread interrupts this thread (Thread#kill, signal delivery,
1301 * VM-shutdown request, and so on), `ubf()' is called (`ubf()' means
1302 * "un-blocking function"). `ubf()' should interrupt `func()' execution by
1303 * toggling a cancellation flag, canceling the invocation of a call inside
1304 * `func()' or similar. Note that `ubf()' may not be called with the GVL.
1305 *
1306 * There are built-in ubfs and you can specify these ubfs:
1307 *
1308 * * RUBY_UBF_IO: ubf for IO operation
1309 * * RUBY_UBF_PROCESS: ubf for process operation
1310 *
1311 * However, we can not guarantee our built-in ubfs interrupt your `func()'
1312 * correctly. Be careful to use rb_thread_call_without_gvl(). If you don't
1313 * provide proper ubf(), your program will not stop for Control+C or other
1314 * shutdown events.
1315 *
1316 * "Check interrupts" on above list means checking asynchronous
1317 * interrupt events (such as Thread#kill, signal delivery, VM-shutdown
1318 * request, and so on) and calling corresponding procedures
1319 * (such as `trap' for signals, raise an exception for Thread#raise).
1320 * If `func()' finished and received interrupts, you may skip interrupt
1321 * checking. For example, assume the following func() it reads data from file.
1322 *
1323 * read_func(...) {
1324 * // (a) before read
1325 * read(buffer); // (b) reading
1326 * // (c) after read
1327 * }
1328 *
1329 * If an interrupt occurs at (a) or (b), then `ubf()' cancels this
1330 * `read_func()' and interrupts are checked. However, if an interrupt occurs
1331 * at (c), after *read* operation is completed, checking interrupts is harmful
1332 * because it causes irrevocable side-effect, the read data will vanish. To
1333 * avoid such problem, the `read_func()' should be used with
1334 * `rb_thread_call_without_gvl2()'.
1335 *
1336 * If `rb_thread_call_without_gvl2()' detects interrupt, it returns
1337 * immediately. This function does not show when the execution was interrupted.
1338 * For example, there are 4 possible timing (a), (b), (c) and before calling
1339 * read_func(). You need to record progress of a read_func() and check
1340 * the progress after `rb_thread_call_without_gvl2()'. You may need to call
1341 * `rb_thread_check_ints()' correctly or your program can not process proper
1342 * process such as `trap' and so on.
1343 *
1344 * NOTE: You can not execute most of Ruby C API and touch Ruby
1345 * objects in `func()' and `ubf()', including raising an
1346 * exception, because current thread doesn't acquire GVL
1347 * (it causes synchronization problems). If you need to
1348 * call ruby functions either use rb_thread_call_with_gvl()
1349 * or read source code of C APIs and confirm safety by
1350 * yourself.
1351 *
1352 * NOTE: In short, this API is difficult to use safely. I recommend you
1353 * use other ways if you have. We lack experiences to use this API.
1354 * Please report your problem related on it.
1355 *
1356 * NOTE: Releasing GVL and re-acquiring GVL may be expensive operations
1357 * for a short running `func()'. Be sure to benchmark and use this
1358 * mechanism when `func()' consumes enough time.
1359 *
1360 * Safe C API:
1361 * * rb_thread_interrupted() - check interrupt flag
1362 * * ruby_xmalloc(), ruby_xrealloc(), ruby_xfree() -
1363 * they will work without GVL, and may acquire GVL when GC is needed.
1364 */
1365 void *
1366 rb_thread_call_without_gvl2(void *(*func)(void *), void *data1,
1367 rb_unblock_function_t *ubf, void *data2)
1368 {
1369 return call_without_gvl(func, data1, ubf, data2, TRUE);
1370 }
1371
1372 void *
1373 rb_thread_call_without_gvl(void *(*func)(void *data), void *data1,
1374 rb_unblock_function_t *ubf, void *data2)
1375 {
1376 return call_without_gvl(func, data1, ubf, data2, FALSE);
1377 }
1378
1379 VALUE
1380 rb_thread_io_blocking_region(rb_blocking_function_t *func, void *data1, int fd)
1381 {
1382 VALUE val = Qundef; /* shouldn't be used */
1383 rb_thread_t *th = GET_THREAD();
1384 int saved_errno = 0;
1385 int state;
1386
1387 th->waiting_fd = fd;
1388
1389 TH_PUSH_TAG(th);
1390 if ((state = EXEC_TAG()) == 0) {
1391 BLOCKING_REGION({
1392 val = func(data1);
1393 saved_errno = errno;
1394 }, ubf_select, th, FALSE);
1395 }
1396 TH_POP_TAG();
1397
1398 /* clear waiting_fd anytime */
1399 th->waiting_fd = -1;
1400
1401 if (state) {
1402 JUMP_TAG(state);
1403 }
1404 /* TODO: check func() */
1405 RUBY_VM_CHECK_INTS_BLOCKING(th);
1406
1407 errno = saved_errno;
1408
1409 return val;
1410 }
1411
1412 VALUE
1413 rb_thread_blocking_region(
1414 rb_blocking_function_t *func, void *data1,
1415 rb_unblock_function_t *ubf, void *data2)
1416 {
1417 void *(*f)(void*) = (void *(*)(void*))func;
1418 return (VALUE)rb_thread_call_without_gvl(f, data1, ubf, data2);
1419 }
1420
1421 /*
1422 * rb_thread_call_with_gvl - re-enter the Ruby world after GVL release.
1423 *
1424 * After releasing GVL using rb_thread_blocking_region() or
1425 * rb_thread_call_without_gvl() you can not access Ruby values or invoke
1426 * methods. If you need to access Ruby you must use this function
1427 * rb_thread_call_with_gvl().
1428 *
1429 * This function rb_thread_call_with_gvl() does:
1430 * (1) acquire GVL.
1431 * (2) call passed function `func'.
1432 * (3) release GVL.
1433 * (4) return a value which is returned at (2).
1434 *
1435 * NOTE: You should not return Ruby object at (2) because such Object
1436 * will not be marked.
1437 *
1438 * NOTE: If an exception is raised in `func', this function DOES NOT
1439 * protect (catch) the exception. If you have any resources
1440 * which should free before throwing exception, you need use
1441 * rb_protect() in `func' and return a value which represents
1442 * exception was raised.
1443 *
1444 * NOTE: This function should not be called by a thread which was not
1445 * created as Ruby thread (created by Thread.new or so). In other
1446 * words, this function *DOES NOT* associate or convert a NON-Ruby
1447 * thread to a Ruby thread.
1448 */
1449 void *
1450 rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
1451 {
1452 rb_thread_t *th = ruby_thread_from_native();
1453 struct rb_blocking_region_buffer *brb;
1454 struct rb_unblock_callback prev_unblock;
1455 void *r;
1456
1457 if (th == 0) {
1458 /* Error has occurred, but we can't use rb_bug()
1459 * because this thread is not Ruby's thread.
1460 * What should we do?
1461 */
1462
1463 fprintf(stderr, "[BUG] rb_thread_call_with_gvl() is called by non-ruby thread\n");
1464 exit(EXIT_FAILURE);
1465 }
1466
1467 brb = (struct rb_blocking_region_buffer *)th->blocking_region_buffer;
1468 prev_unblock = th->unblock;
1469
1470 if (brb == 0) {
1471 rb_bug("rb_thread_call_with_gvl: called by a thread which has GVL.");
1472 }
1473
1474 blocking_region_end(th, brb);
1475 /* enter to Ruby world: You can access Ruby values, methods and so on. */
1476 r = (*func)(data1);
1477 /* leave from Ruby world: You can not access Ruby values, etc. */
1478 blocking_region_begin(th, brb, prev_unblock.func, prev_unblock.arg, FALSE);
1479 return r;
1480 }
1481
1482 /*
1483 * ruby_thread_has_gvl_p - check if current native thread has GVL.
1484 *
1485 ***
1486 *** This API is EXPERIMENTAL!
1487 *** We do not guarantee that this API remains in ruby 1.9.2 or later.
1488 ***
1489 */
1490
1491 int
1492 ruby_thread_has_gvl_p(void)
1493 {
1494 rb_thread_t *th = ruby_thread_from_native();
1495
1496 if (th && th->blocking_region_buffer == 0) {
1497 return 1;
1498 }
1499 else {
1500 return 0;
1501 }
1502 }
1503
1504 /*
1505 * call-seq:
1506 * Thread.pass -> nil
1507 *
1508 * Give the thread scheduler a hint to pass execution to another thread.
1509 * A running thread may or may not switch, it depends on OS and processor.
1510 */
1511
1512 static VALUE
1513 thread_s_pass(VALUE klass)
1514 {
1515 rb_thread_schedule();
1516 return Qnil;
1517 }
1518
1519 /*****************************************************/
1520
1521 /*
1522 * rb_threadptr_pending_interrupt_* - manage asynchronous error queue
1523 *
1524 * Async events such as an exception thrown by Thread#raise,
1525 * Thread#kill and thread termination (after main thread termination)
1526 * will be queued to th->pending_interrupt_queue.
1527 * - clear: clear the queue.
1528 * - enque: enqueue err object into queue.
1529 * - deque: dequeue err object from queue.
1530 * - active_p: return 1 if the queue should be checked.
1531 *
1532 * All rb_threadptr_pending_interrupt_* functions are called by
1533 * a GVL acquired thread, of course.
1534 * Note that all "rb_" prefix APIs need GVL to call.
1535 */
1536
1537 void
1538 rb_threadptr_pending_interrupt_clear(rb_thread_t *th)
1539 {
1540 rb_ary_clear(th->pending_interrupt_queue);
1541 }
1542
1543 void
1544 rb_threadptr_pending_interrupt_enque(rb_thread_t *th, VALUE v)
1545 {
1546 rb_ary_push(th->pending_interrupt_queue, v);
1547 th->pending_interrupt_queue_checked = 0;
1548 }
1549
1550 enum handle_interrupt_timing {
1551 INTERRUPT_NONE,
1552 INTERRUPT_IMMEDIATE,
1553 INTERRUPT_ON_BLOCKING,
1554 INTERRUPT_NEVER
1555 };
1556
1557 static enum handle_interrupt_timing
1558 rb_threadptr_pending_interrupt_check_mask(rb_thread_t *th, VALUE err)
1559 {
1560 VALUE mask;
1561 long mask_stack_len = RARRAY_LEN(th->pending_interrupt_mask_stack);
1562 const VALUE *mask_stack = RARRAY_CONST_PTR(th->pending_interrupt_mask_stack);
1563 VALUE ancestors = rb_mod_ancestors(err); /* TODO: GC guard */
1564 long ancestors_len = RARRAY_LEN(ancestors);
1565 const VALUE *ancestors_ptr = RARRAY_CONST_PTR(ancestors);
1566 int i, j;
1567
1568 for (i=0; i<mask_stack_len; i++) {
1569 mask = mask_stack[mask_stack_len-(i+1)];
1570
1571 for (j=0; j<ancestors_len; j++) {
1572 VALUE klass = ancestors_ptr[j];
1573 VALUE sym;
1574
1575 /* TODO: remove rb_intern() */
1576 if ((sym = rb_hash_aref(mask, klass)) != Qnil) {
1577 if (sym == sym_immediate) {
1578 return INTERRUPT_IMMEDIATE;
1579 }
1580 else if (sym == sym_on_blocking) {
1581 return INTERRUPT_ON_BLOCKING;
1582 }
1583 else if (sym == sym_never) {
1584 return INTERRUPT_NEVER;
1585 }
1586 else {
1587 rb_raise(rb_eThreadError, "unknown mask signature");
1588 }
1589 }
1590 }
1591 /* try to next mask */
1592 }
1593 return INTERRUPT_NONE;
1594 }
1595
1596 static int
1597 rb_threadptr_pending_interrupt_empty_p(rb_thread_t *th)
1598 {
1599 return RARRAY_LEN(th->pending_interrupt_queue) == 0;
1600 }
1601
1602 static int
1603 rb_threadptr_pending_interrupt_include_p(rb_thread_t *th, VALUE err)
1604 {
1605 int i;
1606 for (i=0; i<RARRAY_LEN(th->pending_interrupt_queue); i++) {
1607 VALUE e = RARRAY_AREF(th->pending_interrupt_queue, i);
1608 if (rb_class_inherited_p(e, err)) {
1609 return TRUE;
1610 }
1611 }
1612 return FALSE;
1613 }
1614
1615 static VALUE
1616 rb_threadptr_pending_interrupt_deque(rb_thread_t *th, enum handle_interrupt_timing timing)
1617 {
1618 #if 1 /* 1 to enable Thread#handle_interrupt, 0 to ignore it */
1619 int i;
1620
1621 for (i=0; i<RARRAY_LEN(th->pending_interrupt_queue); i++) {
1622 VALUE err = RARRAY_AREF(th->pending_interrupt_queue, i);
1623
1624 enum handle_interrupt_timing mask_timing = rb_threadptr_pending_interrupt_check_mask(th, CLASS_OF(err));
1625
1626 switch (mask_timing) {
1627 case INTERRUPT_ON_BLOCKING:
1628 if (timing != INTERRUPT_ON_BLOCKING) {
1629 break;
1630 }
1631 /* fall through */
1632 case INTERRUPT_NONE: /* default: IMMEDIATE */
1633 case INTERRUPT_IMMEDIATE:
1634 rb_ary_delete_at(th->pending_interrupt_queue, i);
1635 return err;
1636 case INTERRUPT_NEVER:
1637 break;
1638 }
1639 }
1640
1641 th->pending_interrupt_queue_checked = 1;
1642 return Qundef;
1643 #else
1644 VALUE err = rb_ary_shift(th->pending_interrupt_queue);
1645 if (rb_threadptr_pending_interrupt_empty_p(th)) {
1646 th->pending_interrupt_queue_checked = 1;
1647 }
1648 return err;
1649 #endif
1650 }
1651
1652 int
1653 rb_threadptr_pending_interrupt_active_p(rb_thread_t *th)
1654 {
1655 /*
1656 * For optimization, we don't check async errinfo queue
1657 * if the queue and the thread interrupt mask were not changed
1658 * since last check.
1659 */
1660 if (th->pending_interrupt_queue_checked) {
1661 return 0;
1662 }
1663
1664 if (rb_threadptr_pending_interrupt_empty_p(th)) {
1665 return 0;
1666 }
1667
1668 return 1;
1669 }
1670
1671 static int
1672 handle_interrupt_arg_check_i(VALUE key, VALUE val)
1673 {
1674 if (val != sym_immediate && val != sym_on_blocking && val != sym_never) {
1675 rb_raise(rb_eArgError, "unknown mask signature");
1676 }
1677
1678 return ST_CONTINUE;
1679 }
1680
1681 /*
1682 * call-seq:
1683 * Thread.handle_interrupt(hash) { ... } -> result of the block
1684 *
1685 * Changes asynchronous interrupt timing.
1686 *
1687 * _interrupt_ means asynchronous event and corresponding procedure
1688 * by Thread#raise, Thread#kill, signal trap (not supported yet)
1689 * and main thread termination (if main thread terminates, then all
1690 * other thread will be killed).
1691 *
1692 * The given +hash+ has pairs like <code>ExceptionClass =>
1693 * :TimingSymbol</code>. Where the ExceptionClass is the interrupt handled by
1694 * the given block. The TimingSymbol can be one of the following symbols:
1695 *
1696 * [+:immediate+] Invoke interrupts immediately.
1697 * [+:on_blocking+] Invoke interrupts while _BlockingOperation_.
1698 * [+:never+] Never invoke all interrupts.
1699 *
1700 * _BlockingOperation_ means that the operation will block the calling thread,
1701 * such as read and write. On CRuby implementation, _BlockingOperation_ is any
1702 * operation executed without GVL.
1703 *
1704 * Masked asynchronous interrupts are delayed until they are enabled.
1705 * This method is similar to sigprocmask(3).
1706 *
1707 * === NOTE
1708 *
1709 * Asynchronous interrupts are difficult to use.
1710 *
1711 * If you need to communicate between threads, please consider to use another way such as Queue.
1712 *
1713 * Or use them with deep understanding about this method.
1714 *
1715 * === Usage
1716 *
1717 * In this example, we can guard from Thread#raise exceptions.
1718 *
1719 * Using the +:never+ TimingSymbol the RuntimeError exception will always be
1720 * ignored in the first block of the main thread. In the second
1721 * ::handle_interrupt block we can purposefully handle RuntimeError exceptions.
1722 *
1723 * th = Thread.new do
1724 * Thread.handle_interrupt(RuntimeError => :never) {
1725 * begin
1726 * # You can write resource allocation code safely.
1727 * Thread.handle_interrupt(RuntimeError => :immediate) {
1728 * # ...
1729 * }
1730 * ensure
1731 * # You can write resource deallocation code safely.
1732 * end
1733 * }
1734 * end
1735 * Thread.pass
1736 * # ...
1737 * th.raise "stop"
1738 *
1739 * While we are ignoring the RuntimeError exception, it's safe to write our
1740 * resource allocation code. Then, the ensure block is where we can safely
1741 * deallocate your resources.
1742 *
1743 * ==== Guarding from TimeoutError
1744 *
1745 * In the next example, we will guard from the TimeoutError exception. This
1746 * will help prevent from leaking resources when TimeoutError exceptions occur
1747 * during normal ensure clause. For this example we use the help of the
1748 * standard library Timeout, from lib/timeout.rb
1749 *
1750 * require 'timeout'
1751 * Thread.handle_interrupt(TimeoutError => :never) {
1752 * timeout(10){
1753 * # TimeoutError doesn't occur here
1754 * Thread.handle_interrupt(TimeoutError => :on_blocking) {
1755 * # possible to be killed by TimeoutError
1756 * # while blocking operation
1757 * }
1758 * # TimeoutError doesn't occur here
1759 * }
1760 * }
1761 *
1762 * In the first part of the +timeout+ block, we can rely on TimeoutError being
1763 * ignored. Then in the <code>TimeoutError => :on_blocking</code> block, any
1764 * operation that will block the calling thread is susceptible to a
1765 * TimeoutError exception being raised.
1766 *
1767 * ==== Stack control settings
1768 *
1769 * It's possible to stack multiple levels of ::handle_interrupt blocks in order
1770 * to control more than one ExceptionClass and TimingSymbol at a time.
1771 *
1772 * Thread.handle_interrupt(FooError => :never) {
1773 * Thread.handle_interrupt(BarError => :never) {
1774 * # FooError and BarError are prohibited.
1775 * }
1776 * }
1777 *
1778 * ==== Inheritance with ExceptionClass
1779 *
1780 * All exceptions inherited from the ExceptionClass parameter will be considered.
1781 *
1782 * Thread.handle_interrupt(Exception => :never) {
1783 * # all exceptions inherited from Exception are prohibited.
1784 * }
1785 *
1786 */
1787 static VALUE
1788 rb_thread_s_handle_interrupt(VALUE self, VALUE mask_arg)
1789 {
1790 VALUE mask;
1791 rb_thread_t *th = GET_THREAD();
1792 VALUE r = Qnil;
1793 int state;
1794
1795 if (!rb_block_given_p()) {
1796 rb_raise(rb_eArgError, "block is needed.");
1797 }
1798
1799 mask = rb_convert_type(mask_arg, T_HASH, "Hash", "to_hash");
1800 rb_hash_foreach(mask, handle_interrupt_arg_check_i, 0);
1801 rb_ary_push(th->pending_interrupt_mask_stack, mask);
1802 if (!rb_threadptr_pending_interrupt_empty_p(th)) {
1803 th->pending_interrupt_queue_checked = 0;
1804 RUBY_VM_SET_INTERRUPT(th);
1805 }
1806
1807 TH_PUSH_TAG(th);
1808 if ((state = EXEC_TAG()) == 0) {
1809 r = rb_yield(Qnil);
1810 }
1811 TH_POP_TAG();
1812
1813 rb_ary_pop(th->pending_interrupt_mask_stack);
1814 if (!rb_threadptr_pending_interrupt_empty_p(th)) {
1815 th->pending_interrupt_queue_checked = 0;
1816 RUBY_VM_SET_INTERRUPT(th);
1817 }
1818
1819 RUBY_VM_CHECK_INTS(th);
1820
1821 if (state) {
1822 JUMP_TAG(state);
1823 }
1824
1825 return r;
1826 }
1827
1828 /*
1829 * call-seq:
1830 * target_thread.pending_interrupt?(error = nil) -> true/false
1831 *
1832 * Returns whether or not the asynchronous queue is empty for the target thread.
1833 *
1834 * If +error+ is given, then check only for +error+ type deferred events.
1835 *
1836 * See ::pending_interrupt? for more information.
1837 */
1838 static VALUE
1839 rb_thread_pending_interrupt_p(int argc, VALUE *argv, VALUE target_thread)
1840 {
1841 rb_thread_t *target_th;
1842
1843 GetThreadPtr(target_thread, target_th);
1844
1845 if (rb_threadptr_pending_interrupt_empty_p(target_th)) {
1846 return Qfalse;
1847 }
1848 else {
1849 if (argc == 1) {
1850 VALUE err;
1851 rb_scan_args(argc, argv, "01", &err);
1852 if (!rb_obj_is_kind_of(err, rb_cModule)) {
1853 rb_raise(rb_eTypeError, "class or module required for rescue clause");
1854 }
1855 if (rb_threadptr_pending_interrupt_include_p(target_th, err)) {
1856 return Qtrue;
1857 }
1858 else {
1859 return Qfalse;
1860 }
1861 }
1862 return Qtrue;
1863 }
1864 }
1865
1866 /*
1867 * call-seq:
1868 * Thread.pending_interrupt?(error = nil) -> true/false
1869 *
1870 * Returns whether or not the asynchronous queue is empty.
1871 *
1872 * Since Thread::handle_interrupt can be used to defer asynchronous events,
1873 * this method can be used to determine if there are any deferred events.
1874 *
1875 * If you find this method returns true, then you may finish +:never+ blocks.
1876 *
1877 * For example, the following method processes deferred asynchronous events
1878 * immediately.
1879 *
1880 * def Thread.kick_interrupt_immediately
1881 * Thread.handle_interrupt(Object => :immediate) {
1882 * Thread.pass
1883 * }
1884 * end
1885 *
1886 * If +error+ is given, then check only for +error+ type deferred events.
1887 *
1888 * === Usage
1889 *
1890 * th = Thread.new{
1891 * Thread.handle_interrupt(RuntimeError => :on_blocking){
1892 * while true
1893 * ...
1894 * # reach safe point to invoke interrupt
1895 * if Thread.pending_interrupt?
1896 * Thread.handle_interrupt(Object => :immediate){}
1897 * end
1898 * ...
1899 * end
1900 * }
1901 * }
1902 * ...
1903 * th.raise # stop thread
1904 *
1905 * This example can also be written as the following, which you should use to
1906 * avoid asynchronous interrupts.
1907 *
1908 * flag = true
1909 * th = Thread.new{
1910 * Thread.handle_interrupt(RuntimeError => :on_blocking){
1911 * while true
1912 * ...
1913 * # reach safe point to invoke interrupt
1914 * break if flag == false
1915 * ...
1916 * end
1917 * }
1918 * }
1919 * ...
1920 * flag = false # stop thread
1921 */
1922
1923 static VALUE
1924 rb_thread_s_pending_interrupt_p(int argc, VALUE *argv, VALUE self)
1925 {
1926 return rb_thread_pending_interrupt_p(argc, argv, GET_THREAD()->self);
1927 }
1928
1929 static void
1930 rb_threadptr_to_kill(rb_thread_t *th)
1931 {
1932 rb_threadptr_pending_interrupt_clear(th);
1933 th->status = THREAD_RUNNABLE;
1934 th->to_kill = 1;
1935 th->errinfo = INT2FIX(TAG_FATAL);
1936 TH_JUMP_TAG(th, TAG_FATAL);
1937 }
1938
1939 static inline rb_atomic_t
1940 threadptr_get_interrupts(rb_thread_t *th)
1941 {
1942 rb_atomic_t interrupt;
1943 rb_atomic_t old;
1944
1945 do {
1946 interrupt = th->interrupt_flag;
1947 old = ATOMIC_CAS(th->interrupt_flag, interrupt, interrupt & th->interrupt_mask);
1948 } while (old != interrupt);
1949 return interrupt & (rb_atomic_t)~th->interrupt_mask;
1950 }
1951
1952 void
1953 rb_threadptr_execute_interrupts(rb_thread_t *th, int blocking_timing)
1954 {
1955 rb_atomic_t interrupt;
1956 int postponed_job_interrupt = 0;
1957
1958 if (th->raised_flag) return;
1959
1960 while ((interrupt = threadptr_get_interrupts(th)) != 0) {
1961 int sig;
1962 int timer_interrupt;
1963 int pending_interrupt;
1964 int trap_interrupt;
1965
1966 timer_interrupt = interrupt & TIMER_INTERRUPT_MASK;
1967 pending_interrupt = interrupt & PENDING_INTERRUPT_MASK;
1968 postponed_job_interrupt = interrupt & POSTPONED_JOB_INTERRUPT_MASK;
1969 trap_interrupt = interrupt & TRAP_INTERRUPT_MASK;
1970
1971 if (postponed_job_interrupt) {
1972 rb_postponed_job_flush(th->vm);
1973 }
1974
1975 /* signal handling */
1976 if (trap_interrupt && (th == th->vm->main_thread)) {
1977 enum rb_thread_status prev_status = th->status;
1978 th->status = THREAD_RUNNABLE;
1979 while ((sig = rb_get_next_signal()) != 0) {
1980 rb_signal_exec(th, sig);
1981 }
1982 th->status = prev_status;
1983 }
1984
1985 /* exception from another thread */
1986 if (pending_interrupt && rb_threadptr_pending_interrupt_active_p(th)) {
1987 VALUE err = rb_threadptr_pending_interrupt_deque(th, blocking_timing ? INTERRUPT_ON_BLOCKING : INTERRUPT_NONE);
1988 thread_debug("rb_thread_execute_interrupts: %"PRIdVALUE"\n", err);
1989
1990 if (err == Qundef) {
1991 /* no error */
1992 }
1993 else if (err == eKillSignal /* Thread#kill received */ ||
1994 err == eTerminateSignal /* Terminate thread */ ||
1995 err == INT2FIX(TAG_FATAL) /* Thread.exit etc. */ ) {
1996 rb_threadptr_to_kill(th);
1997 }
1998 else {
1999 /* set runnable if th was slept. */
2000 if (th->status == THREAD_STOPPED ||
2001 th->status == THREAD_STOPPED_FOREVER)
2002 th->status = THREAD_RUNNABLE;
2003 rb_exc_raise(err);
2004 }
2005 }
2006
2007 if (timer_interrupt) {
2008 unsigned long limits_us = TIME_QUANTUM_USEC;
2009
2010 if (th->priority > 0)
2011 limits_us <<= th->priority;
2012 else
2013 limits_us >>= -th->priority;
2014
2015 if (th->status == THREAD_RUNNABLE)
2016 th->running_time_us += TIME_QUANTUM_USEC;
2017
2018 EXEC_EVENT_HOOK(th, RUBY_INTERNAL_EVENT_SWITCH, th->cfp->self, 0, 0, Qundef);
2019
2020 rb_thread_schedule_limits(limits_us);
2021 }
2022 }
2023 }
2024
2025 void
2026 rb_thread_execute_interrupts(VALUE thval)
2027 {
2028 rb_thread_t *th;
2029 GetThreadPtr(thval, th);
2030 rb_threadptr_execute_interrupts(th, 1);
2031 }
2032
2033 static void
2034 rb_threadptr_ready(rb_thread_t *th)
2035 {
2036 rb_threadptr_interrupt(th);
2037 }
2038
2039 static VALUE
2040 rb_threadptr_raise(rb_thread_t *th, int argc, VALUE *argv)
2041 {
2042 VALUE exc;
2043
2044 if (rb_threadptr_dead(th)) {
2045 return Qnil;
2046 }
2047
2048 if (argc == 0) {
2049 exc = rb_exc_new(rb_eRuntimeError, 0, 0);
2050 }
2051 else {
2052 exc = rb_make_exception(argc, argv);
2053 }
2054 rb_threadptr_pending_interrupt_enque(th, exc);
2055 rb_threadptr_interrupt(th);
2056 return Qnil;
2057 }
2058
2059 void
2060 rb_threadptr_signal_raise(rb_thread_t *th, int sig)
2061 {
2062 VALUE argv[2];
2063
2064 argv[0] = rb_eSignal;
2065 argv[1] = INT2FIX(sig);
2066 rb_threadptr_raise(th->vm->main_thread, 2, argv);
2067 }
2068
2069 void
2070 rb_threadptr_signal_exit(rb_thread_t *th)
2071 {
2072 VALUE argv[2];
2073
2074 argv[0] = rb_eSystemExit;
2075 argv[1] = rb_str_new2("exit");
2076 rb_threadptr_raise(th->vm->main_thread, 2, argv);
2077 }
2078
2079 #if defined(POSIX_SIGNAL) && defined(SIGSEGV) && defined(HAVE_SIGALTSTACK)
2080 #define USE_SIGALTSTACK
2081 #endif
2082
2083 void
2084 ruby_thread_stack_overflow(rb_thread_t *th)
2085 {
2086 th->raised_flag = 0;
2087 #ifdef USE_SIGALTSTACK
2088 rb_exc_raise(sysstack_error);
2089 #else
2090 th->errinfo = sysstack_error;
2091 TH_JUMP_TAG(th, TAG_RAISE);
2092 #endif
2093 }
2094
2095 int
2096 rb_threadptr_set_raised(rb_thread_t *th)
2097 {
2098 if (th->raised_flag & RAISED_EXCEPTION) {
2099 return 1;
2100 }
2101 th->raised_flag |= RAISED_EXCEPTION;
2102 return 0;
2103 }
2104
2105 int
2106 rb_threadptr_reset_raised(rb_thread_t *th)
2107 {
2108 if (!(th->raised_flag & RAISED_EXCEPTION)) {
2109 return 0;
2110 }
2111 th->raised_flag &= ~RAISED_EXCEPTION;
2112 return 1;
2113 }
2114
2115 static int
2116 thread_fd_close_i(st_data_t key, st_data_t val, st_data_t data)
2117 {
2118 int fd = (int)data;
2119 rb_thread_t *th;
2120 GetThreadPtr((VALUE)key, th);
2121
2122 if (th->waiting_fd == fd) {
2123 VALUE err = th->vm->special_exceptions[ruby_error_closed_stream];
2124 rb_threadptr_pending_interrupt_enque(th, err);
2125 rb_threadptr_interrupt(th);
2126 }
2127 return ST_CONTINUE;
2128 }
2129
2130 void
2131 rb_thread_fd_close(int fd)
2132 {
2133 st_foreach(GET_THREAD()->vm->living_threads, thread_fd_close_i, (st_index_t)fd);
2134 }
2135
2136 /*
2137 * call-seq:
2138 * thr.raise
2139 * thr.raise(string)
2140 * thr.raise(exception [, string [, array]])
2141 *
2142 * Raises an exception from the given thread. The caller does not have to be
2143 * +thr+. See Kernel#raise for more information.
2144 *
2145 * Thread.abort_on_exception = true
2146 * a = Thread.new { sleep(200) }
2147 * a.raise("Gotcha")
2148 *
2149 * This will produce:
2150 *
2151 * prog.rb:3: Gotcha (RuntimeError)
2152 * from prog.rb:2:in `initialize'
2153 * from prog.rb:2:in `new'
2154 * from prog.rb:2
2155 */
2156
2157 static VALUE
2158 thread_raise_m(int argc, VALUE *argv, VALUE self)
2159 {
2160 rb_thread_t *target_th;
2161 rb_thread_t *th = GET_THREAD();
2162 GetThreadPtr(self, target_th);
2163 rb_threadptr_raise(target_th, argc, argv);
2164
2165 /* To perform Thread.current.raise as Kernel.raise */
2166 if (th == target_th) {
2167 RUBY_VM_CHECK_INTS(th);
2168 }
2169 return Qnil;
2170 }
2171
2172
2173 /*
2174 * call-seq:
2175 * thr.exit -> thr or nil
2176 * thr.kill -> thr or nil
2177 * thr.terminate -> thr or nil
2178 *
2179 * Terminates +thr+ and schedules another thread to be run.
2180 *
2181 * If this thread is already marked to be killed, #exit returns the Thread.
2182 *
2183 * If this is the main thread, or the last thread, exits the process.
2184 */
2185
2186 VALUE
2187 rb_thread_kill(VALUE thread)
2188 {
2189 rb_thread_t *th;
2190
2191 GetThreadPtr(thread, th);
2192
2193 if (th->to_kill || th->status == THREAD_KILLED) {
2194 return thread;
2195 }
2196 if (th == th->vm->main_thread) {
2197 rb_exit(EXIT_SUCCESS);
2198 }
2199
2200 thread_debug("rb_thread_kill: %p (%p)\n", (void *)th, (void *)th->thread_id);
2201
2202 if (th == GET_THREAD()) {
2203 /* kill myself immediately */
2204 rb_threadptr_to_kill(th);
2205 }
2206 else {
2207 rb_threadptr_pending_interrupt_enque(th, eKillSignal);
2208 rb_threadptr_interrupt(th);
2209 }
2210 return thread;
2211 }
2212
2213
2214 /*
2215 * call-seq:
2216 * Thread.kill(thread) -> thread
2217 *
2218 * Causes the given +thread+ to exit, see also Thread::exit.
2219 *
2220 * count = 0
2221 * a = Thread.new { loop { count += 1 } }
2222 * sleep(0.1) #=> 0
2223 * Thread.kill(a) #=> #<Thread:0x401b3d30 dead>
2224 * count #=> 93947
2225 * a.alive? #=> false
2226 */
2227
2228 static VALUE
2229 rb_thread_s_kill(VALUE obj, VALUE th)
2230 {
2231 return rb_thread_kill(th);
2232 }
2233
2234
2235 /*
2236 * call-seq:
2237 * Thread.exit -> thread
2238 *
2239 * Terminates the currently running thread and schedules another thread to be
2240 * run.
2241 *
2242 * If this thread is already marked to be killed, ::exit returns the Thread.
2243 *
2244 * If this is the main thread, or the last thread, exit the process.
2245 */
2246
2247 static VALUE
2248 rb_thread_exit(void)
2249 {
2250 rb_thread_t *th = GET_THREAD();
2251 return rb_thread_kill(th->self);
2252 }
2253
2254
2255 /*
2256 * call-seq:
2257 * thr.wakeup -> thr
2258 *
2259 * Marks a given thread as eligible for scheduling, however it may still
2260 * remain blocked on I/O.
2261 *
2262 * *Note:* This does not invoke the scheduler, see #run for more information.
2263 *
2264 * c = Thread.new { Thread.stop; puts "hey!" }
2265 * sleep 0.1 while c.status!='sleep'
2266 * c.wakeup
2267 * c.join
2268 * #=> "hey!"
2269 */
2270
2271 VALUE
2272 rb_thread_wakeup(VALUE thread)
2273 {
2274 if (!RTEST(rb_thread_wakeup_alive(thread))) {
2275 rb_raise(rb_eThreadError, "killed thread");
2276 }
2277 return thread;
2278 }
2279
2280 VALUE
2281 rb_thread_wakeup_alive(VALUE thread)
2282 {
2283 rb_thread_t *th;
2284 GetThreadPtr(thread, th);
2285
2286 if (th->status == THREAD_KILLED) {
2287 return Qnil;
2288 }
2289 rb_threadptr_ready(th);
2290 if (th->status == THREAD_STOPPED || th->status == THREAD_STOPPED_FOREVER)
2291 th->status = THREAD_RUNNABLE;
2292 return thread;
2293 }
2294
2295
2296 /*
2297 * call-seq:
2298 * thr.run -> thr
2299 *
2300 * Wakes up +thr+, making it eligible for scheduling.
2301 *
2302 * a = Thread.new { puts "a"; Thread.stop; puts "c" }
2303 * sleep 0.1 while a.status!='sleep'
2304 * puts "Got here"
2305 * a.run
2306 * a.join
2307 *
2308 * This will produce:
2309 *
2310 * a
2311 * Got here
2312 * c
2313 *
2314 * See also the instance method #wakeup.
2315 */
2316
2317 VALUE
2318 rb_thread_run(VALUE thread)
2319 {
2320 rb_thread_wakeup(thread);
2321 rb_thread_schedule();
2322 return thread;
2323 }
2324
2325
2326 /*
2327 * call-seq:
2328 * Thread.stop -> nil
2329 *
2330 * Stops execution of the current thread, putting it into a ``sleep'' state,
2331 * and schedules execution of another thread.
2332 *
2333 * a = Thread.new { print "a"; Thread.stop; print "c" }
2334 * sleep 0.1 while a.status!='sleep'
2335 * print "b"
2336 * a.run
2337 * a.join
2338 * #=> "abc"
2339 */
2340
2341 VALUE
2342 rb_thread_stop(void)
2343 {
2344 if (rb_thread_alone()) {
2345 rb_raise(rb_eThreadError,
2346 "stopping only thread\n\tnote: use sleep to stop forever");
2347 }
2348 rb_thread_sleep_deadly();
2349 return Qnil;
2350 }
2351
2352 static int
2353 thread_list_i(st_data_t key, st_data_t val, void *data)
2354 {
2355 VALUE ary = (VALUE)data;
2356 rb_thread_t *th;
2357 GetThreadPtr((VALUE)key, th);
2358
2359 switch (th->status) {
2360 case THREAD_RUNNABLE:
2361 case THREAD_STOPPED:
2362 case THREAD_STOPPED_FOREVER:
2363 rb_ary_push(ary, th->self);
2364 default:
2365 break;
2366 }
2367 return ST_CONTINUE;
2368 }
2369
2370 /********************************************************************/
2371
2372 /*
2373 * call-seq:
2374 * Thread.list -> array
2375 *
2376 * Returns an array of Thread objects for all threads that are either runnable
2377 * or stopped.
2378 *
2379 * Thread.new { sleep(200) }
2380 * Thread.new { 1000000.times {|i| i*i } }
2381 * Thread.new { Thread.stop }
2382 * Thread.list.each {|t| p t}
2383 *
2384 * This will produce:
2385 *
2386 * #<Thread:0x401b3e84 sleep>
2387 * #<Thread:0x401b3f38 run>
2388 * #<Thread:0x401b3fb0 sleep>
2389 * #<Thread:0x401bdf4c run>
2390 */
2391
2392 VALUE
2393 rb_thread_list(void)
2394 {
2395 VALUE ary = rb_ary_new();
2396 st_foreach(GET_THREAD()->vm->living_threads, thread_list_i, ary);
2397 return ary;
2398 }
2399
2400 VALUE
2401 rb_thread_current(void)
2402 {
2403 return GET_THREAD()->self;
2404 }
2405
2406 /*
2407 * call-seq:
2408 * Thread.current -> thread
2409 *
2410 * Returns the currently executing thread.
2411 *
2412 * Thread.current #=> #<Thread:0x401bdf4c run>
2413 */
2414
2415 static VALUE
2416 thread_s_current(VALUE klass)
2417 {
2418 return rb_thread_current();
2419 }
2420
2421 VALUE
2422 rb_thread_main(void)
2423 {
2424 return GET_THREAD()->vm->main_thread->self;
2425 }
2426
2427 /*
2428 * call-seq:
2429 * Thread.main -> thread
2430 *
2431 * Returns the main thread.
2432 */
2433
2434 static VALUE
2435 rb_thread_s_main(VALUE klass)
2436 {
2437 return rb_thread_main();
2438 }
2439
2440
2441 /*
2442 * call-seq:
2443 * Thread.abort_on_exception -> true or false
2444 *
2445 * Returns the status of the global ``abort on exception'' condition.
2446 *
2447 * The default is +false+.
2448 *
2449 * When set to +true+, all threads will abort (the process will
2450 * <code>exit(0)</code>) if an exception is raised in any thread.
2451 *
2452 * Can also be specified by the global $DEBUG flag or command line option
2453 * +-d+.
2454 *
2455 * See also ::abort_on_exception=.
2456 *
2457 * There is also an instance level method to set this for a specific thread,
2458 * see #abort_on_exception.
2459 */
2460
2461 static VALUE
2462 rb_thread_s_abort_exc(void)
2463 {
2464 return GET_THREAD()->vm->thread_abort_on_exception ? Qtrue : Qfalse;
2465 }
2466
2467
2468 /*
2469 * call-seq:
2470 * Thread.abort_on_exception= boolean -> true or false
2471 *
2472 * When set to +true+, all threads will abort if an exception is raised.
2473 * Returns the new state.
2474 *
2475 * Thread.abort_on_exception = true
2476 * t1 = Thread.new do
2477 * puts "In new thread"
2478 * raise "Exception from thread"
2479 * end
2480 * sleep(1)
2481 * puts "not reached"
2482 *
2483 * This will produce:
2484 *
2485 * In new thread
2486 * prog.rb:4: Exception from thread (RuntimeError)
2487 * from prog.rb:2:in `initialize'
2488 * from prog.rb:2:in `new'
2489 * from prog.rb:2
2490 *
2491 * See also ::abort_on_exception.
2492 *
2493 * There is also an instance level method to set this for a specific thread,
2494 * see #abort_on_exception=.
2495 */
2496
2497 static VALUE
2498 rb_thread_s_abort_exc_set(VALUE self, VALUE val)
2499 {
2500 GET_THREAD()->vm->thread_abort_on_exception = RTEST(val);
2501 return val;
2502 }
2503
2504
2505 /*
2506 * call-seq:
2507 * thr.abort_on_exception -> true or false
2508 *
2509 * Returns the status of the thread-local ``abort on exception'' condition for
2510 * this +thr+.
2511 *
2512 * The default is +false+.
2513 *
2514 * See also #abort_on_exception=.
2515 *
2516 * There is also a class level method to set this for all threads, see
2517 * ::abort_on_exception.
2518 */
2519
2520 static VALUE
2521 rb_thread_abort_exc(VALUE thread)
2522 {
2523 rb_thread_t *th;
2524 GetThreadPtr(thread, th);
2525 return th->abort_on_exception ? Qtrue : Qfalse;
2526 }
2527
2528
2529 /*
2530 * call-seq:
2531 * thr.abort_on_exception= boolean -> true or false
2532 *
2533 * When set to +true+, all threads (including the main program) will abort if
2534 * an exception is raised in this +thr+.
2535 *
2536 * The process will effectively <code>exit(0)</code>.
2537 *
2538 * See also #abort_on_exception.
2539 *
2540 * There is also a class level method to set this for all threads, see
2541 * ::abort_on_exception=.
2542 */
2543
2544 static VALUE
2545 rb_thread_abort_exc_set(VALUE thread, VALUE val)
2546 {
2547 rb_thread_t *th;
2548
2549 GetThreadPtr(thread, th);
2550 th->abort_on_exception = RTEST(val);
2551 return val;
2552 }
2553
2554
2555 /*
2556 * call-seq:
2557 * thr.group -> thgrp or nil
2558 *
2559 * Returns the ThreadGroup which contains the given thread, or returns +nil+
2560 * if +thr+ is not a member of any group.
2561 *
2562 * Thread.main.group #=> #<ThreadGroup:0x4029d914>
2563 */
2564
2565 VALUE
2566 rb_thread_group(VALUE thread)
2567 {
2568 rb_thread_t *th;
2569 VALUE group;
2570 GetThreadPtr(thread, th);
2571 group = th->thgroup;
2572
2573 if (!group) {
2574 group = Qnil;
2575 }
2576 return group;
2577 }
2578
2579 static const char *
2580 thread_status_name(rb_thread_t *th)
2581 {
2582 switch (th->status) {
2583 case THREAD_RUNNABLE:
2584 if (th->to_kill)
2585 return "aborting";
2586 else
2587 return "run";
2588 case THREAD_STOPPED:
2589 case THREAD_STOPPED_FOREVER:
2590 return "sleep";
2591 case THREAD_KILLED:
2592 return "dead";
2593 default:
2594 return "unknown";
2595 }
2596 }
2597
2598 static int
2599 rb_threadptr_dead(rb_thread_t *th)
2600 {
2601 return th->status == THREAD_KILLED;
2602 }
2603
2604
2605 /*
2606 * call-seq:
2607 * thr.status -> string, false or nil
2608 *
2609 * Returns the status of +thr+.
2610 *
2611 * [<tt>"sleep"</tt>]
2612 * Returned if this thread is sleeping or waiting on I/O
2613 * [<tt>"run"</tt>]
2614 * When this thread is executing
2615 * [<tt>"aborting"</tt>]
2616 * If this thread is aborting
2617 * [+false+]
2618 * When this thread is terminated normally
2619 * [+nil+]
2620 * If terminated with an exception.
2621 *
2622 * a = Thread.new { raise("die now") }
2623 * b = Thread.new { Thread.stop }
2624 * c = Thread.new { Thread.exit }
2625 * d = Thread.new { sleep }
2626 * d.kill #=> #<Thread:0x401b3678 aborting>
2627 * a.status #=> nil
2628 * b.status #=> "sleep"
2629 * c.status #=> false
2630 * d.status #=> "aborting"
2631 * Thread.current.status #=> "run"
2632 *
2633 * See also the instance methods #alive? and #stop?
2634 */
2635
2636 static VALUE
2637 rb_thread_status(VALUE thread)
2638 {
2639 rb_thread_t *th;
2640 GetThreadPtr(thread, th);
2641
2642 if (rb_threadptr_dead(th)) {
2643 if (!NIL_P(th->errinfo) && !FIXNUM_P(th->errinfo)
2644 /* TODO */ ) {
2645 return Qnil;
2646 }
2647 return Qfalse;
2648 }
2649 return rb_str_new2(thread_status_name(th));
2650 }
2651
2652
2653 /*
2654 * call-seq:
2655 * thr.alive? -> true or false
2656 *
2657 * Returns +true+ if +thr+ is running or sleeping.
2658 *
2659 * thr = Thread.new { }
2660 * thr.join #=> #<Thread:0x401b3fb0 dead>
2661 * Thread.current.alive? #=> true
2662 * thr.alive? #=> false
2663 *
2664 * See also #stop? and #status.
2665 */
2666
2667 static VALUE
2668 rb_thread_alive_p(VALUE thread)
2669 {
2670 rb_thread_t *th;
2671 GetThreadPtr(thread, th);
2672
2673 if (rb_threadptr_dead(th))
2674 return Qfalse;
2675 return Qtrue;
2676 }
2677
2678 /*
2679 * call-seq:
2680 * thr.stop? -> true or false
2681 *
2682 * Returns +true+ if +thr+ is dead or sleeping.
2683 *
2684 * a = Thread.new { Thread.stop }
2685 * b = Thread.current
2686 * a.stop? #=> true
2687 * b.stop? #=> false
2688 *
2689 * See also #alive? and #status.
2690 */
2691
2692 static VALUE
2693 rb_thread_stop_p(VALUE thread)
2694 {
2695 rb_thread_t *th;
2696 GetThreadPtr(thread, th);
2697
2698 if (rb_threadptr_dead(th))
2699 return Qtrue;
2700 if (th->status == THREAD_STOPPED || th->status == THREAD_STOPPED_FOREVER)
2701 return Qtrue;
2702 return Qfalse;
2703 }
2704
2705 /*
2706 * call-seq:
2707 * thr.safe_level -> integer
2708 *
2709 * Returns the safe level in effect for <i>thr</i>. Setting thread-local safe
2710 * levels can help when implementing sandboxes which run insecure code.
2711 *
2712 * thr = Thread.new { $SAFE = 3; sleep }
2713 * Thread.current.safe_level #=> 0
2714 * thr.safe_level #=> 3
2715 */
2716
2717 static VALUE
2718 rb_thread_safe_level(VALUE thread)
2719 {
2720 rb_thread_t *th;
2721 GetThreadPtr(thread, th);
2722
2723 return INT2NUM(th->safe_level);
2724 }
2725
2726 /*
2727 * call-seq:
2728 * thr.inspect -> string
2729 *
2730 * Dump the name, id, and status of _thr_ to a string.
2731 */
2732
2733 static VALUE
2734 rb_thread_inspect(VALUE thread)
2735 {
2736 const char *cname = rb_obj_classname(thread);
2737 rb_thread_t *th;
2738 const char *status;
2739 VALUE str;
2740
2741 GetThreadPtr(thread, th);
2742 status = thread_status_name(th);
2743 str = rb_sprintf("#<%s:%p %s>", cname, (void *)thread, status);
2744 OBJ_INFECT(str, thread);
2745
2746 return str;
2747 }
2748
2749 static VALUE
2750 threadptr_local_aref(rb_thread_t *th, ID id)
2751 {
2752 st_data_t val;
2753
2754 if (th->local_storage && st_lookup(th->local_storage, id, &val)) {
2755 return (VALUE)val;
2756 }
2757 return Qnil;
2758 }
2759
2760 VALUE
2761 rb_thread_local_aref(VALUE thread, ID id)
2762 {
2763 rb_thread_t *th;
2764 GetThreadPtr(thread, th);
2765 return threadptr_local_aref(th, id);
2766 }
2767
2768 /*
2769 * call-seq:
2770 * thr[sym] -> obj or nil
2771 *
2772 * Attribute Reference---Returns the value of a fiber-local variable (current thread's root fiber
2773 * if not explicitly inside a Fiber), using either a symbol or a string name.
2774 * If the specified variable does not exist, returns +nil+.
2775 *
2776 * [
2777 * Thread.new { Thread.current["name"] = "A" },
2778 * Thread.new { Thread.current[:name] = "B" },
2779 * Thread.new { Thread.current["name"] = "C" }
2780 * ].each do |th|
2781 * th.join
2782 * puts "#{th.inspect}: #{th[:name]}"
2783 * end
2784 *
2785 * This will produce:
2786 *
2787 * #<Thread:0x00000002a54220 dead>: A
2788 * #<Thread:0x00000002a541a8 dead>: B
2789 * #<Thread:0x00000002a54130 dead>: C
2790 *
2791 * Thread#[] and Thread#[]= are not thread-local but fiber-local.
2792 * This confusion did not exist in Ruby 1.8 because
2793 * fibers are only available since Ruby 1.9.
2794 * Ruby 1.9 chooses that the methods behaves fiber-local to save
2795 * following idiom for dynamic scope.
2796 *
2797 * def meth(newvalue)
2798 * begin
2799 * oldvalue = Thread.current[:name]
2800 * Thread.current[:name] = newvalue
2801 * yield
2802 * ensure
2803 * Thread.current[:name] = oldvalue
2804 * end
2805 * end
2806 *
2807 * The idiom may not work as dynamic scope if the methods are thread-local
2808 * and a given block switches fiber.
2809 *
2810 * f = Fiber.new {
2811 * meth(1) {
2812 * Fiber.yield
2813 * }
2814 * }
2815 * meth(2) {
2816 * f.resume
2817 * }
2818 * f.resume
2819 * p Thread.current[:name]
2820 * #=> nil if fiber-local
2821 * #=> 2 if thread-local (The value 2 is leaked to outside of meth method.)
2822 *
2823 * For thread-local variables, please see #thread_variable_get and
2824 * #thread_variable_set.
2825 *
2826 */
2827
2828 static VALUE
2829 rb_thread_aref(VALUE thread, VALUE key)
2830 {
2831 ID id = rb_check_id(&key);
2832 if (!id) return Qnil;
2833 return rb_thread_local_aref(thread, id);
2834 }
2835
2836 static VALUE
2837 threadptr_local_aset(rb_thread_t *th, ID id, VALUE val)
2838 {
2839 if (NIL_P(val)) {
2840 if (!th->local_storage) return Qnil;
2841 st_delete_wrap(th->local_storage, id);
2842 return Qnil;
2843 }
2844 else {
2845 if (!th->local_storage) {
2846 th->local_storage = st_init_numtable();
2847 }
2848 st_insert(th->local_storage, id, val);
2849 return val;
2850 }
2851 }
2852
2853 VALUE
2854 rb_thread_local_aset(VALUE thread, ID id, VALUE val)
2855 {
2856 rb_thread_t *th;
2857 GetThreadPtr(thread, th);
2858
2859 if (OBJ_FROZEN(thread)) {
2860 rb_error_frozen("thread locals");
2861 }
2862
2863 return threadptr_local_aset(th, id, val);
2864 }
2865
2866 /*
2867 * call-seq:
2868 * thr[sym] = obj -> obj
2869 *
2870 * Attribute Assignment---Sets or creates the value of a fiber-local variable,
2871 * using either a symbol or a string.
2872 *
2873 * See also Thread#[].
2874 *
2875 * For thread-local variables, please see #thread_variable_set and
2876 * #thread_variable_get.
2877 */
2878
2879 static VALUE
2880 rb_thread_aset(VALUE self, VALUE id, VALUE val)
2881 {
2882 return rb_thread_local_aset(self, rb_to_id(id), val);
2883 }
2884
2885 /*
2886 * call-seq:
2887 * thr.thread_variable_get(key) -> obj or nil
2888 *
2889 * Returns the value of a thread local variable that has been set. Note that
2890 * these are different than fiber local values. For fiber local values,
2891 * please see Thread#[] and Thread#[]=.
2892 *
2893 * Thread local values are carried along with threads, and do not respect
2894 * fibers. For example:
2895 *
2896 * Thread.new {
2897 * Thread.current.thread_variable_set("foo", "bar") # set a thread local
2898 * Thread.current["foo"] = "bar" # set a fiber local
2899 *
2900 * Fiber.new {
2901 * Fiber.yield [
2902 * Thread.current.thread_variable_get("foo"), # get the thread local
2903 * Thread.current["foo"], # get the fiber local
2904 * ]
2905 * }.resume
2906 * }.join.value # => ['bar', nil]
2907 *
2908 * The value "bar" is returned for the thread local, where nil is returned
2909 * for the fiber local. The fiber is executed in the same thread, so the
2910 * thread local values are available.
2911 */
2912
2913 static VALUE
2914 rb_thread_variable_get(VALUE thread, VALUE key)
2915 {
2916 VALUE locals;
2917 ID id = rb_check_id(&key);
2918
2919 if (!id) return Qnil;
2920 locals = rb_ivar_get(thread, id_locals);
2921 return rb_hash_aref(locals, ID2SYM(id));
2922 }
2923
2924 /*
2925 * call-seq:
2926 * thr.thread_variable_set(key, value)
2927 *
2928 * Sets a thread local with +key+ to +value+. Note that these are local to
2929 * threads, and not to fibers. Please see Thread#thread_variable_get and
2930 * Thread#[] for more information.
2931 */
2932
2933 static VALUE
2934 rb_thread_variable_set(VALUE thread, VALUE id, VALUE val)
2935 {
2936 VALUE locals;
2937
2938 if (OBJ_FROZEN(thread)) {
2939 rb_error_frozen("thread locals");
2940 }
2941
2942 locals = rb_ivar_get(thread, id_locals);
2943 return rb_hash_aset(locals, ID2SYM(rb_to_id(id)), val);
2944 }
2945
2946 /*
2947 * call-seq:
2948 * thr.key?(sym) -> true or false
2949 *
2950 * Returns +true+ if the given string (or symbol) exists as a fiber-local
2951 * variable.
2952 *
2953 * me = Thread.current
2954 * me[:oliver] = "a"
2955 * me.key?(:oliver) #=> true
2956 * me.key?(:stanley) #=> false
2957 */
2958
2959 static VALUE
2960 rb_thread_key_p(VALUE self, VALUE key)
2961 {
2962 rb_thread_t *th;
2963 ID id = rb_check_id(&key);
2964
2965 GetThreadPtr(self, th);
2966
2967 if (!id || !th->local_storage) {
2968 return Qfalse;
2969 }
2970 if (st_lookup(th->local_storage, id, 0)) {
2971 return Qtrue;
2972 }
2973 return Qfalse;
2974 }
2975
2976 static int
2977 thread_keys_i(ID key, VALUE value, VALUE ary)
2978 {
2979 rb_ary_push(ary, ID2SYM(key));
2980 return ST_CONTINUE;
2981 }
2982
2983 static int
2984 vm_living_thread_num(rb_vm_t *vm)
2985 {
2986 return (int)vm->living_threads->num_entries;
2987 }
2988
2989 int
2990 rb_thread_alone(void)
2991 {
2992 int num = 1;
2993 if (GET_THREAD()->vm->living_threads) {
2994 num = vm_living_thread_num(GET_THREAD()->vm);
2995 thread_debug("rb_thread_alone: %d\n", num);
2996 }
2997 return num == 1;
2998 }
2999
3000 /*
3001 * call-seq:
3002 * thr.keys -> array
3003 *
3004 * Returns an array of the names of the fiber-local variables (as Symbols).
3005 *
3006 * thr = Thread.new do
3007 * Thread.current[:cat] = 'meow'
3008 * Thread.current["dog"] = 'woof'
3009 * end
3010 * thr.join #=> #<Thread:0x401b3f10 dead>
3011 * thr.keys #=> [:dog, :cat]
3012 */
3013
3014 static VALUE
3015 rb_thread_keys(VALUE self)
3016 {
3017 rb_thread_t *th;
3018 VALUE ary = rb_ary_new();
3019 GetThreadPtr(self, th);
3020
3021 if (th->local_storage) {
3022 st_foreach(th->local_storage, thread_keys_i, ary);
3023 }
3024 return ary;
3025 }
3026
3027 static int
3028 keys_i(VALUE key, VALUE value, VALUE ary)
3029 {
3030 rb_ary_push(ary, key);
3031 return ST_CONTINUE;
3032 }
3033
3034 /*
3035 * call-seq:
3036 * thr.thread_variables -> array
3037 *
3038 * Returns an array of the names of the thread-local variables (as Symbols).
3039 *
3040 * thr = Thread.new do
3041 * Thread.current.thread_variable_set(:cat, 'meow')
3042 * Thread.current.thread_variable_set("dog", 'woof')
3043 * end
3044 * thr.join #=> #<Thread:0x401b3f10 dead>
3045 * thr.thread_variables #=> [:dog, :cat]
3046 *
3047 * Note that these are not fiber local variables. Please see Thread#[] and
3048 * Thread#thread_variable_get for more details.
3049 */
3050
3051 static VALUE
3052 rb_thread_variables(VALUE thread)
3053 {
3054 VALUE locals;
3055 VALUE ary;
3056
3057 locals = rb_ivar_get(thread, id_locals);
3058 ary = rb_ary_new();
3059 rb_hash_foreach(locals, keys_i, ary);
3060
3061 return ary;
3062 }
3063
3064 /*
3065 * call-seq:
3066 * thr.thread_variable?(key) -> true or false
3067 *
3068 * Returns +true+ if the given string (or symbol) exists as a thread-local
3069 * variable.
3070 *
3071 * me = Thread.current
3072 * me.thread_variable_set(:oliver, "a")
3073 * me.thread_variable?(:oliver) #=> true
3074 * me.thread_variable?(:stanley) #=> false
3075 *
3076 * Note that these are not fiber local variables. Please see Thread#[] and
3077 * Thread#thread_variable_get for more details.
3078 */
3079
3080 static VALUE
3081 rb_thread_variable_p(VALUE thread, VALUE key)
3082 {
3083 VALUE locals;
3084 ID id = rb_check_id(&key);
3085
3086 if (!id) return Qfalse;
3087
3088 locals = rb_ivar_get(thread, id_locals);
3089
3090 if (!RHASH(locals)->ntbl)
3091 return Qfalse;
3092
3093 if (st_lookup(RHASH(locals)->ntbl, ID2SYM(id), 0)) {
3094 return Qtrue;
3095 }
3096
3097 return Qfalse;
3098 }
3099
3100 /*
3101 * call-seq:
3102 * thr.priority -> integer
3103 *
3104 * Returns the priority of <i>thr</i>. Default is inherited from the
3105 * current thread which creating the new thread, or zero for the
3106 * initial main thread; higher-priority thread will run more frequently
3107 * than lower-priority threads (but lower-priority threads can also run).
3108 *
3109 * This is just hint for Ruby thread scheduler. It may be ignored on some
3110 * platform.
3111 *
3112 * Thread.current.priority #=> 0
3113 */
3114
3115 static VALUE
3116 rb_thread_priority(VALUE thread)
3117 {
3118 rb_thread_t *th;
3119 GetThreadPtr(thread, th);
3120 return INT2NUM(th->priority);
3121 }
3122
3123
3124 /*
3125 * call-seq:
3126 * thr.priority= integer -> thr
3127 *
3128 * Sets the priority of <i>thr</i> to <i>integer</i>. Higher-priority threads
3129 * will run more frequently than lower-priority threads (but lower-priority
3130 * threads can also run).
3131 *
3132 * This is just hint for Ruby thread scheduler. It may be ignored on some
3133 * platform.
3134 *
3135 * count1 = count2 = 0
3136 * a = Thread.new do
3137 * loop { count1 += 1 }
3138 * end
3139 * a.priority = -1
3140 *
3141 * b = Thread.new do
3142 * loop { count2 += 1 }
3143 * end
3144 * b.priority = -2
3145 * sleep 1 #=> 1
3146 * count1 #=> 622504
3147 * count2 #=> 5832
3148 */
3149
3150 static VALUE
3151 rb_thread_priority_set(VALUE thread, VALUE prio)
3152 {
3153 rb_thread_t *th;
3154 int priority;
3155 GetThreadPtr(thread, th);
3156
3157
3158 #if USE_NATIVE_THREAD_PRIORITY
3159 th->priority = NUM2INT(prio);
3160 native_thread_apply_priority(th);
3161 #else
3162 priority = NUM2INT(prio);
3163 if (priority > RUBY_THREAD_PRIORITY_MAX) {
3164 priority = RUBY_THREAD_PRIORITY_MAX;
3165 }
3166 else if (priority < RUBY_THREAD_PRIORITY_MIN) {
3167 priority = RUBY_THREAD_PRIORITY_MIN;
3168 }
3169 th->priority = priority;
3170 #endif
3171 return INT2NUM(th->priority);
3172 }
3173
3174 /* for IO */
3175
3176 #if defined(NFDBITS) && defined(HAVE_RB_FD_INIT)
3177
3178 /*
3179 * several Unix platforms support file descriptors bigger than FD_SETSIZE
3180 * in select(2) system call.
3181 *
3182 * - Linux 2.2.12 (?)
3183 * - NetBSD 1.2 (src/sys/kern/sys_generic.c:1.25)
3184 * select(2) documents how to allocate fd_set dynamically.
3185 * http://netbsd.gw.com/cgi-bin/man-cgi?select++NetBSD-4.0
3186 * - FreeBSD 2.2 (src/sys/kern/sys_generic.c:1.19)
3187 * - OpenBSD 2.0 (src/sys/kern/sys_generic.c:1.4)
3188 * select(2) documents how to allocate fd_set dynamically.
3189 * http://www.openbsd.org/cgi-bin/man.cgi?query=select&manpath=OpenBSD+4.4
3190 * - HP-UX documents how to allocate fd_set dynamically.
3191 * http://docs.hp.com/en/B2355-60105/select.2.html
3192 * - Solaris 8 has select_large_fdset
3193 * - Mac OS X 10.7 (Lion)
3194 * select(2) returns EINVAL if nfds is greater than FD_SET_SIZE and
3195 * _DARWIN_UNLIMITED_SELECT (or _DARWIN_C_SOURCE) isn't defined.
3196 * http://developer.apple.com/library/mac/#releasenotes/Darwin/SymbolVariantsRelNotes/_index.html
3197 *
3198 * When fd_set is not big enough to hold big file descriptors,
3199 * it should be allocated dynamically.
3200 * Note that this assumes fd_set is structured as bitmap.
3201 *
3202 * rb_fd_init allocates the memory.
3203 * rb_fd_term free the memory.
3204 * rb_fd_set may re-allocates bitmap.
3205 *
3206 * So rb_fd_set doesn't reject file descriptors bigger than FD_SETSIZE.
3207 */
3208
3209 void
3210 rb_fd_init(rb_fdset_t *fds)
3211 {
3212 fds->maxfd = 0;
3213 fds->fdset = ALLOC(fd_set);
3214 FD_ZERO(fds->fdset);
3215 }
3216
3217 void
3218 rb_fd_init_copy(rb_fdset_t *dst, rb_fdset_t *src)
3219 {
3220 size_t size = howmany(rb_fd_max(src), NFDBITS) * sizeof(fd_mask);
3221
3222 if (size < sizeof(fd_set))
3223 size = sizeof(fd_set);
3224 dst->maxfd = src->maxfd;
3225 dst->fdset = xmalloc(size);
3226 memcpy(dst->fdset, src->fdset, size);
3227 }
3228
3229 void
3230 rb_fd_term(rb_fdset_t *fds)
3231 {
3232 if (fds->fdset) xfree(fds->fdset);
3233 fds->maxfd = 0;
3234 fds->fdset = 0;
3235 }
3236
3237 void
3238 rb_fd_zero(rb_fdset_t *fds)
3239 {
3240 if (fds->fdset)
3241 MEMZERO(fds->fdset, fd_mask, howmany(fds->maxfd, NFDBITS));
3242 }
3243
3244 static void
3245 rb_fd_resize(int n, rb_fdset_t *fds)
3246 {
3247 size_t m = howmany(n + 1, NFDBITS) * sizeof(fd_mask);
3248 size_t o = howmany(fds->maxfd, NFDBITS) * sizeof(fd_mask);
3249
3250 if (m < sizeof(fd_set)) m = sizeof(fd_set);
3251 if (o < sizeof(fd_set)) o = sizeof(fd_set);
3252
3253 if (m > o) {
3254 fds->fdset = xrealloc(fds->fdset, m);
3255 memset((char *)fds->fdset + o, 0, m - o);
3256 }
3257 if (n >= fds->maxfd) fds->maxfd = n + 1;
3258 }
3259
3260 void
3261 rb_fd_set(int n, rb_fdset_t *fds)
3262 {
3263 rb_fd_resize(n, fds);
3264 FD_SET(n, fds->fdset);
3265 }
3266
3267 void
3268 rb_fd_clr(int n, rb_fdset_t *fds)
3269 {
3270 if (n >= fds->maxfd) return;
3271 FD_CLR(n, fds->fdset);
3272 }
3273
3274 int
3275 rb_fd_isset(int n, const rb_fdset_t *fds)
3276 {
3277 if (n >= fds->maxfd) return 0;
3278 return FD_ISSET(n, fds->fdset) != 0; /* "!= 0" avoids FreeBSD PR 91421 */
3279 }
3280
3281 void
3282 rb_fd_copy(rb_fdset_t *dst, const fd_set *src, int max)
3283 {
3284 size_t size = howmany(max, NFDBITS) * sizeof(fd_mask);
3285
3286 if (size < sizeof(fd_set)) size = sizeof(fd_set);
3287 dst->maxfd = max;
3288 dst->fdset = xrealloc(dst->fdset, size);
3289 memcpy(dst->fdset, src, size);
3290 }
3291
3292 static void
3293 rb_fd_rcopy(fd_set *dst, rb_fdset_t *src)
3294 {
3295 size_t size = howmany(rb_fd_max(src), NFDBITS) * sizeof(fd_mask);
3296
3297 if (size > sizeof(fd_set)) {
3298 rb_raise(rb_eArgError, "too large fdsets");
3299 }
3300 memcpy(dst, rb_fd_ptr(src), sizeof(fd_set));
3301 }
3302
3303 void
3304 rb_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src)
3305 {
3306 size_t size = howmany(rb_fd_max(src), NFDBITS) * sizeof(fd_mask);
3307
3308 if (size < sizeof(fd_set))
3309 size = sizeof(fd_set);
3310 dst->maxfd = src->maxfd;
3311 dst->fdset = xrealloc(dst->fdset, size);
3312 memcpy(dst->fdset, src->fdset, size);
3313 }
3314
3315 #ifdef __native_client__
3316 int select(int nfds, fd_set *readfds, fd_set *writefds,
3317 fd_set *exceptfds, struct timeval *timeout);
3318 #endif
3319
3320 int
3321 rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout)
3322 {
3323 fd_set *r = NULL, *w = NULL, *e = NULL;
3324 if (readfds) {
3325 rb_fd_resize(n - 1, readfds);
3326 r = rb_fd_ptr(readfds);
3327 }
3328 if (writefds) {
3329 rb_fd_resize(n - 1, writefds);
3330 w = rb_fd_ptr(writefds);
3331 }
3332 if (exceptfds) {
3333 rb_fd_resize(n - 1, exceptfds);
3334 e = rb_fd_ptr(exceptfds);
3335 }
3336 return select(n, r, w, e, timeout);
3337 }
3338
3339 #undef FD_ZERO
3340 #undef FD_SET
3341 #undef FD_CLR
3342 #undef FD_ISSET
3343
3344 #define FD_ZERO(f) rb_fd_zero(f)
3345 #define FD_SET(i, f) rb_fd_set((i), (f))
3346 #define FD_CLR(i, f) rb_fd_clr((i), (f))
3347 #define FD_ISSET(i, f) rb_fd_isset((i), (f))
3348
3349 #elif defined(_WIN32)
3350
3351 void
3352 rb_fd_init(rb_fdset_t *set)
3353 {
3354 set->capa = FD_SETSIZE;
3355 set->fdset = ALLOC(fd_set);
3356 FD_ZERO(set->fdset);
3357 }
3358
3359 void
3360 rb_fd_init_copy(rb_fdset_t *dst, rb_fdset_t *src)
3361 {
3362 rb_fd_init(dst);
3363 rb_fd_dup(dst, src);
3364 }
3365
3366 static void
3367 rb_fd_rcopy(fd_set *dst, rb_fdset_t *src)
3368 {
3369 int max = rb_fd_max(src);
3370
3371 /* we assume src is the result of select() with dst, so dst should be
3372 * larger or equal than src. */
3373 if (max > FD_SETSIZE || (UINT)max > dst->fd_count) {
3374 rb_raise(rb_eArgError, "too large fdsets");
3375 }
3376
3377 memcpy(dst->fd_array, src->fdset->fd_array, max);
3378 dst->fd_count = max;
3379 }
3380
3381 void
3382 rb_fd_term(rb_fdset_t *set)
3383 {
3384 xfree(set->fdset);
3385 set->fdset = NULL;
3386 set->capa = 0;
3387 }
3388
3389 void
3390 rb_fd_set(int fd, rb_fdset_t *set)
3391 {
3392 unsigned int i;
3393 SOCKET s = rb_w32_get_osfhandle(fd);
3394
3395 for (i = 0; i < set->fdset->fd_count; i++) {
3396 if (set->fdset->fd_array[i] == s) {
3397 return;
3398 }
3399 }
3400 if (set->fdset->fd_count >= (unsigned)set->capa) {
3401 set->capa = (set->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
3402 set->fdset = xrealloc(set->fdset, sizeof(unsigned int) + sizeof(SOCKET) * set->capa);
3403 }
3404 set->fdset->fd_array[set->fdset->fd_count++] = s;
3405 }
3406
3407 #undef FD_ZERO
3408 #undef FD_SET
3409 #undef FD_CLR
3410 #undef FD_ISSET
3411
3412 #define FD_ZERO(f) rb_fd_zero(f)
3413 #define FD_SET(i, f) rb_fd_set((i), (f))
3414 #define FD_CLR(i, f) rb_fd_clr((i), (f))
3415 #define FD_ISSET(i, f) rb_fd_isset((i), (f))
3416
3417 #else
3418 #define rb_fd_rcopy(d, s) (*(d) = *(s))
3419 #endif
3420
3421 static int
3422 do_select(int n, rb_fdset_t *read, rb_fdset_t *write, rb_fdset_t *except,
3423 struct timeval *timeout)
3424 {
3425 int UNINITIALIZED_VAR(result);
3426 int lerrno;
3427 rb_fdset_t UNINITIALIZED_VAR(orig_read);
3428 rb_fdset_t UNINITIALIZED_VAR(orig_write);
3429 rb_fdset_t UNINITIALIZED_VAR(orig_except);
3430 double limit = 0;
3431 struct timeval wait_rest;
3432 rb_thread_t *th = GET_THREAD();
3433
3434 if (timeout) {
3435 limit = timeofday();
3436 limit += (double)timeout->tv_sec+(double)timeout->tv_usec*1e-6;
3437 wait_rest = *timeout;
3438 timeout = &wait_rest;
3439 }
3440
3441 if (read)
3442 rb_fd_init_copy(&orig_read, read);
3443 if (write)
3444 rb_fd_init_copy(&orig_write, write);
3445 if (except)
3446 rb_fd_init_copy(&orig_except, except);
3447
3448 retry:
3449 lerrno = 0;
3450
3451 BLOCKING_REGION({
3452 result = native_fd_select(n, read, write, except, timeout, th);
3453 if (result < 0) lerrno = errno;
3454 }, ubf_select, th, FALSE);
3455
3456 RUBY_VM_CHECK_INTS_BLOCKING(th);
3457
3458 errno = lerrno;
3459
3460 if (result < 0) {
3461 switch (errno) {
3462 case EINTR:
3463 #ifdef ERESTART
3464 case ERESTART:
3465 #endif
3466 if (read)
3467 rb_fd_dup(read, &orig_read);
3468 if (write)
3469 rb_fd_dup(write, &orig_write);
3470 if (except)
3471 rb_fd_dup(except, &orig_except);
3472
3473 if (timeout) {
3474 double d = limit - timeofday();
3475
3476 wait_rest.tv_sec = (time_t)d;
3477 wait_rest.tv_usec = (int)((d-(double)wait_rest.tv_sec)*1e6);
3478 if (wait_rest.tv_sec < 0) wait_rest.tv_sec = 0;
3479 if (wait_rest.tv_usec < 0) wait_rest.tv_usec = 0;
3480 }
3481
3482 goto retry;
3483 default:
3484 break;
3485 }
3486 }
3487
3488 if (read)
3489 rb_fd_term(&orig_read);
3490 if (write)
3491 rb_fd_term(&orig_write);
3492 if (except)
3493 rb_fd_term(&orig_except);
3494
3495 return result;
3496 }
3497
3498 static void
3499 rb_thread_wait_fd_rw(int fd, int read)
3500 {
3501 int result = 0;
3502 int events = read ? RB_WAITFD_IN : RB_WAITFD_OUT;
3503
3504 thread_debug("rb_thread_wait_fd_rw(%d, %s)\n", fd, read ? "read" : "write");
3505
3506 if (fd < 0) {
3507 rb_raise(rb_eIOError, "closed stream");
3508 }
3509
3510 result = rb_wait_for_single_fd(fd, events, NULL);
3511 if (result < 0) {
3512 rb_sys_fail(0);
3513 }
3514
3515 thread_debug("rb_thread_wait_fd_rw(%d, %s): done\n", fd, read ? "read" : "write");
3516 }
3517
3518 void
3519 rb_thread_wait_fd(int fd)
3520 {
3521 rb_thread_wait_fd_rw(fd, 1);
3522 }
3523
3524 int
3525 rb_thread_fd_writable(int fd)
3526 {
3527 rb_thread_wait_fd_rw(fd, 0);
3528 return TRUE;
3529 }
3530
3531 int
3532 rb_thread_select(int max, fd_set * read, fd_set * write, fd_set * except,
3533 struct timeval *timeout)
3534 {
3535 rb_fdset_t fdsets[3];
3536 rb_fdset_t *rfds = NULL;
3537 rb_fdset_t *wfds = NULL;
3538 rb_fdset_t *efds = NULL;
3539 int retval;
3540
3541 if (read) {
3542 rfds = &fdsets[0];
3543 rb_fd_init(rfds);
3544 rb_fd_copy(rfds, read, max);
3545 }
3546 if (write) {
3547 wfds = &fdsets[1];
3548 rb_fd_init(wfds);
3549 rb_fd_copy(wfds, write, max);
3550 }
3551 if (except) {
3552 efds = &fdsets[2];
3553 rb_fd_init(efds);
3554 rb_fd_copy(efds, except, max);
3555 }
3556
3557 retval = rb_thread_fd_select(max, rfds, wfds, efds, timeout);
3558
3559 if (rfds) {
3560 rb_fd_rcopy(read, rfds);
3561 rb_fd_term(rfds);
3562 }
3563 if (wfds) {
3564 rb_fd_rcopy(write, wfds);
3565 rb_fd_term(wfds);
3566 }
3567 if (efds) {
3568 rb_fd_rcopy(except, efds);
3569 rb_fd_term(efds);
3570 }
3571
3572 return retval;
3573 }
3574
3575 int
3576 rb_thread_fd_select(int max, rb_fdset_t * read, rb_fdset_t * write, rb_fdset_t * except,
3577 struct timeval *timeout)
3578 {
3579 if (!read && !write && !except) {
3580 if (!timeout) {
3581 rb_thread_sleep_forever();
3582 return 0;
3583 }
3584 rb_thread_wait_for(*timeout);
3585 return 0;
3586 }
3587
3588 if (read) {
3589 rb_fd_resize(max - 1, read);
3590 }
3591 if (write) {
3592 rb_fd_resize(max - 1, write);
3593 }
3594 if (except) {
3595 rb_fd_resize(max - 1, except);
3596 }
3597 return do_select(max, read, write, except, timeout);
3598 }
3599
3600 /*
3601 * poll() is supported by many OSes, but so far Linux is the only
3602 * one we know of that supports using poll() in all places select()
3603 * would work.
3604 */
3605 #if defined(HAVE_POLL) && defined(__linux__)
3606 # define USE_POLL
3607 #endif
3608
3609 #ifdef USE_POLL
3610
3611 /* The same with linux kernel. TODO: make platform independent definition. */
3612 #define POLLIN_SET (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP | POLLERR)
3613 #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
3614 #define POLLEX_SET (POLLPRI)
3615
3616 #ifndef HAVE_PPOLL
3617 /* TODO: don't ignore sigmask */
3618 int
3619 ppoll(struct pollfd *fds, nfds_t nfds,
3620 const struct timespec *ts, const sigset_t *sigmask)
3621 {
3622 int timeout_ms;
3623
3624 if (ts) {
3625 int tmp, tmp2;
3626
3627 if (ts->tv_sec > TIMET_MAX/1000)
3628 timeout_ms = -1;
3629 else {
3630 tmp = ts->tv_sec * 1000;
3631 tmp2 = ts->tv_nsec / (1000 * 1000);
3632 if (TIMET_MAX - tmp < tmp2)
3633 timeout_ms = -1;
3634 else
3635 timeout_ms = tmp + tmp2;
3636 }
3637 }
3638 else
3639 timeout_ms = -1;
3640
3641 return poll(fds, nfds, timeout_ms);
3642 }
3643 #endif
3644
3645 /*
3646 * returns a mask of events
3647 */
3648 int
3649 rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
3650 {
3651 struct pollfd fds;
3652 int result = 0, lerrno;
3653 double limit = 0;
3654 struct timespec ts;
3655 struct timespec *timeout = NULL;
3656 rb_thread_t *th = GET_THREAD();
3657
3658 if (tv) {
3659 ts.tv_sec = tv->tv_sec;
3660 ts.tv_nsec = tv->tv_usec * 1000;
3661 limit = timeofday();
3662 limit += (double)tv->tv_sec + (double)tv->tv_usec * 1e-6;
3663 timeout = &ts;
3664 }
3665
3666 fds.fd = fd;
3667 fds.events = (short)events;
3668
3669 retry:
3670 lerrno = 0;
3671 BLOCKING_REGION({
3672 result = ppoll(&fds, 1, timeout, NULL);
3673 if (result < 0) lerrno = errno;
3674 }, ubf_select, th, FALSE);
3675
3676 RUBY_VM_CHECK_INTS_BLOCKING(th);
3677
3678 if (result < 0) {
3679 errno = lerrno;
3680 switch (errno) {
3681 case EINTR:
3682 #ifdef ERESTART
3683 case ERESTART:
3684 #endif
3685 if (timeout) {
3686 double d = limit - timeofday();
3687
3688 ts.tv_sec = (long)d;
3689 ts.tv_nsec = (long)((d - (double)ts.tv_sec) * 1e9);
3690 if (ts.tv_sec < 0)
3691 ts.tv_sec = 0;
3692 if (ts.tv_nsec < 0)
3693 ts.tv_nsec = 0;
3694 }
3695 goto retry;
3696 }
3697 return -1;
3698 }
3699
3700 if (fds.revents & POLLNVAL) {
3701 errno = EBADF;
3702 return -1;
3703 }
3704
3705 /*
3706 * POLLIN, POLLOUT have a different meanings from select(2)'s read/write bit.
3707 * Therefore we need to fix it up.
3708 */
3709 result = 0;
3710 if (fds.revents & POLLIN_SET)
3711 result |= RB_WAITFD_IN;
3712 if (fds.revents & POLLOUT_SET)
3713 result |= RB_WAITFD_OUT;
3714 if (fds.revents & POLLEX_SET)
3715 result |= RB_WAITFD_PRI;
3716
3717 return result;
3718 }
3719 #else /* ! USE_POLL - implement rb_io_poll_fd() using select() */
3720 static rb_fdset_t *
3721 init_set_fd(int fd, rb_fdset_t *fds)
3722 {
3723 rb_fd_init(fds);
3724 rb_fd_set(fd, fds);
3725
3726 return fds;
3727 }
3728
3729 struct select_args {
3730 union {
3731 int fd;
3732 int error;
3733 } as;
3734 rb_fdset_t *read;
3735 rb_fdset_t *write;
3736 rb_fdset_t *except;
3737 struct timeval *tv;
3738 };
3739
3740 static VALUE
3741 select_single(VALUE ptr)
3742 {
3743 struct select_args *args = (struct select_args *)ptr;
3744 int r;
3745
3746 r = rb_thread_fd_select(args->as.fd + 1,
3747 args->read, args->write, args->except, args->tv);
3748 if (r == -1)
3749 args->as.error = errno;
3750 if (r > 0) {
3751 r = 0;
3752 if (args->read && rb_fd_isset(args->as.fd, args->read))
3753 r |= RB_WAITFD_IN;
3754 if (args->write && rb_fd_isset(args->as.fd, args->write))
3755 r |= RB_WAITFD_OUT;
3756 if (args->except && rb_fd_isset(args->as.fd, args->except))
3757 r |= RB_WAITFD_PRI;
3758 }
3759 return (VALUE)r;
3760 }
3761
3762 static VALUE
3763 select_single_cleanup(VALUE ptr)
3764 {
3765 struct select_args *args = (struct select_args *)ptr;
3766
3767 if (args->read) rb_fd_term(args->read);
3768 if (args->write) rb_fd_term(args->write);
3769 if (args->except) rb_fd_term(args->except);
3770
3771 return (VALUE)-1;
3772 }
3773
3774 int
3775 rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
3776 {
3777 rb_fdset_t rfds, wfds, efds;
3778 struct select_args args;
3779 int r;
3780 VALUE ptr = (VALUE)&args;
3781
3782 args.as.fd = fd;
3783 args.read = (events & RB_WAITFD_IN) ? init_set_fd(fd, &rfds) : NULL;
3784 args.write = (events & RB_WAITFD_OUT) ? init_set_fd(fd, &wfds) : NULL;
3785 args.except = (events & RB_WAITFD_PRI) ? init_set_fd(fd, &efds) : NULL;
3786 args.tv = tv;
3787
3788 r = (int)rb_ensure(select_single, ptr, select_single_cleanup, ptr);
3789 if (r == -1)
3790 errno = args.as.error;
3791
3792 return r;
3793 }
3794 #endif /* ! USE_POLL */
3795
3796 /*
3797 * for GC
3798 */
3799
3800 #ifdef USE_CONSERVATIVE_STACK_END
3801 void
3802 rb_gc_set_stack_end(VALUE **stack_end_p)
3803 {
3804 VALUE stack_end;
3805 *stack_end_p = &stack_end;
3806 }
3807 #endif
3808
3809
3810 /*
3811 *
3812 */
3813
3814 void
3815 rb_threadptr_check_signal(rb_thread_t *mth)
3816 {
3817 /* mth must be main_thread */
3818 if (rb_signal_buff_size() > 0) {
3819 /* wakeup main thread */
3820 rb_threadptr_trap_interrupt(mth);
3821 }
3822 }
3823
3824 static void
3825 timer_thread_function(void *arg)
3826 {
3827 rb_vm_t *vm = GET_VM(); /* TODO: fix me for Multi-VM */
3828
3829 /*
3830 * Tricky: thread_destruct_lock doesn't close a race against
3831 * vm->running_thread switch. however it guarantees th->running_thread
3832 * point to valid pointer or NULL.
3833 */
3834 native_mutex_lock(&vm->thread_destruct_lock);
3835 /* for time slice */
3836 if (vm->running_thread)
3837 RUBY_VM_SET_TIMER_INTERRUPT(vm->running_thread);
3838 native_mutex_unlock(&vm->thread_destruct_lock);
3839
3840 /* check signal */
3841 rb_threadptr_check_signal(vm->main_thread);
3842
3843 #if 0
3844 /* prove profiler */
3845 if (vm->prove_profile.enable) {
3846 rb_thread_t *th = vm->running_thread;
3847
3848 if (vm->during_gc) {
3849 /* GC prove profiling */
3850 }
3851 }
3852 #endif
3853 }
3854
3855 void
3856 rb_thread_stop_timer_thread(int close_anyway)
3857 {
3858 if (timer_thread_id && native_stop_timer_thread(close_anyway)) {
3859 native_reset_timer_thread();
3860 }
3861 }
3862
3863 void
3864 rb_thread_reset_timer_thread(void)
3865 {
3866 native_reset_timer_thread();
3867 }
3868
3869 void
3870 rb_thread_start_timer_thread(void)
3871 {
3872 system_working = 1;
3873 rb_thread_create_timer_thread();
3874 }
3875
3876 static int
3877 clear_coverage_i(st_data_t key, st_data_t val, st_data_t dummy)
3878 {
3879 int i;
3880 VALUE lines = (VALUE)val;
3881
3882 for (i = 0; i < RARRAY_LEN(lines); i++) {
3883 if (RARRAY_AREF(lines, i) != Qnil) {
3884 RARRAY_ASET(lines, i, INT2FIX(0));
3885 }
3886 }
3887 return ST_CONTINUE;
3888 }
3889
3890 static void
3891 clear_coverage(void)
3892 {
3893 VALUE coverages = rb_get_coverages();
3894 if (RTEST(coverages)) {
3895 st_foreach(rb_hash_tbl_raw(coverages), clear_coverage_i, 0);
3896 }
3897 }
3898
3899 static void
3900 rb_thread_atfork_internal(int (*atfork)(st_data_t, st_data_t, st_data_t))
3901 {
3902 rb_thread_t *th = GET_THREAD();
3903 rb_vm_t *vm = th->vm;
3904 VALUE thval = th->self;
3905 vm->main_thread = th;
3906
3907 gvl_atfork(th->vm);
3908 st_foreach(vm->living_threads, atfork, (st_data_t)th);
3909 st_clear(vm->living_threads);
3910 st_insert(vm->living_threads, thval, (st_data_t)th->thread_id);
3911 vm->sleeper = 0;
3912 clear_coverage();
3913 }
3914
3915 static int
3916 terminate_atfork_i(st_data_t key, st_data_t val, st_data_t current_th)
3917 {
3918 VALUE thval = key;
3919 rb_thread_t *th;
3920 GetThreadPtr(thval, th);
3921
3922 if (th != (rb_thread_t *)current_th) {
3923 rb_mutex_abandon_keeping_mutexes(th);
3924 rb_mutex_abandon_locking_mutex(th);
3925 thread_cleanup_func(th, TRUE);
3926 }
3927 return ST_CONTINUE;
3928 }
3929
3930 void
3931 rb_thread_atfork(void)
3932 {
3933 rb_thread_atfork_internal(terminate_atfork_i);
3934 GET_THREAD()->join_list = NULL;
3935
3936 /* We don't want reproduce CVE-2003-0900. */
3937 rb_reset_random_seed();
3938 }
3939
3940 static int
3941 terminate_atfork_before_exec_i(st_data_t key, st_data_t val, st_data_t current_th)
3942 {
3943 VALUE thval = key;
3944 rb_thread_t *th;
3945 GetThreadPtr(thval, th);
3946
3947 if (th != (rb_thread_t *)current_th) {
3948 thread_cleanup_func_before_exec(th);
3949 }
3950 return ST_CONTINUE;
3951 }
3952
3953 void
3954 rb_thread_atfork_before_exec(void)
3955 {
3956 rb_thread_atfork_internal(terminate_atfork_before_exec_i);
3957 }
3958
3959 struct thgroup {
3960 int enclosed;
3961 VALUE group;
3962 };
3963
3964 static size_t
3965 thgroup_memsize(const void *ptr)
3966 {
3967 return ptr ? sizeof(struct thgroup) : 0;
3968 }
3969
3970 static const rb_data_type_t thgroup_data_type = {
3971 "thgroup",
3972 {NULL, RUBY_TYPED_DEFAULT_FREE, thgroup_memsize,},
3973 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
3974 };
3975
3976 /*
3977 * Document-class: ThreadGroup
3978 *
3979 * ThreadGroup provides a means of keeping track of a number of threads as a
3980 * group.
3981 *
3982 * A given Thread object can only belong to one ThreadGroup at a time; adding
3983 * a thread to a new group will remove it from any previous group.
3984 *
3985 * Newly created threads belong to the same group as the thread from which they
3986 * were created.
3987 */
3988
3989 /*
3990 * Document-const: Default
3991 *
3992 * The default ThreadGroup created when Ruby starts; all Threads belong to it
3993 * by default.
3994 */
3995 static VALUE
3996 thgroup_s_alloc(VALUE klass)
3997 {
3998 VALUE group;
3999 struct thgroup *data;
4000
4001 group = TypedData_Make_Struct(klass, struct thgroup, &thgroup_data_type, data);
4002 data->enclosed = 0;
4003 data->group = group;
4004
4005 return group;
4006 }
4007
4008 struct thgroup_list_params {
4009 VALUE ary;
4010 VALUE group;
4011 };
4012
4013 static int
4014 thgroup_list_i(st_data_t key, st_data_t val, st_data_t data)
4015 {
4016 VALUE thread = (VALUE)key;
4017 VALUE ary = ((struct thgroup_list_params *)data)->ary;
4018 VALUE group = ((struct thgroup_list_params *)data)->group;
4019 rb_thread_t *th;
4020 GetThreadPtr(thread, th);
4021
4022 if (th->thgroup == group) {
4023 rb_ary_push(ary, thread);
4024 }
4025 return ST_CONTINUE;
4026 }
4027
4028 /*
4029 * call-seq:
4030 * thgrp.list -> array
4031 *
4032 * Returns an array of all existing Thread objects that belong to this group.
4033 *
4034 * ThreadGroup::Default.list #=> [#<Thread:0x401bdf4c run>]
4035 */
4036
4037 static VALUE
4038 thgroup_list(VALUE group)
4039 {
4040 VALUE ary = rb_ary_new();
4041 struct thgroup_list_params param;
4042
4043 param.ary = ary;
4044 param.group = group;
4045 st_foreach(GET_THREAD()->vm->living_threads, thgroup_list_i, (st_data_t) & param);
4046 return ary;
4047 }
4048
4049
4050 /*
4051 * call-seq:
4052 * thgrp.enclose -> thgrp
4053 *
4054 * Prevents threads from being added to or removed from the receiving
4055 * ThreadGroup.
4056 *
4057 * New threads can still be started in an enclosed ThreadGroup.
4058 *
4059 * ThreadGroup::Default.enclose #=> #<ThreadGroup:0x4029d914>
4060 * thr = Thread::new { Thread.stop } #=> #<Thread:0x402a7210 sleep>
4061 * tg = ThreadGroup::new #=> #<ThreadGroup:0x402752d4>
4062 * tg.add thr
4063 * #=> ThreadError: can't move from the enclosed thread group
4064 */
4065
4066 static VALUE
4067 thgroup_enclose(VALUE group)
4068 {
4069 struct thgroup *data;
4070
4071 TypedData_Get_Struct(group, struct thgroup, &thgroup_data_type, data);
4072 data->enclosed = 1;
4073
4074 return group;
4075 }
4076
4077
4078 /*
4079 * call-seq:
4080 * thgrp.enclosed? -> true or false
4081 *
4082 * Returns +true+ if the +thgrp+ is enclosed. See also ThreadGroup#enclose.
4083 */
4084
4085 static VALUE
4086 thgroup_enclosed_p(VALUE group)
4087 {
4088 struct thgroup *data;
4089
4090 TypedData_Get_Struct(group, struct thgroup, &thgroup_data_type, data);
4091 if (data->enclosed)
4092 return Qtrue;
4093 return Qfalse;
4094 }
4095
4096
4097 /*
4098 * call-seq:
4099 * thgrp.add(thread) -> thgrp
4100 *
4101 * Adds the given +thread+ to this group, removing it from any other
4102 * group to which it may have previously been a member.
4103 *
4104 * puts "Initial group is #{ThreadGroup::Default.list}"
4105 * tg = ThreadGroup.new
4106 * t1 = Thread.new { sleep }
4107 * t2 = Thread.new { sleep }
4108 * puts "t1 is #{t1}"
4109 * puts "t2 is #{t2}"
4110 * tg.add(t1)
4111 * puts "Initial group now #{ThreadGroup::Default.list}"
4112 * puts "tg group now #{tg.list}"
4113 *
4114 * This will produce:
4115 *
4116 * Initial group is #<Thread:0x401bdf4c>
4117 * t1 is #<Thread:0x401b3c90>
4118 * t2 is #<Thread:0x401b3c18>
4119 * Initial group now #<Thread:0x401b3c18>#<Thread:0x401bdf4c>
4120 * tg group now #<Thread:0x401b3c90>
4121 */
4122
4123 static VALUE
4124 thgroup_add(VALUE group, VALUE thread)
4125 {
4126 rb_thread_t *th;
4127 struct thgroup *data;
4128
4129 GetThreadPtr(thread, th);
4130
4131 if (OBJ_FROZEN(group)) {
4132 rb_raise(rb_eThreadError, "can't move to the frozen thread group");
4133 }
4134 TypedData_Get_Struct(group, struct thgroup, &thgroup_data_type, data);
4135 if (data->enclosed) {
4136 rb_raise(rb_eThreadError, "can't move to the enclosed thread group");
4137 }
4138
4139 if (!th->thgroup) {
4140 return Qnil;
4141 }
4142
4143 if (OBJ_FROZEN(th->thgroup)) {
4144 rb_raise(rb_eThreadError, "can't move from the frozen thread group");
4145 }
4146 TypedData_Get_Struct(th->thgroup, struct thgroup, &thgroup_data_type, data);
4147 if (data->enclosed) {
4148 rb_raise(rb_eThreadError,
4149 "can't move from the enclosed thread group");
4150 }
4151
4152 th->thgroup = group;
4153 return group;
4154 }
4155
4156
4157 /*
4158 * Document-class: Mutex
4159 *
4160 * Mutex implements a simple semaphore that can be used to coordinate access to
4161 * shared data from multiple concurrent threads.
4162 *
4163 * Example:
4164 *
4165 * require 'thread'
4166 * semaphore = Mutex.new
4167 *
4168 * a = Thread.new {
4169 * semaphore.synchronize {
4170 * # access shared resource
4171 * }
4172 * }
4173 *
4174 * b = Thread.new {
4175 * semaphore.synchronize {
4176 * # access shared resource
4177 * }
4178 * }
4179 *
4180 */
4181
4182 #define GetMutexPtr(obj, tobj) \
4183 TypedData_Get_Struct((obj), rb_mutex_t, &mutex_data_type, (tobj))
4184
4185 #define mutex_mark NULL
4186
4187 static void
4188 mutex_free(void *ptr)
4189 {
4190 if (ptr) {
4191 rb_mutex_t *mutex = ptr;
4192 if (mutex->th) {
4193 /* rb_warn("free locked mutex"); */
4194 const char *err = rb_mutex_unlock_th(mutex, mutex->th);
4195 if (err) rb_bug("%s", err);
4196 }
4197 native_mutex_destroy(&mutex->lock);
4198 native_cond_destroy(&mutex->cond);
4199 }
4200 ruby_xfree(ptr);
4201 }
4202
4203 static size_t
4204 mutex_memsize(const void *ptr)
4205 {
4206 return ptr ? sizeof(rb_mutex_t) : 0;
4207 }
4208
4209 static const rb_data_type_t mutex_data_type = {
4210 "mutex",
4211 {mutex_mark, mutex_free, mutex_memsize,},
4212 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
4213 };
4214
4215 VALUE
4216 rb_obj_is_mutex(VALUE obj)
4217 {
4218 if (rb_typeddata_is_kind_of(obj, &mutex_data_type)) {
4219 return Qtrue;
4220 }
4221 else {
4222 return Qfalse;
4223 }
4224 }
4225
4226 static VALUE
4227 mutex_alloc(VALUE klass)
4228 {
4229 VALUE volatile obj;
4230 rb_mutex_t *mutex;
4231
4232 obj = TypedData_Make_Struct(klass, rb_mutex_t, &mutex_data_type, mutex);
4233 native_mutex_initialize(&mutex->lock);
4234 native_cond_initialize(&mutex->cond, RB_CONDATTR_CLOCK_MONOTONIC);
4235 return obj;
4236 }
4237
4238 /*
4239 * call-seq:
4240 * Mutex.new -> mutex
4241 *
4242 * Creates a new Mutex
4243 */
4244 static VALUE
4245 mutex_initialize(VALUE self)
4246 {
4247 return self;
4248 }
4249
4250 VALUE
4251 rb_mutex_new(void)
4252 {
4253 return mutex_alloc(rb_cMutex);
4254 }
4255
4256 /*
4257 * call-seq:
4258 * mutex.locked? -> true or false
4259 *
4260 * Returns +true+ if this lock is currently held by some thread.
4261 */
4262 VALUE
4263 rb_mutex_locked_p(VALUE self)
4264 {
4265 rb_mutex_t *mutex;
4266 GetMutexPtr(self, mutex);
4267 return mutex->th ? Qtrue : Qfalse;
4268 }
4269
4270 static void
4271 mutex_locked(rb_thread_t *th, VALUE self)
4272 {
4273 rb_mutex_t *mutex;
4274 GetMutexPtr(self, mutex);
4275
4276 if (th->keeping_mutexes) {
4277 mutex->next_mutex = th->keeping_mutexes;
4278 }
4279 th->keeping_mutexes = mutex;
4280 }
4281
4282 /*
4283 * call-seq:
4284 * mutex.try_lock -> true or false
4285 *
4286 * Attempts to obtain the lock and returns immediately. Returns +true+ if the
4287 * lock was granted.
4288 */
4289 VALUE
4290 rb_mutex_trylock(VALUE self)
4291 {
4292 rb_mutex_t *mutex;
4293 VALUE locked = Qfalse;
4294 GetMutexPtr(self, mutex);
4295
4296 native_mutex_lock(&mutex->lock);
4297 if (mutex->th == 0) {
4298 mutex->th = GET_THREAD();
4299 locked = Qtrue;
4300
4301 mutex_locked(GET_THREAD(), self);
4302 }
4303 native_mutex_unlock(&mutex->lock);
4304
4305 return locked;
4306 }
4307
4308 static int
4309 lock_func(rb_thread_t *th, rb_mutex_t *mutex, int timeout_ms)
4310 {
4311 int interrupted = 0;
4312 int err = 0;
4313
4314 mutex->cond_waiting++;
4315 for (;;) {
4316 if (!mutex->th) {
4317 mutex->th = th;
4318 break;
4319 }
4320 if (RUBY_VM_INTERRUPTED(th)) {
4321 interrupted = 1;
4322 break;
4323 }
4324 if (err == ETIMEDOUT) {
4325 interrupted = 2;
4326 break;
4327 }
4328
4329 if (timeout_ms) {
4330 struct timespec timeout_rel;
4331 struct timespec timeout;
4332
4333 timeout_rel.tv_sec = 0;
4334 timeout_rel.tv_nsec = timeout_ms * 1000 * 1000;
4335 timeout = native_cond_timeout(&mutex->cond, timeout_rel);
4336 err = native_cond_timedwait(&mutex->cond, &mutex->lock, &timeout);
4337 }
4338 else {
4339 native_cond_wait(&mutex->cond, &mutex->lock);
4340 err = 0;
4341 }
4342 }
4343 mutex->cond_waiting--;
4344
4345 return interrupted;
4346 }
4347
4348 static void
4349 lock_interrupt(void *ptr)
4350 {
4351 rb_mutex_t *mutex = (rb_mutex_t *)ptr;
4352 native_mutex_lock(&mutex->lock);
4353 if (mutex->cond_waiting > 0)
4354 native_cond_broadcast(&mutex->cond);
4355 native_mutex_unlock(&mutex->lock);
4356 }
4357
4358 /*
4359 * At maximum, only one thread can use cond_timedwait and watch deadlock
4360 * periodically. Multiple polling thread (i.e. concurrent deadlock check)
4361 * introduces new race conditions. [Bug #6278] [ruby-core:44275]
4362 */
4363 static const rb_thread_t *patrol_thread = NULL;
4364
4365 /*
4366 * call-seq:
4367 * mutex.lock -> self
4368 *
4369 * Attempts to grab the lock and waits if it isn't available.
4370 * Raises +ThreadError+ if +mutex+ was locked by the current thread.
4371 */
4372 VALUE
4373 rb_mutex_lock(VALUE self)
4374 {
4375 rb_thread_t *th = GET_THREAD();
4376 rb_mutex_t *mutex;
4377 GetMutexPtr(self, mutex);
4378
4379 /* When running trap handler */
4380 if (!mutex->allow_trap && th->interrupt_mask & TRAP_INTERRUPT_MASK) {
4381 rb_raise(rb_eThreadError, "can't be called from trap context");
4382 }
4383
4384 if (rb_mutex_trylock(self) == Qfalse) {
4385 if (mutex->th == GET_THREAD()) {
4386 rb_raise(rb_eThreadError, "deadlock; recursive locking");
4387 }
4388
4389 while (mutex->th != th) {
4390 int interrupted;
4391 enum rb_thread_status prev_status = th->status;
4392 volatile int timeout_ms = 0;
4393 struct rb_unblock_callback oldubf;
4394
4395 set_unblock_function(th, lock_interrupt, mutex, &oldubf, FALSE);
4396 th->status = THREAD_STOPPED_FOREVER;
4397 th->locking_mutex = self;
4398
4399 native_mutex_lock(&mutex->lock);
4400 th->vm->sleeper++;
4401 /*
4402 * Carefully! while some contended threads are in lock_func(),
4403 * vm->sleepr is unstable value. we have to avoid both deadlock
4404 * and busy loop.
4405 */
4406 if ((vm_living_thread_num(th->vm) == th->vm->sleeper) &&
4407 !patrol_thread) {
4408 timeout_ms = 100;
4409 patrol_thread = th;
4410 }
4411
4412 GVL_UNLOCK_BEGIN();
4413 interrupted = lock_func(th, mutex, (int)timeout_ms);
4414 native_mutex_unlock(&mutex->lock);
4415 GVL_UNLOCK_END();
4416
4417 if (patrol_thread == th)
4418 patrol_thread = NULL;
4419
4420 reset_unblock_function(th, &oldubf);
4421
4422 th->locking_mutex = Qfalse;
4423 if (mutex->th && interrupted == 2) {
4424 rb_check_deadlock(th->vm);
4425 }
4426 if (th->status == THREAD_STOPPED_FOREVER) {
4427 th->status = prev_status;
4428 }
4429 th->vm->sleeper--;
4430
4431 if (mutex->th == th) mutex_locked(th, self);
4432
4433 if (interrupted) {
4434 RUBY_VM_CHECK_INTS_BLOCKING(th);
4435 }
4436 }
4437 }
4438 return self;
4439 }
4440
4441 /*
4442 * call-seq:
4443 * mutex.owned? -> true or false
4444 *
4445 * Returns +true+ if this lock is currently held by current thread.
4446 * <em>This API is experimental, and subject to change.</em>
4447 */
4448 VALUE
4449 rb_mutex_owned_p(VALUE self)
4450 {
4451 VALUE owned = Qfalse;
4452 rb_thread_t *th = GET_THREAD();
4453 rb_mutex_t *mutex;
4454
4455 GetMutexPtr(self, mutex);
4456
4457 if (mutex->th == th)
4458 owned = Qtrue;
4459
4460 return owned;
4461 }
4462
4463 static const char *
4464 rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t volatile *th)
4465 {
4466 const char *err = NULL;
4467
4468 native_mutex_lock(&mutex->lock);
4469
4470 if (mutex->th == 0) {
4471 err = "Attempt to unlock a mutex which is not locked";
4472 }
4473 else if (mutex->th != th) {
4474 err = "Attempt to unlock a mutex which is locked by another thread";
4475 }
4476 else {
4477 mutex->th = 0;
4478 if (mutex->cond_waiting > 0)
4479 native_cond_signal(&mutex->cond);
4480 }
4481
4482 native_mutex_unlock(&mutex->lock);
4483
4484 if (!err) {
4485 rb_mutex_t *volatile *th_mutex = &th->keeping_mutexes;
4486 while (*th_mutex != mutex) {
4487 th_mutex = &(*th_mutex)->next_mutex;
4488 }
4489 *th_mutex = mutex->next_mutex;
4490 mutex->next_mutex = NULL;
4491 }
4492
4493 return err;
4494 }
4495
4496 /*
4497 * call-seq:
4498 * mutex.unlock -> self
4499 *
4500 * Releases the lock.
4501 * Raises +ThreadError+ if +mutex+ wasn't locked by the current thread.
4502 */
4503 VALUE
4504 rb_mutex_unlock(VALUE self)
4505 {
4506 const char *err;
4507 rb_mutex_t *mutex;
4508 GetMutexPtr(self, mutex);
4509
4510 err = rb_mutex_unlock_th(mutex, GET_THREAD());
4511 if (err) rb_raise(rb_eThreadError, "%s", err);
4512
4513 return self;
4514 }
4515
4516 static void
4517 rb_mutex_abandon_keeping_mutexes(rb_thread_t *th)
4518 {
4519 if (th->keeping_mutexes) {
4520 rb_mutex_abandon_all(th->keeping_mutexes);
4521 }
4522 th->keeping_mutexes = NULL;
4523 }
4524
4525 static void
4526 rb_mutex_abandon_locking_mutex(rb_thread_t *th)
4527 {
4528 rb_mutex_t *mutex;
4529
4530 if (!th->locking_mutex) return;
4531
4532 GetMutexPtr(th->locking_mutex, mutex);
4533 if (mutex->th == th)
4534 rb_mutex_abandon_all(mutex);
4535 th->locking_mutex = Qfalse;
4536 }
4537
4538 static void
4539 rb_mutex_abandon_all(rb_mutex_t *mutexes)
4540 {
4541 rb_mutex_t *mutex;
4542
4543 while (mutexes) {
4544 mutex = mutexes;
4545 mutexes = mutex->next_mutex;
4546 mutex->th = 0;
4547 mutex->next_mutex = 0;
4548 }
4549 }
4550
4551 static VALUE
4552 rb_mutex_sleep_forever(VALUE time)
4553 {
4554 sleep_forever(GET_THREAD(), 1, 0); /* permit spurious check */
4555 return Qnil;
4556 }
4557
4558 static VALUE
4559 rb_mutex_wait_for(VALUE time)
4560 {
4561 struct timeval *t = (struct timeval *)time;
4562 sleep_timeval(GET_THREAD(), *t, 0); /* permit spurious check */
4563 return Qnil;
4564 }
4565
4566 VALUE
4567 rb_mutex_sleep(VALUE self, VALUE timeout)
4568 {
4569 time_t beg, end;
4570 struct timeval t;
4571
4572 if (!NIL_P(timeout)) {
4573 t = rb_time_interval(timeout);
4574 }
4575 rb_mutex_unlock(self);
4576 beg = time(0);
4577 if (NIL_P(timeout)) {
4578 rb_ensure(rb_mutex_sleep_forever, Qnil, rb_mutex_lock, self);
4579 }
4580 else {
4581 rb_ensure(rb_mutex_wait_for, (VALUE)&t, rb_mutex_lock, self);
4582 }
4583 end = time(0) - beg;
4584 return INT2FIX(end);
4585 }
4586
4587 /*
4588 * call-seq:
4589 * mutex.sleep(timeout = nil) -> number
4590 *
4591 * Releases the lock and sleeps +timeout+ seconds if it is given and
4592 * non-nil or forever. Raises +ThreadError+ if +mutex+ wasn't locked by
4593 * the current thread.
4594 *
4595 * When the thread is next woken up, it will attempt to reacquire
4596 * the lock.
4597 *
4598 * Note that this method can wakeup without explicit Thread#wakeup call.
4599 * For example, receiving signal and so on.
4600 */
4601 static VALUE
4602 mutex_sleep(int argc, VALUE *argv, VALUE self)
4603 {
4604 VALUE timeout;
4605
4606 rb_scan_args(argc, argv, "01", &timeout);
4607 return rb_mutex_sleep(self, timeout);
4608 }
4609
4610 /*
4611 * call-seq:
4612 * mutex.synchronize { ... } -> result of the block
4613 *
4614 * Obtains a lock, runs the block, and releases the lock when the block
4615 * completes. See the example under +Mutex+.
4616 */
4617
4618 VALUE
4619 rb_mutex_synchronize(VALUE mutex, VALUE (*func)(VALUE arg), VALUE arg)
4620 {
4621 rb_mutex_lock(mutex);
4622 return rb_ensure(func, arg, rb_mutex_unlock, mutex);
4623 }
4624
4625 /*
4626 * call-seq:
4627 * mutex.synchronize { ... } -> result of the block
4628 *
4629 * Obtains a lock, runs the block, and releases the lock when the block
4630 * completes. See the example under +Mutex+.
4631 */
4632 static VALUE
4633 rb_mutex_synchronize_m(VALUE self, VALUE args)
4634 {
4635 if (!rb_block_given_p()) {
4636 rb_raise(rb_eThreadError, "must be called with a block");
4637 }
4638
4639 return rb_mutex_synchronize(self, rb_yield, Qundef);
4640 }
4641
4642 void rb_mutex_allow_trap(VALUE self, int val)
4643 {
4644 rb_mutex_t *m;
4645 GetMutexPtr(self, m);
4646
4647 m->allow_trap = val;
4648 }
4649
4650 /*
4651 * Document-class: ThreadShield
4652 */
4653 static void
4654 thread_shield_mark(void *ptr)
4655 {
4656 rb_gc_mark((VALUE)ptr);
4657 }
4658
4659 static const rb_data_type_t thread_shield_data_type = {
4660 "thread_shield",
4661 {thread_shield_mark, 0, 0,},
4662 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
4663 };
4664
4665 static VALUE
4666 thread_shield_alloc(VALUE klass)
4667 {
4668 return TypedData_Wrap_Struct(klass, &thread_shield_data_type, (void *)mutex_alloc(0));
4669 }
4670
4671 #define GetThreadShieldPtr(obj) ((VALUE)rb_check_typeddata((obj), &thread_shield_data_type))
4672 #define THREAD_SHIELD_WAITING_MASK (FL_USER0|FL_USER1|FL_USER2|FL_USER3|FL_USER4|FL_USER5|FL_USER6|FL_USER7|FL_USER8|FL_USER9|FL_USER10|FL_USER11|FL_USER12|FL_USER13|FL_USER14|FL_USER15|FL_USER16|FL_USER17|FL_USER18|FL_USER19)
4673 #define THREAD_SHIELD_WAITING_SHIFT (FL_USHIFT)
4674 #define rb_thread_shield_waiting(b) (int)((RBASIC(b)->flags&THREAD_SHIELD_WAITING_MASK)>>THREAD_SHIELD_WAITING_SHIFT)
4675
4676 static inline void
4677 rb_thread_shield_waiting_inc(VALUE b)
4678 {
4679 unsigned int w = rb_thread_shield_waiting(b);
4680 w++;
4681 if (w > (unsigned int)(THREAD_SHIELD_WAITING_MASK>>THREAD_SHIELD_WAITING_SHIFT))
4682 rb_raise(rb_eRuntimeError, "waiting count overflow");
4683 RBASIC(b)->flags &= ~THREAD_SHIELD_WAITING_MASK;
4684 RBASIC(b)->flags |= ((VALUE)w << THREAD_SHIELD_WAITING_SHIFT);
4685 }
4686
4687 static inline void
4688 rb_thread_shield_waiting_dec(VALUE b)
4689 {
4690 unsigned int w = rb_thread_shield_waiting(b);
4691 if (!w) rb_raise(rb_eRuntimeError, "waiting count underflow");
4692 w--;
4693 RBASIC(b)->flags &= ~THREAD_SHIELD_WAITING_MASK;
4694 RBASIC(b)->flags |= ((VALUE)w << THREAD_SHIELD_WAITING_SHIFT);
4695 }
4696
4697 VALUE
4698 rb_thread_shield_new(void)
4699 {
4700 VALUE thread_shield = thread_shield_alloc(rb_cThreadShield);
4701 rb_mutex_lock((VALUE)DATA_PTR(thread_shield));
4702 return thread_shield;
4703 }
4704
4705 /*
4706 * Wait a thread shield.
4707 *
4708 * Returns
4709 * true: acquired the thread shield
4710 * false: the thread shield was destroyed and no other threads waiting
4711 * nil: the thread shield was destroyed but still in use
4712 */
4713 VALUE
4714 rb_thread_shield_wait(VALUE self)
4715 {
4716 VALUE mutex = GetThreadShieldPtr(self);
4717 rb_mutex_t *m;
4718
4719 if (!mutex) return Qfalse;
4720 GetMutexPtr(mutex, m);
4721 if (m->th == GET_THREAD()) return Qnil;
4722 rb_thread_shield_waiting_inc(self);
4723 rb_mutex_lock(mutex);
4724 rb_thread_shield_waiting_dec(self);
4725 if (DATA_PTR(self)) return Qtrue;
4726 rb_mutex_unlock(mutex);
4727 return rb_thread_shield_waiting(self) > 0 ? Qnil : Qfalse;
4728 }
4729
4730 /*
4731 * Release a thread shield, and return true if it has waiting threads.
4732 */
4733 VALUE
4734 rb_thread_shield_release(VALUE self)
4735 {
4736 VALUE mutex = GetThreadShieldPtr(self);
4737 rb_mutex_unlock(mutex);
4738 return rb_thread_shield_waiting(self) > 0 ? Qtrue : Qfalse;
4739 }
4740
4741 /*
4742 * Release and destroy a thread shield, and return true if it has waiting threads.
4743 */
4744 VALUE
4745 rb_thread_shield_destroy(VALUE self)
4746 {
4747 VALUE mutex = GetThreadShieldPtr(self);
4748 DATA_PTR(self) = 0;
4749 rb_mutex_unlock(mutex);
4750 return rb_thread_shield_waiting(self) > 0 ? Qtrue : Qfalse;
4751 }
4752
4753 /* variables for recursive traversals */
4754 static ID recursive_key;
4755
4756 extern const struct st_hash_type st_hashtype_num;
4757
4758 static VALUE
4759 ident_hash_new(void)
4760 {
4761 VALUE hash = rb_hash_new();
4762 rb_hash_tbl_raw(hash)->type = &st_hashtype_num;
4763 return hash;
4764 }
4765
4766 /*
4767 * Returns the current "recursive list" used to detect recursion.
4768 * This list is a hash table, unique for the current thread and for
4769 * the current __callee__.
4770 */
4771
4772 static VALUE
4773 recursive_list_access(void)
4774 {
4775 volatile VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
4776 VALUE sym = ID2SYM(rb_frame_this_func());
4777 VALUE list;
4778 if (NIL_P(hash) || !RB_TYPE_P(hash, T_HASH)) {
4779 hash = ident_hash_new();
4780 rb_thread_local_aset(rb_thread_current(), recursive_key, hash);
4781 list = Qnil;
4782 }
4783 else {
4784 list = rb_hash_aref(hash, sym);
4785 }
4786 if (NIL_P(list) || !RB_TYPE_P(list, T_HASH)) {
4787 list = ident_hash_new();
4788 rb_hash_aset(hash, sym, list);
4789 }
4790 return list;
4791 }
4792
4793 VALUE
4794 rb_threadptr_reset_recursive_data(rb_thread_t *th)
4795 {
4796 VALUE old = threadptr_local_aref(th, recursive_key);
4797 threadptr_local_aset(th, recursive_key, Qnil);
4798 return old;
4799 }
4800
4801 void
4802 rb_threadptr_restore_recursive_data(rb_thread_t *th, VALUE old)
4803 {
4804 threadptr_local_aset(th, recursive_key, old);
4805 }
4806
4807 /*
4808 * Returns Qtrue iff obj_id (or the pair <obj, paired_obj>) is already
4809 * in the recursion list.
4810 * Assumes the recursion list is valid.
4811 */
4812
4813 static VALUE
4814 recursive_check(VALUE list, VALUE obj_id, VALUE paired_obj_id)
4815 {
4816 #if SIZEOF_LONG == SIZEOF_VOIDP
4817 #define OBJ_ID_EQL(obj_id, other) ((obj_id) == (other))
4818 #elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
4819 #define OBJ_ID_EQL(obj_id, other) (RB_TYPE_P((obj_id), T_BIGNUM) ? \
4820 rb_big_eql((obj_id), (other)) : ((obj_id) == (other)))
4821 #endif
4822
4823 VALUE pair_list = rb_hash_lookup2(list, obj_id, Qundef);
4824 if (pair_list == Qundef)
4825 return Qfalse;
4826 if (paired_obj_id) {
4827 if (!RB_TYPE_P(pair_list, T_HASH)) {
4828 if (!OBJ_ID_EQL(paired_obj_id, pair_list))
4829 return Qfalse;
4830 }
4831 else {
4832 if (NIL_P(rb_hash_lookup(pair_list, paired_obj_id)))
4833 return Qfalse;
4834 }
4835 }
4836 return Qtrue;
4837 }
4838
4839 /*
4840 * Pushes obj_id (or the pair <obj_id, paired_obj_id>) in the recursion list.
4841 * For a single obj_id, it sets list[obj_id] to Qtrue.
4842 * For a pair, it sets list[obj_id] to paired_obj_id if possible,
4843 * otherwise list[obj_id] becomes a hash like:
4844 * {paired_obj_id_1 => true, paired_obj_id_2 => true, ... }
4845 * Assumes the recursion list is valid.
4846 */
4847
4848 static void
4849 recursive_push(VALUE list, VALUE obj, VALUE paired_obj)
4850 {
4851 VALUE pair_list;
4852
4853 if (!paired_obj) {
4854 rb_hash_aset(list, obj, Qtrue);
4855 }
4856 else if ((pair_list = rb_hash_lookup2(list, obj, Qundef)) == Qundef) {
4857 rb_hash_aset(list, obj, paired_obj);
4858 }
4859 else {
4860 if (!RB_TYPE_P(pair_list, T_HASH)){
4861 VALUE other_paired_obj = pair_list;
4862 pair_list = rb_hash_new();
4863 rb_hash_aset(pair_list, other_paired_obj, Qtrue);
4864 rb_hash_aset(list, obj, pair_list);
4865 }
4866 rb_hash_aset(pair_list, paired_obj, Qtrue);
4867 }
4868 }
4869
4870 /*
4871 * Pops obj_id (or the pair <obj_id, paired_obj_id>) from the recursion list.
4872 * For a pair, if list[obj_id] is a hash, then paired_obj_id is
4873 * removed from the hash and no attempt is made to simplify
4874 * list[obj_id] from {only_one_paired_id => true} to only_one_paired_id
4875 * Assumes the recursion list is valid.
4876 */
4877
4878 static void
4879 recursive_pop(VALUE list, VALUE obj, VALUE paired_obj)
4880 {
4881 if (paired_obj) {
4882 VALUE pair_list = rb_hash_lookup2(list, obj, Qundef);
4883 if (pair_list == Qundef) {
4884 VALUE symname = rb_inspect(ID2SYM(rb_frame_this_func()));
4885 VALUE thrname = rb_inspect(rb_thread_current());
4886 rb_raise(rb_eTypeError, "invalid inspect_tbl pair_list for %s in %s",
4887 StringValuePtr(symname), StringValuePtr(thrname));
4888 }
4889 if (RB_TYPE_P(pair_list, T_HASH)) {
4890 rb_hash_delete(pair_list, paired_obj);
4891 if (!RHASH_EMPTY_P(pair_list)) {
4892 return; /* keep hash until is empty */
4893 }
4894 }
4895 }
4896 rb_hash_delete(list, obj);
4897 }
4898
4899 struct exec_recursive_params {
4900 VALUE (*func) (VALUE, VALUE, int);
4901 VALUE list;
4902 VALUE obj;
4903 VALUE objid;
4904 VALUE pairid;
4905 VALUE arg;
4906 };
4907
4908 static VALUE
4909 exec_recursive_i(RB_BLOCK_CALL_FUNC_ARGLIST(tag, data))
4910 {
4911 struct exec_recursive_params *p = (void *)data;
4912 return (*p->func)(p->obj, p->arg, FALSE);
4913 }
4914
4915 /*
4916 * Calls func(obj, arg, recursive), where recursive is non-zero if the
4917 * current method is called recursively on obj, or on the pair <obj, pairid>
4918 * If outer is 0, then the innermost func will be called with recursive set
4919 * to Qtrue, otherwise the outermost func will be called. In the latter case,
4920 * all inner func are short-circuited by throw.
4921 * Implementation details: the value thrown is the recursive list which is
4922 * proper to the current method and unlikely to be caught anywhere else.
4923 * list[recursive_key] is used as a flag for the outermost call.
4924 */
4925
4926 static VALUE
4927 exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE pairid, VALUE arg, int outer)
4928 {
4929 VALUE result = Qundef;
4930 struct exec_recursive_params p;
4931 int outermost;
4932 p.list = recursive_list_access();
4933 p.objid = rb_obj_id(obj);
4934 p.obj = obj;
4935 p.pairid = pairid;
4936 p.arg = arg;
4937 outermost = outer && !recursive_check(p.list, ID2SYM(recursive_key), 0);
4938
4939 if (recursive_check(p.list, p.objid, pairid)) {
4940 if (outer && !outermost) {
4941 rb_throw_obj(p.list, p.list);
4942 }
4943 return (*func)(obj, arg, TRUE);
4944 }
4945 else {
4946 int state;
4947
4948 p.func = func;
4949
4950 if (outermost) {
4951 recursive_push(p.list, ID2SYM(recursive_key), 0);
4952 recursive_push(p.list, p.objid, p.pairid);
4953 result = rb_catch_protect(p.list, exec_recursive_i, (VALUE)&p, &state);
4954 recursive_pop(p.list, p.objid, p.pairid);
4955 recursive_pop(p.list, ID2SYM(recursive_key), 0);
4956 if (state) JUMP_TAG(state);
4957 if (result == p.list) {
4958 result = (*func)(obj, arg, TRUE);
4959 }
4960 }
4961 else {
4962 recursive_push(p.list, p.objid, p.pairid);
4963 PUSH_TAG();
4964 if ((state = EXEC_TAG()) == 0) {
4965 result = (*func)(obj, arg, FALSE);
4966 }
4967 POP_TAG();
4968 recursive_pop(p.list, p.objid, p.pairid);
4969 if (state) JUMP_TAG(state);
4970 }
4971 }
4972 *(volatile struct exec_recursive_params *)&p;
4973 return result;
4974 }
4975
4976 /*
4977 * Calls func(obj, arg, recursive), where recursive is non-zero if the
4978 * current method is called recursively on obj
4979 */
4980
4981 VALUE
4982 rb_exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
4983 {
4984 return exec_recursive(func, obj, 0, arg, 0);
4985 }
4986
4987 /*
4988 * Calls func(obj, arg, recursive), where recursive is non-zero if the
4989 * current method is called recursively on the ordered pair <obj, paired_obj>
4990 */
4991
4992 VALUE
4993 rb_exec_recursive_paired(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE paired_obj, VALUE arg)
4994 {
4995 return exec_recursive(func, obj, rb_obj_id(paired_obj), arg, 0);
4996 }
4997
4998 /*
4999 * If recursion is detected on the current method and obj, the outermost
5000 * func will be called with (obj, arg, Qtrue). All inner func will be
5001 * short-circuited using throw.
5002 */
5003
5004 VALUE
5005 rb_exec_recursive_outer(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
5006 {
5007 return exec_recursive(func, obj, 0, arg, 1);
5008 }
5009
5010 /*
5011 * If recursion is detected on the current method, obj and paired_obj,
5012 * the outermost func will be called with (obj, arg, Qtrue). All inner
5013 * func will be short-circuited using throw.
5014 */
5015
5016 VALUE
5017 rb_exec_recursive_paired_outer(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE paired_obj, VALUE arg)
5018 {
5019 return exec_recursive(func, obj, rb_obj_id(paired_obj), arg, 1);
5020 }
5021
5022 /*
5023 * call-seq:
5024 * thread.backtrace -> array
5025 *
5026 * Returns the current backtrace of the target thread.
5027 *
5028 */
5029
5030 static VALUE
5031 rb_thread_backtrace_m(int argc, VALUE *argv, VALUE thval)
5032 {
5033 return rb_vm_thread_backtrace(argc, argv, thval);
5034 }
5035
5036 /* call-seq:
5037 * thread.backtrace_locations(*args) -> array or nil
5038 *
5039 * Returns the execution stack for the target thread---an array containing
5040 * backtrace location objects.
5041 *
5042 * See Thread::Backtrace::Location for more information.
5043 *
5044 * This method behaves similarly to Kernel#caller_locations except it applies
5045 * to a specific thread.
5046 */
5047 static VALUE
5048 rb_thread_backtrace_locations_m(int argc, VALUE *argv, VALUE thval)
5049 {
5050 return rb_vm_thread_backtrace_locations(argc, argv, thval);
5051 }
5052
5053 /*
5054 * Document-class: ThreadError
5055 *
5056 * Raised when an invalid operation is attempted on a thread.
5057 *
5058 * For example, when no other thread has been started:
5059 *
5060 * Thread.stop
5061 *
5062 * This will raises the following exception:
5063 *
5064 * ThreadError: stopping only thread
5065 * note: use sleep to stop forever
5066 */
5067
5068 void
5069 Init_Thread(void)
5070 {
5071 #undef rb_intern
5072 #define rb_intern(str) rb_intern_const(str)
5073
5074 VALUE cThGroup;
5075 rb_thread_t *th = GET_THREAD();
5076
5077 sym_never = ID2SYM(rb_intern("never"));
5078 sym_immediate = ID2SYM(rb_intern("immediate"));
5079 sym_on_blocking = ID2SYM(rb_intern("on_blocking"));
5080 id_locals = rb_intern("locals");
5081
5082 rb_define_singleton_method(rb_cThread, "new", thread_s_new, -1);
5083 rb_define_singleton_method(rb_cThread, "start", thread_start, -2);
5084 rb_define_singleton_method(rb_cThread, "fork", thread_start, -2);
5085 rb_define_singleton_method(rb_cThread, "main", rb_thread_s_main, 0);
5086 rb_define_singleton_method(rb_cThread, "current", thread_s_current, 0);
5087 rb_define_singleton_method(rb_cThread, "stop", rb_thread_stop, 0);
5088 rb_define_singleton_method(rb_cThread, "kill", rb_thread_s_kill, 1);
5089 rb_define_singleton_method(rb_cThread, "exit", rb_thread_exit, 0);
5090 rb_define_singleton_method(rb_cThread, "pass", thread_s_pass, 0);
5091 rb_define_singleton_method(rb_cThread, "list", rb_thread_list, 0);
5092 rb_define_singleton_method(rb_cThread, "abort_on_exception", rb_thread_s_abort_exc, 0);
5093 rb_define_singleton_method(rb_cThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1);
5094 #if THREAD_DEBUG < 0
5095 rb_define_singleton_method(rb_cThread, "DEBUG", rb_thread_s_debug, 0);
5096 rb_define_singleton_method(rb_cThread, "DEBUG=", rb_thread_s_debug_set, 1);
5097 #endif
5098 rb_define_singleton_method(rb_cThread, "handle_interrupt", rb_thread_s_handle_interrupt, 1);
5099 rb_define_singleton_method(rb_cThread, "pending_interrupt?", rb_thread_s_pending_interrupt_p, -1);
5100 rb_define_method(rb_cThread, "pending_interrupt?", rb_thread_pending_interrupt_p, -1);
5101
5102 rb_define_method(rb_cThread, "initialize", thread_initialize, -2);
5103 rb_define_method(rb_cThread, "raise", thread_raise_m, -1);
5104 rb_define_method(rb_cThread, "join", thread_join_m, -1);
5105 rb_define_method(rb_cThread, "value", thread_value, 0);
5106 rb_define_method(rb_cThread, "kill", rb_thread_kill, 0);
5107 rb_define_method(rb_cThread, "terminate", rb_thread_kill, 0);
5108 rb_define_method(rb_cThread, "exit", rb_thread_kill, 0);
5109 rb_define_method(rb_cThread, "run", rb_thread_run, 0);
5110 rb_define_method(rb_cThread, "wakeup", rb_thread_wakeup, 0);
5111 rb_define_method(rb_cThread, "[]", rb_thread_aref, 1);
5112 rb_define_method(rb_cThread, "[]=", rb_thread_aset, 2);
5113 rb_define_method(rb_cThread, "key?", rb_thread_key_p, 1);
5114 rb_define_method(rb_cThread, "keys", rb_thread_keys, 0);
5115 rb_define_method(rb_cThread, "priority", rb_thread_priority, 0);
5116 rb_define_method(rb_cThread, "priority=", rb_thread_priority_set, 1);
5117 rb_define_method(rb_cThread, "status", rb_thread_status, 0);
5118 rb_define_method(rb_cThread, "thread_variable_get", rb_thread_variable_get, 1);
5119 rb_define_method(rb_cThread, "thread_variable_set", rb_thread_variable_set, 2);
5120 rb_define_method(rb_cThread, "thread_variables", rb_thread_variables, 0);
5121 rb_define_method(rb_cThread, "thread_variable?", rb_thread_variable_p, 1);
5122 rb_define_method(rb_cThread, "alive?", rb_thread_alive_p, 0);
5123 rb_define_method(rb_cThread, "stop?", rb_thread_stop_p, 0);
5124 rb_define_method(rb_cThread, "abort_on_exception", rb_thread_abort_exc, 0);
5125 rb_define_method(rb_cThread, "abort_on_exception=", rb_thread_abort_exc_set, 1);
5126 rb_define_method(rb_cThread, "safe_level", rb_thread_safe_level, 0);
5127 rb_define_method(rb_cThread, "group", rb_thread_group, 0);
5128 rb_define_method(rb_cThread, "backtrace", rb_thread_backtrace_m, -1);
5129 rb_define_method(rb_cThread, "backtrace_locations", rb_thread_backtrace_locations_m, -1);
5130
5131 rb_define_method(rb_cThread, "inspect", rb_thread_inspect, 0);
5132
5133 closed_stream_error = rb_exc_new2(rb_eIOError, "stream closed");
5134 OBJ_TAINT(closed_stream_error);
5135 OBJ_FREEZE(closed_stream_error);
5136
5137 cThGroup = rb_define_class("ThreadGroup", rb_cObject);
5138 rb_define_alloc_func(cThGroup, thgroup_s_alloc);
5139 rb_define_method(cThGroup, "list", thgroup_list, 0);
5140 rb_define_method(cThGroup, "enclose", thgroup_enclose, 0);
5141 rb_define_method(cThGroup, "enclosed?", thgroup_enclosed_p, 0);
5142 rb_define_method(cThGroup, "add", thgroup_add, 1);
5143
5144 {
5145 th->thgroup = th->vm->thgroup_default = rb_obj_alloc(cThGroup);
5146 rb_define_const(cThGroup, "Default", th->thgroup);
5147 }
5148
5149 rb_cMutex = rb_define_class("Mutex", rb_cObject);
5150 rb_define_alloc_func(rb_cMutex, mutex_alloc);
5151 rb_define_method(rb_cMutex, "initialize", mutex_initialize, 0);
5152 rb_define_method(rb_cMutex, "locked?", rb_mutex_locked_p, 0);
5153 rb_define_method(rb_cMutex, "try_lock", rb_mutex_trylock, 0);
5154 rb_define_method(rb_cMutex, "lock", rb_mutex_lock, 0);
5155 rb_define_method(rb_cMutex, "unlock", rb_mutex_unlock, 0);
5156 rb_define_method(rb_cMutex, "sleep", mutex_sleep, -1);
5157 rb_define_method(rb_cMutex, "synchronize", rb_mutex_synchronize_m, 0);
5158 rb_define_method(rb_cMutex, "owned?", rb_mutex_owned_p, 0);
5159
5160 recursive_key = rb_intern("__recursive_key__");
5161 rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError);
5162
5163 /* init thread core */
5164 {
5165 /* main thread setting */
5166 {
5167 /* acquire global vm lock */
5168 gvl_init(th->vm);
5169 gvl_acquire(th->vm, th);
5170 native_mutex_initialize(&th->vm->thread_destruct_lock);
5171 native_mutex_initialize(&th->interrupt_lock);
5172 native_cond_initialize(&th->interrupt_cond,
5173 RB_CONDATTR_CLOCK_MONOTONIC);
5174
5175 th->pending_interrupt_queue = rb_ary_tmp_new(0);
5176 th->pending_interrupt_queue_checked = 0;
5177 th->pending_interrupt_mask_stack = rb_ary_tmp_new(0);
5178
5179 th->interrupt_mask = 0;
5180 }
5181 }
5182
5183 rb_thread_create_timer_thread();
5184
5185 /* suppress warnings on cygwin, mingw and mswin.*/
5186 (void)native_mutex_trylock;
5187 }
5188
5189 int
5190 ruby_native_thread_p(void)
5191 {
5192 rb_thread_t *th = ruby_thread_from_native();
5193
5194 return th != 0;
5195 }
5196
5197 static int
5198 check_deadlock_i(st_data_t key, st_data_t val, int *found)
5199 {
5200 VALUE thval = key;
5201 rb_thread_t *th;
5202 GetThreadPtr(thval, th);
5203
5204 if (th->status != THREAD_STOPPED_FOREVER || RUBY_VM_INTERRUPTED(th)) {
5205 *found = 1;
5206 }
5207 else if (th->locking_mutex) {
5208 rb_mutex_t *mutex;
5209 GetMutexPtr(th->locking_mutex, mutex);
5210
5211 native_mutex_lock(&mutex->lock);
5212 if (mutex->th == th || (!mutex->th && mutex->cond_waiting)) {
5213 *found = 1;
5214 }
5215 native_mutex_unlock(&mutex->lock);
5216 }
5217
5218 return (*found) ? ST_STOP : ST_CONTINUE;
5219 }
5220
5221 #ifdef DEBUG_DEADLOCK_CHECK
5222 static int
5223 debug_i(st_data_t key, st_data_t val, int *found)
5224 {
5225 VALUE thval = key;
5226 rb_thread_t *th;
5227 GetThreadPtr(thval, th);
5228
5229 printf("th:%p %d %d", th, th->status, th->interrupt_flag);
5230 if (th->locking_mutex) {
5231 rb_mutex_t *mutex;
5232 GetMutexPtr(th->locking_mutex, mutex);
5233
5234 native_mutex_lock(&mutex->lock);
5235 printf(" %p %d\n", mutex->th, mutex->cond_waiting);
5236 native_mutex_unlock(&mutex->lock);
5237 }
5238 else
5239 puts("");
5240
5241 return ST_CONTINUE;
5242 }
5243 #endif
5244
5245 static void
5246 rb_check_deadlock(rb_vm_t *vm)
5247 {
5248 int found = 0;
5249
5250 if (vm_living_thread_num(vm) > vm->sleeper) return;
5251 if (vm_living_thread_num(vm) < vm->sleeper) rb_bug("sleeper must not be more than vm_living_thread_num(vm)");
5252 if (patrol_thread && patrol_thread != GET_THREAD()) return;
5253
5254 st_foreach(vm->living_threads, check_deadlock_i, (st_data_t)&found);
5255
5256 if (!found) {
5257 VALUE argv[2];
5258 argv[0] = rb_eFatal;
5259 argv[1] = rb_str_new2("No live threads left. Deadlock?");
5260 #ifdef DEBUG_DEADLOCK_CHECK
5261 printf("%d %d %p %p\n", vm->living_threads->num_entries, vm->sleeper, GET_THREAD(), vm->main_thread);
5262 st_foreach(vm->living_threads, debug_i, (st_data_t)0);
5263 #endif
5264 vm->sleeper--;
5265 rb_threadptr_raise(vm->main_thread, 2, argv);
5266 }
5267 }
5268
5269 static void
5270 update_coverage(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
5271 {
5272 VALUE coverage = GET_THREAD()->cfp->iseq->coverage;
5273 if (coverage && RBASIC(coverage)->klass == 0) {
5274 long line = rb_sourceline() - 1;
5275 long count;
5276 if (RARRAY_AREF(coverage, line) == Qnil) {
5277 return;
5278 }
5279 count = FIX2LONG(RARRAY_AREF(coverage, line)) + 1;
5280 if (POSFIXABLE(count)) {
5281 RARRAY_ASET(coverage, line, LONG2FIX(count));
5282 }
5283 }
5284 }
5285
5286 VALUE
5287 rb_get_coverages(void)
5288 {
5289 return GET_VM()->coverages;
5290 }
5291
5292 void
5293 rb_set_coverages(VALUE coverages)
5294 {
5295 GET_VM()->coverages = coverages;
5296 rb_add_event_hook(update_coverage, RUBY_EVENT_COVERAGE, Qnil);
5297 }
5298
5299 void
5300 rb_reset_coverages(void)
5301 {
5302 GET_VM()->coverages = Qfalse;
5303 rb_remove_event_hook(update_coverage);
5304 }
5305
5306 VALUE
5307 rb_uninterruptible(VALUE (*b_proc)(ANYARGS), VALUE data)
5308 {
5309 VALUE interrupt_mask = rb_hash_new();
5310 rb_thread_t *cur_th = GET_THREAD();
5311
5312 rb_hash_aset(interrupt_mask, rb_cObject, sym_never);
5313 rb_ary_push(cur_th->pending_interrupt_mask_stack, interrupt_mask);
5314
5315 return rb_ensure(b_proc, data, rb_ary_pop, cur_th->pending_interrupt_mask_stack);
5316 }
5317
5318 void
5319 ruby_kill(rb_pid_t pid, int sig)
5320 {
5321 int err;
5322 rb_thread_t *th = GET_THREAD();
5323
5324 /*
5325 * When target pid is self, many caller assume signal will be
5326 * delivered immediately and synchronously.
5327 */
5328 {
5329 GVL_UNLOCK_BEGIN();
5330 native_mutex_lock(&th->interrupt_lock);
5331 err = kill(pid, sig);
5332 native_cond_wait(&th->interrupt_cond, &th->interrupt_lock);
5333 native_mutex_unlock(&th->interrupt_lock);
5334 GVL_UNLOCK_END();
5335 }
5336 if (err < 0) {
5337 rb_sys_fail(0);
5338 }
5339 }
RBASIC_CLEAR_CLASS
#define RBASIC_CLEAR_CLASS(obj)
Definition: internal.h:607
vm_living_thread_num
static int vm_living_thread_num(rb_vm_t *vm)
Definition: thread.c:2984
rb_time_interval
struct timeval rb_time_interval(VALUE num)
Definition: time.c:2411
rb_thread_struct::cfp
rb_control_frame_t * cfp
Definition: vm_core.h:531
rb_threadptr_unlock_all_locking_mutexes
void rb_threadptr_unlock_all_locking_mutexes(rb_thread_t *th)
Definition: thread.c:404
rb_thread_struct::join_list
rb_thread_list_t * join_list
Definition: vm_core.h:613
T_OBJECT
#define T_OBJECT
Definition: ruby.h:477
sym_never
static VALUE sym_never
Definition: thread.c:82
thgroup_enclose
static VALUE thgroup_enclose(VALUE group)
Definition: thread.c:4067
rb_eStandardError
VALUE rb_eStandardError
Definition: error.c:546
thgroup_list_params::ary
VALUE ary
Definition: thread.c:4009
rb_mutex_struct::cond
rb_nativethread_cond_t cond
Definition: thread.c:391
rb_thread_variable_p
static VALUE rb_thread_variable_p(VALUE thread, VALUE key)
Definition: thread.c:3081
eKillSignal
#define eKillSignal
Definition: thread.c:93
rb_thread_struct::stack_end
VALUE * stack_end
Definition: vm_core.h:622
RUBY_VM_CHECK_INTS
#define RUBY_VM_CHECK_INTS(th)
Definition: vm_core.h:989
rb_thread_struct::running_time_us
unsigned long running_time_us
Definition: vm_core.h:654
rb_thread_struct::vm
rb_vm_t * vm
Definition: vm_core.h:526
rb_exc_new
VALUE rb_exc_new(VALUE etype, const char *ptr, long len)
Definition: error.c:573
thgroup_add
static VALUE thgroup_add(VALUE group, VALUE thread)
Definition: thread.c:4124
ruby_kill
void ruby_kill(rb_pid_t pid, int sig)
Definition: thread.c:5319
check_deadlock_i
static int check_deadlock_i(st_data_t key, st_data_t val, int *found)
Definition: thread.c:5198
rb_exc_new2
#define rb_exc_new2
Definition: intern.h:247
rb_mutex_sleep
VALUE rb_mutex_sleep(VALUE self, VALUE timeout)
Definition: thread.c:4567
ruby_thread_has_gvl_p
int ruby_thread_has_gvl_p(void)
Definition: thread.c:1492
rb_ary_pop
VALUE rb_ary_pop(VALUE ary)
Definition: array.c:940
rb_thread_s_handle_interrupt
static VALUE rb_thread_s_handle_interrupt(VALUE self, VALUE mask_arg)
Definition: thread.c:1788
patrol_thread
static const rb_thread_t * patrol_thread
Definition: thread.c:4363
rb_mutex_struct::next_mutex
struct rb_mutex_struct * next_mutex
Definition: thread.c:393
ruby_thread_stack_overflow
void ruby_thread_stack_overflow(rb_thread_t *th)
Definition: thread.c:2084
RARRAY_LEN
#define RARRAY_LEN(a)
Definition: ruby.h:878
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:327
rb_thread_priority
static VALUE rb_thread_priority(VALUE thread)
Definition: thread.c:3116
gettimeofday
int gettimeofday(struct timeval *, struct timezone *)
Definition: win32.c:4307
rb_postponed_job_flush
void rb_postponed_job_flush(rb_vm_t *vm)
Definition: vm_trace.c:1512
FALSE
#define FALSE
Definition: nkf.h:174
RUBY_TYPED_FREE_IMMEDIATELY
#define RUBY_TYPED_FREE_IMMEDIATELY
Definition: ruby.h:1015
rb_hash_lookup
#define rb_hash_lookup
Definition: tcltklib.c:269
mutex_mark
#define mutex_mark
Definition: thread.c:4185
lock_func
static int lock_func(rb_thread_t *th, rb_mutex_t *mutex, int timeout_ms)
Definition: thread.c:4309
rb_mutex_unlock_th
static const char * rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t volatile *th)
Definition: thread.c:4464
rb_obj_id
VALUE rb_obj_id(VALUE obj)
Definition: gc.c:2373
thread_cleanup_func_before_exec
static void thread_cleanup_func_before_exec(void *th_ptr)
Definition: thread.c:464
INT2NUM
#define INT2NUM(x)
Definition: ruby.h:1288
trap
static VALUE trap(int sig, sighandler_t func, VALUE command)
Definition: signal.c:1049
rb_vm_struct::running_thread
struct rb_thread_struct * running_thread
Definition: vm_core.h:355
rb_make_exception
VALUE rb_make_exception(int argc, VALUE *argv)
Definition: eval.c:682
rb_mutex_allow_trap
void rb_mutex_allow_trap(VALUE self, int val)
Definition: thread.c:4642
select_args::fd
int fd
Definition: thread.c:3731
select_args::tv
struct timeval * tv
Definition: thread.c:3737
st_table
Definition: st.h:69
rb_nativethread_lock_unlock
void rb_nativethread_lock_unlock(rb_nativethread_lock_t *lock)
Definition: thread.c:298
RUBY_VM_SET_INTERRUPT
#define RUBY_VM_SET_INTERRUPT(th)
Definition: vm_core.h:960
rb_thread_abort_exc_set
static VALUE rb_thread_abort_exc_set(VALUE thread, VALUE val)
Definition: thread.c:2545
rb_mutex_owned_p
VALUE rb_mutex_owned_p(VALUE self)
Definition: thread.c:4449
rb_thread_struct::local_storage
st_table * local_storage
Definition: vm_core.h:611
join_arg::limit
double limit
Definition: thread.c:756
ST_STOP
Definition: st.h:100
rb_thread_struct::pending_interrupt_queue_checked
int pending_interrupt_queue_checked
Definition: vm_core.h:582
rb_eSignal
VALUE rb_eSignal
Definition: error.c:544
rb_mutex_abandon_all
static void rb_mutex_abandon_all(rb_mutex_t *mutexes)
Definition: thread.c:4539
rb_thread_blocking_region_begin
struct rb_blocking_region_buffer * rb_thread_blocking_region_begin(void)
Definition: thread.c:1232
select_args::read
rb_fdset_t * read
Definition: thread.c:3734
rb_exec_recursive_outer
VALUE rb_exec_recursive_outer(VALUE(*func)(VALUE, VALUE, int), VALUE obj, VALUE arg)
Definition: thread.c:5005
NUM2INT
#define NUM2INT(x)
Definition: ruby.h:630
count
int count
Definition: encoding.c:48
max
static int max(int a, int b)
Definition: strftime.c:141
exec_recursive_params::func
VALUE(* func)(VALUE, VALUE, int)
Definition: thread.c:4900
rb_define_singleton_method
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1655
thgroup_enclosed_p
static VALUE thgroup_enclosed_p(VALUE group)
Definition: thread.c:4086
rb_thread_check_trap_pending
int rb_thread_check_trap_pending(void)
Definition: thread.c:1149
rb_threadptr_execute_interrupts
void rb_threadptr_execute_interrupts(rb_thread_t *th, int blocking_timing)
Definition: thread.c:1953
rb_thread_list
VALUE rb_thread_list(void)
Definition: thread.c:2393
thread_join_sleep
static VALUE thread_join_sleep(VALUE arg)
Definition: thread.c:782
rb_iseq_struct::coverage
const VALUE coverage
Definition: vm_core.h:229
rb_mutex_struct
Definition: thread.c:388
rb_exec_recursive
VALUE rb_exec_recursive(VALUE(*func)(VALUE, VALUE, int), VALUE obj, VALUE arg)
Definition: thread.c:4982
exec_recursive_params::list
VALUE list
Definition: thread.c:4901
CLASS_OF
#define CLASS_OF(v)
Definition: ruby.h:440
terminate_atfork_before_exec_i
static int terminate_atfork_before_exec_i(st_data_t key, st_data_t val, st_data_t current_th)
Definition: thread.c:3941
rb_thread_blocking_region_end
void rb_thread_blocking_region_end(struct rb_blocking_region_buffer *region)
Definition: thread.c:1241
rb_thread_variables
static VALUE rb_thread_variables(VALUE thread)
Definition: thread.c:3052
rb_thread_list_struct::th
struct rb_thread_struct * th
Definition: vm_core.h:509
rb_unblock_function_t
void rb_unblock_function_t(void *)
Definition: intern.h:864
rb_ary_delete_at
VALUE rb_ary_delete_at(VALUE ary, long pos)
Definition: array.c:2951
recursive_list_access
static VALUE recursive_list_access(void)
Definition: thread.c:4773
rb_unblock_callback::func
rb_unblock_function_t * func
Definition: vm_core.h:500
Qtrue
#define Qtrue
Definition: ruby.h:426
rb_remove_event_hook
int rb_remove_event_hook(rb_event_hook_func_t func)
Definition: vm_trace.c:204
st_insert
int st_insert(st_table *, st_data_t, st_data_t)
update_coverage
static void update_coverage(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
Definition: thread.c:5270
thread_s_new
static VALUE thread_s_new(int argc, VALUE *argv, VALUE klass)
Definition: thread.c:685
rb_error_frozen
void rb_error_frozen(const char *what)
Definition: error.c:2077
TypedData_Wrap_Struct
#define TypedData_Wrap_Struct(klass, data_type, sval)
Definition: ruby.h:1027
CLOCK_MONOTONIC
#define CLOCK_MONOTONIC
Definition: win32.h:129
rb_thread_struct::pending_interrupt_mask_stack
VALUE pending_interrupt_mask_stack
Definition: vm_core.h:583
rb_ary_shift
VALUE rb_ary_shift(VALUE ary)
Definition: array.c:991
threadptr_local_aref
static VALUE threadptr_local_aref(rb_thread_t *th, ID id)
Definition: thread.c:2750
ST_CONTINUE
Definition: st.h:100
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1041
rb_mod_ancestors
VALUE rb_mod_ancestors(VALUE mod)
Definition: class.c:1056
mutex_initialize
static VALUE mutex_initialize(VALUE self)
Definition: thread.c:4245
eval_intern.h
rb_mutex_abandon_keeping_mutexes
static void rb_mutex_abandon_keeping_mutexes(rb_thread_t *th)
Definition: thread.c:4517
thread_pthread.c
rb_threadptr_signal_raise
void rb_threadptr_signal_raise(rb_thread_t *th, int sig)
Definition: thread.c:2060
timeval::tv_sec
long tv_sec
Definition: ossl_asn1.c:17
rb_mutex_struct::th
struct rb_thread_struct volatile * th
Definition: thread.c:392
double2timeval
static struct timeval double2timeval(double d)
Definition: thread.c:960
rb_frame_this_func
ID rb_frame_this_func(void)
Definition: eval.c:943
sysstack_error
#define sysstack_error
Definition: vm_core.h:899
rb_w32_get_osfhandle
SOCKET rb_w32_get_osfhandle(int)
Definition: win32.c:984
rb_eTypeError
VALUE rb_eTypeError
Definition: error.c:548
rb_thread_stop
VALUE rb_thread_stop(void)
Definition: thread.c:2342
TH_JUMP_TAG
#define TH_JUMP_TAG(th, st)
Definition: eval_intern.h:171
mutex_alloc
static VALUE mutex_alloc(VALUE klass)
Definition: thread.c:4227
rb_mutex_synchronize
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Definition: thread.c:4619
mutex_data_type
static const rb_data_type_t mutex_data_type
Definition: thread.c:4209
rb_thread_struct::waiting_fd
int waiting_fd
Definition: vm_core.h:539
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:896
rb_thread_wait_for
void rb_thread_wait_for(struct timeval time)
Definition: thread.c:1115
rb_vm_struct::living_threads
st_table * living_threads
Definition: vm_core.h:357
rb_signal_exec
void rb_signal_exec(rb_thread_t *th, int sig)
Definition: signal.c:861
handle_interrupt_arg_check_i
static int handle_interrupt_arg_check_i(VALUE key, VALUE val)
Definition: thread.c:1672
rb_hash_tbl_raw
struct st_table * rb_hash_tbl_raw(VALUE hash)
Definition: hash.c:351
rb_ary_tmp_new
VALUE rb_ary_tmp_new(long capa)
Definition: array.c:534
rb_fd_zero
#define rb_fd_zero(f)
Definition: intern.h:349
kill
int kill(int, int)
Definition: win32.c:4439
rb_thread_safe_level
static VALUE rb_thread_safe_level(VALUE thread)
Definition: thread.c:2718
rb_thread_aset
static VALUE rb_thread_aset(VALUE self, VALUE id, VALUE val)
Definition: thread.c:2880
rb_thread_current
VALUE rb_thread_current(void)
Definition: thread.c:2401
PRIxVALUE
#define PRIxVALUE
Definition: ruby.h:135
rb_threadptr_pending_interrupt_enque
void rb_threadptr_pending_interrupt_enque(rb_thread_t *th, VALUE v)
Definition: thread.c:1544
OBJ_ID_EQL
#define OBJ_ID_EQL(obj_id, other)
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
rb_thread_alloc
VALUE rb_thread_alloc(VALUE klass)
Definition: vm.c:2229
rb_mutex_sleep_forever
static VALUE rb_mutex_sleep_forever(VALUE time)
Definition: thread.c:4552
rb_thread_abort_exc
static VALUE rb_thread_abort_exc(VALUE thread)
Definition: thread.c:2521
blocking_region_end
static void blocking_region_end(rb_thread_t *th, struct rb_blocking_region_buffer *region)
Definition: thread.c:1218
rb_ivar_get
VALUE rb_ivar_get(VALUE, ID)
Definition: variable.c:1115
rb_nativethread_lock_initialize
void rb_nativethread_lock_initialize(rb_nativethread_lock_t *lock)
Definition: thread.c:280
rb_thread_call_without_gvl
void * rb_thread_call_without_gvl(void *(*func)(void *data), void *data1, rb_unblock_function_t *ubf, void *data2)
Definition: thread.c:1373
rb_ary_clear
VALUE rb_ary_clear(VALUE ary)
Definition: array.c:3381
gc.h
rb_nativethread_lock_t
pthread_mutex_t rb_nativethread_lock_t
Definition: thread_pthread.h:19
clear_coverage
static void clear_coverage(void)
Definition: thread.c:3891
rb_thread_alone
int rb_thread_alone(void)
Definition: thread.c:2990
rb_convert_type
VALUE rb_convert_type(VALUE, int, const char *, const char *)
Definition: object.c:2616
TH_EXEC_TAG
#define TH_EXEC_TAG()
Definition: eval_intern.h:165
thread_win32.c
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
rb_obj_is_kind_of
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Definition: object.c:652
T_HASH
#define T_HASH
Definition: ruby.h:485
sleep_forever
static void sleep_forever(rb_thread_t *th, int nodeadlock, int spurious_check)
Definition: thread.c:987
rb_thread_local_aref
VALUE rb_thread_local_aref(VALUE thread, ID id)
Definition: thread.c:2761
rb_thread_struct::thgroup
VALUE thgroup
Definition: vm_core.h:569
rb_mutex_struct::lock
rb_nativethread_lock_t lock
Definition: thread.c:390
DATA_PTR
#define DATA_PTR(dta)
Definition: ruby.h:992
rb_catch_protect
VALUE rb_catch_protect(VALUE t, rb_block_call_func *func, VALUE data, int *stateptr)
Definition: vm_eval.c:1835
RUBY_VM_SET_TRAP_INTERRUPT
#define RUBY_VM_SET_TRAP_INTERRUPT(th)
Definition: vm_core.h:962
thgroup_memsize
static size_t thgroup_memsize(const void *ptr)
Definition: thread.c:3965
rb_mutex_abandon_locking_mutex
static void rb_mutex_abandon_locking_mutex(rb_thread_t *th)
Definition: thread.c:4526
sym_immediate
static VALUE sym_immediate
Definition: thread.c:80
blocking_region_begin
static int blocking_region_begin(rb_thread_t *th, struct rb_blocking_region_buffer *region, rb_unblock_function_t *ubf, void *arg, int fail_if_interrupted)
Definition: thread.c:1200
rb_gc_mark
void rb_gc_mark(VALUE ptr)
Definition: gc.c:3604
thread_shield_mark
static void thread_shield_mark(void *ptr)
Definition: thread.c:4654
st_index_t
st_data_t st_index_t
Definition: st.h:48
TAG_RAISE
#define TAG_RAISE
Definition: eval_intern.h:193
PUSH_TAG
#define PUSH_TAG()
Definition: eval_intern.h:141
mutex_memsize
static size_t mutex_memsize(const void *ptr)
Definition: thread.c:4204
system_working
static volatile int system_working
Definition: thread.c:95
thread_join
static VALUE thread_join(rb_thread_t *target_th, double delay)
Definition: thread.c:808
remove_from_join_list
static VALUE remove_from_join_list(VALUE arg)
Definition: thread.c:761
select_args::as
union select_args::@154 as
rb_thread_kill
VALUE rb_thread_kill(VALUE thread)
Definition: thread.c:2187
rb_mutex_locked_p
VALUE rb_mutex_locked_p(VALUE self)
Definition: thread.c:4263
rb_threadptr_dead
static int rb_threadptr_dead(rb_thread_t *th)
Definition: thread.c:2599
rb_check_id
ID rb_check_id(volatile VALUE *namep)
Returns ID for the given name if it is interned already, or 0.
Definition: ripper.c:17324
FIXNUM_P
#define FIXNUM_P(f)
Definition: ruby.h:347
rb_thread_alive_p
static VALUE rb_thread_alive_p(VALUE thread)
Definition: thread.c:2668
rb_thread_struct
Definition: vm_core.h:524
select_args::write
rb_fdset_t * write
Definition: thread.c:3735
rb_exec_recursive_paired
VALUE rb_exec_recursive_paired(VALUE(*func)(VALUE, VALUE, int), VALUE obj, VALUE paired_obj, VALUE arg)
Definition: thread.c:4993
rb_fd_rcopy
#define rb_fd_rcopy(d, s)
Definition: thread.c:3418
rb_thread_struct::value
VALUE value
Definition: vm_core.h:570
io.h
rb_thread_start_timer_thread
void rb_thread_start_timer_thread(void)
Definition: thread.c:3870
rb_thread_struct::machine
struct rb_thread_struct::@169 machine
init_set_fd
static rb_fdset_t * init_set_fd(int fd, rb_fdset_t *fds)
Definition: thread.c:3721
rb_obj_classname
const char * rb_obj_classname(VALUE)
Definition: variable.c:406
rb_cMutex
VALUE rb_cMutex
Definition: thread.c:77
rb_mutex_struct::allow_trap
int allow_trap
Definition: thread.c:395
RB_WAITFD_OUT
#define RB_WAITFD_OUT
Definition: io.h:49
rb_vm_struct::thgroup_default
VALUE thgroup_default
Definition: vm_core.h:358
rb_fd_set
#define rb_fd_set(n, f)
Definition: intern.h:350
timespec::tv_sec
time_t tv_sec
Definition: missing.h:51
sym
#define sym(x)
Definition: date_core.c:3695
rb_thread_stop_p
static VALUE rb_thread_stop_p(VALUE thread)
Definition: thread.c:2693
thread_cleanup_func
static void thread_cleanup_func(void *th_ptr, int atfork)
Definition: thread.c:475
timeofday
static double timeofday(void)
Definition: thread.c:1083
st_data_t
RUBY_SYMBOL_EXPORT_BEGIN typedef unsigned long st_data_t
Definition: st.h:20
TAG_FATAL
#define TAG_FATAL
Definition: eval_intern.h:195
ruby_native_thread_p
int ruby_native_thread_p(void)
Definition: thread.c:5190
rb_thread_s_abort_exc_set
static VALUE rb_thread_s_abort_exc_set(VALUE self, VALUE val)
Definition: thread.c:2498
threadptr_get_interrupts
static rb_atomic_t threadptr_get_interrupts(rb_thread_t *th)
Definition: thread.c:1940
rb_fd_isset
#define rb_fd_isset(n, f)
Definition: intern.h:352
RB_BLOCK_CALL_FUNC_ARGLIST
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Definition: ruby.h:1511
rb_thread_struct::first_func
VALUE(* first_func)(ANYARGS)
Definition: vm_core.h:617
rb_hash_foreach
void rb_hash_foreach(VALUE hash, int(*func)(ANYARGS), VALUE farg)
Definition: hash.c:264
rb_thread_wakeup
VALUE rb_thread_wakeup(VALUE thread)
Definition: thread.c:2272
join_arg
Definition: thread.c:754
exec_recursive_params::objid
VALUE objid
Definition: thread.c:4903
rb_thread_s_main
static VALUE rb_thread_s_main(VALUE klass)
Definition: thread.c:2435
rb_exc_raise
void rb_exc_raise(VALUE mesg)
Definition: eval.c:567
rb_thread_wait_fd_rw
static void rb_thread_wait_fd_rw(int fd, int read)
Definition: thread.c:3499
sym_on_blocking
static VALUE sym_on_blocking
Definition: thread.c:81
rb_thread_struct::stack
VALUE * stack
Definition: vm_core.h:529
select_args
Definition: io.c:8315
rb_thread_schedule_limits
static void rb_thread_schedule_limits(unsigned long limits_us)
Definition: thread.c:1170
RB_TYPE_P
#define RB_TYPE_P(obj, type)
Definition: ruby.h:1664
rb_reset_random_seed
void rb_reset_random_seed(void)
Definition: random.c:1323
rb_thread_fd_writable
int rb_thread_fd_writable(int fd)
Definition: thread.c:3525
RHASH
#define RHASH(obj)
Definition: ruby.h:1124
rb_threadptr_interrupt_common
static void rb_threadptr_interrupt_common(rb_thread_t *th, int trap)
Definition: thread.c:341
thgroup_s_alloc
static VALUE thgroup_s_alloc(VALUE klass)
Definition: thread.c:3996
POSFIXABLE
#define POSFIXABLE(f)
Definition: ruby.h:348
rb_control_frame_struct::self
VALUE self
Definition: vm_core.h:450
INTERRUPT_NONE
Definition: thread.c:1551
RUBY_VM_INTERRUPTED_ANY
#define RUBY_VM_INTERRUPTED_ANY(th)
Definition: vm_core.h:964
st_hash_type
Definition: st.h:55
TH_POP_TAG
#define TH_POP_TAG()
Definition: eval_intern.h:128
st_lookup
int st_lookup(st_table *, st_data_t, st_data_t *)
thread_list_i
static int thread_list_i(st_data_t key, st_data_t val, void *data)
Definition: thread.c:2353
MEMZERO
#define MEMZERO(p, type, n)
Definition: ruby.h:1351
PRI_TIMET_PREFIX
#define PRI_TIMET_PREFIX
Definition: ruby.h:145
coverage
static VALUE coverage(VALUE fname, int n)
Definition: ripper.c:11902
closed_stream_error
#define closed_stream_error
Definition: thread.c:97
rb_vm_thread_backtrace
VALUE rb_vm_thread_backtrace(int argc, VALUE *argv, VALUE thval)
Definition: vm_backtrace.c:906
thread_status_name
static const char * thread_status_name(rb_thread_t *th)
Definition: thread.c:2580
join_arg::target
rb_thread_t * target
Definition: thread.c:755
exec_recursive_params::arg
VALUE arg
Definition: thread.c:4905
RUBY_THREAD_PRIORITY_MAX
#define RUBY_THREAD_PRIORITY_MAX
Definition: thread.c:69
rb_fdset_t
fd_set rb_fdset_t
Definition: intern.h:348
rb_fd_term
#define rb_fd_term(f)
Definition: intern.h:359
rb_thread_priority_set
static VALUE rb_thread_priority_set(VALUE thread, VALUE prio)
Definition: thread.c:3151
thread.h
rb_num2dbl
double rb_num2dbl(VALUE)
Definition: object.c:2964
thgroup
Definition: thread.c:3959
do_select
static int do_select(int n, rb_fdset_t *read, rb_fdset_t *write, rb_fdset_t *except, struct timeval *timeout)
Definition: thread.c:3422
sleep_for_polling
static void sleep_for_polling(rb_thread_t *th)
Definition: thread.c:1106
rb_block_given_p
int rb_block_given_p(void)
Definition: eval.c:712
rb_hash_aset
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:1393
EXEC_TAG
#define EXEC_TAG()
Definition: eval_intern.h:168
rb_thread_struct::locking_mutex
VALUE locking_mutex
Definition: vm_core.h:590
thread_shield_data_type
static const rb_data_type_t thread_shield_data_type
Definition: thread.c:4659
val
#define val
timeval::tv_usec
long tv_usec
Definition: ossl_asn1.c:18
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1553
rb_eRuntimeError
VALUE rb_eRuntimeError
Definition: error.c:547
rb_thread_inspect
static VALUE rb_thread_inspect(VALUE thread)
Definition: thread.c:2734
RB_WAITFD_PRI
#define RB_WAITFD_PRI
Definition: io.h:48
THREAD_KILLED
Definition: vm_core.h:479
id_locals
static ID id_locals
Definition: thread.c:83
PRIdVALUE
#define PRIdVALUE
Definition: ruby.h:132
rb_threadptr_raise
static VALUE rb_threadptr_raise(rb_thread_t *, int, VALUE *)
Definition: thread.c:2040
rb_fd_ptr
#define rb_fd_ptr(f)
Definition: intern.h:356
rb_mutex_trylock
VALUE rb_mutex_trylock(VALUE self)
Definition: thread.c:4290
rb_typeddata_is_kind_of
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:510
timev.h
rb_ary_new
VALUE rb_ary_new(void)
Definition: array.c:495
rb_thread_struct::blocking_region_buffer
void * blocking_region_buffer
Definition: vm_core.h:567
exec_recursive
static VALUE exec_recursive(VALUE(*func)(VALUE, VALUE, int), VALUE obj, VALUE pairid, VALUE arg, int outer)
Definition: thread.c:4927
thread_create_core
static VALUE thread_create_core(VALUE thval, VALUE args, VALUE(*fn)(ANYARGS))
Definition: thread.c:625
Init_Thread
void Init_Thread(void)
Definition: thread.c:5069
JUMP_TAG
#define JUMP_TAG(st)
Definition: eval_intern.h:173
THREAD_STOPPED_FOREVER
Definition: vm_core.h:478
rb_control_frame_struct::iseq
rb_iseq_t * iseq
Definition: vm_core.h:448
NIL_P
#define NIL_P(v)
Definition: ruby.h:438
rb_threadptr_pending_interrupt_include_p
static int rb_threadptr_pending_interrupt_include_p(rb_thread_t *th, VALUE err)
Definition: thread.c:1603
timespec::tv_nsec
long tv_nsec
Definition: missing.h:52
rb_thread_stop_timer_thread
void rb_thread_stop_timer_thread(int close_anyway)
Definition: thread.c:3856
UNLIKELY
#define UNLIKELY(x)
Definition: vm_core.h:109
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:630
rb_threadptr_ready
static void rb_threadptr_ready(rb_thread_t *th)
Definition: thread.c:2034
st_delete
int st_delete(st_table *, st_data_t *, st_data_t *)
thgroup::enclosed
int enclosed
Definition: thread.c:3960
rb_intern
#define rb_intern(str)
rb_define_const
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2225
rb_thread_atfork_before_exec
void rb_thread_atfork_before_exec(void)
Definition: thread.c:3954
thread_debug
#define thread_debug
Definition: thread.c:210
rb_threadptr_pending_interrupt_empty_p
static int rb_threadptr_pending_interrupt_empty_p(rb_thread_t *th)
Definition: thread.c:1597
OBJ_FROZEN
#define OBJ_FROZEN(x)
Definition: ruby.h:1185
rb_threadptr_check_signal
void rb_threadptr_check_signal(rb_thread_t *mth)
Definition: thread.c:3815
rb_class_inherited_p
VALUE rb_class_inherited_p(VALUE, VALUE)
Definition: object.c:1564
rb_vm_struct::thread_abort_on_exception
int thread_abort_on_exception
Definition: vm_core.h:361
argc
int argc
Definition: ruby.c:131
rb_thread_status
rb_thread_status
Definition: vm_core.h:475
rb_thread_variable_get
static VALUE rb_thread_variable_get(VALUE thread, VALUE key)
Definition: thread.c:2914
Qfalse
#define Qfalse
Definition: ruby.h:425
INTERRUPT_ON_BLOCKING
Definition: thread.c:1553
exec_recursive_params::obj
VALUE obj
Definition: thread.c:4902
ruby_thread_init_stack
void ruby_thread_init_stack(rb_thread_t *th)
Definition: thread.c:497
rb_proc_location
VALUE rb_proc_location(VALUE self)
Definition: proc.c:928
rb_thread_exit
static VALUE rb_thread_exit(void)
Definition: thread.c:2248
rb_cModule
RUBY_EXTERN VALUE rb_cModule
Definition: ruby.h:1572
rb_thread_check_ints
void rb_thread_check_ints(void)
Definition: thread.c:1139
RUBY_UBF_PROCESS
#define RUBY_UBF_PROCESS
Definition: intern.h:873
rb_exit
void rb_exit(int status)
Definition: process.c:3647
rb_thread_fd_close
void rb_thread_fd_close(int fd)
Definition: thread.c:2131
if
if((ID)(DISPID) nameid!=nameid)
Definition: win32ole.c:770
T_NODE
#define T_NODE
Definition: ruby.h:498
rb_thread_shield_new
VALUE rb_thread_shield_new(void)
Definition: thread.c:4698
rb_vm_struct::sleeper
volatile int sleeper
Definition: vm_core.h:363
ruby_stop
void ruby_stop(int ex)
Calls ruby_cleanup() and exits the process.
Definition: eval.c:264
rb_str_new2
#define rb_str_new2
Definition: intern.h:840
rb_obj_alloc
VALUE rb_obj_alloc(VALUE)
Definition: object.c:1801
err
int err
Definition: win32.c:114
OBJ_FREEZE
#define OBJ_FREEZE(x)
Definition: ruby.h:1186
EXIT_FAILURE
#define EXIT_FAILURE
Definition: eval_intern.h:24
INTERRUPT_NEVER
Definition: thread.c:1554
rb_thread_shield_release
VALUE rb_thread_shield_release(VALUE self)
Definition: thread.c:4734
rb_thread_atfork
void rb_thread_atfork(void)
Definition: thread.c:3931
POP_TAG
#define POP_TAG()
Definition: eval_intern.h:142
GVL_UNLOCK_BEGIN
#define GVL_UNLOCK_BEGIN()
Definition: thread.c:136
thgroup_data_type
static const rb_data_type_t thgroup_data_type
Definition: thread.c:3970
rb_blocking_region_buffer
Definition: thread.c:109
rb_thread_create
VALUE rb_thread_create(VALUE(*fn)(ANYARGS), void *arg)
Definition: thread.c:745
rb_throw_obj
void rb_throw_obj(VALUE tag, VALUE value)
Definition: vm_eval.c:1733
thread_s_current
static VALUE thread_s_current(VALUE klass)
Definition: thread.c:2416
FD_SET
#define FD_SET(fd, set)
Definition: win32.h:629
rb_cThreadShield
VALUE rb_cThreadShield
Definition: thread.c:78
sleep_wait_for_interrupt
static void sleep_wait_for_interrupt(rb_thread_t *th, double sleepsec, int spurious_check)
Definition: thread.c:1100
ATOMIC_CAS
#define ATOMIC_CAS(var, oldval, newval)
Definition: ruby_atomic.h:132
exec_recursive_params::pairid
VALUE pairid
Definition: thread.c:4904
ALLOC
#define ALLOC(type)
Definition: ruby.h:1334
rb_thread_polling
void rb_thread_polling(void)
Definition: thread.c:1122
select_args::read
VALUE read
Definition: io.c:8316
GetMutexPtr
#define GetMutexPtr(obj, tobj)
Definition: thread.c:4182
rb_thread_backtrace_locations_m
static VALUE rb_thread_backtrace_locations_m(int argc, VALUE *argv, VALUE thval)
Definition: thread.c:5048
rb_thread_select
int rb_thread_select(int max, fd_set *read, fd_set *write, fd_set *except, struct timeval *timeout)
Definition: thread.c:3532
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:942
RARRAY_CONST_PTR
#define RARRAY_CONST_PTR(a)
Definition: ruby.h:886
rb_thread_call_without_gvl2
void * rb_thread_call_without_gvl2(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Definition: thread.c:1366
rb_blocking_region_buffer::oldubf
struct rb_unblock_callback oldubf
Definition: thread.c:111
timeval
Definition: ossl_asn1.c:16
func
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:113
rb_thread_set_current
#define rb_thread_set_current(th)
Definition: vm_core.h:940
errno
int errno
TRUE
#define TRUE
Definition: nkf.h:175
rb_uninterruptible
VALUE rb_uninterruptible(VALUE(*b_proc)(ANYARGS), VALUE data)
Definition: thread.c:5307
POSTPONED_JOB_INTERRUPT_MASK
Definition: vm_core.h:955
thgroup_list_i
static int thgroup_list_i(st_data_t key, st_data_t val, st_data_t data)
Definition: thread.c:4014
EXIT_SUCCESS
#define EXIT_SUCCESS
Definition: error.c:29
rb_vm_struct::special_exceptions
VALUE special_exceptions[ruby_special_error_count]
Definition: vm_core.h:368
rb_thread_struct::keeping_mutexes
struct rb_mutex_struct * keeping_mutexes
Definition: vm_core.h:591
rb_thread_shield_wait
VALUE rb_thread_shield_wait(VALUE self)
Definition: thread.c:4714
rb_sprintf
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1250
rb_get_next_signal
int rb_get_next_signal(void)
Definition: signal.c:685
rb_proc_t
Definition: vm_core.h:700
rb_hash_delete
VALUE rb_hash_delete(VALUE hash, VALUE key)
Definition: hash.c:996
ruby_error_closed_stream
Definition: vm_core.h:330
rb_thread_fd_select
int rb_thread_fd_select(int max, rb_fdset_t *read, rb_fdset_t *write, rb_fdset_t *except, struct timeval *timeout)
Definition: thread.c:3576
rb_fd_copy
#define rb_fd_copy(d, s, n)
Definition: intern.h:353
set_unblock_function
static int set_unblock_function(rb_thread_t *th, rb_unblock_function_t *func, void *arg, struct rb_unblock_callback *old, int fail_if_interrupted)
Definition: thread.c:304
const
#define const
Definition: strftime.c:102
thread_fd_close_i
static int thread_fd_close_i(st_data_t key, st_data_t val, st_data_t data)
Definition: thread.c:2116
rb_thread_list_struct
Definition: vm_core.h:507
rb_hash_new
VALUE rb_hash_new(void)
Definition: hash.c:298
ruby_xfree
void ruby_xfree(void *x)
Definition: gc.c:6242
DELAY_INFTY
#define DELAY_INFTY
Definition: thread.c:752
rb_threadptr_reset_raised
int rb_threadptr_reset_raised(rb_thread_t *th)
Definition: thread.c:2106
thgroup_list_params
Definition: thread.c:4008
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1728
buf
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4308
RUBY_VM_SET_TIMER_INTERRUPT
#define RUBY_VM_SET_TIMER_INTERRUPT(th)
Definition: vm_core.h:959
internal.h
rb_add_event_hook
void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
Definition: vm_trace.c:145
ID
unsigned long ID
Definition: ruby.h:89
thread_initialize
static VALUE thread_initialize(VALUE thread, VALUE args)
Definition: thread.c:720
handle_interrupt_timing
handle_interrupt_timing
Definition: thread.c:1550
rb_check_deadlock
static void rb_check_deadlock(rb_vm_t *vm)
Definition: thread.c:5246
rb_mutex_synchronize_m
static VALUE rb_mutex_synchronize_m(VALUE self, VALUE args)
Definition: thread.c:4633
GVL_UNLOCK_END
#define GVL_UNLOCK_END()
Definition: thread.c:141
Qnil
#define Qnil
Definition: ruby.h:427
rb_thread_sleep_forever
void rb_thread_sleep_forever(void)
Definition: thread.c:1069
thread_shield_alloc
static VALUE thread_shield_alloc(VALUE klass)
Definition: thread.c:4666
thgroup::group
VALUE group
Definition: thread.c:3961
OBJ_TAINT
#define OBJ_TAINT(x)
Definition: ruby.h:1177
VALUE
unsigned long VALUE
Definition: ruby.h:88
THREAD_SHIELD_WAITING_MASK
#define THREAD_SHIELD_WAITING_MASK
Definition: thread.c:4672
SAVE_ROOT_JMPBUF
#define SAVE_ROOT_JMPBUF(th, stmt)
Definition: eval_intern.h:112
rb_thread_struct::to_kill
int to_kill
Definition: vm_core.h:563
result
static VALUE result
Definition: nkf.c:40
rb_cThread
RUBY_EXTERN VALUE rb_cThread
Definition: ruby.h:1586
rb_wait_for_single_fd
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Definition: thread.c:3775
keys_i
static int keys_i(VALUE key, VALUE value, VALUE ary)
Definition: thread.c:3028
UNINITIALIZED_VAR
#define UNINITIALIZED_VAR(x)
Definition: vm_core.h:121
RBASIC
#define RBASIC(obj)
Definition: ruby.h:1116
rb_class2name
const char * rb_class2name(VALUE)
Definition: variable.c:397
rb_vm_struct::main_thread
struct rb_thread_struct * main_thread
Definition: vm_core.h:354
clear_coverage_i
static int clear_coverage_i(st_data_t key, st_data_t val, st_data_t dummy)
Definition: thread.c:3877
select_args::error
int error
Definition: thread.c:3732
rb_thread_s_pending_interrupt_p
static VALUE rb_thread_s_pending_interrupt_p(int argc, VALUE *argv, VALUE self)
Definition: thread.c:1924
rb_thread_struct::first_proc
VALUE first_proc
Definition: vm_core.h:615
thgroup_list_params::group
VALUE group
Definition: thread.c:4010
rb_threadptr_pending_interrupt_clear
void rb_threadptr_pending_interrupt_clear(rb_thread_t *th)
Definition: thread.c:1538
rb_gc_set_stack_end
void rb_gc_set_stack_end(VALUE **stack_end_p)
Definition: thread.c:3802
rb_thread_shield_waiting_dec
static void rb_thread_shield_waiting_dec(VALUE b)
Definition: thread.c:4688
TH_PUSH_TAG
#define TH_PUSH_TAG(th)
Definition: eval_intern.h:122
clock_gettime
int clock_gettime(clockid_t, struct timespec *)
Definition: win32.c:4319
rb_thread_schedule
void rb_thread_schedule(void)
Definition: thread.c:1187
rb_mutex_new
VALUE rb_mutex_new(void)
Definition: thread.c:4251
rb_ensure
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:839
rb_thread_cond_struct
Definition: thread_pthread.h:21
rb_exec_recursive_paired_outer
VALUE rb_exec_recursive_paired_outer(VALUE(*func)(VALUE, VALUE, int), VALUE obj, VALUE paired_obj, VALUE arg)
Definition: thread.c:5017
thread_value
static VALUE thread_value(VALUE self)
Definition: thread.c:926
reset_unblock_function
static void reset_unblock_function(rb_thread_t *th, const struct rb_unblock_callback *old)
Definition: thread.c:333
rb_thread_struct::interrupt_flag
rb_atomic_t interrupt_flag
Definition: vm_core.h:585
rb_thread_struct::interrupt_cond
rb_nativethread_cond_t interrupt_cond
Definition: vm_core.h:588
timer_thread_function
static void timer_thread_function(void *)
Definition: thread.c:3825
rb_thread_wait_fd
void rb_thread_wait_fd(int fd)
Definition: thread.c:3519
rb_thread_struct::priority
int priority
Definition: vm_core.h:564
st_init_numtable
st_table * st_init_numtable(void)
Definition: st.c:272
rb_thread_struct::raised_flag
int raised_flag
Definition: vm_core.h:533
rb_blocking_function_t
VALUE rb_blocking_function_t(void *)
Definition: intern.h:865
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:1976
rb_thread_main
VALUE rb_thread_main(void)
Definition: thread.c:2422
rb_threadptr_restore_recursive_data
void rb_threadptr_restore_recursive_data(rb_thread_t *th, VALUE old)
Definition: thread.c:4802
rb_thread_backtrace_m
static VALUE rb_thread_backtrace_m(int argc, VALUE *argv, VALUE thval)
Definition: thread.c:5031
TIMER_INTERRUPT_MASK
Definition: vm_core.h:953
rb_thread_struct::abort_on_exception
int abort_on_exception
Definition: vm_core.h:650
INTERRUPT_IMMEDIATE
Definition: thread.c:1552
rb_thread_pending_interrupt_p
static VALUE rb_thread_pending_interrupt_p(int argc, VALUE *argv, VALUE target_thread)
Definition: thread.c:1839
rb_thread_struct::status
enum rb_thread_status status
Definition: vm_core.h:562
st_delete_wrap
static void st_delete_wrap(st_table *table, st_data_t key)
Definition: thread.c:100
rb_thread_sleep
void rb_thread_sleep(int sec)
Definition: thread.c:1164
rb_fd_max
#define rb_fd_max(f)
Definition: intern.h:360
thread_s_pass
static VALUE thread_s_pass(VALUE klass)
Definition: thread.c:1513
rb_threadptr_reset_recursive_data
VALUE rb_threadptr_reset_recursive_data(rb_thread_t *th)
Definition: thread.c:4794
thread_join_m
static VALUE thread_join_m(int argc, VALUE *argv, VALUE self)
Definition: thread.c:899
RSTRING_PTR
#define RSTRING_PTR(str)
Definition: ruby.h:845
thread_start_func_2
#define thread_start_func_2(th, st, rst)
Definition: thread.c:214
exec_recursive_params
Definition: thread.c:4899
rb_thread_sleep_deadly
void rb_thread_sleep_deadly(void)
Definition: thread.c:1076
rb_blocking_region_buffer::prev_status
enum rb_thread_status prev_status
Definition: thread.c:110
mutex_sleep
static VALUE mutex_sleep(int argc, VALUE *argv, VALUE self)
Definition: thread.c:4602
RARRAY_ASET
#define RARRAY_ASET(a, i, v)
Definition: ruby.h:902
rb_thread_struct::first_args
VALUE first_args
Definition: vm_core.h:616
rb_thread_recycle_stack_release
void rb_thread_recycle_stack_release(VALUE *)
Definition: vm.c:1992
rb_thread_terminate_all
void rb_thread_terminate_all(void)
Definition: thread.c:421
THREAD_SHIELD_WAITING_SHIFT
#define THREAD_SHIELD_WAITING_SHIFT
Definition: thread.c:4673
rb_threadptr_to_kill
static void rb_threadptr_to_kill(rb_thread_t *th)
Definition: thread.c:1930
size
int size
Definition: encoding.c:49
rb_reset_coverages
void rb_reset_coverages(void)
Definition: thread.c:5300
f
#define f
rb_hash_lookup2
VALUE rb_hash_lookup2(VALUE hash, VALUE key, VALUE def)
Definition: hash.c:708
INT2FIX
#define INT2FIX(i)
Definition: ruby.h:231
rb_thread_execute_interrupts
void rb_thread_execute_interrupts(VALUE thval)
Definition: thread.c:2026
rb_sourceline
int rb_sourceline(void)
Definition: vm.c:1001
thgroup_list
static VALUE thgroup_list(VALUE group)
Definition: thread.c:4038
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition: ruby.h:901
rb_thread_struct::stack_start
VALUE * stack_start
Definition: vm_core.h:621
RUBY_INTERNAL_EVENT_SWITCH
#define RUBY_INTERNAL_EVENT_SWITCH
Definition: ruby.h:1729
rb_thread_struct::interrupt_mask
unsigned long interrupt_mask
Definition: vm_core.h:586
rb_block_proc
VALUE rb_block_proc(void)
Definition: proc.c:620
xmalloc
#define xmalloc
Definition: defines.h:108
RUBY_THREAD_PRIORITY_MIN
#define RUBY_THREAD_PRIORITY_MIN
Definition: thread.c:70
TRAP_INTERRUPT_MASK
Definition: vm_core.h:956
ANYARGS
#define ANYARGS
Definition: defines.h:98
rb_thread_group
VALUE rb_thread_group(VALUE thread)
Definition: thread.c:2566
rb_thread_struct::unblock
struct rb_unblock_callback unblock
Definition: vm_core.h:589
rb_data_type_struct
Definition: ruby.h:966
rb_event_flag_t
unsigned long rb_event_flag_t
Definition: ruby.h:1740
BLOCKING_REGION
#define BLOCKING_REGION(exec, ubf, ubfarg, fail_if_interrupted)
Definition: thread.c:151
rb_unblock_callback::arg
void * arg
Definition: vm_core.h:501
rb_hash_aref
VALUE rb_hash_aref(VALUE hash, VALUE key)
Definition: hash.c:697
rb_fd_select
#define rb_fd_select(n, rfds, wfds, efds, timeout)
Definition: intern.h:361
RB_GC_SAVE_MACHINE_CONTEXT
#define RB_GC_SAVE_MACHINE_CONTEXT(th)
Definition: thread.c:128
rb_thread_reset_timer_thread
void rb_thread_reset_timer_thread(void)
Definition: thread.c:3864
rb_thread_struct::thread_id
rb_nativethread_id_t thread_id
Definition: vm_core.h:561
rb_thread_status
static VALUE rb_thread_status(VALUE thread)
Definition: thread.c:2637
rb_vm_struct::thread_destruct_lock
rb_nativethread_lock_t thread_destruct_lock
Definition: vm_core.h:352
rb_signal_buff_size
int rb_signal_buff_size(void)
Definition: signal.c:655
rb_thread_shield_waiting_inc
static void rb_thread_shield_waiting_inc(VALUE b)
Definition: thread.c:4677
key
uint8_t key[16]
Definition: random.c:1250
rb_fd_clr
#define rb_fd_clr(n, f)
Definition: intern.h:351
strerror
RUBY_EXTERN char * strerror(int)
Definition: strerror.c:11
LONG2FIX
#define LONG2FIX(i)
Definition: ruby.h:232
RTEST
#define RTEST(v)
Definition: ruby.h:437
FD_CLR
#define FD_CLR(f, s)
Definition: win32.h:647
rb_thread_struct::root_fiber
VALUE root_fiber
Definition: vm_core.h:642
join_arg::waiting
rb_thread_t * waiting
Definition: thread.c:755
OBJ_INFECT
#define OBJ_INFECT(x, s)
Definition: ruby.h:1180
list
struct rb_encoding_entry * list
Definition: encoding.c:47
ETIMEDOUT
#define ETIMEDOUT
Definition: win32.h:584
rb_thread_shield_destroy
VALUE rb_thread_shield_destroy(VALUE self)
Definition: thread.c:4745
rb_threadptr_pending_interrupt_deque
static VALUE rb_threadptr_pending_interrupt_deque(rb_thread_t *th, enum handle_interrupt_timing timing)
Definition: thread.c:1616
recursive_push
static void recursive_push(VALUE list, VALUE obj, VALUE paired_obj)
Definition: thread.c:4849
thread_start
static VALUE thread_start(VALUE klass, VALUE args)
Definition: thread.c:713
timespec
Definition: missing.h:50
threadptr_local_aset
static VALUE threadptr_local_aset(rb_thread_t *th, ID id, VALUE val)
Definition: thread.c:2837
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1030
rb_nativethread_lock_lock
void rb_nativethread_lock_lock(rb_nativethread_lock_t *lock)
Definition: thread.c:292
rb_mutex_wait_for
static VALUE rb_mutex_wait_for(VALUE time)
Definition: thread.c:4559
PENDING_INTERRUPT_MASK
Definition: vm_core.h:954
rb_ary_dup
VALUE rb_ary_dup(VALUE ary)
Definition: array.c:1888
st_table::type
const struct st_hash_type * type
Definition: st.h:70
RAISED_EXCEPTION
Definition: eval_intern.h:217
rb_unblock_callback
Definition: vm_core.h:499
GetThreadPtr
#define GetThreadPtr(obj, ptr)
Definition: vm_core.h:472
hash
static unsigned int hash(const char *str, unsigned int len)
Definition: lex.c:56
rb_atomic_t
int rb_atomic_t
Definition: ruby_atomic.h:120
thread_raise_m
static VALUE thread_raise_m(int argc, VALUE *argv, VALUE self)
Definition: thread.c:2158
rb_fd_resize
#define rb_fd_resize(n, f)
Definition: intern.h:355
rb_thread_shield_waiting
#define rb_thread_shield_waiting(b)
Definition: thread.c:4674
EXEC_EVENT_HOOK
#define EXEC_EVENT_HOOK(th_, flag_, self_, id_, klass_, data_)
Definition: vm_core.h:1034
sleep_timeval
static void sleep_timeval(rb_thread_t *th, struct timeval time, int spurious_check)
Definition: thread.c:1027
ruby_debug
#define ruby_debug
Definition: ruby.h:1476
RUBY_EVENT_COVERAGE
#define RUBY_EVENT_COVERAGE
Definition: ruby.h:1726
rb_vm_struct
Definition: vm_core.h:348
xrealloc
#define xrealloc
Definition: defines.h:111
rb_eIOError
RUBY_EXTERN VALUE rb_eIOError
Definition: ruby.h:1603
ID2SYM
#define ID2SYM(x)
Definition: ruby.h:355
THREAD_RUNNABLE
Definition: vm_core.h:476
rb_thread_io_blocking_region
VALUE rb_thread_io_blocking_region(rb_blocking_function_t *func, void *data1, int fd)
Definition: thread.c:1380
rb_threadptr_trap_interrupt
void rb_threadptr_trap_interrupt(rb_thread_t *th)
Definition: thread.c:365
rb_thread_struct::safe_level
int safe_level
Definition: vm_core.h:532
exec_recursive_i
static VALUE exec_recursive_i(RB_BLOCK_CALL_FUNC_ARGLIST(tag, data))
Definition: thread.c:4909
StringValuePtr
#define StringValuePtr(v)
Definition: ruby.h:540
rb_eFatal
VALUE rb_eFatal
Definition: error.c:545
join_arg::forever
int forever
Definition: thread.c:757
rb_thread_struct::self
VALUE self
Definition: vm_core.h:525
rb_fd_init_copy
#define rb_fd_init_copy(d, s)
Definition: intern.h:358
terminate_i
static int terminate_i(st_data_t key, st_data_t val, rb_thread_t *main_thread)
Definition: thread.c:371
rb_thread_list_struct::next
struct rb_thread_list_struct * next
Definition: vm_core.h:508
RUBY_VM_INTERRUPTED
#define RUBY_VM_INTERRUPTED(th)
Definition: vm_core.h:963
st_hashtype_num
const struct st_hash_type st_hashtype_num
rb_fd_init
#define rb_fd_init(f)
Definition: intern.h:357
rb_inspect
VALUE rb_inspect(VALUE)
Definition: object.c:470
rb_thread_s_abort_exc
static VALUE rb_thread_s_abort_exc(void)
Definition: thread.c:2462
rb_thread_local_aset
VALUE rb_thread_local_aset(VALUE thread, ID id, VALUE val)
Definition: thread.c:2854
recursive_pop
static void recursive_pop(VALUE list, VALUE obj, VALUE paired_obj)
Definition: thread.c:4879
rb_fd_dup
#define rb_fd_dup(d, s)
Definition: intern.h:354
rb_vm_gvl_destroy
void rb_vm_gvl_destroy(rb_vm_t *vm)
Definition: thread.c:272
rb_threadptr_pending_interrupt_active_p
int rb_threadptr_pending_interrupt_active_p(rb_thread_t *th)
Definition: thread.c:1653
rb_thread_aref
static VALUE rb_thread_aref(VALUE thread, VALUE key)
Definition: thread.c:2829
st_clear
void st_clear(st_table *)
Definition: st.c:308
select_args::except
rb_fdset_t * except
Definition: thread.c:3736
mutex_locked
static void mutex_locked(rb_thread_t *th, VALUE self)
Definition: thread.c:4271
ident_hash_new
static VALUE ident_hash_new(void)
Definition: thread.c:4759
waiting_delete::th
VALUE th
Definition: thread.c:257
FD_ISSET
#define FD_ISSET(f, s)
Definition: win32.h:650
RUBY_TYPED_DEFAULT_FREE
#define RUBY_TYPED_DEFAULT_FREE
Definition: ruby.h:1011
NOINLINE
NOINLINE(static int thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_start))
rb_thread_keys
static VALUE rb_thread_keys(VALUE self)
Definition: thread.c:3015
GetThreadShieldPtr
#define GetThreadShieldPtr(obj)
Definition: thread.c:4671
vsnprintf
#define vsnprintf
Definition: subst.h:7
rb_thread_struct::interrupt_lock
rb_nativethread_lock_t interrupt_lock
Definition: vm_core.h:587
xfree
void void xfree(void *)
RB_WAITFD_IN
#define RB_WAITFD_IN
Definition: io.h:47
rb_thread_struct::pending_interrupt_queue
VALUE pending_interrupt_queue
Definition: vm_core.h:581
RHASH_EMPTY_P
#define RHASH_EMPTY_P(h)
Definition: ruby.h:931
select_args::write
VALUE write
Definition: io.c:8316
rb_thread_call_with_gvl
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
Definition: thread.c:1450
getclockofday
static void getclockofday(struct timeval *tp)
Definition: thread.c:1011
select_single_cleanup
static VALUE select_single_cleanup(VALUE ptr)
Definition: thread.c:3763
rb_vm_make_jump_tag_but_local_jump
VALUE rb_vm_make_jump_tag_but_local_jump(int state, VALUE val)
Definition: vm.c:1101
select_single
static VALUE select_single(VALUE ptr)
Definition: thread.c:3741
rb_mutex_t
struct rb_mutex_struct rb_mutex_t
eTerminateSignal
#define eTerminateSignal
Definition: thread.c:94
rb_mutex_struct::cond_waiting
int cond_waiting
Definition: thread.c:394
rb_get_coverages
VALUE rb_get_coverages(void)
Definition: thread.c:5287
select_args::except
VALUE except
Definition: io.c:8316
rb_vm_thread_backtrace_locations
VALUE rb_vm_thread_backtrace_locations(int argc, VALUE *argv, VALUE thval)
Definition: vm_backtrace.c:912
rb_eSystemExit
VALUE rb_eSystemExit
Definition: error.c:542
NULL
#define NULL
Definition: _sdbm.c:103
FIX2LONG
#define FIX2LONG(x)
Definition: ruby.h:345
Qundef
#define Qundef
Definition: ruby.h:428
thread_keys_i
static int thread_keys_i(ID key, VALUE value, VALUE ary)
Definition: thread.c:2977
call_without_gvl
static void * call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2, int fail_if_interrupted)
Definition: thread.c:1252
rb_thread_struct::errinfo
VALUE errinfo
Definition: vm_core.h:573
GET_THROWOBJ_STATE
#define GET_THROWOBJ_STATE(obj)
Definition: eval_intern.h:207
rb_thread_variable_set
static VALUE rb_thread_variable_set(VALUE thread, VALUE id, VALUE val)
Definition: thread.c:2934
rb_threadptr_interrupt
void rb_threadptr_interrupt(rb_thread_t *th)
Definition: thread.c:359
st_table::num_entries
st_index_t num_entries
Definition: st.h:85
rb_thread_wakeup_alive
VALUE rb_thread_wakeup_alive(VALUE thread)
Definition: thread.c:2281
rb_thread_blocking_region
VALUE rb_thread_blocking_region(rb_blocking_function_t *func, void *data1, rb_unblock_function_t *ubf, void *data2)
Definition: thread.c:1413
rb_obj_call_init
void rb_obj_call_init(VALUE obj, int argc, VALUE *argv)
Definition: eval.c:1298
mutex_free
static void mutex_free(void *ptr)
Definition: thread.c:4188
rb_mutex_unlock
VALUE rb_mutex_unlock(VALUE self)
Definition: thread.c:4504
GET_THREAD
static rb_thread_t * GET_THREAD(void)
Definition: vm_core.h:927
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1488
st_foreach
int st_foreach(st_table *, int(*)(ANYARGS), st_data_t)
Definition: st.c:1034
GET_THROWOBJ_VAL
#define GET_THROWOBJ_VAL(obj)
Definition: eval_intern.h:205
rb_set_coverages
void rb_set_coverages(VALUE coverages)
Definition: thread.c:5293
rb_to_id
ID rb_to_id(VALUE)
Definition: string.c:8730
select
int select(int num_fds, fd_set *in_fds, fd_set *out_fds, fd_set *ex_fds, struct timeval *timeout)
rb_eThreadError
VALUE rb_eThreadError
Definition: eval.c:730
rb_thread_key_p
static VALUE rb_thread_key_p(VALUE self, VALUE key)
Definition: thread.c:2960
rb_eArgError
VALUE rb_eArgError
Definition: error.c:549
RUBY_VM_CHECK_INTS_BLOCKING
#define RUBY_VM_CHECK_INTS_BLOCKING(th)
Definition: vm_core.h:978
rb_obj_is_mutex
VALUE rb_obj_is_mutex(VALUE obj)
Definition: thread.c:4216
rb_thread_s_kill
static VALUE rb_thread_s_kill(VALUE obj, VALUE th)
Definition: thread.c:2229
recursive_check
static VALUE recursive_check(VALUE list, VALUE obj_id, VALUE paired_obj_id)
Definition: thread.c:4814
rb_thread_run
VALUE rb_thread_run(VALUE thread)
Definition: thread.c:2318
rb_threadptr_signal_exit
void rb_threadptr_signal_exit(rb_thread_t *th)
Definition: thread.c:2070
lock_interrupt
static void lock_interrupt(void *ptr)
Definition: thread.c:4349
rb_thread_atfork_internal
static void rb_thread_atfork_internal(int(*atfork)(st_data_t, st_data_t, st_data_t))
Definition: thread.c:3900
TYPEOF_TIMEVAL_TV_SEC
#define TYPEOF_TIMEVAL_TV_SEC
Definition: timev.h:22
argv
char ** argv
Definition: ruby.c:132
THREAD_STOPPED
Definition: vm_core.h:477
rb_thread_interrupted
int rb_thread_interrupted(VALUE thval)
Definition: thread.c:1156
rb_time_timeval
struct timeval rb_time_timeval(VALUE)
Definition: time.c:2417
rb_mutex_lock
VALUE rb_mutex_lock(VALUE self)
Definition: thread.c:4373
rb_threadptr_set_raised
int rb_threadptr_set_raised(rb_thread_t *th)
Definition: thread.c:2096
RUBY_UBF_IO
#define RUBY_UBF_IO
Definition: intern.h:872
rb_threadptr_pending_interrupt_check_mask
static enum handle_interrupt_timing rb_threadptr_pending_interrupt_check_mask(rb_thread_t *th, VALUE err)
Definition: thread.c:1558
terminate_atfork_i
static int terminate_atfork_i(st_data_t key, st_data_t val, st_data_t current_th)
Definition: thread.c:3916
GET_VM
#define GET_VM()
Definition: vm_core.h:920
rb_nativethread_lock_destroy
void rb_nativethread_lock_destroy(rb_nativethread_lock_t *lock)
Definition: thread.c:286
recursive_key
static ID recursive_key
Definition: thread.c:4754