Ruby  2.1.4p265(2014-10-27revision48166)
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 
79 
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);
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
101 {
102  st_delete(table, &key, 0);
103 }
104 
105 /********************************************************************************/
106 
107 #define THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
108 
112 };
113 
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
273 {
274  gvl_release(vm);
275  gvl_destroy(vm);
276  native_mutex_destroy(&vm->thread_destruct_lock);
277 }
278 
279 void
281 {
282  native_mutex_initialize(lock);
283 }
284 
285 void
287 {
288  native_mutex_destroy(lock);
289 }
290 
291 void
293 {
294  native_mutex_lock(lock);
295 }
296 
297 void
299 {
300  native_mutex_unlock(lock);
301 }
302 
303 static int
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
334 {
335  native_mutex_lock(&th->interrupt_lock);
336  th->unblock = *old;
337  native_mutex_unlock(&th->interrupt_lock);
338 }
339 
340 static void
342 {
343  native_mutex_lock(&th->interrupt_lock);
344  if (trap)
346  else
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
360 {
362 }
363 
364 void
366 {
368 }
369 
370 static int
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);
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 {
392  struct rb_thread_struct volatile *th;
396 } rb_mutex_t;
397 
398 static void rb_mutex_abandon_all(rb_mutex_t *mutexes);
401 static const char* rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t volatile *th);
402 
403 void
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
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 */
433 
434  retry:
435  thread_debug("rb_thread_terminate_all (main thread: %p)\n", (void *)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);
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
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;
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
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);
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 ||
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 */
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) {
600  join_list->th->status = THREAD_RUNNABLE;
601  default: break;
602  }
603  join_list = join_list->next;
604  }
605 
607  rb_check_deadlock(th->vm);
608 
609  if (!th->root_fiber) {
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);
619  gvl_release(th->vm);
620 
621  return 0;
622 }
623 
624 static VALUE
626 {
627  rb_thread_t *th, *current_th = GET_THREAD();
628  int err;
629 
630  if (OBJ_FROZEN(GET_THREAD()->thgroup)) {
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 
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
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
714 {
715  return thread_create_core(rb_thread_alloc(klass), args, 0);
716 }
717 
718 /* :nodoc: */
719 static VALUE
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 {
748 }
749 
750 
751 /* +infty, for this purpose */
752 #define DELAY_INFTY 1E30
753 
754 struct join_arg {
756  double limit;
757  int forever;
758 };
759 
760 static VALUE
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
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) {
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)) {
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
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
927 {
928  rb_thread_t *th;
929  GetThreadPtr(self, th);
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;
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  }
1004  if (!spurious_check)
1005  break;
1006  }
1007  th->status = prev_status;
1008 }
1009 
1010 static void
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;
1048  while (th->status == THREAD_STOPPED) {
1049  native_sleep(th, &tv);
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
1070 {
1071  thread_debug("rb_thread_sleep_forever\n");
1072  sleep_forever(GET_THREAD(), 0, 1);
1073 }
1074 
1075 void
1077 {
1078  thread_debug("rb_thread_sleep_deadly\n");
1079  sleep_forever(GET_THREAD(), 1, 1);
1080 }
1081 
1082 static double
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
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
1116 {
1117  rb_thread_t *th = GET_THREAD();
1118  sleep_timeval(th, time, 1);
1119 }
1120 
1121 void
1123 {
1124  if (!rb_thread_alone()) {
1125  rb_thread_t *th = GET_THREAD();
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
1140 {
1142 }
1143 
1144 /*
1145  * Hidden API for tcl/tk wrapper.
1146  * There is no guarantee to perpetuate it.
1147  */
1148 int
1150 {
1151  return rb_signal_buff_size() != 0;
1152 }
1153 
1154 /* This function can be called in blocking region. */
1155 int
1157 {
1158  rb_thread_t *th;
1159  GetThreadPtr(thval, th);
1160  return (int)RUBY_VM_INTERRUPTED(th);
1161 }
1162 
1163 void
1165 {
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");
1179  gvl_yield(th->vm, th);
1181  thread_debug("rb_thread_schedule/switch done\n");
1182  }
1183  }
1184 }
1185 
1186 void
1188 {
1189  rb_thread_t *cur_th = GET_THREAD();
1191 
1192  if (UNLIKELY(RUBY_VM_INTERRUPTED_ANY(cur_th))) {
1194  }
1195 }
1196 
1197 /* blocking region */
1198 
1199 static inline int
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);
1209  gvl_release(th->vm);
1210  return TRUE;
1211  }
1212  else {
1213  return FALSE;
1214  }
1215 }
1216 
1217 static inline void
1219 {
1220  gvl_acquire(th->vm, 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 
1233 {
1234  rb_thread_t *th = GET_THREAD();
1236  blocking_region_begin(th, region, ubf_select, th, FALSE);
1237  return region;
1238 }
1239 
1240 void
1242 {
1243  int saved_errno = errno;
1244  rb_thread_t *th = ruby_thread_from_native();
1245  blocking_region_end(th, region);
1246  xfree(region);
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) {
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
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() */
1406 
1407  errno = saved_errno;
1408 
1409  return val;
1410 }
1411 
1412 VALUE
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 
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
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
1514 {
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
1539 {
1541 }
1542 
1543 void
1545 {
1548 }
1549 
1555 };
1556 
1557 static enum handle_interrupt_timing
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
1598 {
1599  return RARRAY_LEN(th->pending_interrupt_queue) == 0;
1600 }
1601 
1602 static int
1604 {
1605  int i;
1606  for (i=0; i<RARRAY_LEN(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
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++) {
1623 
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:
1635  return err;
1636  case INTERRUPT_NEVER:
1637  break;
1638  }
1639  }
1640 
1642  return Qundef;
1643 #else
1647  }
1648  return err;
1649 #endif
1650 }
1651 
1652 int
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  */
1661  return 0;
1662  }
1663 
1665  return 0;
1666  }
1667 
1668  return 1;
1669 }
1670 
1671 static int
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
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");
1805  }
1806 
1807  TH_PUSH_TAG(th);
1808  if ((state = EXEC_TAG()) == 0) {
1809  r = rb_yield(Qnil);
1810  }
1811  TH_POP_TAG();
1812 
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
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
1925 {
1926  return rb_thread_pending_interrupt_p(argc, argv, GET_THREAD()->self);
1927 }
1928 
1929 static void
1931 {
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
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
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) {
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)) {
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. */ ) {
1997  }
1998  else {
1999  /* set runnable if th was slept. */
2000  if (th->status == THREAD_STOPPED ||
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 
2019 
2020  rb_thread_schedule_limits(limits_us);
2021  }
2022  }
2023 }
2024 
2025 void
2027 {
2028  rb_thread_t *th;
2029  GetThreadPtr(thval, th);
2031 }
2032 
2033 static void
2035 {
2037 }
2038 
2039 static VALUE
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  }
2056  return Qnil;
2057 }
2058 
2059 void
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
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
2085 {
2086  th->raised_flag = 0;
2087 #ifdef USE_SIGALTSTACK
2089 #else
2090  th->errinfo = sysstack_error;
2091  TH_JUMP_TAG(th, TAG_RAISE);
2092 #endif
2093 }
2094 
2095 int
2097 {
2098  if (th->raised_flag & RAISED_EXCEPTION) {
2099  return 1;
2100  }
2102  return 0;
2103 }
2104 
2105 int
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
2117 {
2118  int fd = (int)data;
2119  rb_thread_t *th;
2120  GetThreadPtr((VALUE)key, th);
2121 
2122  if (th->waiting_fd == fd) {
2126  }
2127  return ST_CONTINUE;
2128 }
2129 
2130 void
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
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
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) {
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 */
2205  }
2206  else {
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
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
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
2273 {
2274  if (!RTEST(rb_thread_wakeup_alive(thread))) {
2275  rb_raise(rb_eThreadError, "killed thread");
2276  }
2277  return thread;
2278 }
2279 
2280 VALUE
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
2319 {
2320  rb_thread_wakeup(thread);
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
2343 {
2344  if (rb_thread_alone()) {
2346  "stopping only thread\n\tnote: use sleep to stop forever");
2347  }
2349  return Qnil;
2350 }
2351 
2352 static int
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:
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
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
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
2417 {
2418  return rb_thread_current();
2419 }
2420 
2421 VALUE
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
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
2463 {
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
2499 {
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
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
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
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 *
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:
2590  return "sleep";
2591  case THREAD_KILLED:
2592  return "dead";
2593  default:
2594  return "unknown";
2595  }
2596 }
2597 
2598 static int
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
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
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
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
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
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
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
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
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
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) {
2847  }
2848  st_insert(th->local_storage, id, val);
2849  return val;
2850 }
2851 }
2852 
2853 VALUE
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
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
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
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
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
2978 {
2979  rb_ary_push(ary, ID2SYM(key));
2980  return ST_CONTINUE;
2981 }
2982 
2983 static int
2985 {
2986  return (int)vm->living_threads->num_entries;
2987 }
2988 
2989 int
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
3016 {
3017  rb_thread_t *th;
3018  VALUE ary = rb_ary_new();
3019  GetThreadPtr(self, th);
3020 
3021  if (th->local_storage) {
3023  }
3024  return ary;
3025 }
3026 
3027 static int
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
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
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
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
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
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
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 {
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 
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
3520 {
3521  rb_thread_wait_fd_rw(fd, 1);
3522 }
3523 
3524 int
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) {
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 
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 *
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;
3737  struct timeval *tv;
3738 };
3739 
3740 static VALUE
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
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
3803 {
3804  VALUE stack_end;
3805  *stack_end_p = &stack_end;
3806 }
3807 #endif
3808 
3809 
3810 /*
3811  *
3812  */
3813 
3814 void
3816 {
3817  /* mth must be main_thread */
3818  if (rb_signal_buff_size() > 0) {
3819  /* wakeup main thread */
3821  }
3822 }
3823 
3824 static void
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)
3838  native_mutex_unlock(&vm->thread_destruct_lock);
3839 
3840  /* check signal */
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
3857 {
3858  if (timer_thread_id && native_stop_timer_thread(close_anyway)) {
3859  native_reset_timer_thread();
3860  }
3861 }
3862 
3863 void
3865 {
3866  native_reset_timer_thread();
3867 }
3868 
3869 void
3871 {
3872  system_working = 1;
3873  rb_thread_create_timer_thread();
3874 }
3875 
3876 static int
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
3892 {
3893  VALUE coverages = rb_get_coverages();
3894  if (RTEST(coverages)) {
3896  }
3897 }
3898 
3899 static void
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
3917 {
3918  VALUE thval = key;
3919  rb_thread_t *th;
3920  GetThreadPtr(thval, th);
3921 
3922  if (th != (rb_thread_t *)current_th) {
3926  }
3927  return ST_CONTINUE;
3928 }
3929 
3930 void
3932 {
3934  GET_THREAD()->join_list = NULL;
3935 
3936  /* We don't want reproduce CVE-2003-0900. */
3938 }
3939 
3940 static int
3942 {
3943  VALUE thval = key;
3944  rb_thread_t *th;
3945  GetThreadPtr(thval, th);
3946 
3947  if (th != (rb_thread_t *)current_th) {
3949  }
3950  return ST_CONTINUE;
3951 }
3952 
3953 void
3955 {
3957 }
3958 
3959 struct thgroup {
3962 };
3963 
3964 static size_t
3965 thgroup_memsize(const void *ptr)
3966 {
3967  return ptr ? sizeof(struct thgroup) : 0;
3968 }
3969 
3971  "thgroup",
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
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 
4011 };
4012 
4013 static int
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
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
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
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
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  }
4147  if (data->enclosed) {
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 
4210  "mutex",
4213 };
4214 
4215 VALUE
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
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
4246 {
4247  return self;
4248 }
4249 
4250 VALUE
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
4264 {
4265  rb_mutex_t *mutex;
4266  GetMutexPtr(self, mutex);
4267  return mutex->th ? Qtrue : Qfalse;
4268 }
4269 
4270 static void
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
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  */
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
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);
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) {
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
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 *
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
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
4518 {
4519  if (th->keeping_mutexes) {
4521  }
4522  th->keeping_mutexes = NULL;
4523 }
4524 
4525 static void
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
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
4553 {
4554  sleep_forever(GET_THREAD(), 1, 0); /* permit spurious check */
4555  return Qnil;
4556 }
4557 
4558 static VALUE
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
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)) {
4579  }
4580  else {
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
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
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
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
4655 {
4656  rb_gc_mark((VALUE)ptr);
4657 }
4658 
4660  "thread_shield",
4661  {thread_shield_mark, 0, 0,},
4663 };
4664 
4665 static VALUE
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
4678 {
4679  unsigned int w = rb_thread_shield_waiting(b);
4680  w++;
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
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
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
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;
4723  rb_mutex_lock(mutex);
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
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
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 */
4755 
4756 extern const struct st_hash_type st_hashtype_num;
4757 
4758 static VALUE
4760 {
4761  VALUE hash = rb_hash_new();
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
4774 {
4775  volatile VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
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
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
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
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
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 
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
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
4928 {
4929  VALUE result = Qundef;
4930  struct exec_recursive_params p;
4931  int outermost;
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
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
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
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
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
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
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
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 
5092  rb_define_singleton_method(rb_cThread, "abort_on_exception", rb_thread_s_abort_exc, 0);
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
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);
5107  rb_define_method(rb_cThread, "terminate", rb_thread_kill, 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);
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);
5129  rb_define_method(rb_cThread, "backtrace_locations", rb_thread_backtrace_locations_m, -1);
5130 
5132 
5133  closed_stream_error = rb_exc_new2(rb_eIOError, "stream closed");
5136 
5137  cThGroup = rb_define_class("ThreadGroup", rb_cObject);
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);
5151  rb_define_method(rb_cMutex, "initialize", mutex_initialize, 0);
5153  rb_define_method(rb_cMutex, "try_lock", rb_mutex_trylock, 0);
5156  rb_define_method(rb_cMutex, "sleep", mutex_sleep, -1);
5159 
5160  recursive_key = rb_intern("__recursive_key__");
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 
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
5191 {
5192  rb_thread_t *th = ruby_thread_from_native();
5193 
5194  return th != 0;
5195 }
5196 
5197 static int
5199 {
5200  VALUE thval = key;
5201  rb_thread_t *th;
5202  GetThreadPtr(thval, th);
5203 
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
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 
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 {
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
5288 {
5289  return GET_VM()->coverages;
5290 }
5291 
5292 void
5294 {
5295  GET_VM()->coverages = coverages;
5297 }
5298 
5299 void
5301 {
5302  GET_VM()->coverages = Qfalse;
5304 }
5305 
5306 VALUE
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 }
#define RBASIC_CLEAR_CLASS(obj)
Definition: internal.h:607
static int vm_living_thread_num(rb_vm_t *vm)
Definition: thread.c:2984
struct timeval rb_time_interval(VALUE num)
Definition: time.c:2411
rb_control_frame_t * cfp
Definition: vm_core.h:531
void rb_threadptr_unlock_all_locking_mutexes(rb_thread_t *th)
Definition: thread.c:404
rb_thread_list_t * join_list
Definition: vm_core.h:613
#define T_OBJECT
Definition: ruby.h:477
static VALUE sym_never
Definition: thread.c:82
static VALUE thgroup_enclose(VALUE group)
Definition: thread.c:4067
VALUE rb_eStandardError
Definition: error.c:546
rb_nativethread_cond_t cond
Definition: thread.c:391
static VALUE rb_thread_variable_p(VALUE thread, VALUE key)
Definition: thread.c:3081
#define eKillSignal
Definition: thread.c:93
VALUE * stack_end
Definition: vm_core.h:622
#define RUBY_VM_CHECK_INTS(th)
Definition: vm_core.h:989
unsigned long running_time_us
Definition: vm_core.h:654
rb_vm_t * vm
Definition: vm_core.h:526
VALUE rb_exc_new(VALUE etype, const char *ptr, long len)
Definition: error.c:573
static VALUE thgroup_add(VALUE group, VALUE thread)
Definition: thread.c:4124
void ruby_kill(rb_pid_t pid, int sig)
Definition: thread.c:5319
static int check_deadlock_i(st_data_t key, st_data_t val, int *found)
Definition: thread.c:5198
#define rb_exc_new2
Definition: intern.h:247
VALUE rb_mutex_sleep(VALUE self, VALUE timeout)
Definition: thread.c:4567
int ruby_thread_has_gvl_p(void)
Definition: thread.c:1492
VALUE rb_ary_pop(VALUE ary)
Definition: array.c:940
static VALUE rb_thread_s_handle_interrupt(VALUE self, VALUE mask_arg)
Definition: thread.c:1788
static const rb_thread_t * patrol_thread
Definition: thread.c:4363
struct rb_mutex_struct * next_mutex
Definition: thread.c:393
void ruby_thread_stack_overflow(rb_thread_t *th)
Definition: thread.c:2084
#define RARRAY_LEN(a)
Definition: ruby.h:878
void rb_bug(const char *fmt,...)
Definition: error.c:327
static VALUE rb_thread_priority(VALUE thread)
Definition: thread.c:3116
int gettimeofday(struct timeval *, struct timezone *)
Definition: win32.c:4307
void rb_postponed_job_flush(rb_vm_t *vm)
Definition: vm_trace.c:1512
#define FALSE
Definition: nkf.h:174
#define RUBY_TYPED_FREE_IMMEDIATELY
Definition: ruby.h:1015
#define rb_hash_lookup
Definition: tcltklib.c:269
#define mutex_mark
Definition: thread.c:4185
static int lock_func(rb_thread_t *th, rb_mutex_t *mutex, int timeout_ms)
Definition: thread.c:4309
static const char * rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t volatile *th)
Definition: thread.c:4464
VALUE rb_obj_id(VALUE obj)
Definition: gc.c:2373
static void thread_cleanup_func_before_exec(void *th_ptr)
Definition: thread.c:464
#define INT2NUM(x)
Definition: ruby.h:1288
static VALUE trap(int sig, sighandler_t func, VALUE command)
Definition: signal.c:1049
struct rb_thread_struct * running_thread
Definition: vm_core.h:355
VALUE rb_make_exception(int argc, VALUE *argv)
Definition: eval.c:682
void rb_mutex_allow_trap(VALUE self, int val)
Definition: thread.c:4642
struct timeval * tv
Definition: thread.c:3737
Definition: st.h:69
void rb_nativethread_lock_unlock(rb_nativethread_lock_t *lock)
Definition: thread.c:298
#define RUBY_VM_SET_INTERRUPT(th)
Definition: vm_core.h:960
static VALUE rb_thread_abort_exc_set(VALUE thread, VALUE val)
Definition: thread.c:2545
VALUE rb_mutex_owned_p(VALUE self)
Definition: thread.c:4449
st_table * local_storage
Definition: vm_core.h:611
double limit
Definition: thread.c:756
Definition: st.h:100
int pending_interrupt_queue_checked
Definition: vm_core.h:582
VALUE rb_eSignal
Definition: error.c:544
static void rb_mutex_abandon_all(rb_mutex_t *mutexes)
Definition: thread.c:4539
struct rb_blocking_region_buffer * rb_thread_blocking_region_begin(void)
Definition: thread.c:1232
rb_fdset_t * read
Definition: thread.c:3734
VALUE rb_exec_recursive_outer(VALUE(*func)(VALUE, VALUE, int), VALUE obj, VALUE arg)
Definition: thread.c:5005
#define NUM2INT(x)
Definition: ruby.h:630
int count
Definition: encoding.c:48
static int max(int a, int b)
Definition: strftime.c:141
VALUE(* func)(VALUE, VALUE, int)
Definition: thread.c:4900
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
static VALUE thgroup_enclosed_p(VALUE group)
Definition: thread.c:4086
int rb_thread_check_trap_pending(void)
Definition: thread.c:1149
void rb_threadptr_execute_interrupts(rb_thread_t *th, int blocking_timing)
Definition: thread.c:1953
VALUE rb_thread_list(void)
Definition: thread.c:2393
static VALUE thread_join_sleep(VALUE arg)
Definition: thread.c:782
const VALUE coverage
Definition: vm_core.h:229
VALUE rb_exec_recursive(VALUE(*func)(VALUE, VALUE, int), VALUE obj, VALUE arg)
Definition: thread.c:4982
#define CLASS_OF(v)
Definition: ruby.h:440
static int terminate_atfork_before_exec_i(st_data_t key, st_data_t val, st_data_t current_th)
Definition: thread.c:3941
void rb_thread_blocking_region_end(struct rb_blocking_region_buffer *region)
Definition: thread.c:1241
static VALUE rb_thread_variables(VALUE thread)
Definition: thread.c:3052
struct rb_thread_struct * th
Definition: vm_core.h:509
void rb_unblock_function_t(void *)
Definition: intern.h:864
VALUE rb_ary_delete_at(VALUE ary, long pos)
Definition: array.c:2951
static VALUE recursive_list_access(void)
Definition: thread.c:4773
rb_unblock_function_t * func
Definition: vm_core.h:500
#define Qtrue
Definition: ruby.h:426
int rb_remove_event_hook(rb_event_hook_func_t func)
Definition: vm_trace.c:204
int st_insert(st_table *, st_data_t, st_data_t)
static void update_coverage(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
Definition: thread.c:5270
static VALUE thread_s_new(int argc, VALUE *argv, VALUE klass)
Definition: thread.c:685
void rb_error_frozen(const char *what)
Definition: error.c:2077
#define TypedData_Wrap_Struct(klass, data_type, sval)
Definition: ruby.h:1027
#define CLOCK_MONOTONIC
Definition: win32.h:129
VALUE pending_interrupt_mask_stack
Definition: vm_core.h:583
VALUE rb_ary_shift(VALUE ary)
Definition: array.c:991
static VALUE threadptr_local_aref(rb_thread_t *th, ID id)
Definition: thread.c:2750
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1041
VALUE rb_mod_ancestors(VALUE mod)
Definition: class.c:1056
static VALUE mutex_initialize(VALUE self)
Definition: thread.c:4245
static void rb_mutex_abandon_keeping_mutexes(rb_thread_t *th)
Definition: thread.c:4517
void rb_threadptr_signal_raise(rb_thread_t *th, int sig)
Definition: thread.c:2060
long tv_sec
Definition: ossl_asn1.c:17
struct rb_thread_struct volatile * th
Definition: thread.c:392
static struct timeval double2timeval(double d)
Definition: thread.c:960
ID rb_frame_this_func(void)
Definition: eval.c:943
#define sysstack_error
Definition: vm_core.h:899
SOCKET rb_w32_get_osfhandle(int)
Definition: win32.c:984
VALUE rb_eTypeError
Definition: error.c:548
VALUE rb_thread_stop(void)
Definition: thread.c:2342
#define TH_JUMP_TAG(th, st)
Definition: eval_intern.h:171
static VALUE mutex_alloc(VALUE klass)
Definition: thread.c:4227
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Definition: thread.c:4619
static const rb_data_type_t mutex_data_type
Definition: thread.c:4209
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:896
void rb_thread_wait_for(struct timeval time)
Definition: thread.c:1115
st_table * living_threads
Definition: vm_core.h:357
void rb_signal_exec(rb_thread_t *th, int sig)
Definition: signal.c:861
static int handle_interrupt_arg_check_i(VALUE key, VALUE val)
Definition: thread.c:1672
struct st_table * rb_hash_tbl_raw(VALUE hash)
Definition: hash.c:351
VALUE rb_ary_tmp_new(long capa)
Definition: array.c:534
#define rb_fd_zero(f)
Definition: intern.h:349
int kill(int, int)
Definition: win32.c:4439
static VALUE rb_thread_safe_level(VALUE thread)
Definition: thread.c:2718
static VALUE rb_thread_aset(VALUE self, VALUE id, VALUE val)
Definition: thread.c:2880
VALUE rb_thread_current(void)
Definition: thread.c:2401
#define PRIxVALUE
Definition: ruby.h:135
void rb_threadptr_pending_interrupt_enque(rb_thread_t *th, VALUE v)
Definition: thread.c:1544
#define OBJ_ID_EQL(obj_id, other)
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
VALUE rb_thread_alloc(VALUE klass)
Definition: vm.c:2229
static VALUE rb_mutex_sleep_forever(VALUE time)
Definition: thread.c:4552
static VALUE rb_thread_abort_exc(VALUE thread)
Definition: thread.c:2521
static void blocking_region_end(rb_thread_t *th, struct rb_blocking_region_buffer *region)
Definition: thread.c:1218
VALUE rb_ivar_get(VALUE, ID)
Definition: variable.c:1115
void rb_nativethread_lock_initialize(rb_nativethread_lock_t *lock)
Definition: thread.c:280
void * rb_thread_call_without_gvl(void *(*func)(void *data), void *data1, rb_unblock_function_t *ubf, void *data2)
Definition: thread.c:1373
VALUE rb_ary_clear(VALUE ary)
Definition: array.c:3381
pthread_mutex_t rb_nativethread_lock_t
static void clear_coverage(void)
Definition: thread.c:3891
int rb_thread_alone(void)
Definition: thread.c:2990
VALUE rb_convert_type(VALUE, int, const char *, const char *)
Definition: object.c:2616
#define TH_EXEC_TAG()
Definition: eval_intern.h:165
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Definition: object.c:652
#define T_HASH
Definition: ruby.h:485
static void sleep_forever(rb_thread_t *th, int nodeadlock, int spurious_check)
Definition: thread.c:987
VALUE rb_thread_local_aref(VALUE thread, ID id)
Definition: thread.c:2761
rb_nativethread_lock_t lock
Definition: thread.c:390
#define DATA_PTR(dta)
Definition: ruby.h:992
VALUE rb_catch_protect(VALUE t, rb_block_call_func *func, VALUE data, int *stateptr)
Definition: vm_eval.c:1835
#define RUBY_VM_SET_TRAP_INTERRUPT(th)
Definition: vm_core.h:962
static size_t thgroup_memsize(const void *ptr)
Definition: thread.c:3965
static void rb_mutex_abandon_locking_mutex(rb_thread_t *th)
Definition: thread.c:4526
static VALUE sym_immediate
Definition: thread.c:80
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
void rb_gc_mark(VALUE ptr)
Definition: gc.c:3604
static void thread_shield_mark(void *ptr)
Definition: thread.c:4654
st_data_t st_index_t
Definition: st.h:48
#define TAG_RAISE
Definition: eval_intern.h:193
#define PUSH_TAG()
Definition: eval_intern.h:141
static size_t mutex_memsize(const void *ptr)
Definition: thread.c:4204
static volatile int system_working
Definition: thread.c:95
static VALUE thread_join(rb_thread_t *target_th, double delay)
Definition: thread.c:808
static VALUE remove_from_join_list(VALUE arg)
Definition: thread.c:761
union select_args::@154 as
VALUE rb_thread_kill(VALUE thread)
Definition: thread.c:2187
VALUE rb_mutex_locked_p(VALUE self)
Definition: thread.c:4263
static int rb_threadptr_dead(rb_thread_t *th)
Definition: thread.c:2599
ID rb_check_id(volatile VALUE *namep)
Returns ID for the given name if it is interned already, or 0.
Definition: ripper.c:17324
#define FIXNUM_P(f)
Definition: ruby.h:347
static VALUE rb_thread_alive_p(VALUE thread)
Definition: thread.c:2668
rb_fdset_t * write
Definition: thread.c:3735
VALUE rb_exec_recursive_paired(VALUE(*func)(VALUE, VALUE, int), VALUE obj, VALUE paired_obj, VALUE arg)
Definition: thread.c:4993
#define rb_fd_rcopy(d, s)
Definition: thread.c:3418
void rb_thread_start_timer_thread(void)
Definition: thread.c:3870
struct rb_thread_struct::@169 machine
static rb_fdset_t * init_set_fd(int fd, rb_fdset_t *fds)
Definition: thread.c:3721
const char * rb_obj_classname(VALUE)
Definition: variable.c:406
VALUE rb_cMutex
Definition: thread.c:77
int allow_trap
Definition: thread.c:395
#define RB_WAITFD_OUT
Definition: io.h:49
VALUE thgroup_default
Definition: vm_core.h:358
#define rb_fd_set(n, f)
Definition: intern.h:350
time_t tv_sec
Definition: missing.h:51
#define sym(x)
Definition: date_core.c:3695
static VALUE rb_thread_stop_p(VALUE thread)
Definition: thread.c:2693
static void thread_cleanup_func(void *th_ptr, int atfork)
Definition: thread.c:475
static double timeofday(void)
Definition: thread.c:1083
RUBY_SYMBOL_EXPORT_BEGIN typedef unsigned long st_data_t
Definition: st.h:20
#define TAG_FATAL
Definition: eval_intern.h:195
int ruby_native_thread_p(void)
Definition: thread.c:5190
static VALUE rb_thread_s_abort_exc_set(VALUE self, VALUE val)
Definition: thread.c:2498
static rb_atomic_t threadptr_get_interrupts(rb_thread_t *th)
Definition: thread.c:1940
#define rb_fd_isset(n, f)
Definition: intern.h:352
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Definition: ruby.h:1511
VALUE(* first_func)(ANYARGS)
Definition: vm_core.h:617
void rb_hash_foreach(VALUE hash, int(*func)(ANYARGS), VALUE farg)
Definition: hash.c:264
VALUE rb_thread_wakeup(VALUE thread)
Definition: thread.c:2272
static VALUE rb_thread_s_main(VALUE klass)
Definition: thread.c:2435
void rb_exc_raise(VALUE mesg)
Definition: eval.c:567
static void rb_thread_wait_fd_rw(int fd, int read)
Definition: thread.c:3499
static VALUE sym_on_blocking
Definition: thread.c:81
VALUE * stack
Definition: vm_core.h:529
static void rb_thread_schedule_limits(unsigned long limits_us)
Definition: thread.c:1170
#define RB_TYPE_P(obj, type)
Definition: ruby.h:1664
void rb_reset_random_seed(void)
Definition: random.c:1323
int rb_thread_fd_writable(int fd)
Definition: thread.c:3525
#define RHASH(obj)
Definition: ruby.h:1124
static void rb_threadptr_interrupt_common(rb_thread_t *th, int trap)
Definition: thread.c:341
static VALUE thgroup_s_alloc(VALUE klass)
Definition: thread.c:3996
#define POSFIXABLE(f)
Definition: ruby.h:348
#define RUBY_VM_INTERRUPTED_ANY(th)
Definition: vm_core.h:964
#define TH_POP_TAG()
Definition: eval_intern.h:128
int st_lookup(st_table *, st_data_t, st_data_t *)
static int thread_list_i(st_data_t key, st_data_t val, void *data)
Definition: thread.c:2353
#define MEMZERO(p, type, n)
Definition: ruby.h:1351
#define PRI_TIMET_PREFIX
Definition: ruby.h:145
static VALUE coverage(VALUE fname, int n)
Definition: ripper.c:11902
#define closed_stream_error
Definition: thread.c:97
VALUE rb_vm_thread_backtrace(int argc, VALUE *argv, VALUE thval)
Definition: vm_backtrace.c:906
static const char * thread_status_name(rb_thread_t *th)
Definition: thread.c:2580
rb_thread_t * target
Definition: thread.c:755
#define RUBY_THREAD_PRIORITY_MAX
Definition: thread.c:69
fd_set rb_fdset_t
Definition: intern.h:348
#define rb_fd_term(f)
Definition: intern.h:359
static VALUE rb_thread_priority_set(VALUE thread, VALUE prio)
Definition: thread.c:3151
double rb_num2dbl(VALUE)
Definition: object.c:2964
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
static void sleep_for_polling(rb_thread_t *th)
Definition: thread.c:1106
int rb_block_given_p(void)
Definition: eval.c:712
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:1393
#define EXEC_TAG()
Definition: eval_intern.h:168
VALUE locking_mutex
Definition: vm_core.h:590
static const rb_data_type_t thread_shield_data_type
Definition: thread.c:4659
#define val
long tv_usec
Definition: ossl_asn1.c:18
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1553
VALUE rb_eRuntimeError
Definition: error.c:547
static VALUE rb_thread_inspect(VALUE thread)
Definition: thread.c:2734
#define RB_WAITFD_PRI
Definition: io.h:48
static ID id_locals
Definition: thread.c:83
#define PRIdVALUE
Definition: ruby.h:132
static VALUE rb_threadptr_raise(rb_thread_t *, int, VALUE *)
Definition: thread.c:2040
#define rb_fd_ptr(f)
Definition: intern.h:356
VALUE rb_mutex_trylock(VALUE self)
Definition: thread.c:4290
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:510
VALUE rb_ary_new(void)
Definition: array.c:495
void * blocking_region_buffer
Definition: vm_core.h:567
static VALUE exec_recursive(VALUE(*func)(VALUE, VALUE, int), VALUE obj, VALUE pairid, VALUE arg, int outer)
Definition: thread.c:4927
static VALUE thread_create_core(VALUE thval, VALUE args, VALUE(*fn)(ANYARGS))
Definition: thread.c:625
void Init_Thread(void)
Definition: thread.c:5069
#define JUMP_TAG(st)
Definition: eval_intern.h:173
rb_iseq_t * iseq
Definition: vm_core.h:448
#define NIL_P(v)
Definition: ruby.h:438
static int rb_threadptr_pending_interrupt_include_p(rb_thread_t *th, VALUE err)
Definition: thread.c:1603
long tv_nsec
Definition: missing.h:52
void rb_thread_stop_timer_thread(int close_anyway)
Definition: thread.c:3856
#define UNLIKELY(x)
Definition: vm_core.h:109
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:630
static void rb_threadptr_ready(rb_thread_t *th)
Definition: thread.c:2034
int st_delete(st_table *, st_data_t *, st_data_t *)
int enclosed
Definition: thread.c:3960
#define rb_intern(str)
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2225
void rb_thread_atfork_before_exec(void)
Definition: thread.c:3954
#define thread_debug
Definition: thread.c:210
static int rb_threadptr_pending_interrupt_empty_p(rb_thread_t *th)
Definition: thread.c:1597
#define OBJ_FROZEN(x)
Definition: ruby.h:1185
void rb_threadptr_check_signal(rb_thread_t *mth)
Definition: thread.c:3815
VALUE rb_class_inherited_p(VALUE, VALUE)
Definition: object.c:1564
int thread_abort_on_exception
Definition: vm_core.h:361
int argc
Definition: ruby.c:131
rb_thread_status
Definition: vm_core.h:475
static VALUE rb_thread_variable_get(VALUE thread, VALUE key)
Definition: thread.c:2914
#define Qfalse
Definition: ruby.h:425
void ruby_thread_init_stack(rb_thread_t *th)
Definition: thread.c:497
VALUE rb_proc_location(VALUE self)
Definition: proc.c:928
static VALUE rb_thread_exit(void)
Definition: thread.c:2248
RUBY_EXTERN VALUE rb_cModule
Definition: ruby.h:1572
void rb_thread_check_ints(void)
Definition: thread.c:1139
#define RUBY_UBF_PROCESS
Definition: intern.h:873
void rb_exit(int status)
Definition: process.c:3647
void rb_thread_fd_close(int fd)
Definition: thread.c:2131
if((ID)(DISPID) nameid!=nameid)
Definition: win32ole.c:770
#define T_NODE
Definition: ruby.h:498
VALUE rb_thread_shield_new(void)
Definition: thread.c:4698
volatile int sleeper
Definition: vm_core.h:363
void ruby_stop(int ex)
Calls ruby_cleanup() and exits the process.
Definition: eval.c:264
#define rb_str_new2
Definition: intern.h:840
VALUE rb_obj_alloc(VALUE)
Definition: object.c:1801
int err
Definition: win32.c:114
#define OBJ_FREEZE(x)
Definition: ruby.h:1186
#define EXIT_FAILURE
Definition: eval_intern.h:24
VALUE rb_thread_shield_release(VALUE self)
Definition: thread.c:4734
void rb_thread_atfork(void)
Definition: thread.c:3931
#define POP_TAG()
Definition: eval_intern.h:142
#define GVL_UNLOCK_BEGIN()
Definition: thread.c:136
static const rb_data_type_t thgroup_data_type
Definition: thread.c:3970
VALUE rb_thread_create(VALUE(*fn)(ANYARGS), void *arg)
Definition: thread.c:745
void rb_throw_obj(VALUE tag, VALUE value)
Definition: vm_eval.c:1733
static VALUE thread_s_current(VALUE klass)
Definition: thread.c:2416
#define FD_SET(fd, set)
Definition: win32.h:629
VALUE rb_cThreadShield
Definition: thread.c:78
static void sleep_wait_for_interrupt(rb_thread_t *th, double sleepsec, int spurious_check)
Definition: thread.c:1100
#define ATOMIC_CAS(var, oldval, newval)
Definition: ruby_atomic.h:132
#define ALLOC(type)
Definition: ruby.h:1334
void rb_thread_polling(void)
Definition: thread.c:1122
VALUE read
Definition: io.c:8316
#define GetMutexPtr(obj, tobj)
Definition: thread.c:4182
static VALUE rb_thread_backtrace_locations_m(int argc, VALUE *argv, VALUE thval)
Definition: thread.c:5048
int rb_thread_select(int max, fd_set *read, fd_set *write, fd_set *except, struct timeval *timeout)
Definition: thread.c:3532
VALUE rb_yield(VALUE)
Definition: vm_eval.c:942
#define RARRAY_CONST_PTR(a)
Definition: ruby.h:886
void * rb_thread_call_without_gvl2(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Definition: thread.c:1366
struct rb_unblock_callback oldubf
Definition: thread.c:111
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:113
#define rb_thread_set_current(th)
Definition: vm_core.h:940
int errno
#define TRUE
Definition: nkf.h:175
VALUE rb_uninterruptible(VALUE(*b_proc)(ANYARGS), VALUE data)
Definition: thread.c:5307
static int thgroup_list_i(st_data_t key, st_data_t val, st_data_t data)
Definition: thread.c:4014
#define EXIT_SUCCESS
Definition: error.c:29
VALUE special_exceptions[ruby_special_error_count]
Definition: vm_core.h:368
struct rb_mutex_struct * keeping_mutexes
Definition: vm_core.h:591
VALUE rb_thread_shield_wait(VALUE self)
Definition: thread.c:4714
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1250
int rb_get_next_signal(void)
Definition: signal.c:685
VALUE rb_hash_delete(VALUE hash, VALUE key)
Definition: hash.c:996
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
#define rb_fd_copy(d, s, n)
Definition: intern.h:353
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
#define const
Definition: strftime.c:102
static int thread_fd_close_i(st_data_t key, st_data_t val, st_data_t data)
Definition: thread.c:2116
VALUE rb_hash_new(void)
Definition: hash.c:298
void ruby_xfree(void *x)
Definition: gc.c:6242
#define DELAY_INFTY
Definition: thread.c:752
int rb_threadptr_reset_raised(rb_thread_t *th)
Definition: thread.c:2106
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1728
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4308
#define RUBY_VM_SET_TIMER_INTERRUPT(th)
Definition: vm_core.h:959
void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
Definition: vm_trace.c:145
unsigned long ID
Definition: ruby.h:89
static VALUE thread_initialize(VALUE thread, VALUE args)
Definition: thread.c:720
handle_interrupt_timing
Definition: thread.c:1550
static void rb_check_deadlock(rb_vm_t *vm)
Definition: thread.c:5246
static VALUE rb_mutex_synchronize_m(VALUE self, VALUE args)
Definition: thread.c:4633
#define GVL_UNLOCK_END()
Definition: thread.c:141
#define Qnil
Definition: ruby.h:427
void rb_thread_sleep_forever(void)
Definition: thread.c:1069
static VALUE thread_shield_alloc(VALUE klass)
Definition: thread.c:4666
VALUE group
Definition: thread.c:3961
#define OBJ_TAINT(x)
Definition: ruby.h:1177
unsigned long VALUE
Definition: ruby.h:88
#define THREAD_SHIELD_WAITING_MASK
Definition: thread.c:4672
#define SAVE_ROOT_JMPBUF(th, stmt)
Definition: eval_intern.h:112
static VALUE result
Definition: nkf.c:40
RUBY_EXTERN VALUE rb_cThread
Definition: ruby.h:1586
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Definition: thread.c:3775
static int keys_i(VALUE key, VALUE value, VALUE ary)
Definition: thread.c:3028
#define UNINITIALIZED_VAR(x)
Definition: vm_core.h:121
#define RBASIC(obj)
Definition: ruby.h:1116
const char * rb_class2name(VALUE)
Definition: variable.c:397
struct rb_thread_struct * main_thread
Definition: vm_core.h:354
static int clear_coverage_i(st_data_t key, st_data_t val, st_data_t dummy)
Definition: thread.c:3877
int error
Definition: thread.c:3732
static VALUE rb_thread_s_pending_interrupt_p(int argc, VALUE *argv, VALUE self)
Definition: thread.c:1924
VALUE first_proc
Definition: vm_core.h:615
void rb_threadptr_pending_interrupt_clear(rb_thread_t *th)
Definition: thread.c:1538
void rb_gc_set_stack_end(VALUE **stack_end_p)
Definition: thread.c:3802
static void rb_thread_shield_waiting_dec(VALUE b)
Definition: thread.c:4688
#define TH_PUSH_TAG(th)
Definition: eval_intern.h:122
int clock_gettime(clockid_t, struct timespec *)
Definition: win32.c:4319
void rb_thread_schedule(void)
Definition: thread.c:1187
VALUE rb_mutex_new(void)
Definition: thread.c:4251
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:839
VALUE rb_exec_recursive_paired_outer(VALUE(*func)(VALUE, VALUE, int), VALUE obj, VALUE paired_obj, VALUE arg)
Definition: thread.c:5017
static VALUE thread_value(VALUE self)
Definition: thread.c:926
static void reset_unblock_function(rb_thread_t *th, const struct rb_unblock_callback *old)
Definition: thread.c:333
rb_atomic_t interrupt_flag
Definition: vm_core.h:585
rb_nativethread_cond_t interrupt_cond
Definition: vm_core.h:588
static void timer_thread_function(void *)
Definition: thread.c:3825
void rb_thread_wait_fd(int fd)
Definition: thread.c:3519
st_table * st_init_numtable(void)
Definition: st.c:272
VALUE rb_blocking_function_t(void *)
Definition: intern.h:865
void rb_sys_fail(const char *mesg)
Definition: error.c:1976
VALUE rb_thread_main(void)
Definition: thread.c:2422
void rb_threadptr_restore_recursive_data(rb_thread_t *th, VALUE old)
Definition: thread.c:4802
static VALUE rb_thread_backtrace_m(int argc, VALUE *argv, VALUE thval)
Definition: thread.c:5031
int abort_on_exception
Definition: vm_core.h:650
static VALUE rb_thread_pending_interrupt_p(int argc, VALUE *argv, VALUE target_thread)
Definition: thread.c:1839
enum rb_thread_status status
Definition: vm_core.h:562
static void st_delete_wrap(st_table *table, st_data_t key)
Definition: thread.c:100
void rb_thread_sleep(int sec)
Definition: thread.c:1164
#define rb_fd_max(f)
Definition: intern.h:360
static VALUE thread_s_pass(VALUE klass)
Definition: thread.c:1513
VALUE rb_threadptr_reset_recursive_data(rb_thread_t *th)
Definition: thread.c:4794
static VALUE thread_join_m(int argc, VALUE *argv, VALUE self)
Definition: thread.c:899
#define RSTRING_PTR(str)
Definition: ruby.h:845
#define thread_start_func_2(th, st, rst)
Definition: thread.c:214
void rb_thread_sleep_deadly(void)
Definition: thread.c:1076
enum rb_thread_status prev_status
Definition: thread.c:110
static VALUE mutex_sleep(int argc, VALUE *argv, VALUE self)
Definition: thread.c:4602
#define RARRAY_ASET(a, i, v)
Definition: ruby.h:902
VALUE first_args
Definition: vm_core.h:616
void rb_thread_recycle_stack_release(VALUE *)
Definition: vm.c:1992
void rb_thread_terminate_all(void)
Definition: thread.c:421
#define THREAD_SHIELD_WAITING_SHIFT
Definition: thread.c:4673
static void rb_threadptr_to_kill(rb_thread_t *th)
Definition: thread.c:1930
int size
Definition: encoding.c:49
void rb_reset_coverages(void)
Definition: thread.c:5300
#define f
VALUE rb_hash_lookup2(VALUE hash, VALUE key, VALUE def)
Definition: hash.c:708
#define INT2FIX(i)
Definition: ruby.h:231
void rb_thread_execute_interrupts(VALUE thval)
Definition: thread.c:2026
int rb_sourceline(void)
Definition: vm.c:1001
static VALUE thgroup_list(VALUE group)
Definition: thread.c:4038
#define RARRAY_AREF(a, i)
Definition: ruby.h:901
VALUE * stack_start
Definition: vm_core.h:621
#define RUBY_INTERNAL_EVENT_SWITCH
Definition: ruby.h:1729
unsigned long interrupt_mask
Definition: vm_core.h:586
VALUE rb_block_proc(void)
Definition: proc.c:620
#define xmalloc
Definition: defines.h:108
#define RUBY_THREAD_PRIORITY_MIN
Definition: thread.c:70
#define ANYARGS
Definition: defines.h:98
VALUE rb_thread_group(VALUE thread)
Definition: thread.c:2566
struct rb_unblock_callback unblock
Definition: vm_core.h:589
unsigned long rb_event_flag_t
Definition: ruby.h:1740
#define BLOCKING_REGION(exec, ubf, ubfarg, fail_if_interrupted)
Definition: thread.c:151
VALUE rb_hash_aref(VALUE hash, VALUE key)
Definition: hash.c:697
#define rb_fd_select(n, rfds, wfds, efds, timeout)
Definition: intern.h:361
#define RB_GC_SAVE_MACHINE_CONTEXT(th)
Definition: thread.c:128
void rb_thread_reset_timer_thread(void)
Definition: thread.c:3864
rb_nativethread_id_t thread_id
Definition: vm_core.h:561
static VALUE rb_thread_status(VALUE thread)
Definition: thread.c:2637
rb_nativethread_lock_t thread_destruct_lock
Definition: vm_core.h:352
int rb_signal_buff_size(void)
Definition: signal.c:655
static void rb_thread_shield_waiting_inc(VALUE b)
Definition: thread.c:4677
uint8_t key[16]
Definition: random.c:1250
#define rb_fd_clr(n, f)
Definition: intern.h:351
RUBY_EXTERN char * strerror(int)
Definition: strerror.c:11
#define LONG2FIX(i)
Definition: ruby.h:232
#define RTEST(v)
Definition: ruby.h:437
#define FD_CLR(f, s)
Definition: win32.h:647
VALUE root_fiber
Definition: vm_core.h:642
rb_thread_t * waiting
Definition: thread.c:755
#define OBJ_INFECT(x, s)
Definition: ruby.h:1180
struct rb_encoding_entry * list
Definition: encoding.c:47
#define ETIMEDOUT
Definition: win32.h:584
VALUE rb_thread_shield_destroy(VALUE self)
Definition: thread.c:4745
static VALUE rb_threadptr_pending_interrupt_deque(rb_thread_t *th, enum handle_interrupt_timing timing)
Definition: thread.c:1616
static void recursive_push(VALUE list, VALUE obj, VALUE paired_obj)
Definition: thread.c:4849
static VALUE thread_start(VALUE klass, VALUE args)
Definition: thread.c:713
static VALUE threadptr_local_aset(rb_thread_t *th, ID id, VALUE val)
Definition: thread.c:2837
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1030
void rb_nativethread_lock_lock(rb_nativethread_lock_t *lock)
Definition: thread.c:292
static VALUE rb_mutex_wait_for(VALUE time)
Definition: thread.c:4559
VALUE rb_ary_dup(VALUE ary)
Definition: array.c:1888
const struct st_hash_type * type
Definition: st.h:70
#define GetThreadPtr(obj, ptr)
Definition: vm_core.h:472
static unsigned int hash(const char *str, unsigned int len)
Definition: lex.c:56
int rb_atomic_t
Definition: ruby_atomic.h:120
static VALUE thread_raise_m(int argc, VALUE *argv, VALUE self)
Definition: thread.c:2158
#define rb_fd_resize(n, f)
Definition: intern.h:355
#define rb_thread_shield_waiting(b)
Definition: thread.c:4674
#define EXEC_EVENT_HOOK(th_, flag_, self_, id_, klass_, data_)
Definition: vm_core.h:1034
static void sleep_timeval(rb_thread_t *th, struct timeval time, int spurious_check)
Definition: thread.c:1027
#define ruby_debug
Definition: ruby.h:1476
#define RUBY_EVENT_COVERAGE
Definition: ruby.h:1726
#define xrealloc
Definition: defines.h:111
RUBY_EXTERN VALUE rb_eIOError
Definition: ruby.h:1603
#define ID2SYM(x)
Definition: ruby.h:355
VALUE rb_thread_io_blocking_region(rb_blocking_function_t *func, void *data1, int fd)
Definition: thread.c:1380
void rb_threadptr_trap_interrupt(rb_thread_t *th)
Definition: thread.c:365
static VALUE exec_recursive_i(RB_BLOCK_CALL_FUNC_ARGLIST(tag, data))
Definition: thread.c:4909
#define StringValuePtr(v)
Definition: ruby.h:540
VALUE rb_eFatal
Definition: error.c:545
int forever
Definition: thread.c:757
#define rb_fd_init_copy(d, s)
Definition: intern.h:358
static int terminate_i(st_data_t key, st_data_t val, rb_thread_t *main_thread)
Definition: thread.c:371
struct rb_thread_list_struct * next
Definition: vm_core.h:508
#define RUBY_VM_INTERRUPTED(th)
Definition: vm_core.h:963
const struct st_hash_type st_hashtype_num
#define rb_fd_init(f)
Definition: intern.h:357
VALUE rb_inspect(VALUE)
Definition: object.c:470
static VALUE rb_thread_s_abort_exc(void)
Definition: thread.c:2462
VALUE rb_thread_local_aset(VALUE thread, ID id, VALUE val)
Definition: thread.c:2854
static void recursive_pop(VALUE list, VALUE obj, VALUE paired_obj)
Definition: thread.c:4879
#define rb_fd_dup(d, s)
Definition: intern.h:354
void rb_vm_gvl_destroy(rb_vm_t *vm)
Definition: thread.c:272
int rb_threadptr_pending_interrupt_active_p(rb_thread_t *th)
Definition: thread.c:1653
static VALUE rb_thread_aref(VALUE thread, VALUE key)
Definition: thread.c:2829
void st_clear(st_table *)
Definition: st.c:308
rb_fdset_t * except
Definition: thread.c:3736
static void mutex_locked(rb_thread_t *th, VALUE self)
Definition: thread.c:4271
static VALUE ident_hash_new(void)
Definition: thread.c:4759
VALUE th
Definition: thread.c:257
#define FD_ISSET(f, s)
Definition: win32.h:650
#define RUBY_TYPED_DEFAULT_FREE
Definition: ruby.h:1011
NOINLINE(static int thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_start))
static VALUE rb_thread_keys(VALUE self)
Definition: thread.c:3015
#define GetThreadShieldPtr(obj)
Definition: thread.c:4671
#define vsnprintf
Definition: subst.h:7
rb_nativethread_lock_t interrupt_lock
Definition: vm_core.h:587
void void xfree(void *)
#define RB_WAITFD_IN
Definition: io.h:47
VALUE pending_interrupt_queue
Definition: vm_core.h:581
#define RHASH_EMPTY_P(h)
Definition: ruby.h:931
VALUE write
Definition: io.c:8316
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
Definition: thread.c:1450
static void getclockofday(struct timeval *tp)
Definition: thread.c:1011
static VALUE select_single_cleanup(VALUE ptr)
Definition: thread.c:3763
VALUE rb_vm_make_jump_tag_but_local_jump(int state, VALUE val)
Definition: vm.c:1101
static VALUE select_single(VALUE ptr)
Definition: thread.c:3741
struct rb_mutex_struct rb_mutex_t
#define eTerminateSignal
Definition: thread.c:94
int cond_waiting
Definition: thread.c:394
VALUE rb_get_coverages(void)
Definition: thread.c:5287
VALUE except
Definition: io.c:8316
VALUE rb_vm_thread_backtrace_locations(int argc, VALUE *argv, VALUE thval)
Definition: vm_backtrace.c:912
VALUE rb_eSystemExit
Definition: error.c:542
#define NULL
Definition: _sdbm.c:103
#define FIX2LONG(x)
Definition: ruby.h:345
#define Qundef
Definition: ruby.h:428
static int thread_keys_i(ID key, VALUE value, VALUE ary)
Definition: thread.c:2977
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
#define GET_THROWOBJ_STATE(obj)
Definition: eval_intern.h:207
static VALUE rb_thread_variable_set(VALUE thread, VALUE id, VALUE val)
Definition: thread.c:2934
void rb_threadptr_interrupt(rb_thread_t *th)
Definition: thread.c:359
st_index_t num_entries
Definition: st.h:85
VALUE rb_thread_wakeup_alive(VALUE thread)
Definition: thread.c:2281
VALUE rb_thread_blocking_region(rb_blocking_function_t *func, void *data1, rb_unblock_function_t *ubf, void *data2)
Definition: thread.c:1413
void rb_obj_call_init(VALUE obj, int argc, VALUE *argv)
Definition: eval.c:1298
static void mutex_free(void *ptr)
Definition: thread.c:4188
VALUE rb_mutex_unlock(VALUE self)
Definition: thread.c:4504
static rb_thread_t * GET_THREAD(void)
Definition: vm_core.h:927
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1488
int st_foreach(st_table *, int(*)(ANYARGS), st_data_t)
Definition: st.c:1034
#define GET_THROWOBJ_VAL(obj)
Definition: eval_intern.h:205
void rb_set_coverages(VALUE coverages)
Definition: thread.c:5293
ID rb_to_id(VALUE)
Definition: string.c:8730
int select(int num_fds, fd_set *in_fds, fd_set *out_fds, fd_set *ex_fds, struct timeval *timeout)
VALUE rb_eThreadError
Definition: eval.c:730
static VALUE rb_thread_key_p(VALUE self, VALUE key)
Definition: thread.c:2960
VALUE rb_eArgError
Definition: error.c:549
#define RUBY_VM_CHECK_INTS_BLOCKING(th)
Definition: vm_core.h:978
VALUE rb_obj_is_mutex(VALUE obj)
Definition: thread.c:4216
static VALUE rb_thread_s_kill(VALUE obj, VALUE th)
Definition: thread.c:2229
static VALUE recursive_check(VALUE list, VALUE obj_id, VALUE paired_obj_id)
Definition: thread.c:4814
VALUE rb_thread_run(VALUE thread)
Definition: thread.c:2318
void rb_threadptr_signal_exit(rb_thread_t *th)
Definition: thread.c:2070
static void lock_interrupt(void *ptr)
Definition: thread.c:4349
static void rb_thread_atfork_internal(int(*atfork)(st_data_t, st_data_t, st_data_t))
Definition: thread.c:3900
#define TYPEOF_TIMEVAL_TV_SEC
Definition: timev.h:22
char ** argv
Definition: ruby.c:132
int rb_thread_interrupted(VALUE thval)
Definition: thread.c:1156
struct timeval rb_time_timeval(VALUE)
Definition: time.c:2417
VALUE rb_mutex_lock(VALUE self)
Definition: thread.c:4373
int rb_threadptr_set_raised(rb_thread_t *th)
Definition: thread.c:2096
#define RUBY_UBF_IO
Definition: intern.h:872
static enum handle_interrupt_timing rb_threadptr_pending_interrupt_check_mask(rb_thread_t *th, VALUE err)
Definition: thread.c:1558
static int terminate_atfork_i(st_data_t key, st_data_t val, st_data_t current_th)
Definition: thread.c:3916
#define GET_VM()
Definition: vm_core.h:920
void rb_nativethread_lock_destroy(rb_nativethread_lock_t *lock)
Definition: thread.c:286
static ID recursive_key
Definition: thread.c:4754