Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# thread.c

Go to the documentation of this file.

    00001 /**********************************************************************
    00002
    00003   thread.c -
    00004
    00005   $Author: yugui $
    00006
    00007   Copyright (C) 2004-2007 Koichi Sasada
    00008
    00009 **********************************************************************/
    00010
    00011 /*
    00012   YARV Thread Design
    00013
    00014   model 1: Userlevel Thread
    00015     Same as traditional ruby thread.
    00016
    00017   model 2: Native Thread with Global VM lock
    00018     Using pthread (or Windows thread) and Ruby threads run concurrent.
    00019
    00020   model 3: Native Thread with fine grain lock
    00021     Using pthread and Ruby threads run concurrent or parallel.
    00022
    00023 ------------------------------------------------------------------------
    00024
    00025   model 2:
    00026     A thread has mutex (GVL: Global VM Lock or Giant VM Lock) can run.
    00027     When thread scheduling, running thread release GVL.  If running thread
    00028     try blocking operation, this thread must release GVL and another
    00029     thread can continue this flow.  After blocking operation, thread
    00030     must check interrupt (RUBY_VM_CHECK_INTS).
    00031
    00032     Every VM can run parallel.
    00033
    00034     Ruby threads are scheduled by OS thread scheduler.
    00035
    00036 ------------------------------------------------------------------------
    00037
    00038   model 3:
    00039     Every threads run concurrent or parallel and to access shared object
    00040     exclusive access control is needed.  For example, to access String
    00041     object or Array object, fine grain lock must be locked every time.
    00042  */
    00043
    00044
    00045 /* for model 2 */
    00046
    00047 #include "eval_intern.h"
    00048 #include "gc.h"
    00049
    00050 #ifndef USE_NATIVE_THREAD_PRIORITY
    00051 #define USE_NATIVE_THREAD_PRIORITY 0
    00052 #define RUBY_THREAD_PRIORITY_MAX 3
    00053 #define RUBY_THREAD_PRIORITY_MIN -3
    00054 #endif
    00055
    00056 #ifndef THREAD_DEBUG
    00057 #define THREAD_DEBUG 0
    00058 #endif
    00059
    00060 VALUE rb_cMutex;
    00061 VALUE rb_cBarrier;
    00062
    00063 static void sleep_timeval(rb_thread_t *th, struct timeval time);
    00064 static void sleep_wait_for_interrupt(rb_thread_t *th, double sleepsec);
    00065 static void sleep_forever(rb_thread_t *th, int nodeadlock);
    00066 static double timeofday(void);
    00067 struct timeval rb_time_interval(VALUE);
    00068 static int rb_threadptr_dead(rb_thread_t *th);
    00069
    00070 static void rb_check_deadlock(rb_vm_t *vm);
    00071
    00072 int rb_signal_buff_size(void);
    00073 void rb_signal_exec(rb_thread_t *th, int sig);
    00074 void rb_disable_interrupt(void);
    00075 void rb_thread_stop_timer_thread(void);
    00076
    00077 static const VALUE eKillSignal = INT2FIX(0);
    00078 static const VALUE eTerminateSignal = INT2FIX(1);
    00079 static volatile int system_working = 1;
    00080
    00081 inline static void
    00082 st_delete_wrap(st_table *table, st_data_t key)
    00083 {
    00084     st_delete(table, &key, 0);
    00085 }
    00086
    00087 /********************************************************************************/
    00088
    00089 #define THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
    00090
    00091 struct rb_blocking_region_buffer {
    00092     enum rb_thread_status prev_status;
    00093     struct rb_unblock_callback oldubf;
    00094 };
    00095
    00096 static void set_unblock_function(rb_thread_t *th, rb_unblock_function_t *func, void *arg,
    00097                                  struct rb_unblock_callback *old);
    00098 static void reset_unblock_function(rb_thread_t *th, const struct rb_unblock_callback *old);
    00099
    00100 static inline void blocking_region_end(rb_thread_t *th, struct rb_blocking_region_buffer *region);
    00101
    00102 #define RB_GC_SAVE_MACHINE_CONTEXT(th) \
    00103   do { \
    00104     rb_gc_save_machine_context(th); \
    00105     SET_MACHINE_STACK_END(&(th)->machine_stack_end); \
    00106   } while (0)
    00107
    00108 #define GVL_UNLOCK_BEGIN() do { \
    00109   rb_thread_t *_th_stored = GET_THREAD(); \
    00110   RB_GC_SAVE_MACHINE_CONTEXT(_th_stored); \
    00111   native_mutex_unlock(&_th_stored->vm->global_vm_lock)
    00112
    00113 #define GVL_UNLOCK_END() \
    00114   native_mutex_lock(&_th_stored->vm->global_vm_lock); \
    00115   rb_thread_set_current(_th_stored); \
    00116 } while(0)
    00117
    00118 #define BLOCKING_REGION_CORE(exec) do { \
    00119     GVL_UNLOCK_BEGIN(); {\
    00120             exec; \
    00121     } \
    00122     GVL_UNLOCK_END(); \
    00123 } while(0);
    00124
    00125 #define blocking_region_begin(th, region, func, arg) \
    00126   do { \
    00127     (region)->prev_status = (th)->status; \
    00128     set_unblock_function((th), (func), (arg), &(region)->oldubf); \
    00129     (th)->blocking_region_buffer = (region); \
    00130     (th)->status = THREAD_STOPPED; \
    00131     thread_debug("enter blocking region (%p)\n", (void *)(th)); \
    00132     RB_GC_SAVE_MACHINE_CONTEXT(th); \
    00133     native_mutex_unlock(&(th)->vm->global_vm_lock); \
    00134   } while (0)
    00135
    00136 #define BLOCKING_REGION(exec, ubf, ubfarg) do { \
    00137     rb_thread_t *__th = GET_THREAD(); \
    00138     struct rb_blocking_region_buffer __region; \
    00139     blocking_region_begin(__th, &__region, ubf, ubfarg); \
    00140     exec; \
    00141     blocking_region_end(__th, &__region); \
    00142     RUBY_VM_CHECK_INTS(); \
    00143 } while(0)
    00144
    00145 #if THREAD_DEBUG
    00146 #ifdef HAVE_VA_ARGS_MACRO
    00147 void rb_thread_debug(const char *file, int line, const char *fmt, ...);
    00148 #define thread_debug(fmt, ...) rb_thread_debug(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
    00149 #define POSITION_FORMAT "%s:%d:"
    00150 #define POSITION_ARGS ,file, line
    00151 #else
    00152 void rb_thread_debug(const char *fmt, ...);
    00153 #define thread_debug rb_thread_debug
    00154 #define POSITION_FORMAT
    00155 #define POSITION_ARGS
    00156 #endif
    00157
    00158 # if THREAD_DEBUG < 0
    00159 static int rb_thread_debug_enabled;
    00160
    00161 /*
    00162  *  call-seq:
    00163  *     Thread.DEBUG     -> num
    00164  *
    00165  *  Returns the thread debug level.  Available only if compiled with
    00166  *  THREAD_DEBUG=-1.
    00167  */
    00168
    00169 static VALUE
    00170 rb_thread_s_debug(void)
    00171 {
    00172     return INT2NUM(rb_thread_debug_enabled);
    00173 }
    00174
    00175 /*
    00176  *  call-seq:
    00177  *     Thread.DEBUG = num
    00178  *
    00179  *  Sets the thread debug level.  Available only if compiled with
    00180  *  THREAD_DEBUG=-1.
    00181  */
    00182
    00183 static VALUE
    00184 rb_thread_s_debug_set(VALUE self, VALUE val)
    00185 {
    00186     rb_thread_debug_enabled = RTEST(val) ? NUM2INT(val) : 0;
    00187     return val;
    00188 }
    00189 # else
    00190 # define rb_thread_debug_enabled THREAD_DEBUG
    00191 # endif
    00192 #else
    00193 #define thread_debug if(0)printf
    00194 #endif
    00195
    00196 #ifndef __ia64
    00197 #define thread_start_func_2(th, st, rst) thread_start_func_2(th, st)
    00198 #endif
    00199 NOINLINE(static int thread_start_func_2(rb_thread_t *th, VALUE *stack_start,
    00200                                         VALUE *register_stack_start));
    00201 static void timer_thread_function(void *);
    00202
    00203 #if   defined(_WIN32)
    00204 #include "thread_win32.c"
    00205
    00206 #define DEBUG_OUT() \
    00207   WaitForSingleObject(&debug_mutex, INFINITE); \
    00208   printf(POSITION_FORMAT"%p - %s" POSITION_ARGS, GetCurrentThreadId(), buf); \
    00209   fflush(stdout); \
    00210   ReleaseMutex(&debug_mutex);
    00211
    00212 #elif defined(HAVE_PTHREAD_H)
    00213 #include "thread_pthread.c"
    00214
    00215 #define DEBUG_OUT() \
    00216   pthread_mutex_lock(&debug_mutex); \
    00217   printf(POSITION_FORMAT"%#"PRIxVALUE" - %s" POSITION_ARGS, (VALUE)pthread_self(), buf); \
    00218   fflush(stdout); \
    00219   pthread_mutex_unlock(&debug_mutex);
    00220
    00221 #else
    00222 #error "unsupported thread type"
    00223 #endif
    00224
    00225 #if THREAD_DEBUG
    00226 static int debug_mutex_initialized = 1;
    00227 static rb_thread_lock_t debug_mutex;
    00228
    00229 void
    00230 rb_thread_debug(
    00231 #ifdef HAVE_VA_ARGS_MACRO
    00232     const char *file, int line,
    00233 #endif
    00234     const char *fmt, ...)
    00235 {
    00236     va_list args;
    00237     char buf[BUFSIZ];
    00238
    00239     if (!rb_thread_debug_enabled) return;
    00240
    00241     if (debug_mutex_initialized == 1) {
    00242         debug_mutex_initialized = 0;
    00243         native_mutex_initialize(&debug_mutex);
    00244     }
    00245
    00246     va_start(args, fmt);
    00247     vsnprintf(buf, BUFSIZ, fmt, args);
    00248     va_end(args);
    00249
    00250     DEBUG_OUT();
    00251 }
    00252 #endif
    00253
    00254 void
    00255 rb_thread_lock_unlock(rb_thread_lock_t *lock)
    00256 {
    00257     native_mutex_unlock(lock);
    00258 }
    00259
    00260 void
    00261 rb_thread_lock_destroy(rb_thread_lock_t *lock)
    00262 {
    00263     native_mutex_destroy(lock);
    00264 }
    00265
    00266 static void
    00267 set_unblock_function(rb_thread_t *th, rb_unblock_function_t *func, void *arg,
    00268                      struct rb_unblock_callback *old)
    00269 {
    00270   check_ints:
    00271     RUBY_VM_CHECK_INTS(); /* check signal or so */
    00272     native_mutex_lock(&th->interrupt_lock);
    00273     if (th->interrupt_flag) {
    00274         native_mutex_unlock(&th->interrupt_lock);
    00275         goto check_ints;
    00276     }
    00277     else {
    00278         if (old) *old = th->unblock;
    00279         th->unblock.func = func;
    00280         th->unblock.arg = arg;
    00281     }
    00282     native_mutex_unlock(&th->interrupt_lock);
    00283 }
    00284
    00285 static void
    00286 reset_unblock_function(rb_thread_t *th, const struct rb_unblock_callback *old)
    00287 {
    00288     native_mutex_lock(&th->interrupt_lock);
    00289     th->unblock = *old;
    00290     native_mutex_unlock(&th->interrupt_lock);
    00291 }
    00292
    00293 void
    00294 rb_threadptr_interrupt(rb_thread_t *th)
    00295 {
    00296     native_mutex_lock(&th->interrupt_lock);
    00297     RUBY_VM_SET_INTERRUPT(th);
    00298     if (th->unblock.func) {
    00299         (th->unblock.func)(th->unblock.arg);
    00300     }
    00301     else {
    00302         /* none */
    00303     }
    00304     native_mutex_unlock(&th->interrupt_lock);
    00305 }
    00306
    00307
    00308 static int
    00309 terminate_i(st_data_t key, st_data_t val, rb_thread_t *main_thread)
    00310 {
    00311     VALUE thval = key;
    00312     rb_thread_t *th;
    00313     GetThreadPtr(thval, th);
    00314
    00315     if (th != main_thread) {
    00316         thread_debug("terminate_i: %p\n", (void *)th);
    00317         rb_threadptr_interrupt(th);
    00318         th->thrown_errinfo = eTerminateSignal;
    00319         th->status = THREAD_TO_KILL;
    00320     }
    00321     else {
    00322         thread_debug("terminate_i: main thread (%p)\n", (void *)th);
    00323     }
    00324     return ST_CONTINUE;
    00325 }
    00326
    00327 typedef struct rb_mutex_struct
    00328 {
    00329     rb_thread_lock_t lock;
    00330     rb_thread_cond_t cond;
    00331     struct rb_thread_struct volatile *th;
    00332     volatile int cond_waiting, cond_notified;
    00333     struct rb_mutex_struct *next_mutex;
    00334 } mutex_t;
    00335
    00336 static void rb_mutex_unlock_all(mutex_t *mutex, rb_thread_t *th);
    00337 static void rb_mutex_abandon_all(mutex_t *mutexes);
    00338
    00339 void
    00340 rb_thread_terminate_all(void)
    00341 {
    00342     rb_thread_t *th = GET_THREAD(); /* main thread */
    00343     rb_vm_t *vm = th->vm;
    00344
    00345     if (vm->main_thread != th) {
    00346         rb_bug("rb_thread_terminate_all: called by child thread (%p, %p)",
    00347                (void *)vm->main_thread, (void *)th);
    00348     }
    00349
    00350     /* unlock all locking mutexes */
    00351     if (th->keeping_mutexes) {
    00352         rb_mutex_unlock_all(th->keeping_mutexes, GET_THREAD());
    00353     }
    00354
    00355     thread_debug("rb_thread_terminate_all (main thread: %p)\n", (void *)th);
    00356     st_foreach(vm->living_threads, terminate_i, (st_data_t)th);
    00357
    00358     while (!rb_thread_alone()) {
    00359         PUSH_TAG();
    00360         if (EXEC_TAG() == 0) {
    00361             rb_thread_schedule();
    00362         }
    00363         else {
    00364             /* ignore exception */
    00365         }
    00366         POP_TAG();
    00367     }
    00368     rb_thread_stop_timer_thread();
    00369 }
    00370
    00371 static void
    00372 thread_unlock_all_locking_mutexes(rb_thread_t *th)
    00373 {
    00374     if (th->keeping_mutexes) {
    00375         rb_mutex_unlock_all(th->keeping_mutexes, th);
    00376         th->keeping_mutexes = NULL;
    00377     }
    00378 }
    00379
    00380 static void
    00381 thread_cleanup_func_before_exec(void *th_ptr)
    00382 {
    00383     rb_thread_t *th = th_ptr;
    00384     th->status = THREAD_KILLED;
    00385     th->machine_stack_start = th->machine_stack_end = 0;
    00386 #ifdef __ia64
    00387     th->machine_register_stack_start = th->machine_register_stack_end = 0;
    00388 #endif
    00389 }
    00390
    00391 static void
    00392 thread_cleanup_func(void *th_ptr)
    00393 {
    00394     rb_thread_t *th = th_ptr;
    00395
    00396     th->locking_mutex = Qfalse;
    00397     thread_cleanup_func_before_exec(th_ptr);
    00398     native_thread_destroy(th);
    00399 }
    00400
    00401 extern void ruby_error_print(void);
    00402 static VALUE rb_threadptr_raise(rb_thread_t *, int, VALUE *);
    00403 void rb_thread_recycle_stack_release(VALUE *);
    00404
    00405 void
    00406 ruby_thread_init_stack(rb_thread_t *th)
    00407 {
    00408     native_thread_init_stack(th);
    00409 }
    00410
    00411 static int
    00412 thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_start)
    00413 {
    00414     int state;
    00415     VALUE args = th->first_args;
    00416     rb_proc_t *proc;
    00417     rb_thread_t *join_th;
    00418     rb_thread_t *main_th;
    00419     VALUE errinfo = Qnil;
    00420 # ifdef USE_SIGALTSTACK
    00421     void rb_register_sigaltstack(rb_thread_t *th);
    00422
    00423     rb_register_sigaltstack(th);
    00424 # endif
    00425
    00426     ruby_thread_set_native(th);
    00427
    00428     th->machine_stack_start = stack_start;
    00429 #ifdef __ia64
    00430     th->machine_register_stack_start = register_stack_start;
    00431 #endif
    00432     thread_debug("thread start: %p\n", (void *)th);
    00433
    00434     native_mutex_lock(&th->vm->global_vm_lock);
    00435     {
    00436         thread_debug("thread start (get lock): %p\n", (void *)th);
    00437         rb_thread_set_current(th);
    00438
    00439         TH_PUSH_TAG(th);
    00440         if ((state = EXEC_TAG()) == 0) {
    00441             SAVE_ROOT_JMPBUF(th, {
    00442                 if (!th->first_func) {
    00443                     GetProcPtr(th->first_proc, proc);
    00444                     th->errinfo = Qnil;
    00445                     th->local_lfp = proc->block.lfp;
    00446                     th->local_svar = Qnil;
    00447                     th->value = rb_vm_invoke_proc(th, proc, proc->block.self,
    00448                                                   (int)RARRAY_LEN(args), RARRAY_PTR(args), 0);
    00449                 }
    00450                 else {
    00451                     th->value = (*th->first_func)((void *)args);
    00452                 }
    00453             });
    00454         }
    00455         else {
    00456             errinfo = th->errinfo;
    00457             if (NIL_P(errinfo)) errinfo = rb_errinfo();
    00458             if (state == TAG_FATAL) {
    00459                 /* fatal error within this thread, need to stop whole script */
    00460             }
    00461             else if (rb_obj_is_kind_of(errinfo, rb_eSystemExit)) {
    00462                 if (th->safe_level >= 4) {
    00463                     th->errinfo = rb_exc_new3(rb_eSecurityError,
    00464                                               rb_sprintf("Insecure exit at level %d", th->safe_level));
    00465                     errinfo = Qnil;
    00466                 }
    00467             }
    00468             else if (th->safe_level < 4 &&
    00469                      (th->vm->thread_abort_on_exception ||
    00470                       th->abort_on_exception || RTEST(ruby_debug))) {
    00471                 /* exit on main_thread */
    00472             }
    00473             else {
    00474                 errinfo = Qnil;
    00475             }
    00476             th->value = Qnil;
    00477         }
    00478
    00479         th->status = THREAD_KILLED;
    00480         thread_debug("thread end: %p\n", (void *)th);
    00481
    00482         main_th = th->vm->main_thread;
    00483         if (th != main_th) {
    00484             if (TYPE(errinfo) == T_OBJECT) {
    00485                 /* treat with normal error object */
    00486                 rb_threadptr_raise(main_th, 1, &errinfo);
    00487             }
    00488         }
    00489         TH_POP_TAG();
    00490
    00491         /* locking_mutex must be Qfalse */
    00492         if (th->locking_mutex != Qfalse) {
    00493             rb_bug("thread_start_func_2: locking_mutex must not be set (%p:%"PRIxVALUE")",
    00494                    (void *)th, th->locking_mutex);
    00495         }
    00496
    00497         /* delete self other than main thread from living_threads */
    00498         if (th != main_th) {
    00499             st_delete_wrap(th->vm->living_threads, th->self);
    00500         }
    00501
    00502         /* wake up joining threads */
    00503         join_th = th->join_list_head;
    00504         while (join_th) {
    00505             if (join_th == main_th) errinfo = Qnil;
    00506             rb_threadptr_interrupt(join_th);
    00507             switch (join_th->status) {
    00508               case THREAD_STOPPED: case THREAD_STOPPED_FOREVER:
    00509                 join_th->status = THREAD_RUNNABLE;
    00510               default: break;
    00511             }
    00512             join_th = join_th->join_list_next;
    00513         }
    00514
    00515         if (!th->root_fiber) {
    00516             rb_thread_recycle_stack_release(th->stack);
    00517             th->stack = 0;
    00518         }
    00519     }
    00520     thread_unlock_all_locking_mutexes(th);
    00521     if (th != main_th) rb_check_deadlock(th->vm);
    00522     if (th->vm->main_thread == th) {
    00523         ruby_cleanup(state);
    00524     }
    00525     else {
    00526         thread_cleanup_func(th);
    00527         native_mutex_unlock(&th->vm->global_vm_lock);
    00528     }
    00529
    00530     return 0;
    00531 }
    00532
    00533 static VALUE
    00534 thread_create_core(VALUE thval, VALUE args, VALUE (*fn)(ANYARGS))
    00535 {
    00536     rb_thread_t *th;
    00537     int err;
    00538
    00539     if (OBJ_FROZEN(GET_THREAD()->thgroup)) {
    00540         rb_raise(rb_eThreadError,
    00541                  "can't start a new thread (frozen ThreadGroup)");
    00542     }
    00543     GetThreadPtr(thval, th);
    00544
    00545     /* setup thread environment */
    00546     th->first_func = fn;
    00547     th->first_proc = fn ? Qfalse : rb_block_proc();
    00548     th->first_args = args; /* GC: shouldn't put before above line */
    00549
    00550     th->priority = GET_THREAD()->priority;
    00551     th->thgroup = GET_THREAD()->thgroup;
    00552
    00553     native_mutex_initialize(&th->interrupt_lock);
    00554     if (GET_VM()->event_hooks != NULL)
    00555         th->event_flags |= RUBY_EVENT_VM;
    00556
    00557     /* kick thread */
    00558     st_insert(th->vm->living_threads, thval, (st_data_t) th->thread_id);
    00559     err = native_thread_create(th);
    00560     if (err) {
    00561         st_delete_wrap(th->vm->living_threads, th->self);
    00562         th->status = THREAD_KILLED;
    00563         rb_raise(rb_eThreadError, "can't create Thread (%d)", err);
    00564     }
    00565     return thval;
    00566 }
    00567
    00568 /* :nodoc: */
    00569 static VALUE
    00570 thread_s_new(int argc, VALUE *argv, VALUE klass)
    00571 {
    00572     rb_thread_t *th;
    00573     VALUE thread = rb_thread_alloc(klass);
    00574     rb_obj_call_init(thread, argc, argv);
    00575     GetThreadPtr(thread, th);
    00576     if (!th->first_args) {
    00577         rb_raise(rb_eThreadError, "uninitialized thread - check `%s#initialize'",
    00578                  rb_class2name(klass));
    00579     }
    00580     return thread;
    00581 }
    00582
    00583 /*
    00584  *  call-seq:
    00585  *     Thread.start([args]*) {|args| block }   -> thread
    00586  *     Thread.fork([args]*) {|args| block }    -> thread
    00587  *
    00588  *  Basically the same as <code>Thread::new</code>. However, if class
    00589  *  <code>Thread</code> is subclassed, then calling <code>start</code> in that
    00590  *  subclass will not invoke the subclass's <code>initialize</code> method.
    00591  */
    00592
    00593 static VALUE
    00594 thread_start(VALUE klass, VALUE args)
    00595 {
    00596     return thread_create_core(rb_thread_alloc(klass), args, 0);
    00597 }
    00598
    00599 /* :nodoc: */
    00600 static VALUE
    00601 thread_initialize(VALUE thread, VALUE args)
    00602 {
    00603     rb_thread_t *th;
    00604     if (!rb_block_given_p()) {
    00605         rb_raise(rb_eThreadError, "must be called with a block");
    00606     }
    00607     GetThreadPtr(thread, th);
    00608     if (th->first_args) {
    00609         VALUE rb_proc_location(VALUE self);
    00610         VALUE proc = th->first_proc, line, loc;
    00611         const char *file;
    00612         if (!proc || !RTEST(loc = rb_proc_location(proc))) {
    00613             rb_raise(rb_eThreadError, "already initialized thread");
    00614         }
    00615         file = RSTRING_PTR(RARRAY_PTR(loc)[0]);
    00616         if (NIL_P(line = RARRAY_PTR(loc)[1])) {
    00617             rb_raise(rb_eThreadError, "already initialized thread - %s",
    00618                      file);
    00619         }
    00620         rb_raise(rb_eThreadError, "already initialized thread - %s:%d",
    00621                  file, NUM2INT(line));
    00622     }
    00623     return thread_create_core(thread, args, 0);
    00624 }
    00625
    00626 VALUE
    00627 rb_thread_create(VALUE (*fn)(ANYARGS), void *arg)
    00628 {
    00629     return thread_create_core(rb_thread_alloc(rb_cThread), (VALUE)arg, fn);
    00630 }
    00631
    00632
    00633 /* +infty, for this purpose */
    00634 #define DELAY_INFTY 1E30
    00635
    00636 struct join_arg {
    00637     rb_thread_t *target, *waiting;
    00638     double limit;
    00639     int forever;
    00640 };
    00641
    00642 static VALUE
    00643 remove_from_join_list(VALUE arg)
    00644 {
    00645     struct join_arg *p = (struct join_arg *)arg;
    00646     rb_thread_t *target_th = p->target, *th = p->waiting;
    00647
    00648     if (target_th->status != THREAD_KILLED) {
    00649         rb_thread_t **pth = &target_th->join_list_head;
    00650
    00651         while (*pth) {
    00652             if (*pth == th) {
    00653                 *pth = th->join_list_next;
    00654                 break;
    00655             }
    00656             pth = &(*pth)->join_list_next;
    00657         }
    00658     }
    00659
    00660     return Qnil;
    00661 }
    00662
    00663 static VALUE
    00664 thread_join_sleep(VALUE arg)
    00665 {
    00666     struct join_arg *p = (struct join_arg *)arg;
    00667     rb_thread_t *target_th = p->target, *th = p->waiting;
    00668     double now, limit = p->limit;
    00669
    00670     while (target_th->status != THREAD_KILLED) {
    00671         if (p->forever) {
    00672             sleep_forever(th, 1);
    00673         }
    00674         else {
    00675             now = timeofday();
    00676             if (now > limit) {
    00677                 thread_debug("thread_join: timeout (thid: %p)\n",
    00678                              (void *)target_th->thread_id);
    00679                 return Qfalse;
    00680             }
    00681             sleep_wait_for_interrupt(th, limit - now);
    00682         }
    00683         thread_debug("thread_join: interrupted (thid: %p)\n",
    00684                      (void *)target_th->thread_id);
    00685     }
    00686     return Qtrue;
    00687 }
    00688
    00689 static VALUE
    00690 thread_join(rb_thread_t *target_th, double delay)
    00691 {
    00692     rb_thread_t *th = GET_THREAD();
    00693     struct join_arg arg;
    00694
    00695     arg.target = target_th;
    00696     arg.waiting = th;
    00697     arg.limit = timeofday() + delay;
    00698     arg.forever = delay == DELAY_INFTY;
    00699
    00700     thread_debug("thread_join (thid: %p)\n", (void *)target_th->thread_id);
    00701
    00702     if (target_th->status != THREAD_KILLED) {
    00703         th->join_list_next = target_th->join_list_head;
    00704         target_th->join_list_head = th;
    00705         if (!rb_ensure(thread_join_sleep, (VALUE)&arg,
    00706                        remove_from_join_list, (VALUE)&arg)) {
    00707             return Qnil;
    00708         }
    00709     }
    00710
    00711     thread_debug("thread_join: success (thid: %p)\n",
    00712                  (void *)target_th->thread_id);
    00713
    00714     if (target_th->errinfo != Qnil) {
    00715         VALUE err = target_th->errinfo;
    00716
    00717         if (FIXNUM_P(err)) {
    00718             /* */
    00719         }
    00720         else if (TYPE(target_th->errinfo) == T_NODE) {
    00721             rb_exc_raise(rb_vm_make_jump_tag_but_local_jump(
    00722                 GET_THROWOBJ_STATE(err), GET_THROWOBJ_VAL(err)));
    00723         }
    00724         else {
    00725             /* normal exception */
    00726             rb_exc_raise(err);
    00727         }
    00728     }
    00729     return target_th->self;
    00730 }
    00731
    00732 /*
    00733  *  call-seq:
    00734  *     thr.join          -> thr
    00735  *     thr.join(limit)   -> thr
    00736  *
    00737  *  The calling thread will suspend execution and run <i>thr</i>. Does not
    00738  *  return until <i>thr</i> exits or until <i>limit</i> seconds have passed. If
    00739  *  the time limit expires, <code>nil</code> will be returned, otherwise
    00740  *  <i>thr</i> is returned.
    00741  *
    00742  *  Any threads not joined will be killed when the main program exits.  If
    00743  *  <i>thr</i> had previously raised an exception and the
    00744  *  <code>abort_on_exception</code> and <code>$DEBUG</code> flags are not set
    00745  *  (so the exception has not yet been processed) it will be processed at this
    00746  *  time.
    00747  *
    00748  *     a = Thread.new { print "a"; sleep(10); print "b"; print "c" }
    00749  *     x = Thread.new { print "x"; Thread.pass; print "y"; print "z" }
    00750  *     x.join # Let x thread finish, a will be killed on exit.
    00751  *
    00752  *  <em>produces:</em>
    00753  *
    00754  *     axyz
    00755  *
    00756  *  The following example illustrates the <i>limit</i> parameter.
    00757  *
    00758  *     y = Thread.new { 4.times { sleep 0.1; puts 'tick... ' }}
    00759  *     puts "Waiting" until y.join(0.15)
    00760  *
    00761  *  <em>produces:</em>
    00762  *
    00763  *     tick...
    00764  *     Waiting
    00765  *     tick...
    00766  *     Waitingtick...
    00767  *
    00768  *
    00769  *     tick...
    00770  */
    00771
    00772 static VALUE
    00773 thread_join_m(int argc, VALUE *argv, VALUE self)
    00774 {
    00775     rb_thread_t *target_th;
    00776     double delay = DELAY_INFTY;
    00777     VALUE limit;
    00778
    00779     GetThreadPtr(self, target_th);
    00780
    00781     rb_scan_args(argc, argv, "01", &limit);
    00782     if (!NIL_P(limit)) {
    00783         delay = rb_num2dbl(limit);
    00784     }
    00785
    00786     return thread_join(target_th, delay);
    00787 }
    00788
    00789 /*
    00790  *  call-seq:
    00791  *     thr.value   -> obj
    00792  *
    00793  *  Waits for <i>thr</i> to complete (via <code>Thread#join</code>) and returns
    00794  *  its value.
    00795  *
    00796  *     a = Thread.new { 2 + 2 }
    00797  *     a.value   #=> 4
    00798  */
    00799
    00800 static VALUE
    00801 thread_value(VALUE self)
    00802 {
    00803     rb_thread_t *th;
    00804     GetThreadPtr(self, th);
    00805     thread_join(th, DELAY_INFTY);
    00806     return th->value;
    00807 }
    00808
    00809 /*
    00810  * Thread Scheduling
    00811  */
    00812
    00813 static struct timeval
    00814 double2timeval(double d)
    00815 {
    00816     struct timeval time;
    00817
    00818     time.tv_sec = (int)d;
    00819     time.tv_usec = (int)((d - (int)d) * 1e6);
    00820     if (time.tv_usec < 0) {
    00821         time.tv_usec += (int)1e6;
    00822         time.tv_sec -= 1;
    00823     }
    00824     return time;
    00825 }
    00826
    00827 static void
    00828 sleep_forever(rb_thread_t *th, int deadlockable)
    00829 {
    00830     enum rb_thread_status prev_status = th->status;
    00831
    00832     th->status = deadlockable ? THREAD_STOPPED_FOREVER : THREAD_STOPPED;
    00833     do {
    00834         if (deadlockable) {
    00835             th->vm->sleeper++;
    00836             rb_check_deadlock(th->vm);
    00837         }
    00838         native_sleep(th, 0);
    00839         if (deadlockable) {
    00840             th->vm->sleeper--;
    00841         }
    00842         RUBY_VM_CHECK_INTS();
    00843     } while (th->status == THREAD_STOPPED_FOREVER);
    00844     th->status = prev_status;
    00845 }
    00846
    00847 static void
    00848 getclockofday(struct timeval *tp)
    00849 {
    00850 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
    00851     struct timespec ts;
    00852
    00853     if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
    00854         tp->tv_sec = ts.tv_sec;
    00855         tp->tv_usec = ts.tv_nsec / 1000;
    00856     } else
    00857 #endif
    00858     {
    00859         gettimeofday(tp, NULL);
    00860     }
    00861 }
    00862
    00863 static void
    00864 sleep_timeval(rb_thread_t *th, struct timeval tv)
    00865 {
    00866     struct timeval to, tvn;
    00867     enum rb_thread_status prev_status = th->status;
    00868
    00869     getclockofday(&to);
    00870     to.tv_sec += tv.tv_sec;
    00871     if ((to.tv_usec += tv.tv_usec) >= 1000000) {
    00872         to.tv_sec++;
    00873         to.tv_usec -= 1000000;
    00874     }
    00875
    00876     th->status = THREAD_STOPPED;
    00877     do {
    00878         native_sleep(th, &tv);
    00879         RUBY_VM_CHECK_INTS();
    00880         getclockofday(&tvn);
    00881         if (to.tv_sec < tvn.tv_sec) break;
    00882         if (to.tv_sec == tvn.tv_sec && to.tv_usec <= tvn.tv_usec) break;
    00883         thread_debug("sleep_timeval: %ld.%.6ld > %ld.%.6ld\n",
    00884                      (long)to.tv_sec, (long)to.tv_usec,
    00885                      (long)tvn.tv_sec, (long)tvn.tv_usec);
    00886         tv.tv_sec = to.tv_sec - tvn.tv_sec;
    00887         if ((tv.tv_usec = to.tv_usec - tvn.tv_usec) < 0) {
    00888             --tv.tv_sec;
    00889             tv.tv_usec += 1000000;
    00890         }
    00891     } while (th->status == THREAD_STOPPED);
    00892     th->status = prev_status;
    00893 }
    00894
    00895 void
    00896 rb_thread_sleep_forever(void)
    00897 {
    00898     thread_debug("rb_thread_sleep_forever\n");
    00899     sleep_forever(GET_THREAD(), 0);
    00900 }
    00901
    00902 static void
    00903 rb_thread_sleep_deadly(void)
    00904 {
    00905     thread_debug("rb_thread_sleep_deadly\n");
    00906     sleep_forever(GET_THREAD(), 1);
    00907 }
    00908
    00909 static double
    00910 timeofday(void)
    00911 {
    00912 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
    00913     struct timespec tp;
    00914
    00915     if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
    00916         return (double)tp.tv_sec + (double)tp.tv_nsec * 1e-9;
    00917     } else
    00918 #endif
    00919     {
    00920         struct timeval tv;
    00921         gettimeofday(&tv, NULL);
    00922         return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6;
    00923     }
    00924 }
    00925
    00926 static void
    00927 sleep_wait_for_interrupt(rb_thread_t *th, double sleepsec)
    00928 {
    00929     sleep_timeval(th, double2timeval(sleepsec));
    00930 }
    00931
    00932 static void
    00933 sleep_for_polling(rb_thread_t *th)
    00934 {
    00935     struct timeval time;
    00936     time.tv_sec = 0;
    00937     time.tv_usec = 100 * 1000;  /* 0.1 sec */
    00938     sleep_timeval(th, time);
    00939 }
    00940
    00941 void
    00942 rb_thread_wait_for(struct timeval time)
    00943 {
    00944     rb_thread_t *th = GET_THREAD();
    00945     sleep_timeval(th, time);
    00946 }
    00947
    00948 void
    00949 rb_thread_polling(void)
    00950 {
    00951     RUBY_VM_CHECK_INTS();
    00952     if (!rb_thread_alone()) {
    00953         rb_thread_t *th = GET_THREAD();
    00954         sleep_for_polling(th);
    00955     }
    00956 }
    00957
    00958 /*
    00959  * CAUTION: This function causes thread switching.
    00960  *          rb_thread_check_ints() check ruby's interrupts.
    00961  *          some interrupt needs thread switching/invoke handlers,
    00962  *          and so on.
    00963  */
    00964
    00965 void
    00966 rb_thread_check_ints(void)
    00967 {
    00968     RUBY_VM_CHECK_INTS();
    00969 }
    00970
    00971 /*
    00972  * Hidden API for tcl/tk wrapper.
    00973  * There is no guarantee to perpetuate it.
    00974  */
    00975 int
    00976 rb_thread_check_trap_pending(void)
    00977 {
    00978     return GET_THREAD()->exec_signal != 0;
    00979 }
    00980
    00981 /* This function can be called in blocking region. */
    00982 int
    00983 rb_thread_interrupted(VALUE thval)
    00984 {
    00985     rb_thread_t *th;
    00986     GetThreadPtr(thval, th);
    00987     return RUBY_VM_INTERRUPTED(th);
    00988 }
    00989
    00990 struct timeval rb_time_timeval(VALUE);
    00991
    00992 void
    00993 rb_thread_sleep(int sec)
    00994 {
    00995     rb_thread_wait_for(rb_time_timeval(INT2FIX(sec)));
    00996 }
    00997
    00998 static void rb_threadptr_execute_interrupts_rec(rb_thread_t *, int);
    00999
    01000 static void
    01001 rb_thread_schedule_rec(int sched_depth)
    01002 {
    01003     thread_debug("rb_thread_schedule\n");
    01004     if (!rb_thread_alone()) {
    01005         rb_thread_t *th = GET_THREAD();
    01006
    01007         thread_debug("rb_thread_schedule/switch start\n");
    01008
    01009         RB_GC_SAVE_MACHINE_CONTEXT(th);
    01010         native_mutex_unlock(&th->vm->global_vm_lock);
    01011         {
    01012             native_thread_yield();
    01013         }
    01014         native_mutex_lock(&th->vm->global_vm_lock);
    01015
    01016         rb_thread_set_current(th);
    01017         thread_debug("rb_thread_schedule/switch done\n");
    01018
    01019         if (!sched_depth && UNLIKELY(GET_THREAD()->interrupt_flag)) {
    01020             rb_threadptr_execute_interrupts_rec(GET_THREAD(), sched_depth+1);
    01021         }
    01022     }
    01023 }
    01024
    01025 void
    01026 rb_thread_schedule(void)
    01027 {
    01028     rb_thread_schedule_rec(0);
    01029 }
    01030
    01031 /* blocking region */
    01032
    01033 static inline void
    01034 blocking_region_end(rb_thread_t *th, struct rb_blocking_region_buffer *region)
    01035 {
    01036     native_mutex_lock(&th->vm->global_vm_lock);
    01037     rb_thread_set_current(th);
    01038     thread_debug("leave blocking region (%p)\n", (void *)th);
    01039     remove_signal_thread_list(th);
    01040     th->blocking_region_buffer = 0;
    01041     reset_unblock_function(th, &region->oldubf);
    01042     if (th->status == THREAD_STOPPED) {
    01043         th->status = region->prev_status;
    01044     }
    01045 }
    01046
    01047 struct rb_blocking_region_buffer *
    01048 rb_thread_blocking_region_begin(void)
    01049 {
    01050     rb_thread_t *th = GET_THREAD();
    01051     struct rb_blocking_region_buffer *region = ALLOC(struct rb_blocking_region_buffer);
    01052     blocking_region_begin(th, region, ubf_select, th);
    01053     return region;
    01054 }
    01055
    01056 void
    01057 rb_thread_blocking_region_end(struct rb_blocking_region_buffer *region)
    01058 {
    01059     int saved_errno = errno;
    01060     rb_thread_t *th = GET_THREAD();
    01061     blocking_region_end(th, region);
    01062     xfree(region);
    01063     RUBY_VM_CHECK_INTS();
    01064     errno = saved_errno;
    01065 }
    01066
    01067 /*
    01068  * rb_thread_blocking_region - permit concurrent/parallel execution.
    01069  *
    01070  * This function does:
    01071  *   (1) release GVL.
    01072  *       Other Ruby threads may run in parallel.
    01073  *   (2) call func with data1.
    01074  *   (3) acquire GVL.
    01075  *       Other Ruby threads can not run in parallel any more.
    01076  *
    01077  *   If another thread interrupts this thread (Thread#kill, signal delivery,
    01078  *   VM-shutdown request, and so on), `ubf()' is called (`ubf()' means
    01079  *   "un-blocking function").  `ubf()' should interrupt `func()' execution.
    01080  *
    01081  *   There are built-in ubfs and you can specify these ubfs.
    01082  *   However, we can not guarantee our built-in ubfs interrupt
    01083  *   your `func()' correctly.  Be careful to use rb_thread_blocking_region().
    01084  *
    01085  *     * RUBY_UBF_IO: ubf for IO operation
    01086  *     * RUBY_UBF_PROCESS: ubf for process operation
    01087  *
    01088  *   NOTE: You can not execute most of Ruby C API and touch Ruby
    01089  *         objects in `func()' and `ubf()', including raising an
    01090  *         exception, because current thread doesn't acquire GVL
    01091  *         (cause synchronization problem).  If you need to do it,
    01092  *         read source code of C APIs and confirm by yourself.
    01093  *
    01094  *   NOTE: In short, this API is difficult to use safely.  I recommend you
    01095  *         use other ways if you have.  We lack experiences to use this API.
    01096  *         Please report your problem related on it.
    01097  *
    01098  *   Safe C API:
    01099  *     * rb_thread_interrupted() - check interrupt flag
    01100  *     * ruby_xalloc(), ruby_xrealloc(), ruby_xfree() -
    01101  *         if they called without GVL, acquire GVL automatically.
    01102  */
    01103 VALUE
    01104 rb_thread_blocking_region(
    01105     rb_blocking_function_t *func, void *data1,
    01106     rb_unblock_function_t *ubf, void *data2)
    01107 {
    01108     VALUE val;
    01109     rb_thread_t *th = GET_THREAD();
    01110     int saved_errno = 0;
    01111
    01112     if (ubf == RUBY_UBF_IO || ubf == RUBY_UBF_PROCESS) {
    01113         ubf = ubf_select;
    01114         data2 = th;
    01115     }
    01116
    01117     BLOCKING_REGION({
    01118         val = func(data1);
    01119         saved_errno = errno;
    01120     }, ubf, data2);
    01121     errno = saved_errno;
    01122
    01123     return val;
    01124 }
    01125
    01126 /* alias of rb_thread_blocking_region() */
    01127
    01128 VALUE
    01129 rb_thread_call_without_gvl(
    01130     rb_blocking_function_t *func, void *data1,
    01131     rb_unblock_function_t *ubf, void *data2)
    01132 {
    01133     return rb_thread_blocking_region(func, data1, ubf, data2);
    01134 }
    01135
    01136 /*
    01137  * rb_thread_call_with_gvl - re-enter into Ruby world while releasing GVL.
    01138  *
    01139  ***
    01140  *** This API is EXPERIMENTAL!
    01141  *** We do not guarantee that this API remains in ruby 1.9.2 or later.
    01142  ***
    01143  *
    01144  * While releasing GVL using rb_thread_blocking_region() or
    01145  * rb_thread_call_without_gvl(), you can not access Ruby values or invoke methods.
    01146  * If you need to access it, you must use this function rb_thread_call_with_gvl().
    01147  *
    01148  * This function rb_thread_call_with_gvl() does:
    01149  * (1) acquire GVL.
    01150  * (2) call passed function `func'.
    01151  * (3) release GVL.
    01152  * (4) return a value which is returned at (2).
    01153  *
    01154  * NOTE: You should not return Ruby object at (2) because such Object
    01155  *       will not marked.
    01156  *
    01157  * NOTE: If an exception is raised in `func', this function "DOES NOT"
    01158  *       protect (catch) the exception.  If you have any resources
    01159  *       which should free before throwing exception, you need use
    01160  *       rb_protect() in `func' and return a value which represents
    01161  *       exception is raised.
    01162  *
    01163  * NOTE: This functions should not be called by a thread which
    01164  *       is not created as Ruby thread (created by Thread.new or so).
    01165  *       In other words, this function *DOES NOT* associate
    01166  *       NON-Ruby thread to Ruby thread.
    01167  */
    01168 void *
    01169 rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
    01170 {
    01171     rb_thread_t *th = ruby_thread_from_native();
    01172     struct rb_blocking_region_buffer *brb;
    01173     struct rb_unblock_callback prev_unblock;
    01174     void *r;
    01175
    01176     if (th == 0) {
    01177         /* Error is occurred, but we can't use rb_bug()
    01178          * because this thread is not Ruby's thread.
    01179          * What should we do?
    01180          */
    01181
    01182         fprintf(stderr, "[BUG] rb_thread_call_with_gvl() is called by non-ruby thread\n");
    01183         exit(1);
    01184     }
    01185
    01186     brb = (struct rb_blocking_region_buffer *)th->blocking_region_buffer;
    01187     prev_unblock = th->unblock;
    01188
    01189     if (brb == 0) {
    01190         rb_bug("rb_thread_call_with_gvl: called by a thread which has GVL.");
    01191     }
    01192
    01193     blocking_region_end(th, brb);
    01194     /* enter to Ruby world: You can access Ruby values, methods and so on. */
    01195     r = (*func)(data1);
    01196     /* leave from Ruby world: You can not access Ruby values, etc. */
    01197     blocking_region_begin(th, brb, prev_unblock.func, prev_unblock.arg);
    01198     return r;
    01199 }
    01200
    01201 /*
    01202  * ruby_thread_has_gvl_p - check if current native thread has GVL.
    01203  *
    01204  ***
    01205  *** This API is EXPERIMENTAL!
    01206  *** We do not guarantee that this API remains in ruby 1.9.2 or later.
    01207  ***
    01208  */
    01209
    01210 int
    01211 ruby_thread_has_gvl_p(void)
    01212 {
    01213     rb_thread_t *th = ruby_thread_from_native();
    01214
    01215     if (th && th->blocking_region_buffer == 0) {
    01216         return 1;
    01217     }
    01218     else {
    01219         return 0;
    01220     }
    01221 }
    01222
    01223 /*
    01224  *  call-seq:
    01225  *     Thread.pass   -> nil
    01226  *
    01227  *  Invokes the thread scheduler to pass execution to another thread.
    01228  *
    01229  *     a = Thread.new { print "a"; Thread.pass;
    01230  *                      print "b"; Thread.pass;
    01231  *                      print "c" }
    01232  *     b = Thread.new { print "x"; Thread.pass;
    01233  *                      print "y"; Thread.pass;
    01234  *                      print "z" }
    01235  *     a.join
    01236  *     b.join
    01237  *
    01238  *  <em>produces:</em>
    01239  *
    01240  *     axbycz
    01241  */
    01242
    01243 static VALUE
    01244 thread_s_pass(VALUE klass)
    01245 {
    01246     rb_thread_schedule();
    01247     return Qnil;
    01248 }
    01249
    01250 /*
    01251  *
    01252  */
    01253
    01254 static void
    01255 rb_threadptr_execute_interrupts_rec(rb_thread_t *th, int sched_depth)
    01256 {
    01257     if (GET_VM()->main_thread == th) {
    01258         while (rb_signal_buff_size() && !th->exec_signal) native_thread_yield();
    01259     }
    01260
    01261     if (th->raised_flag) return;
    01262
    01263     while (th->interrupt_flag) {
    01264         enum rb_thread_status status = th->status;
    01265         int timer_interrupt = th->interrupt_flag & 0x01;
    01266         int finalizer_interrupt = th->interrupt_flag & 0x04;
    01267
    01268         th->status = THREAD_RUNNABLE;
    01269         th->interrupt_flag = 0;
    01270
    01271         /* signal handling */
    01272         if (th->exec_signal) {
    01273             int sig = th->exec_signal;
    01274             th->exec_signal = 0;
    01275             rb_signal_exec(th, sig);
    01276         }
    01277
    01278         /* exception from another thread */
    01279         if (th->thrown_errinfo) {
    01280             VALUE err = th->thrown_errinfo;
    01281             th->thrown_errinfo = 0;
    01282             thread_debug("rb_thread_execute_interrupts: %ld\n", err);
    01283
    01284             if (err == eKillSignal || err == eTerminateSignal) {
    01285                 th->errinfo = INT2FIX(TAG_FATAL);
    01286                 TH_JUMP_TAG(th, TAG_FATAL);
    01287             }
    01288             else {
    01289                 rb_exc_raise(err);
    01290             }
    01291         }
    01292         th->status = status;
    01293
    01294         if (finalizer_interrupt) {
    01295             rb_gc_finalize_deferred();
    01296         }
    01297
    01298         if (!sched_depth && timer_interrupt) {
    01299             sched_depth++;
    01300             EXEC_EVENT_HOOK(th, RUBY_EVENT_SWITCH, th->cfp->self, 0, 0);
    01301
    01302             if (th->slice > 0) {
    01303                 th->slice--;
    01304             }
    01305             else {
    01306               reschedule:
    01307                 rb_thread_schedule_rec(sched_depth+1);
    01308                 if (th->slice < 0) {
    01309                     th->slice++;
    01310                     goto reschedule;
    01311                 }
    01312                 else {
    01313                     th->slice = th->priority;
    01314                 }
    01315             }
    01316         }
    01317     }
    01318 }
    01319
    01320 void
    01321 rb_threadptr_execute_interrupts(rb_thread_t *th)
    01322 {
    01323     rb_threadptr_execute_interrupts_rec(th, 0);
    01324 }
    01325
    01326 void
    01327 rb_gc_mark_threads(void)
    01328 {
    01329     /* TODO: remove */
    01330 }
    01331
    01332 /*****************************************************/
    01333
    01334 static void
    01335 rb_threadptr_ready(rb_thread_t *th)
    01336 {
    01337     rb_threadptr_interrupt(th);
    01338 }
    01339
    01340 static VALUE
    01341 rb_threadptr_raise(rb_thread_t *th, int argc, VALUE *argv)
    01342 {
    01343     VALUE exc;
    01344
    01345   again:
    01346     if (rb_threadptr_dead(th)) {
    01347         return Qnil;
    01348     }
    01349
    01350     if (th->thrown_errinfo != 0 || th->raised_flag) {
    01351         rb_thread_schedule();
    01352         goto again;
    01353     }
    01354
    01355     exc = rb_make_exception(argc, argv);
    01356     th->thrown_errinfo = exc;
    01357     rb_threadptr_ready(th);
    01358     return Qnil;
    01359 }
    01360
    01361 void
    01362 rb_threadptr_signal_raise(rb_thread_t *th, int sig)
    01363 {
    01364     VALUE argv[2];
    01365
    01366     argv[0] = rb_eSignal;
    01367     argv[1] = INT2FIX(sig);
    01368     rb_threadptr_raise(th->vm->main_thread, 2, argv);
    01369 }
    01370
    01371 void
    01372 rb_threadptr_signal_exit(rb_thread_t *th)
    01373 {
    01374     VALUE argv[2];
    01375
    01376     argv[0] = rb_eSystemExit;
    01377     argv[1] = rb_str_new2("exit");
    01378     rb_threadptr_raise(th->vm->main_thread, 2, argv);
    01379 }
    01380
    01381 #if defined(POSIX_SIGNAL) && defined(SIGSEGV) && defined(HAVE_SIGALTSTACK)
    01382 #define USE_SIGALTSTACK
    01383 #endif
    01384
    01385 void
    01386 ruby_thread_stack_overflow(rb_thread_t *th)
    01387 {
    01388     th->raised_flag = 0;
    01389 #ifdef USE_SIGALTSTACK
    01390     th->raised_flag = 0;
    01391     rb_exc_raise(sysstack_error);
    01392 #else
    01393     th->errinfo = sysstack_error;
    01394     TH_JUMP_TAG(th, TAG_RAISE);
    01395 #endif
    01396 }
    01397
    01398 int
    01399 rb_threadptr_set_raised(rb_thread_t *th)
    01400 {
    01401     if (th->raised_flag & RAISED_EXCEPTION) {
    01402         return 1;
    01403     }
    01404     th->raised_flag |= RAISED_EXCEPTION;
    01405     return 0;
    01406 }
    01407
    01408 int
    01409 rb_threadptr_reset_raised(rb_thread_t *th)
    01410 {
    01411     if (!(th->raised_flag & RAISED_EXCEPTION)) {
    01412         return 0;
    01413     }
    01414     th->raised_flag &= ~RAISED_EXCEPTION;
    01415     return 1;
    01416 }
    01417
    01418 void
    01419 rb_thread_fd_close(int fd)
    01420 {
    01421     /* TODO: fix me */
    01422 }
    01423
    01424 /*
    01425  *  call-seq:
    01426  *     thr.raise
    01427  *     thr.raise(string)
    01428  *     thr.raise(exception [, string [, array]])
    01429  *
    01430  *  Raises an exception (see <code>Kernel::raise</code>) from <i>thr</i>. The
    01431  *  caller does not have to be <i>thr</i>.
    01432  *
    01433  *     Thread.abort_on_exception = true
    01434  *     a = Thread.new { sleep(200) }
    01435  *     a.raise("Gotcha")
    01436  *
    01437  *  <em>produces:</em>
    01438  *
    01439  *     prog.rb:3: Gotcha (RuntimeError)
    01440  *      from prog.rb:2:in `initialize'
    01441  *      from prog.rb:2:in `new'
    01442  *      from prog.rb:2
    01443  */
    01444
    01445 static VALUE
    01446 thread_raise_m(int argc, VALUE *argv, VALUE self)
    01447 {
    01448     rb_thread_t *th;
    01449     GetThreadPtr(self, th);
    01450     rb_threadptr_raise(th, argc, argv);
    01451     return Qnil;
    01452 }
    01453
    01454
    01455 /*
    01456  *  call-seq:
    01457  *     thr.exit        -> thr or nil
    01458  *     thr.kill        -> thr or nil
    01459  *     thr.terminate   -> thr or nil
    01460  *
    01461  *  Terminates <i>thr</i> and schedules another thread to be run. If this thread
    01462  *  is already marked to be killed, <code>exit</code> returns the
    01463  *  <code>Thread</code>. If this is the main thread, or the last thread, exits
    01464  *  the process.
    01465  */
    01466
    01467 VALUE
    01468 rb_thread_kill(VALUE thread)
    01469 {
    01470     rb_thread_t *th;
    01471
    01472     GetThreadPtr(thread, th);
    01473
    01474     if (th != GET_THREAD() && th->safe_level < 4) {
    01475         rb_secure(4);
    01476     }
    01477     if (th->status == THREAD_TO_KILL || th->status == THREAD_KILLED) {
    01478         return thread;
    01479     }
    01480     if (th == th->vm->main_thread) {
    01481         rb_exit(EXIT_SUCCESS);
    01482     }
    01483
    01484     thread_debug("rb_thread_kill: %p (%p)\n", (void *)th, (void *)th->thread_id);
    01485
    01486     rb_threadptr_interrupt(th);
    01487     th->thrown_errinfo = eKillSignal;
    01488     th->status = THREAD_TO_KILL;
    01489
    01490     return thread;
    01491 }
    01492
    01493
    01494 /*
    01495  *  call-seq:
    01496  *     Thread.kill(thread)   -> thread
    01497  *
    01498  *  Causes the given <em>thread</em> to exit (see <code>Thread::exit</code>).
    01499  *
    01500  *     count = 0
    01501  *     a = Thread.new { loop { count += 1 } }
    01502  *     sleep(0.1)       #=> 0
    01503  *     Thread.kill(a)   #=> #<Thread:0x401b3d30 dead>
    01504  *     count            #=> 93947
    01505  *     a.alive?         #=> false
    01506  */
    01507
    01508 static VALUE
    01509 rb_thread_s_kill(VALUE obj, VALUE th)
    01510 {
    01511     return rb_thread_kill(th);
    01512 }
    01513
    01514
    01515 /*
    01516  *  call-seq:
    01517  *     Thread.exit   -> thread
    01518  *
    01519  *  Terminates the currently running thread and schedules another thread to be
    01520  *  run. If this thread is already marked to be killed, <code>exit</code>
    01521  *  returns the <code>Thread</code>. If this is the main thread, or the last
    01522  *  thread, exit the process.
    01523  */
    01524
    01525 static VALUE
    01526 rb_thread_exit(void)
    01527 {
    01528     return rb_thread_kill(GET_THREAD()->self);
    01529 }
    01530
    01531
    01532 /*
    01533  *  call-seq:
    01534  *     thr.wakeup   -> thr
    01535  *
    01536  *  Marks <i>thr</i> as eligible for scheduling (it may still remain blocked on
    01537  *  I/O, however). Does not invoke the scheduler (see <code>Thread#run</code>).
    01538  *
    01539  *     c = Thread.new { Thread.stop; puts "hey!" }
    01540  *     c.wakeup
    01541  *
    01542  *  <em>produces:</em>
    01543  *
    01544  *     hey!
    01545  */
    01546
    01547 VALUE
    01548 rb_thread_wakeup(VALUE thread)
    01549 {
    01550     rb_thread_t *th;
    01551     GetThreadPtr(thread, th);
    01552
    01553     if (th->status == THREAD_KILLED) {
    01554         rb_raise(rb_eThreadError, "killed thread");
    01555     }
    01556     rb_threadptr_ready(th);
    01557     if (th->status != THREAD_TO_KILL) {
    01558         th->status = THREAD_RUNNABLE;
    01559     }
    01560     return thread;
    01561 }
    01562
    01563
    01564 /*
    01565  *  call-seq:
    01566  *     thr.run   -> thr
    01567  *
    01568  *  Wakes up <i>thr</i>, making it eligible for scheduling.
    01569  *
    01570  *     a = Thread.new { puts "a"; Thread.stop; puts "c" }
    01571  *     Thread.pass
    01572  *     puts "Got here"
    01573  *     a.run
    01574  *     a.join
    01575  *
    01576  *  <em>produces:</em>
    01577  *
    01578  *     a
    01579  *     Got here
    01580  *     c
    01581  */
    01582
    01583 VALUE
    01584 rb_thread_run(VALUE thread)
    01585 {
    01586     rb_thread_wakeup(thread);
    01587     rb_thread_schedule();
    01588     return thread;
    01589 }
    01590
    01591
    01592 /*
    01593  *  call-seq:
    01594  *     Thread.stop   -> nil
    01595  *
    01596  *  Stops execution of the current thread, putting it into a ``sleep'' state,
    01597  *  and schedules execution of another thread.
    01598  *
    01599  *     a = Thread.new { print "a"; Thread.stop; print "c" }
    01600  *     Thread.pass
    01601  *     print "b"
    01602  *     a.run
    01603  *     a.join
    01604  *
    01605  *  <em>produces:</em>
    01606  *
    01607  *     abc
    01608  */
    01609
    01610 VALUE
    01611 rb_thread_stop(void)
    01612 {
    01613     if (rb_thread_alone()) {
    01614         rb_raise(rb_eThreadError,
    01615                  "stopping only thread\n\tnote: use sleep to stop forever");
    01616     }
    01617     rb_thread_sleep_deadly();
    01618     return Qnil;
    01619 }
    01620
    01621 static int
    01622 thread_list_i(st_data_t key, st_data_t val, void *data)
    01623 {
    01624     VALUE ary = (VALUE)data;
    01625     rb_thread_t *th;
    01626     GetThreadPtr((VALUE)key, th);
    01627
    01628     switch (th->status) {
    01629       case THREAD_RUNNABLE:
    01630       case THREAD_STOPPED:
    01631       case THREAD_STOPPED_FOREVER:
    01632       case THREAD_TO_KILL:
    01633         rb_ary_push(ary, th->self);
    01634       default:
    01635         break;
    01636     }
    01637     return ST_CONTINUE;
    01638 }
    01639
    01640 /********************************************************************/
    01641
    01642 /*
    01643  *  call-seq:
    01644  *     Thread.list   -> array
    01645  *
    01646  *  Returns an array of <code>Thread</code> objects for all threads that are
    01647  *  either runnable or stopped.
    01648  *
    01649  *     Thread.new { sleep(200) }
    01650  *     Thread.new { 1000000.times {|i| i*i } }
    01651  *     Thread.new { Thread.stop }
    01652  *     Thread.list.each {|t| p t}
    01653  *
    01654  *  <em>produces:</em>
    01655  *
    01656  *     #<Thread:0x401b3e84 sleep>
    01657  *     #<Thread:0x401b3f38 run>
    01658  *     #<Thread:0x401b3fb0 sleep>
    01659  *     #<Thread:0x401bdf4c run>
    01660  */
    01661
    01662 VALUE
    01663 rb_thread_list(void)
    01664 {
    01665     VALUE ary = rb_ary_new();
    01666     st_foreach(GET_THREAD()->vm->living_threads, thread_list_i, ary);
    01667     return ary;
    01668 }
    01669
    01670 VALUE
    01671 rb_thread_current(void)
    01672 {
    01673     return GET_THREAD()->self;
    01674 }
    01675
    01676 /*
    01677  *  call-seq:
    01678  *     Thread.current   -> thread
    01679  *
    01680  *  Returns the currently executing thread.
    01681  *
    01682  *     Thread.current   #=> #<Thread:0x401bdf4c run>
    01683  */
    01684
    01685 static VALUE
    01686 thread_s_current(VALUE klass)
    01687 {
    01688     return rb_thread_current();
    01689 }
    01690
    01691 VALUE
    01692 rb_thread_main(void)
    01693 {
    01694     return GET_THREAD()->vm->main_thread->self;
    01695 }
    01696
    01697 /*
    01698  *  call-seq:
    01699  *     Thread.main   -> thread
    01700  *
    01701  *  Returns the main thread.
    01702  */
    01703
    01704 static VALUE
    01705 rb_thread_s_main(VALUE klass)
    01706 {
    01707     return rb_thread_main();
    01708 }
    01709
    01710
    01711 /*
    01712  *  call-seq:
    01713  *     Thread.abort_on_exception   -> true or false
    01714  *
    01715  *  Returns the status of the global ``abort on exception'' condition.  The
    01716  *  default is <code>false</code>. When set to <code>true</code>, or if the
    01717  *  global <code>$DEBUG</code> flag is <code>true</code> (perhaps because the
    01718  *  command line option <code>-d</code> was specified) all threads will abort
    01719  *  (the process will <code>exit(0)</code>) if an exception is raised in any
    01720  *  thread. See also <code>Thread::abort_on_exception=</code>.
    01721  */
    01722
    01723 static VALUE
    01724 rb_thread_s_abort_exc(void)
    01725 {
    01726     return GET_THREAD()->vm->thread_abort_on_exception ? Qtrue : Qfalse;
    01727 }
    01728
    01729
    01730 /*
    01731  *  call-seq:
    01732  *     Thread.abort_on_exception= boolean   -> true or false
    01733  *
    01734  *  When set to <code>true</code>, all threads will abort if an exception is
    01735  *  raised. Returns the new state.
    01736  *
    01737  *     Thread.abort_on_exception = true
    01738  *     t1 = Thread.new do
    01739  *       puts  "In new thread"
    01740  *       raise "Exception from thread"
    01741  *     end
    01742  *     sleep(1)
    01743  *     puts "not reached"
    01744  *
    01745  *  <em>produces:</em>
    01746  *
    01747  *     In new thread
    01748  *     prog.rb:4: Exception from thread (RuntimeError)
    01749  *      from prog.rb:2:in `initialize'
    01750  *      from prog.rb:2:in `new'
    01751  *      from prog.rb:2
    01752  */
    01753
    01754 static VALUE
    01755 rb_thread_s_abort_exc_set(VALUE self, VALUE val)
    01756 {
    01757     rb_secure(4);
    01758     GET_THREAD()->vm->thread_abort_on_exception = RTEST(val);
    01759     return val;
    01760 }
    01761
    01762
    01763 /*
    01764  *  call-seq:
    01765  *     thr.abort_on_exception   -> true or false
    01766  *
    01767  *  Returns the status of the thread-local ``abort on exception'' condition for
    01768  *  <i>thr</i>. The default is <code>false</code>. See also
    01769  *  <code>Thread::abort_on_exception=</code>.
    01770  */
    01771
    01772 static VALUE
    01773 rb_thread_abort_exc(VALUE thread)
    01774 {
    01775     rb_thread_t *th;
    01776     GetThreadPtr(thread, th);
    01777     return th->abort_on_exception ? Qtrue : Qfalse;
    01778 }
    01779
    01780
    01781 /*
    01782  *  call-seq:
    01783  *     thr.abort_on_exception= boolean   -> true or false
    01784  *
    01785  *  When set to <code>true</code>, causes all threads (including the main
    01786  *  program) to abort if an exception is raised in <i>thr</i>. The process will
    01787  *  effectively <code>exit(0)</code>.
    01788  */
    01789
    01790 static VALUE
    01791 rb_thread_abort_exc_set(VALUE thread, VALUE val)
    01792 {
    01793     rb_thread_t *th;
    01794     rb_secure(4);
    01795
    01796     GetThreadPtr(thread, th);
    01797     th->abort_on_exception = RTEST(val);
    01798     return val;
    01799 }
    01800
    01801
    01802 /*
    01803  *  call-seq:
    01804  *     thr.group   -> thgrp or nil
    01805  *
    01806  *  Returns the <code>ThreadGroup</code> which contains <i>thr</i>, or nil if
    01807  *  the thread is not a member of any group.
    01808  *
    01809  *     Thread.main.group   #=> #<ThreadGroup:0x4029d914>
    01810  */
    01811
    01812 VALUE
    01813 rb_thread_group(VALUE thread)
    01814 {
    01815     rb_thread_t *th;
    01816     VALUE group;
    01817     GetThreadPtr(thread, th);
    01818     group = th->thgroup;
    01819
    01820     if (!group) {
    01821         group = Qnil;
    01822     }
    01823     return group;
    01824 }
    01825
    01826 static const char *
    01827 thread_status_name(enum rb_thread_status status)
    01828 {
    01829     switch (status) {
    01830       case THREAD_RUNNABLE:
    01831         return "run";
    01832       case THREAD_STOPPED:
    01833       case THREAD_STOPPED_FOREVER:
    01834         return "sleep";
    01835       case THREAD_TO_KILL:
    01836         return "aborting";
    01837       case THREAD_KILLED:
    01838         return "dead";
    01839       default:
    01840         return "unknown";
    01841     }
    01842 }
    01843
    01844 static int
    01845 rb_threadptr_dead(rb_thread_t *th)
    01846 {
    01847     return th->status == THREAD_KILLED;
    01848 }
    01849
    01850
    01851 /*
    01852  *  call-seq:
    01853  *     thr.status   -> string, false or nil
    01854  *
    01855  *  Returns the status of <i>thr</i>: ``<code>sleep</code>'' if <i>thr</i> is
    01856  *  sleeping or waiting on I/O, ``<code>run</code>'' if <i>thr</i> is executing,
    01857  *  ``<code>aborting</code>'' if <i>thr</i> is aborting, <code>false</code> if
    01858  *  <i>thr</i> terminated normally, and <code>nil</code> if <i>thr</i>
    01859  *  terminated with an exception.
    01860  *
    01861  *     a = Thread.new { raise("die now") }
    01862  *     b = Thread.new { Thread.stop }
    01863  *     c = Thread.new { Thread.exit }
    01864  *     d = Thread.new { sleep }
    01865  *     d.kill                  #=> #<Thread:0x401b3678 aborting>
    01866  *     a.status                #=> nil
    01867  *     b.status                #=> "sleep"
    01868  *     c.status                #=> false
    01869  *     d.status                #=> "aborting"
    01870  *     Thread.current.status   #=> "run"
    01871  */
    01872
    01873 static VALUE
    01874 rb_thread_status(VALUE thread)
    01875 {
    01876     rb_thread_t *th;
    01877     GetThreadPtr(thread, th);
    01878
    01879     if (rb_threadptr_dead(th)) {
    01880         if (!NIL_P(th->errinfo) && !FIXNUM_P(th->errinfo)
    01881             /* TODO */ ) {
    01882             return Qnil;
    01883         }
    01884         return Qfalse;
    01885     }
    01886     return rb_str_new2(thread_status_name(th->status));
    01887 }
    01888
    01889
    01890 /*
    01891  *  call-seq:
    01892  *     thr.alive?   -> true or false
    01893  *
    01894  *  Returns <code>true</code> if <i>thr</i> is running or sleeping.
    01895  *
    01896  *     thr = Thread.new { }
    01897  *     thr.join                #=> #<Thread:0x401b3fb0 dead>
    01898  *     Thread.current.alive?   #=> true
    01899  *     thr.alive?              #=> false
    01900  */
    01901
    01902 static VALUE
    01903 rb_thread_alive_p(VALUE thread)
    01904 {
    01905     rb_thread_t *th;
    01906     GetThreadPtr(thread, th);
    01907
    01908     if (rb_threadptr_dead(th))
    01909         return Qfalse;
    01910     return Qtrue;
    01911 }
    01912
    01913 /*
    01914  *  call-seq:
    01915  *     thr.stop?   -> true or false
    01916  *
    01917  *  Returns <code>true</code> if <i>thr</i> is dead or sleeping.
    01918  *
    01919  *     a = Thread.new { Thread.stop }
    01920  *     b = Thread.current
    01921  *     a.stop?   #=> true
    01922  *     b.stop?   #=> false
    01923  */
    01924
    01925 static VALUE
    01926 rb_thread_stop_p(VALUE thread)
    01927 {
    01928     rb_thread_t *th;
    01929     GetThreadPtr(thread, th);
    01930
    01931     if (rb_threadptr_dead(th))
    01932         return Qtrue;
    01933     if (th->status == THREAD_STOPPED || th->status == THREAD_STOPPED_FOREVER)
    01934         return Qtrue;
    01935     return Qfalse;
    01936 }
    01937
    01938 /*
    01939  *  call-seq:
    01940  *     thr.safe_level   -> integer
    01941  *
    01942  *  Returns the safe level in effect for <i>thr</i>. Setting thread-local safe
    01943  *  levels can help when implementing sandboxes which run insecure code.
    01944  *
    01945  *     thr = Thread.new { $SAFE = 3; sleep }
    01946  *     Thread.current.safe_level   #=> 0
    01947  *     thr.safe_level              #=> 3
    01948  */
    01949
    01950 static VALUE
    01951 rb_thread_safe_level(VALUE thread)
    01952 {
    01953     rb_thread_t *th;
    01954     GetThreadPtr(thread, th);
    01955
    01956     return INT2NUM(th->safe_level);
    01957 }
    01958
    01959 /*
    01960  * call-seq:
    01961  *   thr.inspect   -> string
    01962  *
    01963  * Dump the name, id, and status of _thr_ to a string.
    01964  */
    01965
    01966 static VALUE
    01967 rb_thread_inspect(VALUE thread)
    01968 {
    01969     const char *cname = rb_obj_classname(thread);
    01970     rb_thread_t *th;
    01971     const char *status;
    01972     VALUE str;
    01973
    01974     GetThreadPtr(thread, th);
    01975     status = thread_status_name(th->status);
    01976     str = rb_sprintf("#<%s:%p %s>", cname, (void *)thread, status);
    01977     OBJ_INFECT(str, thread);
    01978
    01979     return str;
    01980 }
    01981
    01982 VALUE
    01983 rb_thread_local_aref(VALUE thread, ID id)
    01984 {
    01985     rb_thread_t *th;
    01986     VALUE val;
    01987
    01988     GetThreadPtr(thread, th);
    01989     if (rb_safe_level() >= 4 && th != GET_THREAD()) {
    01990         rb_raise(rb_eSecurityError, "Insecure: thread locals");
    01991     }
    01992     if (!th->local_storage) {
    01993         return Qnil;
    01994     }
    01995     if (st_lookup(th->local_storage, id, &val)) {
    01996         return val;
    01997     }
    01998     return Qnil;
    01999 }
    02000
    02001 /*
    02002  *  call-seq:
    02003  *      thr[sym]   -> obj or nil
    02004  *
    02005  *  Attribute Reference---Returns the value of a thread-local variable, using
    02006  *  either a symbol or a string name. If the specified variable does not exist,
    02007  *  returns <code>nil</code>.
    02008  *
    02009  *     a = Thread.new { Thread.current["name"] = "A"; Thread.stop }
    02010  *     b = Thread.new { Thread.current[:name]  = "B"; Thread.stop }
    02011  *     c = Thread.new { Thread.current["name"] = "C"; Thread.stop }
    02012  *     Thread.list.each {|x| puts "#{x.inspect}: #{x[:name]}" }
    02013  *
    02014  *  <em>produces:</em>
    02015  *
    02016  *     #<Thread:0x401b3b3c sleep>: C
    02017  *     #<Thread:0x401b3bc8 sleep>: B
    02018  *     #<Thread:0x401b3c68 sleep>: A
    02019  *     #<Thread:0x401bdf4c run>:
    02020  */
    02021
    02022 static VALUE
    02023 rb_thread_aref(VALUE thread, VALUE id)
    02024 {
    02025     return rb_thread_local_aref(thread, rb_to_id(id));
    02026 }
    02027
    02028 VALUE
    02029 rb_thread_local_aset(VALUE thread, ID id, VALUE val)
    02030 {
    02031     rb_thread_t *th;
    02032     GetThreadPtr(thread, th);
    02033
    02034     if (rb_safe_level() >= 4 && th != GET_THREAD()) {
    02035         rb_raise(rb_eSecurityError, "Insecure: can't modify thread locals");
    02036     }
    02037     if (OBJ_FROZEN(thread)) {
    02038         rb_error_frozen("thread locals");
    02039     }
    02040     if (!th->local_storage) {
    02041         th->local_storage = st_init_numtable();
    02042     }
    02043     if (NIL_P(val)) {
    02044         st_delete_wrap(th->local_storage, id);
    02045         return Qnil;
    02046     }
    02047     st_insert(th->local_storage, id, val);
    02048     return val;
    02049 }
    02050
    02051 /*
    02052  *  call-seq:
    02053  *      thr[sym] = obj   -> obj
    02054  *
    02055  *  Attribute Assignment---Sets or creates the value of a thread-local variable,
    02056  *  using either a symbol or a string. See also <code>Thread#[]</code>.
    02057  */
    02058
    02059 static VALUE
    02060 rb_thread_aset(VALUE self, VALUE id, VALUE val)
    02061 {
    02062     return rb_thread_local_aset(self, rb_to_id(id), val);
    02063 }
    02064
    02065 /*
    02066  *  call-seq:
    02067  *     thr.key?(sym)   -> true or false
    02068  *
    02069  *  Returns <code>true</code> if the given string (or symbol) exists as a
    02070  *  thread-local variable.
    02071  *
    02072  *     me = Thread.current
    02073  *     me[:oliver] = "a"
    02074  *     me.key?(:oliver)    #=> true
    02075  *     me.key?(:stanley)   #=> false
    02076  */
    02077
    02078 static VALUE
    02079 rb_thread_key_p(VALUE self, VALUE key)
    02080 {
    02081     rb_thread_t *th;
    02082     ID id = rb_to_id(key);
    02083
    02084     GetThreadPtr(self, th);
    02085
    02086     if (!th->local_storage) {
    02087         return Qfalse;
    02088     }
    02089     if (st_lookup(th->local_storage, id, 0)) {
    02090         return Qtrue;
    02091     }
    02092     return Qfalse;
    02093 }
    02094
    02095 static int
    02096 thread_keys_i(ID key, VALUE value, VALUE ary)
    02097 {
    02098     rb_ary_push(ary, ID2SYM(key));
    02099     return ST_CONTINUE;
    02100 }
    02101
    02102 static int
    02103 vm_living_thread_num(rb_vm_t *vm)
    02104 {
    02105     return vm->living_threads->num_entries;
    02106 }
    02107
    02108 int
    02109 rb_thread_alone(void)
    02110 {
    02111     int num = 1;
    02112     if (GET_THREAD()->vm->living_threads) {
    02113         num = vm_living_thread_num(GET_THREAD()->vm);
    02114         thread_debug("rb_thread_alone: %d\n", num);
    02115     }
    02116     return num == 1;
    02117 }
    02118
    02119 /*
    02120  *  call-seq:
    02121  *     thr.keys   -> array
    02122  *
    02123  *  Returns an an array of the names of the thread-local variables (as Symbols).
    02124  *
    02125  *     thr = Thread.new do
    02126  *       Thread.current[:cat] = 'meow'
    02127  *       Thread.current["dog"] = 'woof'
    02128  *     end
    02129  *     thr.join   #=> #<Thread:0x401b3f10 dead>
    02130  *     thr.keys   #=> [:dog, :cat]
    02131  */
    02132
    02133 static VALUE
    02134 rb_thread_keys(VALUE self)
    02135 {
    02136     rb_thread_t *th;
    02137     VALUE ary = rb_ary_new();
    02138     GetThreadPtr(self, th);
    02139
    02140     if (th->local_storage) {
    02141         st_foreach(th->local_storage, thread_keys_i, ary);
    02142     }
    02143     return ary;
    02144 }
    02145
    02146 /*
    02147  *  call-seq:
    02148  *     thr.priority   -> integer
    02149  *
    02150  *  Returns the priority of <i>thr</i>. Default is inherited from the
    02151  *  current thread which creating the new thread, or zero for the
    02152  *  initial main thread; higher-priority thread will run more frequently
    02153  *  than lower-priority threads (but lower-priority threads can also run).
    02154  *
    02155  *  This is just hint for Ruby thread scheduler.  It may be ignored on some
    02156  *  platform.
    02157  *
    02158  *     Thread.current.priority   #=> 0
    02159  */
    02160
    02161 static VALUE
    02162 rb_thread_priority(VALUE thread)
    02163 {
    02164     rb_thread_t *th;
    02165     GetThreadPtr(thread, th);
    02166     return INT2NUM(th->priority);
    02167 }
    02168
    02169
    02170 /*
    02171  *  call-seq:
    02172  *     thr.priority= integer   -> thr
    02173  *
    02174  *  Sets the priority of <i>thr</i> to <i>integer</i>. Higher-priority threads
    02175  *  will run more frequently than lower-priority threads (but lower-priority
    02176  *  threads can also run).
    02177  *
    02178  *  This is just hint for Ruby thread scheduler.  It may be ignored on some
    02179  *  platform.
    02180  *
    02181  *     count1 = count2 = 0
    02182  *     a = Thread.new do
    02183  *           loop { count1 += 1 }
    02184  *         end
    02185  *     a.priority = -1
    02186  *
    02187  *     b = Thread.new do
    02188  *           loop { count2 += 1 }
    02189  *         end
    02190  *     b.priority = -2
    02191  *     sleep 1   #=> 1
    02192  *     count1    #=> 622504
    02193  *     count2    #=> 5832
    02194  */
    02195
    02196 static VALUE
    02197 rb_thread_priority_set(VALUE thread, VALUE prio)
    02198 {
    02199     rb_thread_t *th;
    02200     int priority;
    02201     GetThreadPtr(thread, th);
    02202
    02203     rb_secure(4);
    02204
    02205 #if USE_NATIVE_THREAD_PRIORITY
    02206     th->priority = NUM2INT(prio);
    02207     native_thread_apply_priority(th);
    02208 #else
    02209     priority = NUM2INT(prio);
    02210     if (priority > RUBY_THREAD_PRIORITY_MAX) {
    02211         priority = RUBY_THREAD_PRIORITY_MAX;
    02212     }
    02213     else if (priority < RUBY_THREAD_PRIORITY_MIN) {
    02214         priority = RUBY_THREAD_PRIORITY_MIN;
    02215     }
    02216     th->priority = priority;
    02217     th->slice = priority;
    02218 #endif
    02219     return INT2NUM(th->priority);
    02220 }
    02221
    02222 /* for IO */
    02223
    02224 #if defined(NFDBITS) && defined(HAVE_RB_FD_INIT)
    02225
    02226 /*
    02227  * several Unix platforms support file descriptors bigger than FD_SETSIZE
    02228  * in select(2) system call.
    02229  *
    02230  * - Linux 2.2.12 (?)
    02231  * - NetBSD 1.2 (src/sys/kern/sys_generic.c:1.25)
    02232  *   select(2) documents how to allocate fd_set dynamically.
    02233  *   http://netbsd.gw.com/cgi-bin/man-cgi?select++NetBSD-4.0
    02234  * - FreeBSD 2.2 (src/sys/kern/sys_generic.c:1.19)
    02235  * - OpenBSD 2.0 (src/sys/kern/sys_generic.c:1.4)
    02236  *   select(2) documents how to allocate fd_set dynamically.
    02237  *   http://www.openbsd.org/cgi-bin/man.cgi?query=select&manpath=OpenBSD+4.4
    02238  * - HP-UX documents how to allocate fd_set dynamically.
    02239  *   http://docs.hp.com/en/B2355-60105/select.2.html
    02240  * - Solaris 8 has select_large_fdset
    02241  *
    02242  * When fd_set is not big enough to hold big file descriptors,
    02243  * it should be allocated dynamically.
    02244  * Note that this assumes fd_set is structured as bitmap.
    02245  *
    02246  * rb_fd_init allocates the memory.
    02247  * rb_fd_term free the memory.
    02248  * rb_fd_set may re-allocates bitmap.
    02249  *
    02250  * So rb_fd_set doesn't reject file descriptors bigger than FD_SETSIZE.
    02251  */
    02252
    02253 void
    02254 rb_fd_init(volatile rb_fdset_t *fds)
    02255 {
    02256     fds->maxfd = 0;
    02257     fds->fdset = ALLOC(fd_set);
    02258     FD_ZERO(fds->fdset);
    02259 }
    02260
    02261 void
    02262 rb_fd_term(rb_fdset_t *fds)
    02263 {
    02264     if (fds->fdset) xfree(fds->fdset);
    02265     fds->maxfd = 0;
    02266     fds->fdset = 0;
    02267 }
    02268
    02269 void
    02270 rb_fd_zero(rb_fdset_t *fds)
    02271 {
    02272     if (fds->fdset) {
    02273         MEMZERO(fds->fdset, fd_mask, howmany(fds->maxfd, NFDBITS));
    02274         FD_ZERO(fds->fdset);
    02275     }
    02276 }
    02277
    02278 static void
    02279 rb_fd_resize(int n, rb_fdset_t *fds)
    02280 {
    02281     size_t m = howmany(n + 1, NFDBITS) * sizeof(fd_mask);
    02282     size_t o = howmany(fds->maxfd, NFDBITS) * sizeof(fd_mask);
    02283
    02284     if (m < sizeof(fd_set)) m = sizeof(fd_set);
    02285     if (o < sizeof(fd_set)) o = sizeof(fd_set);
    02286
    02287     if (m > o) {
    02288         fds->fdset = xrealloc(fds->fdset, m);
    02289         memset((char *)fds->fdset + o, 0, m - o);
    02290     }
    02291     if (n >= fds->maxfd) fds->maxfd = n + 1;
    02292 }
    02293
    02294 void
    02295 rb_fd_set(int n, rb_fdset_t *fds)
    02296 {
    02297     rb_fd_resize(n, fds);
    02298     FD_SET(n, fds->fdset);
    02299 }
    02300
    02301 void
    02302 rb_fd_clr(int n, rb_fdset_t *fds)
    02303 {
    02304     if (n >= fds->maxfd) return;
    02305     FD_CLR(n, fds->fdset);
    02306 }
    02307
    02308 int
    02309 rb_fd_isset(int n, const rb_fdset_t *fds)
    02310 {
    02311     if (n >= fds->maxfd) return 0;
    02312     return FD_ISSET(n, fds->fdset) != 0; /* "!= 0" avoids FreeBSD PR 91421 */
    02313 }
    02314
    02315 void
    02316 rb_fd_copy(rb_fdset_t *dst, const fd_set *src, int max)
    02317 {
    02318     size_t size = howmany(max, NFDBITS) * sizeof(fd_mask);
    02319
    02320     if (size < sizeof(fd_set)) size = sizeof(fd_set);
    02321     dst->maxfd = max;
    02322     dst->fdset = xrealloc(dst->fdset, size);
    02323     memcpy(dst->fdset, src, size);
    02324 }
    02325
    02326 int
    02327 rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout)
    02328 {
    02329     fd_set *r = NULL, *w = NULL, *e = NULL;
    02330     if (readfds) {
    02331         rb_fd_resize(n - 1, readfds);
    02332         r = rb_fd_ptr(readfds);
    02333     }
    02334     if (writefds) {
    02335         rb_fd_resize(n - 1, writefds);
    02336         w = rb_fd_ptr(writefds);
    02337     }
    02338     if (exceptfds) {
    02339         rb_fd_resize(n - 1, exceptfds);
    02340         e = rb_fd_ptr(exceptfds);
    02341     }
    02342     return select(n, r, w, e, timeout);
    02343 }
    02344
    02345 #undef FD_ZERO
    02346 #undef FD_SET
    02347 #undef FD_CLR
    02348 #undef FD_ISSET
    02349
    02350 #define FD_ZERO(f)      rb_fd_zero(f)
    02351 #define FD_SET(i, f)    rb_fd_set(i, f)
    02352 #define FD_CLR(i, f)    rb_fd_clr(i, f)
    02353 #define FD_ISSET(i, f)  rb_fd_isset(i, f)
    02354
    02355 #elif defined(_WIN32)
    02356
    02357 void
    02358 rb_fd_init(volatile rb_fdset_t *set)
    02359 {
    02360     set->capa = FD_SETSIZE;
    02361     set->fdset = ALLOC(fd_set);
    02362     FD_ZERO(set->fdset);
    02363 }
    02364
    02365 void
    02366 rb_fd_term(rb_fdset_t *set)
    02367 {
    02368     xfree(set->fdset);
    02369     set->fdset = NULL;
    02370     set->capa = 0;
    02371 }
    02372
    02373 void
    02374 rb_fd_set(int fd, rb_fdset_t *set)
    02375 {
    02376     unsigned int i;
    02377     SOCKET s = rb_w32_get_osfhandle(fd);
    02378
    02379     for (i = 0; i < set->fdset->fd_count; i++) {
    02380         if (set->fdset->fd_array[i] == s) {
    02381             return;
    02382         }
    02383     }
    02384     if (set->fdset->fd_count >= (unsigned)set->capa) {
    02385         set->capa = (set->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
    02386         set->fdset = xrealloc(set->fdset, sizeof(unsigned int) + sizeof(SOCKET) * set->capa);
    02387     }
    02388     set->fdset->fd_array[set->fdset->fd_count++] = s;
    02389 }
    02390
    02391 #undef FD_ZERO
    02392 #undef FD_SET
    02393 #undef FD_CLR
    02394 #undef FD_ISSET
    02395
    02396 #define FD_ZERO(f)      rb_fd_zero(f)
    02397 #define FD_SET(i, f)    rb_fd_set(i, f)
    02398 #define FD_CLR(i, f)    rb_fd_clr(i, f)
    02399 #define FD_ISSET(i, f)  rb_fd_isset(i, f)
    02400
    02401 #endif
    02402
    02403 #if defined(__CYGWIN__) || defined(_WIN32)
    02404 static long
    02405 cmp_tv(const struct timeval *a, const struct timeval *b)
    02406 {
    02407     long d = (a->tv_sec - b->tv_sec);
    02408     return (d != 0) ? d : (a->tv_usec - b->tv_usec);
    02409 }
    02410
    02411 static int
    02412 subtract_tv(struct timeval *rest, const struct timeval *wait)
    02413 {
    02414     if (rest->tv_sec < wait->tv_sec) {
    02415         return 0;
    02416     }
    02417     while (rest->tv_usec < wait->tv_usec) {
    02418         if (rest->tv_sec <= wait->tv_sec) {
    02419             return 0;
    02420         }
    02421         rest->tv_sec -= 1;
    02422         rest->tv_usec += 1000 * 1000;
    02423     }
    02424     rest->tv_sec -= wait->tv_sec;
    02425     rest->tv_usec -= wait->tv_usec;
    02426     return rest->tv_sec != 0 || rest->tv_usec != 0;
    02427 }
    02428 #endif
    02429
    02430 static int
    02431 do_select(int n, fd_set *read, fd_set *write, fd_set *except,
    02432           struct timeval *timeout)
    02433 {
    02434     int result, lerrno;
    02435     fd_set UNINITIALIZED_VAR(orig_read);
    02436     fd_set UNINITIALIZED_VAR(orig_write);
    02437     fd_set UNINITIALIZED_VAR(orig_except);
    02438
    02439 #ifndef linux
    02440     double limit = 0;
    02441     struct timeval wait_rest;
    02442 # if defined(__CYGWIN__) || defined(_WIN32)
    02443     struct timeval start_time;
    02444 # endif
    02445
    02446     if (timeout) {
    02447 # if defined(__CYGWIN__) || defined(_WIN32)
    02448         gettimeofday(&start_time, NULL);
    02449         limit = (double)start_time.tv_sec + (double)start_time.tv_usec*1e-6;
    02450 # else
    02451         limit = timeofday();
    02452 # endif
    02453         limit += (double)timeout->tv_sec+(double)timeout->tv_usec*1e-6;
    02454         wait_rest = *timeout;
    02455         timeout = &wait_rest;
    02456     }
    02457 #endif
    02458
    02459     if (read) orig_read = *read;
    02460     if (write) orig_write = *write;
    02461     if (except) orig_except = *except;
    02462
    02463   retry:
    02464     lerrno = 0;
    02465
    02466 #if defined(__CYGWIN__) || defined(_WIN32)
    02467     {
    02468         int finish = 0;
    02469         /* polling duration: 100ms */
    02470         struct timeval wait_100ms, *wait;
    02471         wait_100ms.tv_sec = 0;
    02472         wait_100ms.tv_usec = 100 * 1000; /* 100 ms */
    02473
    02474         do {
    02475             wait = (timeout == 0 || cmp_tv(&wait_100ms, timeout) < 0) ? &wait_100ms : timeout;
    02476             BLOCKING_REGION({
    02477                 do {
    02478                     result = select(n, read, write, except, wait);
    02479                     if (result < 0) lerrno = errno;
    02480                     if (result != 0) break;
    02481
    02482                     if (read) *read = orig_read;
    02483                     if (write) *write = orig_write;
    02484                     if (except) *except = orig_except;
    02485                     if (timeout) {
    02486                         struct timeval elapsed;
    02487                         gettimeofday(&elapsed, NULL);
    02488                         subtract_tv(&elapsed, &start_time);
    02489                         gettimeofday(&start_time, NULL);
    02490                         if (!subtract_tv(timeout, &elapsed)) {
    02491                             finish = 1;
    02492                             break;
    02493                         }
    02494                         if (cmp_tv(&wait_100ms, timeout) > 0) wait = timeout;
    02495                     }
    02496                 } while (__th->interrupt_flag == 0);
    02497             }, 0, 0);
    02498         } while (result == 0 && !finish);
    02499     }
    02500 #else
    02501     BLOCKING_REGION({
    02502         result = select(n, read, write, except, timeout);
    02503         if (result < 0) lerrno = errno;
    02504     }, ubf_select, GET_THREAD());
    02505 #endif
    02506
    02507     errno = lerrno;
    02508
    02509     if (result < 0) {
    02510         switch (errno) {
    02511           case EINTR:
    02512 #ifdef ERESTART
    02513           case ERESTART:
    02514 #endif
    02515             if (read) *read = orig_read;
    02516             if (write) *write = orig_write;
    02517             if (except) *except = orig_except;
    02518 #ifndef linux
    02519             if (timeout) {
    02520                 double d = limit - timeofday();
    02521
    02522                 wait_rest.tv_sec = (unsigned int)d;
    02523                 wait_rest.tv_usec = (int)((d-(double)wait_rest.tv_sec)*1e6);
    02524                 if (wait_rest.tv_sec < 0)  wait_rest.tv_sec = 0;
    02525                 if (wait_rest.tv_usec < 0) wait_rest.tv_usec = 0;
    02526             }
    02527 #endif
    02528             goto retry;
    02529           default:
    02530             break;
    02531         }
    02532     }
    02533     return result;
    02534 }
    02535
    02536 static void
    02537 rb_thread_wait_fd_rw(int fd, int read)
    02538 {
    02539     int result = 0;
    02540     thread_debug("rb_thread_wait_fd_rw(%d, %s)\n", fd, read ? "read" : "write");
    02541
    02542     if (fd < 0) {
    02543         rb_raise(rb_eIOError, "closed stream");
    02544     }
    02545     if (rb_thread_alone()) return;
    02546     while (result <= 0) {
    02547         rb_fdset_t set;
    02548         rb_fd_init(&set);
    02549         FD_SET(fd, &set);
    02550
    02551         if (read) {
    02552             result = do_select(fd + 1, rb_fd_ptr(&set), 0, 0, 0);
    02553         }
    02554         else {
    02555             result = do_select(fd + 1, 0, rb_fd_ptr(&set), 0, 0);
    02556         }
    02557
    02558         rb_fd_term(&set);
    02559
    02560         if (result < 0) {
    02561             rb_sys_fail(0);
    02562         }
    02563     }
    02564
    02565     thread_debug("rb_thread_wait_fd_rw(%d, %s): done\n", fd, read ? "read" : "write");
    02566 }
    02567
    02568 void
    02569 rb_thread_wait_fd(int fd)
    02570 {
    02571     rb_thread_wait_fd_rw(fd, 1);
    02572 }
    02573
    02574 int
    02575 rb_thread_fd_writable(int fd)
    02576 {
    02577     rb_thread_wait_fd_rw(fd, 0);
    02578     return TRUE;
    02579 }
    02580
    02581 int
    02582 rb_thread_select(int max, fd_set * read, fd_set * write, fd_set * except,
    02583                  struct timeval *timeout)
    02584 {
    02585     if (!read && !write && !except) {
    02586         if (!timeout) {
    02587             rb_thread_sleep_forever();
    02588             return 0;
    02589         }
    02590         rb_thread_wait_for(*timeout);
    02591         return 0;
    02592     }
    02593     else {
    02594         return do_select(max, read, write, except, timeout);
    02595     }
    02596 }
    02597
    02598
    02599 int
    02600 rb_thread_fd_select(int max, rb_fdset_t * read, rb_fdset_t * write, rb_fdset_t * except,
    02601                     struct timeval *timeout)
    02602 {
    02603     fd_set *r = NULL, *w = NULL, *e = NULL;
    02604
    02605     if (!read && !write && !except) {
    02606         if (!timeout) {
    02607             rb_thread_sleep_forever();
    02608             return 0;
    02609         }
    02610         rb_thread_wait_for(*timeout);
    02611         return 0;
    02612     }
    02613
    02614     if (read) {
    02615         rb_fd_resize(max - 1, read);
    02616         r = rb_fd_ptr(read);
    02617     }
    02618     if (write) {
    02619         rb_fd_resize(max - 1, write);
    02620         w = rb_fd_ptr(write);
    02621     }
    02622     if (except) {
    02623         rb_fd_resize(max - 1, except);
    02624         e = rb_fd_ptr(except);
    02625     }
    02626     return do_select(max, r, w, e, timeout);
    02627 }
    02628
    02629
    02630 /*
    02631  * for GC
    02632  */
    02633
    02634 #ifdef USE_CONSERVATIVE_STACK_END
    02635 void
    02636 rb_gc_set_stack_end(VALUE **stack_end_p)
    02637 {
    02638     VALUE stack_end;
    02639     *stack_end_p = &stack_end;
    02640 }
    02641 #endif
    02642
    02643 void
    02644 rb_gc_save_machine_context(rb_thread_t *th)
    02645 {
    02646     FLUSH_REGISTER_WINDOWS;
    02647 #ifdef __ia64
    02648     th->machine_register_stack_end = rb_ia64_bsp();
    02649 #endif
    02650     setjmp(th->machine_regs);
    02651 }
    02652
    02653 /*
    02654  *
    02655  */
    02656
    02657 int rb_get_next_signal(void);
    02658
    02659 void
    02660 rb_threadptr_check_signal(rb_thread_t *mth)
    02661 {
    02662     int sig;
    02663
    02664     /* mth must be main_thread */
    02665
    02666     if (!mth->exec_signal && (sig = rb_get_next_signal()) > 0) {
    02667         enum rb_thread_status prev_status = mth->status;
    02668         thread_debug("main_thread: %s, sig: %d\n",
    02669                      thread_status_name(prev_status), sig);
    02670         mth->exec_signal = sig;
    02671         if (mth->status != THREAD_KILLED) mth->status = THREAD_RUNNABLE;
    02672         rb_threadptr_interrupt(mth);
    02673         mth->status = prev_status;
    02674     }
    02675 }
    02676
    02677 static void
    02678 timer_thread_function(void *arg)
    02679 {
    02680     rb_vm_t *vm = GET_VM(); /* TODO: fix me for Multi-VM */
    02681
    02682     /* for time slice */
    02683     RUBY_VM_SET_TIMER_INTERRUPT(vm->running_thread);
    02684
    02685     /* check signal */
    02686     rb_threadptr_check_signal(vm->main_thread);
    02687
    02688 #if 0
    02689     /* prove profiler */
    02690     if (vm->prove_profile.enable) {
    02691         rb_thread_t *th = vm->running_thread;
    02692
    02693         if (vm->during_gc) {
    02694             /* GC prove profiling */
    02695         }
    02696     }
    02697 #endif
    02698 }
    02699
    02700 void
    02701 rb_thread_stop_timer_thread(void)
    02702 {
    02703     if (timer_thread_id && native_stop_timer_thread()) {
    02704         native_reset_timer_thread();
    02705     }
    02706 }
    02707
    02708 void
    02709 rb_thread_reset_timer_thread(void)
    02710 {
    02711     native_reset_timer_thread();
    02712 }
    02713
    02714 void
    02715 rb_thread_start_timer_thread(void)
    02716 {
    02717     system_working = 1;
    02718     rb_thread_create_timer_thread();
    02719 }
    02720
    02721 static int
    02722 clear_coverage_i(st_data_t key, st_data_t val, st_data_t dummy)
    02723 {
    02724     int i;
    02725     VALUE lines = (VALUE)val;
    02726
    02727     for (i = 0; i < RARRAY_LEN(lines); i++) {
    02728         if (RARRAY_PTR(lines)[i] != Qnil) {
    02729             RARRAY_PTR(lines)[i] = INT2FIX(0);
    02730         }
    02731     }
    02732     return ST_CONTINUE;
    02733 }
    02734
    02735 static void
    02736 clear_coverage(void)
    02737 {
    02738     extern VALUE rb_get_coverages(void);
    02739     VALUE coverages = rb_get_coverages();
    02740     if (RTEST(coverages)) {
    02741         st_foreach(RHASH_TBL(coverages), clear_coverage_i, 0);
    02742     }
    02743 }
    02744
    02745 static void
    02746 rb_thread_atfork_internal(int (*atfork)(st_data_t, st_data_t, st_data_t))
    02747 {
    02748     rb_thread_t *th = GET_THREAD();
    02749     rb_vm_t *vm = th->vm;
    02750     VALUE thval = th->self;
    02751     vm->main_thread = th;
    02752
    02753     native_mutex_reinitialize_atfork(&th->vm->global_vm_lock);
    02754     st_foreach(vm->living_threads, atfork, (st_data_t)th);
    02755     st_clear(vm->living_threads);
    02756     st_insert(vm->living_threads, thval, (st_data_t)th->thread_id);
    02757     vm->sleeper = 0;
    02758     clear_coverage();
    02759 }
    02760
    02761 static int
    02762 terminate_atfork_i(st_data_t key, st_data_t val, st_data_t current_th)
    02763 {
    02764     VALUE thval = key;
    02765     rb_thread_t *th;
    02766     GetThreadPtr(thval, th);
    02767
    02768     if (th != (rb_thread_t *)current_th) {
    02769         if (th->keeping_mutexes) {
    02770             rb_mutex_abandon_all(th->keeping_mutexes);
    02771         }
    02772         th->keeping_mutexes = NULL;
    02773         thread_cleanup_func(th);
    02774     }
    02775     return ST_CONTINUE;
    02776 }
    02777
    02778 void
    02779 rb_thread_atfork(void)
    02780 {
    02781     rb_thread_atfork_internal(terminate_atfork_i);
    02782     GET_THREAD()->join_list_head = 0;
    02783     rb_reset_random_seed();
    02784 }
    02785
    02786 static int
    02787 terminate_atfork_before_exec_i(st_data_t key, st_data_t val, st_data_t current_th)
    02788 {
    02789     VALUE thval = key;
    02790     rb_thread_t *th;
    02791     GetThreadPtr(thval, th);
    02792
    02793     if (th != (rb_thread_t *)current_th) {
    02794         thread_cleanup_func_before_exec(th);
    02795     }
    02796     return ST_CONTINUE;
    02797 }
    02798
    02799 void
    02800 rb_thread_atfork_before_exec(void)
    02801 {
    02802     rb_thread_atfork_internal(terminate_atfork_before_exec_i);
    02803 }
    02804
    02805 struct thgroup {
    02806     int enclosed;
    02807     VALUE group;
    02808 };
    02809
    02810 static size_t
    02811 thgroup_memsize(const void *ptr)
    02812 {
    02813     return ptr ? sizeof(struct thgroup) : 0;
    02814 }
    02815
    02816 static const rb_data_type_t thgroup_data_type = {
    02817     "thgroup",
    02818     NULL, RUBY_TYPED_DEFAULT_FREE, thgroup_memsize,
    02819 };
    02820
    02821 /*
    02822  * Document-class: ThreadGroup
    02823  *
    02824  *  <code>ThreadGroup</code> provides a means of keeping track of a number of
    02825  *  threads as a group. A <code>Thread</code> can belong to only one
    02826  *  <code>ThreadGroup</code> at a time; adding a thread to a new group will
    02827  *  remove it from any previous group.
    02828  *
    02829  *  Newly created threads belong to the same group as the thread from which they
    02830  *  were created.
    02831  */
    02832
    02833 static VALUE
    02834 thgroup_s_alloc(VALUE klass)
    02835 {
    02836     VALUE group;
    02837     struct thgroup *data;
    02838
    02839     group = TypedData_Make_Struct(klass, struct thgroup, &thgroup_data_type, data);
    02840     data->enclosed = 0;
    02841     data->group = group;
    02842
    02843     return group;
    02844 }
    02845
    02846 struct thgroup_list_params {
    02847     VALUE ary;
    02848     VALUE group;
    02849 };
    02850
    02851 static int
    02852 thgroup_list_i(st_data_t key, st_data_t val, st_data_t data)
    02853 {
    02854     VALUE thread = (VALUE)key;
    02855     VALUE ary = ((struct thgroup_list_params *)data)->ary;
    02856     VALUE group = ((struct thgroup_list_params *)data)->group;
    02857     rb_thread_t *th;
    02858     GetThreadPtr(thread, th);
    02859
    02860     if (th->thgroup == group) {
    02861         rb_ary_push(ary, thread);
    02862     }
    02863     return ST_CONTINUE;
    02864 }
    02865
    02866 /*
    02867  *  call-seq:
    02868  *     thgrp.list   -> array
    02869  *
    02870  *  Returns an array of all existing <code>Thread</code> objects that belong to
    02871  *  this group.
    02872  *
    02873  *     ThreadGroup::Default.list   #=> [#<Thread:0x401bdf4c run>]
    02874  */
    02875
    02876 static VALUE
    02877 thgroup_list(VALUE group)
    02878 {
    02879     VALUE ary = rb_ary_new();
    02880     struct thgroup_list_params param;
    02881
    02882     param.ary = ary;
    02883     param.group = group;
    02884     st_foreach(GET_THREAD()->vm->living_threads, thgroup_list_i, (st_data_t) & param);
    02885     return ary;
    02886 }
    02887
    02888
    02889 /*
    02890  *  call-seq:
    02891  *     thgrp.enclose   -> thgrp
    02892  *
    02893  *  Prevents threads from being added to or removed from the receiving
    02894  *  <code>ThreadGroup</code>. New threads can still be started in an enclosed
    02895  *  <code>ThreadGroup</code>.
    02896  *
    02897  *     ThreadGroup::Default.enclose        #=> #<ThreadGroup:0x4029d914>
    02898  *     thr = Thread::new { Thread.stop }   #=> #<Thread:0x402a7210 sleep>
    02899  *     tg = ThreadGroup::new               #=> #<ThreadGroup:0x402752d4>
    02900  *     tg.add thr
    02901  *
    02902  *  <em>produces:</em>
    02903  *
    02904  *     ThreadError: can't move from the enclosed thread group
    02905  */
    02906
    02907 static VALUE
    02908 thgroup_enclose(VALUE group)
    02909 {
    02910     struct thgroup *data;
    02911
    02912     TypedData_Get_Struct(group, struct thgroup, &thgroup_data_type, data);
    02913     data->enclosed = 1;
    02914
    02915     return group;
    02916 }
    02917
    02918
    02919 /*
    02920  *  call-seq:
    02921  *     thgrp.enclosed?   -> true or false
    02922  *
    02923  *  Returns <code>true</code> if <em>thgrp</em> is enclosed. See also
    02924  *  ThreadGroup#enclose.
    02925  */
    02926
    02927 static VALUE
    02928 thgroup_enclosed_p(VALUE group)
    02929 {
    02930     struct thgroup *data;
    02931
    02932     TypedData_Get_Struct(group, struct thgroup, &thgroup_data_type, data);
    02933     if (data->enclosed)
    02934         return Qtrue;
    02935     return Qfalse;
    02936 }
    02937
    02938
    02939 /*
    02940  *  call-seq:
    02941  *     thgrp.add(thread)   -> thgrp
    02942  *
    02943  *  Adds the given <em>thread</em> to this group, removing it from any other
    02944  *  group to which it may have previously belonged.
    02945  *
    02946  *     puts "Initial group is #{ThreadGroup::Default.list}"
    02947  *     tg = ThreadGroup.new
    02948  *     t1 = Thread.new { sleep }
    02949  *     t2 = Thread.new { sleep }
    02950  *     puts "t1 is #{t1}"
    02951  *     puts "t2 is #{t2}"
    02952  *     tg.add(t1)
    02953  *     puts "Initial group now #{ThreadGroup::Default.list}"
    02954  *     puts "tg group now #{tg.list}"
    02955  *
    02956  *  <em>produces:</em>
    02957  *
    02958  *     Initial group is #<Thread:0x401bdf4c>
    02959  *     t1 is #<Thread:0x401b3c90>
    02960  *     t2 is #<Thread:0x401b3c18>
    02961  *     Initial group now #<Thread:0x401b3c18>#<Thread:0x401bdf4c>
    02962  *     tg group now #<Thread:0x401b3c90>
    02963  */
    02964
    02965 static VALUE
    02966 thgroup_add(VALUE group, VALUE thread)
    02967 {
    02968     rb_thread_t *th;
    02969     struct thgroup *data;
    02970
    02971     rb_secure(4);
    02972     GetThreadPtr(thread, th);
    02973
    02974     if (OBJ_FROZEN(group)) {
    02975         rb_raise(rb_eThreadError, "can't move to the frozen thread group");
    02976     }
    02977     TypedData_Get_Struct(group, struct thgroup, &thgroup_data_type, data);
    02978     if (data->enclosed) {
    02979         rb_raise(rb_eThreadError, "can't move to the enclosed thread group");
    02980     }
    02981
    02982     if (!th->thgroup) {
    02983         return Qnil;
    02984     }
    02985
    02986     if (OBJ_FROZEN(th->thgroup)) {
    02987         rb_raise(rb_eThreadError, "can't move from the frozen thread group");
    02988     }
    02989     TypedData_Get_Struct(th->thgroup, struct thgroup, &thgroup_data_type, data);
    02990     if (data->enclosed) {
    02991         rb_raise(rb_eThreadError,
    02992                  "can't move from the enclosed thread group");
    02993     }
    02994
    02995     th->thgroup = group;
    02996     return group;
    02997 }
    02998
    02999
    03000 /*
    03001  *  Document-class: Mutex
    03002  *
    03003  *  Mutex implements a simple semaphore that can be used to coordinate access to
    03004  *  shared data from multiple concurrent threads.
    03005  *
    03006  *  Example:
    03007  *
    03008  *    require 'thread'
    03009  *    semaphore = Mutex.new
    03010  *
    03011  *    a = Thread.new {
    03012  *      semaphore.synchronize {
    03013  *        # access shared resource
    03014  *      }
    03015  *    }
    03016  *
    03017  *    b = Thread.new {
    03018  *      semaphore.synchronize {
    03019  *        # access shared resource
    03020  *      }
    03021  *    }
    03022  *
    03023  */
    03024
    03025 #define GetMutexPtr(obj, tobj) \
    03026     TypedData_Get_Struct(obj, mutex_t, &mutex_data_type, tobj)
    03027
    03028 static const char *mutex_unlock(mutex_t *mutex, rb_thread_t volatile *th);
    03029
    03030 #define mutex_mark NULL
    03031
    03032 static void
    03033 mutex_free(void *ptr)
    03034 {
    03035     if (ptr) {
    03036         mutex_t *mutex = ptr;
    03037         if (mutex->th) {
    03038             /* rb_warn("free locked mutex"); */
    03039             const char *err = mutex_unlock(mutex, mutex->th);
    03040             if (err) rb_bug("%s", err);
    03041         }
    03042         native_mutex_destroy(&mutex->lock);
    03043         native_cond_destroy(&mutex->cond);
    03044     }
    03045     ruby_xfree(ptr);
    03046 }
    03047
    03048 static size_t
    03049 mutex_memsize(const void *ptr)
    03050 {
    03051     return ptr ? sizeof(mutex_t) : 0;
    03052 }
    03053
    03054 static const rb_data_type_t mutex_data_type = {
    03055     "mutex",
    03056     mutex_mark, mutex_free, mutex_memsize,
    03057 };
    03058
    03059 static VALUE
    03060 mutex_alloc(VALUE klass)
    03061 {
    03062     VALUE volatile obj;
    03063     mutex_t *mutex;
    03064
    03065     obj = TypedData_Make_Struct(klass, mutex_t, &mutex_data_type, mutex);
    03066     native_mutex_initialize(&mutex->lock);
    03067     native_cond_initialize(&mutex->cond);
    03068     return obj;
    03069 }
    03070
    03071 /*
    03072  *  call-seq:
    03073  *     Mutex.new   -> mutex
    03074  *
    03075  *  Creates a new Mutex
    03076  */
    03077 static VALUE
    03078 mutex_initialize(VALUE self)
    03079 {
    03080     return self;
    03081 }
    03082
    03083 VALUE
    03084 rb_mutex_new(void)
    03085 {
    03086     return mutex_alloc(rb_cMutex);
    03087 }
    03088
    03089 /*
    03090  * call-seq:
    03091  *    mutex.locked?  -> true or false
    03092  *
    03093  * Returns +true+ if this lock is currently held by some thread.
    03094  */
    03095 VALUE
    03096 rb_mutex_locked_p(VALUE self)
    03097 {
    03098     mutex_t *mutex;
    03099     GetMutexPtr(self, mutex);
    03100     return mutex->th ? Qtrue : Qfalse;
    03101 }
    03102
    03103 static void
    03104 mutex_locked(rb_thread_t *th, VALUE self)
    03105 {
    03106     mutex_t *mutex;
    03107     GetMutexPtr(self, mutex);
    03108
    03109     if (th->keeping_mutexes) {
    03110         mutex->next_mutex = th->keeping_mutexes;
    03111     }
    03112     th->keeping_mutexes = mutex;
    03113 }
    03114
    03115 /*
    03116  * call-seq:
    03117  *    mutex.try_lock  -> true or false
    03118  *
    03119  * Attempts to obtain the lock and returns immediately. Returns +true+ if the
    03120  * lock was granted.
    03121  */
    03122 VALUE
    03123 rb_mutex_trylock(VALUE self)
    03124 {
    03125     mutex_t *mutex;
    03126     VALUE locked = Qfalse;
    03127     GetMutexPtr(self, mutex);
    03128
    03129     native_mutex_lock(&mutex->lock);
    03130     if (mutex->th == 0) {
    03131         mutex->th = GET_THREAD();
    03132         locked = Qtrue;
    03133
    03134         mutex_locked(GET_THREAD(), self);
    03135     }
    03136     native_mutex_unlock(&mutex->lock);
    03137
    03138     return locked;
    03139 }
    03140
    03141 static int
    03142 lock_func(rb_thread_t *th, mutex_t *mutex, int last_thread)
    03143 {
    03144     int interrupted = 0;
    03145 #if 0 /* for debug */
    03146     native_thread_yield();
    03147 #endif
    03148
    03149     native_mutex_lock(&mutex->lock);
    03150     th->transition_for_lock = 0;
    03151     while (mutex->th || (mutex->th = th, 0)) {
    03152         if (last_thread) {
    03153             interrupted = 2;
    03154             break;
    03155         }
    03156
    03157         mutex->cond_waiting++;
    03158         native_cond_wait(&mutex->cond, &mutex->lock);
    03159         mutex->cond_notified--;
    03160
    03161         if (RUBY_VM_INTERRUPTED(th)) {
    03162             interrupted = 1;
    03163             break;
    03164         }
    03165     }
    03166     th->transition_for_lock = 1;
    03167     native_mutex_unlock(&mutex->lock);
    03168
    03169     if (interrupted == 2) native_thread_yield();
    03170 #if 0 /* for debug */
    03171     native_thread_yield();
    03172 #endif
    03173
    03174     return interrupted;
    03175 }
    03176
    03177 static void
    03178 lock_interrupt(void *ptr)
    03179 {
    03180     mutex_t *mutex = (mutex_t *)ptr;
    03181     native_mutex_lock(&mutex->lock);
    03182     if (mutex->cond_waiting > 0) {
    03183         native_cond_broadcast(&mutex->cond);
    03184         mutex->cond_notified = mutex->cond_waiting;
    03185         mutex->cond_waiting = 0;
    03186     }
    03187     native_mutex_unlock(&mutex->lock);
    03188 }
    03189
    03190 /*
    03191  * call-seq:
    03192  *    mutex.lock  -> self
    03193  *
    03194  * Attempts to grab the lock and waits if it isn't available.
    03195  * Raises +ThreadError+ if +mutex+ was locked by the current thread.
    03196  */
    03197 VALUE
    03198 rb_mutex_lock(VALUE self)
    03199 {
    03200
    03201     if (rb_mutex_trylock(self) == Qfalse) {
    03202         mutex_t *mutex;
    03203         rb_thread_t *th = GET_THREAD();
    03204         GetMutexPtr(self, mutex);
    03205
    03206         if (mutex->th == GET_THREAD()) {
    03207             rb_raise(rb_eThreadError, "deadlock; recursive locking");
    03208         }
    03209
    03210         while (mutex->th != th) {
    03211             int interrupted;
    03212             enum rb_thread_status prev_status = th->status;
    03213             int last_thread = 0;
    03214             struct rb_unblock_callback oldubf;
    03215
    03216             set_unblock_function(th, lock_interrupt, mutex, &oldubf);
    03217             th->status = THREAD_STOPPED_FOREVER;
    03218             th->vm->sleeper++;
    03219             th->locking_mutex = self;
    03220             if (vm_living_thread_num(th->vm) == th->vm->sleeper) {
    03221                 last_thread = 1;
    03222             }
    03223
    03224             th->transition_for_lock = 1;
    03225             BLOCKING_REGION_CORE({
    03226                 interrupted = lock_func(th, mutex, last_thread);
    03227             });
    03228             th->transition_for_lock = 0;
    03229             remove_signal_thread_list(th);
    03230             reset_unblock_function(th, &oldubf);
    03231
    03232             th->locking_mutex = Qfalse;
    03233             if (mutex->th && interrupted == 2) {
    03234                 rb_check_deadlock(th->vm);
    03235             }
    03236             if (th->status == THREAD_STOPPED_FOREVER) {
    03237                 th->status = prev_status;
    03238             }
    03239             th->vm->sleeper--;
    03240
    03241             if (mutex->th == th) mutex_locked(th, self);
    03242
    03243             if (interrupted) {
    03244                 RUBY_VM_CHECK_INTS();
    03245             }
    03246         }
    03247     }
    03248     return self;
    03249 }
    03250
    03251 static const char *
    03252 mutex_unlock(mutex_t *mutex, rb_thread_t volatile *th)
    03253 {
    03254     const char *err = NULL;
    03255     mutex_t *th_mutex;
    03256
    03257     native_mutex_lock(&mutex->lock);
    03258
    03259     if (mutex->th == 0) {
    03260         err = "Attempt to unlock a mutex which is not locked";
    03261     }
    03262     else if (mutex->th != th) {
    03263         err = "Attempt to unlock a mutex which is locked by another thread";
    03264     }
    03265     else {
    03266         mutex->th = 0;
    03267         if (mutex->cond_waiting > 0) {
    03268             /* waiting thread */
    03269             native_cond_signal(&mutex->cond);
    03270             mutex->cond_waiting--;
    03271             mutex->cond_notified++;
    03272         }
    03273     }
    03274
    03275     native_mutex_unlock(&mutex->lock);
    03276
    03277     if (!err) {
    03278         th_mutex = th->keeping_mutexes;
    03279         if (th_mutex == mutex) {
    03280             th->keeping_mutexes = mutex->next_mutex;
    03281         }
    03282         else {
    03283             while (1) {
    03284                 mutex_t *tmp_mutex;
    03285                 tmp_mutex = th_mutex->next_mutex;
    03286                 if (tmp_mutex == mutex) {
    03287                     th_mutex->next_mutex = tmp_mutex->next_mutex;
    03288                     break;
    03289                 }
    03290                 th_mutex = tmp_mutex;
    03291             }
    03292         }
    03293         mutex->next_mutex = NULL;
    03294     }
    03295
    03296     return err;
    03297 }
    03298
    03299 /*
    03300  * call-seq:
    03301  *    mutex.unlock    -> self
    03302  *
    03303  * Releases the lock.
    03304  * Raises +ThreadError+ if +mutex+ wasn't locked by the current thread.
    03305  */
    03306 VALUE
    03307 rb_mutex_unlock(VALUE self)
    03308 {
    03309     const char *err;
    03310     mutex_t *mutex;
    03311     GetMutexPtr(self, mutex);
    03312
    03313     err = mutex_unlock(mutex, GET_THREAD());
    03314     if (err) rb_raise(rb_eThreadError, "%s", err);
    03315
    03316     return self;
    03317 }
    03318
    03319 static void
    03320 rb_mutex_unlock_all(mutex_t *mutexes, rb_thread_t *th)
    03321 {
    03322     const char *err;
    03323     mutex_t *mutex;
    03324
    03325     while (mutexes) {
    03326         mutex = mutexes;
    03327         /* rb_warn("mutex #<%p> remains to be locked by terminated thread",
    03328                 mutexes); */
    03329         mutexes = mutex->next_mutex;
    03330         err = mutex_unlock(mutex, th);
    03331         if (err) rb_bug("invalid keeping_mutexes: %s", err);
    03332     }
    03333 }
    03334
    03335 static void
    03336 rb_mutex_abandon_all(mutex_t *mutexes)
    03337 {
    03338     mutex_t *mutex;
    03339
    03340     while (mutexes) {
    03341         mutex = mutexes;
    03342         mutexes = mutex->next_mutex;
    03343         mutex->th = 0;
    03344         mutex->next_mutex = 0;
    03345     }
    03346 }
    03347
    03348 static VALUE
    03349 rb_mutex_sleep_forever(VALUE time)
    03350 {
    03351     rb_thread_sleep_deadly();
    03352     return Qnil;
    03353 }
    03354
    03355 static VALUE
    03356 rb_mutex_wait_for(VALUE time)
    03357 {
    03358     const struct timeval *t = (struct timeval *)time;
    03359     rb_thread_wait_for(*t);
    03360     return Qnil;
    03361 }
    03362
    03363 VALUE
    03364 rb_mutex_sleep(VALUE self, VALUE timeout)
    03365 {
    03366     time_t beg, end;
    03367     struct timeval t;
    03368
    03369     if (!NIL_P(timeout)) {
    03370         t = rb_time_interval(timeout);
    03371     }
    03372     rb_mutex_unlock(self);
    03373     beg = time(0);
    03374     if (NIL_P(timeout)) {
    03375         rb_ensure(rb_mutex_sleep_forever, Qnil, rb_mutex_lock, self);
    03376     }
    03377     else {
    03378         rb_ensure(rb_mutex_wait_for, (VALUE)&t, rb_mutex_lock, self);
    03379     }
    03380     end = time(0) - beg;
    03381     return INT2FIX(end);
    03382 }
    03383
    03384 /*
    03385  * call-seq:
    03386  *    mutex.sleep(timeout = nil)    -> number
    03387  *
    03388  * Releases the lock and sleeps +timeout+ seconds if it is given and
    03389  * non-nil or forever.  Raises +ThreadError+ if +mutex+ wasn't locked by
    03390  * the current thread.
    03391  */
    03392 static VALUE
    03393 mutex_sleep(int argc, VALUE *argv, VALUE self)
    03394 {
    03395     VALUE timeout;
    03396
    03397     rb_scan_args(argc, argv, "01", &timeout);
    03398     return rb_mutex_sleep(self, timeout);
    03399 }
    03400
    03401 /*
    03402  * call-seq:
    03403  *    mutex.synchronize { ... }    -> result of the block
    03404  *
    03405  * Obtains a lock, runs the block, and releases the lock when the block
    03406  * completes.  See the example under +Mutex+.
    03407  */
    03408
    03409 VALUE
    03410 rb_mutex_synchronize(VALUE mutex, VALUE (*func)(VALUE arg), VALUE arg)
    03411 {
    03412     rb_mutex_lock(mutex);
    03413     return rb_ensure(func, arg, rb_mutex_unlock, mutex);
    03414 }
    03415
    03416 /*
    03417  * Document-class: Barrier
    03418  */
    03419 static void
    03420 barrier_mark(void *ptr)
    03421 {
    03422     rb_gc_mark((VALUE)ptr);
    03423 }
    03424
    03425 static const rb_data_type_t barrier_data_type = {
    03426     "barrier",
    03427     barrier_mark, 0, 0,
    03428 };
    03429
    03430 static VALUE
    03431 barrier_alloc(VALUE klass)
    03432 {
    03433     return TypedData_Wrap_Struct(klass, &barrier_data_type, (void *)mutex_alloc(0));
    03434 }
    03435
    03436 #define GetBarrierPtr(obj) (VALUE)rb_check_typeddata(obj, &barrier_data_type)
    03437
    03438 VALUE
    03439 rb_barrier_new(void)
    03440 {
    03441     VALUE barrier = barrier_alloc(rb_cBarrier);
    03442     rb_mutex_lock((VALUE)DATA_PTR(barrier));
    03443     return barrier;
    03444 }
    03445
    03446 VALUE
    03447 rb_barrier_wait(VALUE self)
    03448 {
    03449     VALUE mutex = GetBarrierPtr(self);
    03450     mutex_t *m;
    03451
    03452     if (!mutex) return Qfalse;
    03453     GetMutexPtr(mutex, m);
    03454     if (m->th == GET_THREAD()) return Qfalse;
    03455     rb_mutex_lock(mutex);
    03456     if (DATA_PTR(self)) return Qtrue;
    03457     rb_mutex_unlock(mutex);
    03458     return Qfalse;
    03459 }
    03460
    03461 VALUE
    03462 rb_barrier_release(VALUE self)
    03463 {
    03464     return rb_mutex_unlock(GetBarrierPtr(self));
    03465 }
    03466
    03467 VALUE
    03468 rb_barrier_destroy(VALUE self)
    03469 {
    03470     VALUE mutex = GetBarrierPtr(self);
    03471     DATA_PTR(self) = 0;
    03472     return rb_mutex_unlock(mutex);
    03473 }
    03474
    03475 /* variables for recursive traversals */
    03476 static ID recursive_key;
    03477
    03478 /*
    03479  * Returns the current "recursive list" used to detect recursion.
    03480  * This list is a hash table, unique for the current thread and for
    03481  * the current __callee__.
    03482  */
    03483
    03484 static VALUE
    03485 recursive_list_access(void)
    03486 {
    03487     volatile VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
    03488     VALUE sym = ID2SYM(rb_frame_this_func());
    03489     VALUE list;
    03490     if (NIL_P(hash) || TYPE(hash) != T_HASH) {
    03491         hash = rb_hash_new();
    03492         OBJ_UNTRUST(hash);
    03493         rb_thread_local_aset(rb_thread_current(), recursive_key, hash);
    03494         list = Qnil;
    03495     }
    03496     else {
    03497         list = rb_hash_aref(hash, sym);
    03498     }
    03499     if (NIL_P(list) || TYPE(list) != T_HASH) {
    03500         list = rb_hash_new();
    03501         OBJ_UNTRUST(list);
    03502         rb_hash_aset(hash, sym, list);
    03503     }
    03504     return list;
    03505 }
    03506
    03507 /*
    03508  * Returns Qtrue iff obj_id (or the pair <obj, paired_obj>) is already
    03509  * in the recursion list.
    03510  * Assumes the recursion list is valid.
    03511  */
    03512
    03513 static VALUE
    03514 recursive_check(VALUE list, VALUE obj_id, VALUE paired_obj_id)
    03515 {
    03516     VALUE pair_list = rb_hash_lookup2(list, obj_id, Qundef);
    03517     if (pair_list == Qundef)
    03518         return Qfalse;
    03519     if (paired_obj_id) {
    03520         if (TYPE(pair_list) != T_HASH) {
    03521         if (pair_list != paired_obj_id)
    03522             return Qfalse;
    03523         }
    03524         else {
    03525         if (NIL_P(rb_hash_lookup(pair_list, paired_obj_id)))
    03526             return Qfalse;
    03527         }
    03528     }
    03529     return Qtrue;
    03530 }
    03531
    03532 /*
    03533  * Pushes obj_id (or the pair <obj_id, paired_obj_id>) in the recursion list.
    03534  * For a single obj_id, it sets list[obj_id] to Qtrue.
    03535  * For a pair, it sets list[obj_id] to paired_obj_id if possible,
    03536  * otherwise list[obj_id] becomes a hash like:
    03537  *   {paired_obj_id_1 => true, paired_obj_id_2 => true, ... }
    03538  * Assumes the recursion list is valid.
    03539  */
    03540
    03541 static void
    03542 recursive_push(VALUE list, VALUE obj, VALUE paired_obj)
    03543 {
    03544     VALUE pair_list;
    03545
    03546     if (!paired_obj) {
    03547         rb_hash_aset(list, obj, Qtrue);
    03548     }
    03549     else if ((pair_list = rb_hash_lookup2(list, obj, Qundef)) == Qundef) {
    03550         rb_hash_aset(list, obj, paired_obj);
    03551     }
    03552     else {
    03553         if (TYPE(pair_list) != T_HASH){
    03554             VALUE other_paired_obj = pair_list;
    03555             pair_list = rb_hash_new();
    03556             OBJ_UNTRUST(pair_list);
    03557             rb_hash_aset(pair_list, other_paired_obj, Qtrue);
    03558             rb_hash_aset(list, obj, pair_list);
    03559         }
    03560         rb_hash_aset(pair_list, paired_obj, Qtrue);
    03561     }
    03562 }
    03563
    03564 /*
    03565  * Pops obj_id (or the pair <obj_id, paired_obj_id>) from the recursion list.
    03566  * For a pair, if list[obj_id] is a hash, then paired_obj_id is
    03567  * removed from the hash and no attempt is made to simplify
    03568  * list[obj_id] from {only_one_paired_id => true} to only_one_paired_id
    03569  * Assumes the recursion list is valid.
    03570  */
    03571
    03572 static void
    03573 recursive_pop(VALUE list, VALUE obj, VALUE paired_obj)
    03574 {
    03575     if (paired_obj) {
    03576         VALUE pair_list = rb_hash_lookup2(list, obj, Qundef);
    03577         if (pair_list == Qundef) {
    03578             VALUE symname = rb_inspect(ID2SYM(rb_frame_this_func()));
    03579             VALUE thrname = rb_inspect(rb_thread_current());
    03580             rb_raise(rb_eTypeError, "invalid inspect_tbl pair_list for %s in %s",
    03581                      StringValuePtr(symname), StringValuePtr(thrname));
    03582         }
    03583         if (TYPE(pair_list) == T_HASH) {
    03584             rb_hash_delete(pair_list, paired_obj);
    03585             if (!RHASH_EMPTY_P(pair_list)) {
    03586                 return; /* keep hash until is empty */
    03587             }
    03588         }
    03589     }
    03590     rb_hash_delete(list, obj);
    03591 }
    03592
    03593 struct exec_recursive_params {
    03594     VALUE (*func) (VALUE, VALUE, int);
    03595     VALUE list;
    03596     VALUE obj;
    03597     VALUE objid;
    03598     VALUE pairid;
    03599     VALUE arg;
    03600 };
    03601
    03602 static VALUE
    03603 exec_recursive_i(VALUE tag, struct exec_recursive_params *p)
    03604 {
    03605     VALUE result = Qundef;
    03606     int state;
    03607
    03608     recursive_push(p->list, p->objid, p->pairid);
    03609     PUSH_TAG();
    03610     if ((state = EXEC_TAG()) == 0) {
    03611         result = (*p->func)(p->obj, p->arg, FALSE);
    03612     }
    03613     POP_TAG();
    03614     recursive_pop(p->list, p->objid, p->pairid);
    03615     if (state)
    03616         JUMP_TAG(state);
    03617     return result;
    03618 }
    03619
    03620 /*
    03621  * Calls func(obj, arg, recursive), where recursive is non-zero if the
    03622  * current method is called recursively on obj, or on the pair <obj, pairid>
    03623  * If outer is 0, then the innermost func will be called with recursive set
    03624  * to Qtrue, otherwise the outermost func will be called. In the latter case,
    03625  * all inner func are short-circuited by throw.
    03626  * Implementation details: the value thrown is the recursive list which is
    03627  * proper to the current method and unlikely to be catched anywhere else.
    03628  * list[recursive_key] is used as a flag for the outermost call.
    03629  */
    03630
    03631 static VALUE
    03632 exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE pairid, VALUE arg, int outer)
    03633 {
    03634     struct exec_recursive_params p;
    03635     int outermost;
    03636     p.list = recursive_list_access();
    03637     p.objid = rb_obj_id(obj);
    03638     outermost = outer && !recursive_check(p.list, ID2SYM(recursive_key), 0);
    03639
    03640     if (recursive_check(p.list, p.objid, pairid)) {
    03641         if (outer && !outermost) {
    03642             rb_throw_obj(p.list, p.list);
    03643         }
    03644         return (*func)(obj, arg, TRUE);
    03645     }
    03646     else {
    03647         VALUE result = Qundef;
    03648         p.func = func;
    03649         p.obj = obj;
    03650         p.pairid = pairid;
    03651         p.arg = arg;
    03652
    03653         if (outermost) {
    03654             recursive_push(p.list, ID2SYM(recursive_key), 0);
    03655             result = rb_catch_obj(p.list, exec_recursive_i, (VALUE)&p);
    03656             recursive_pop(p.list, ID2SYM(recursive_key), 0);
    03657             if (result == p.list) {
    03658                 result = (*func)(obj, arg, TRUE);
    03659             }
    03660         }
    03661         else {
    03662             result = exec_recursive_i(0, &p);
    03663         }
    03664         return result;
    03665     }
    03666 }
    03667
    03668 /*
    03669  * Calls func(obj, arg, recursive), where recursive is non-zero if the
    03670  * current method is called recursively on obj
    03671  */
    03672
    03673 VALUE
    03674 rb_exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
    03675 {
    03676     return exec_recursive(func, obj, 0, arg, 0);
    03677 }
    03678
    03679 /*
    03680  * Calls func(obj, arg, recursive), where recursive is non-zero if the
    03681  * current method is called recursively on the ordered pair <obj, paired_obj>
    03682  */
    03683
    03684 VALUE
    03685 rb_exec_recursive_paired(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE paired_obj, VALUE arg)
    03686 {
    03687     return exec_recursive(func, obj, rb_obj_id(paired_obj), arg, 0);
    03688 }
    03689
    03690 /*
    03691  * If recursion is detected on the current method and obj, the outermost
    03692  * func will be called with (obj, arg, Qtrue). All inner func will be
    03693  * short-circuited using throw.
    03694  */
    03695
    03696 VALUE
    03697 rb_exec_recursive_outer(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
    03698 {
    03699     return exec_recursive(func, obj, 0, arg, 1);
    03700 }
    03701
    03702 /* tracer */
    03703
    03704 static rb_event_hook_t *
    03705 alloc_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
    03706 {
    03707     rb_event_hook_t *hook = ALLOC(rb_event_hook_t);
    03708     hook->func = func;
    03709     hook->flag = events;
    03710     hook->data = data;
    03711     return hook;
    03712 }
    03713
    03714 static void
    03715 thread_reset_event_flags(rb_thread_t *th)
    03716 {
    03717     rb_event_hook_t *hook = th->event_hooks;
    03718     rb_event_flag_t flag = th->event_flags & RUBY_EVENT_VM;
    03719
    03720     while (hook) {
    03721         flag |= hook->flag;
    03722         hook = hook->next;
    03723     }
    03724     th->event_flags = flag;
    03725 }
    03726
    03727 static void
    03728 rb_threadptr_add_event_hook(rb_thread_t *th,
    03729                          rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
    03730 {
    03731     rb_event_hook_t *hook = alloc_event_hook(func, events, data);
    03732     hook->next = th->event_hooks;
    03733     th->event_hooks = hook;
    03734     thread_reset_event_flags(th);
    03735 }
    03736
    03737 static rb_thread_t *
    03738 thval2thread_t(VALUE thval)
    03739 {
    03740     rb_thread_t *th;
    03741     GetThreadPtr(thval, th);
    03742     return th;
    03743 }
    03744
    03745 void
    03746 rb_thread_add_event_hook(VALUE thval,
    03747                          rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
    03748 {
    03749     rb_threadptr_add_event_hook(thval2thread_t(thval), func, events, data);
    03750 }
    03751
    03752 static int
    03753 set_threads_event_flags_i(st_data_t key, st_data_t val, st_data_t flag)
    03754 {
    03755     VALUE thval = key;
    03756     rb_thread_t *th;
    03757     GetThreadPtr(thval, th);
    03758
    03759     if (flag) {
    03760         th->event_flags |= RUBY_EVENT_VM;
    03761     }
    03762     else {
    03763         th->event_flags &= (~RUBY_EVENT_VM);
    03764     }
    03765     return ST_CONTINUE;
    03766 }
    03767
    03768 static void
    03769 set_threads_event_flags(int flag)
    03770 {
    03771     st_foreach(GET_VM()->living_threads, set_threads_event_flags_i, (st_data_t) flag);
    03772 }
    03773
    03774 static inline void
    03775 exec_event_hooks(const rb_event_hook_t *hook, rb_event_flag_t flag, VALUE self, ID id, VALUE klass)
    03776 {
    03777     for (; hook; hook = hook->next) {
    03778         if (flag & hook->flag) {
    03779             (*hook->func)(flag, hook->data, self, id, klass);
    03780         }
    03781     }
    03782 }
    03783
    03784 void
    03785 rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t flag, VALUE self, ID id, VALUE klass)
    03786 {
    03787     const VALUE errinfo = th->errinfo;
    03788     const rb_event_flag_t wait_event = th->event_flags;
    03789
    03790     if (self == rb_mRubyVMFrozenCore) return;
    03791     if (wait_event & flag) {
    03792         exec_event_hooks(th->event_hooks, flag, self, id, klass);
    03793     }
    03794     if (wait_event & RUBY_EVENT_VM) {
    03795         if (th->vm->event_hooks == NULL) {
    03796             th->event_flags &= (~RUBY_EVENT_VM);
    03797         }
    03798         else {
    03799             exec_event_hooks(th->vm->event_hooks, flag, self, id, klass);
    03800         }
    03801     }
    03802     th->errinfo = errinfo;
    03803 }
    03804
    03805 void
    03806 rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
    03807 {
    03808     rb_event_hook_t *hook = alloc_event_hook(func, events, data);
    03809     rb_vm_t *vm = GET_VM();
    03810
    03811     hook->next = vm->event_hooks;
    03812     vm->event_hooks = hook;
    03813
    03814     set_threads_event_flags(1);
    03815 }
    03816
    03817 static int
    03818 remove_event_hook(rb_event_hook_t **root, rb_event_hook_func_t func)
    03819 {
    03820     rb_event_hook_t *prev = NULL, *hook = *root, *next;
    03821
    03822     while (hook) {
    03823         next = hook->next;
    03824         if (func == 0 || hook->func == func) {
    03825             if (prev) {
    03826                 prev->next = hook->next;
    03827             }
    03828             else {
    03829                 *root = hook->next;
    03830             }
    03831             xfree(hook);
    03832         }
    03833         else {
    03834             prev = hook;
    03835         }
    03836         hook = next;
    03837     }
    03838     return -1;
    03839 }
    03840
    03841 static int
    03842 rb_threadptr_revmove_event_hook(rb_thread_t *th, rb_event_hook_func_t func)
    03843 {
    03844     int ret = remove_event_hook(&th->event_hooks, func);
    03845     thread_reset_event_flags(th);
    03846     return ret;
    03847 }
    03848
    03849 int
    03850 rb_thread_remove_event_hook(VALUE thval, rb_event_hook_func_t func)
    03851 {
    03852     return rb_threadptr_revmove_event_hook(thval2thread_t(thval), func);
    03853 }
    03854
    03855 int
    03856 rb_remove_event_hook(rb_event_hook_func_t func)
    03857 {
    03858     rb_vm_t *vm = GET_VM();
    03859     rb_event_hook_t *hook = vm->event_hooks;
    03860     int ret = remove_event_hook(&vm->event_hooks, func);
    03861
    03862     if (hook != NULL && vm->event_hooks == NULL) {
    03863         set_threads_event_flags(0);
    03864     }
    03865
    03866     return ret;
    03867 }
    03868
    03869 static int
    03870 clear_trace_func_i(st_data_t key, st_data_t val, st_data_t flag)
    03871 {
    03872     rb_thread_t *th;
    03873     GetThreadPtr((VALUE)key, th);
    03874     rb_threadptr_revmove_event_hook(th, 0);
    03875     return ST_CONTINUE;
    03876 }
    03877
    03878 void
    03879 rb_clear_trace_func(void)
    03880 {
    03881     st_foreach(GET_VM()->living_threads, clear_trace_func_i, (st_data_t) 0);
    03882     rb_remove_event_hook(0);
    03883 }
    03884
    03885 static void call_trace_func(rb_event_flag_t, VALUE data, VALUE self, ID id, VALUE klass);
    03886
    03887 /*
    03888  *  call-seq:
    03889  *     set_trace_func(proc)    -> proc
    03890  *     set_trace_func(nil)     -> nil
    03891  *
    03892  *  Establishes _proc_ as the handler for tracing, or disables
    03893  *  tracing if the parameter is +nil+. _proc_ takes up
    03894  *  to six parameters: an event name, a filename, a line number, an
    03895  *  object id, a binding, and the name of a class. _proc_ is
    03896  *  invoked whenever an event occurs. Events are: <code>c-call</code>
    03897  *  (call a C-language routine), <code>c-return</code> (return from a
    03898  *  C-language routine), <code>call</code> (call a Ruby method),
    03899  *  <code>class</code> (start a class or module definition),
    03900  *  <code>end</code> (finish a class or module definition),
    03901  *  <code>line</code> (execute code on a new line), <code>raise</code>
    03902  *  (raise an exception), and <code>return</code> (return from a Ruby
    03903  *  method). Tracing is disabled within the context of _proc_.
    03904  *
    03905  *      class Test
    03906  *      def test
    03907  *        a = 1
    03908  *        b = 2
    03909  *      end
    03910  *      end
    03911  *
    03912  *      set_trace_func proc { |event, file, line, id, binding, classname|
    03913  *         printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
    03914  *      }
    03915  *      t = Test.new
    03916  *      t.test
    03917  *
    03918  *        line prog.rb:11               false
    03919  *      c-call prog.rb:11        new    Class
    03920  *      c-call prog.rb:11 initialize   Object
    03921  *    c-return prog.rb:11 initialize   Object
    03922  *    c-return prog.rb:11        new    Class
    03923  *        line prog.rb:12               false
    03924  *        call prog.rb:2        test     Test
    03925  *        line prog.rb:3        test     Test
    03926  *        line prog.rb:4        test     Test
    03927  *      return prog.rb:4        test     Test
    03928  */
    03929
    03930 static VALUE
    03931 set_trace_func(VALUE obj, VALUE trace)
    03932 {
    03933     rb_remove_event_hook(call_trace_func);
    03934
    03935     if (NIL_P(trace)) {
    03936         return Qnil;
    03937     }
    03938
    03939     if (!rb_obj_is_proc(trace)) {
    03940         rb_raise(rb_eTypeError, "trace_func needs to be Proc");
    03941     }
    03942
    03943     rb_add_event_hook(call_trace_func, RUBY_EVENT_ALL, trace);
    03944     return trace;
    03945 }
    03946
    03947 static void
    03948 thread_add_trace_func(rb_thread_t *th, VALUE trace)
    03949 {
    03950     if (!rb_obj_is_proc(trace)) {
    03951         rb_raise(rb_eTypeError, "trace_func needs to be Proc");
    03952     }
    03953
    03954     rb_threadptr_add_event_hook(th, call_trace_func, RUBY_EVENT_ALL, trace);
    03955 }
    03956
    03957 /*
    03958  *  call-seq:
    03959  *     thr.add_trace_func(proc)    -> proc
    03960  *
    03961  *  Adds _proc_ as a handler for tracing.
    03962  *  See <code>Thread#set_trace_func</code> and +set_trace_func+.
    03963  */
    03964
    03965 static VALUE
    03966 thread_add_trace_func_m(VALUE obj, VALUE trace)
    03967 {
    03968     rb_thread_t *th;
    03969     GetThreadPtr(obj, th);
    03970     thread_add_trace_func(th, trace);
    03971     return trace;
    03972 }
    03973
    03974 /*
    03975  *  call-seq:
    03976  *     thr.set_trace_func(proc)    -> proc
    03977  *     thr.set_trace_func(nil)     -> nil
    03978  *
    03979  *  Establishes _proc_ on _thr_ as the handler for tracing, or
    03980  *  disables tracing if the parameter is +nil+.
    03981  *  See +set_trace_func+.
    03982  */
    03983
    03984 static VALUE
    03985 thread_set_trace_func_m(VALUE obj, VALUE trace)
    03986 {
    03987     rb_thread_t *th;
    03988     GetThreadPtr(obj, th);
    03989     rb_threadptr_revmove_event_hook(th, call_trace_func);
    03990
    03991     if (NIL_P(trace)) {
    03992         return Qnil;
    03993     }
    03994     thread_add_trace_func(th, trace);
    03995     return trace;
    03996 }
    03997
    03998 static const char *
    03999 get_event_name(rb_event_flag_t event)
    04000 {
    04001     switch (event) {
    04002       case RUBY_EVENT_LINE:
    04003         return "line";
    04004       case RUBY_EVENT_CLASS:
    04005         return "class";
    04006       case RUBY_EVENT_END:
    04007         return "end";
    04008       case RUBY_EVENT_CALL:
    04009         return "call";
    04010       case RUBY_EVENT_RETURN:
    04011         return "return";
    04012       case RUBY_EVENT_C_CALL:
    04013         return "c-call";
    04014       case RUBY_EVENT_C_RETURN:
    04015         return "c-return";
    04016       case RUBY_EVENT_RAISE:
    04017         return "raise";
    04018       default:
    04019         return "unknown";
    04020     }
    04021 }
    04022
    04023 VALUE ruby_suppress_tracing(VALUE (*func)(VALUE, int), VALUE arg, int always);
    04024
    04025 struct call_trace_func_args {
    04026     rb_event_flag_t event;
    04027     VALUE proc;
    04028     VALUE self;
    04029     ID id;
    04030     VALUE klass;
    04031 };
    04032
    04033 static VALUE
    04034 call_trace_proc(VALUE args, int tracing)
    04035 {
    04036     struct call_trace_func_args *p = (struct call_trace_func_args *)args;
    04037     const char *srcfile = rb_sourcefile();
    04038     VALUE eventname = rb_str_new2(get_event_name(p->event));
    04039     VALUE filename = srcfile ? rb_str_new2(srcfile) : Qnil;
    04040     VALUE argv[6];
    04041     int line = rb_sourceline();
    04042     ID id = 0;
    04043     VALUE klass = 0;
    04044
    04045     if (p->event == RUBY_EVENT_C_CALL ||
    04046         p->event == RUBY_EVENT_C_RETURN) {
    04047         id = p->id;
    04048         klass = p->klass;
    04049     }
    04050     else {
    04051         rb_thread_method_id_and_class(GET_THREAD(), &id, &klass);
    04052     }
    04053     if (id == ID_ALLOCATOR)
    04054       return Qnil;
    04055     if (klass) {
    04056         if (TYPE(klass) == T_ICLASS) {
    04057             klass = RBASIC(klass)->klass;
    04058         }
    04059         else if (FL_TEST(klass, FL_SINGLETON)) {
    04060             klass = rb_iv_get(klass, "__attached__");
    04061         }
    04062     }
    04063
    04064     argv[0] = eventname;
    04065     argv[1] = filename;
    04066     argv[2] = INT2FIX(line);
    04067     argv[3] = id ? ID2SYM(id) : Qnil;
    04068     argv[4] = (p->self && srcfile) ? rb_binding_new() : Qnil;
    04069     argv[5] = klass ? klass : Qnil;
    04070
    04071     return rb_proc_call_with_block(p->proc, 6, argv, Qnil);
    04072 }
    04073
    04074 static void
    04075 call_trace_func(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
    04076 {
    04077     struct call_trace_func_args args;
    04078
    04079     args.event = event;
    04080     args.proc = proc;
    04081     args.self = self;
    04082     args.id = id;
    04083     args.klass = klass;
    04084     ruby_suppress_tracing(call_trace_proc, (VALUE)&args, FALSE);
    04085 }
    04086
    04087 VALUE
    04088 ruby_suppress_tracing(VALUE (*func)(VALUE, int), VALUE arg, int always)
    04089 {
    04090     rb_thread_t *th = GET_THREAD();
    04091     int state, tracing;
    04092     volatile int raised;
    04093     volatile int outer_state;
    04094     VALUE result = Qnil;
    04095
    04096     if ((tracing = th->tracing) != 0 && !always) {
    04097         return Qnil;
    04098     }
    04099     else {
    04100         th->tracing = 1;
    04101     }
    04102
    04103     raised = rb_threadptr_reset_raised(th);
    04104     outer_state = th->state;
    04105     th->state = 0;
    04106
    04107     PUSH_TAG();
    04108     if ((state = EXEC_TAG()) == 0) {
    04109         result = (*func)(arg, tracing);
    04110     }
    04111
    04112     if (raised) {
    04113         rb_threadptr_set_raised(th);
    04114     }
    04115     POP_TAG();
    04116
    04117     th->tracing = tracing;
    04118     if (state) {
    04119         JUMP_TAG(state);
    04120     }
    04121     th->state = outer_state;
    04122
    04123     return result;
    04124 }
    04125
    04126 VALUE rb_thread_backtrace(VALUE thval);
    04127
    04128 /*
    04129  *  call-seq:
    04130  *     thr.backtrace    -> array
    04131  *
    04132  *  Returns the current back trace of the _thr_.
    04133  */
    04134
    04135 static VALUE
    04136 rb_thread_backtrace_m(VALUE thval)
    04137 {
    04138     return rb_thread_backtrace(thval);
    04139 }
    04140
    04141 /*
    04142  *  Document-class: ThreadError
    04143  *
    04144  *  Raised when an invalid operation is attempted on a thread.
    04145  *
    04146  *  For example, when no other thread has been started:
    04147  *
    04148  *     Thread.stop
    04149  *
    04150  *  <em>raises the exception:</em>
    04151  *
    04152  *     ThreadError: stopping only thread
    04153  */
    04154
    04155 /*
    04156  *  +Thread+ encapsulates the behavior of a thread of
    04157  *  execution, including the main thread of the Ruby script.
    04158  *
    04159  *  In the descriptions of the methods in this class, the parameter _sym_
    04160  *  refers to a symbol, which is either a quoted string or a
    04161  *  +Symbol+ (such as <code>:name</code>).
    04162  */
    04163
    04164 void
    04165 Init_Thread(void)
    04166 {
    04167 #undef rb_intern
    04168 #define rb_intern(str) rb_intern_const(str)
    04169
    04170     VALUE cThGroup;
    04171
    04172     rb_define_singleton_method(rb_cThread, "new", thread_s_new, -1);
    04173     rb_define_singleton_method(rb_cThread, "start", thread_start, -2);
    04174     rb_define_singleton_method(rb_cThread, "fork", thread_start, -2);
    04175     rb_define_singleton_method(rb_cThread, "main", rb_thread_s_main, 0);
    04176     rb_define_singleton_method(rb_cThread, "current", thread_s_current, 0);
    04177     rb_define_singleton_method(rb_cThread, "stop", rb_thread_stop, 0);
    04178     rb_define_singleton_method(rb_cThread, "kill", rb_thread_s_kill, 1);
    04179     rb_define_singleton_method(rb_cThread, "exit", rb_thread_exit, 0);
    04180     rb_define_singleton_method(rb_cThread, "pass", thread_s_pass, 0);
    04181     rb_define_singleton_method(rb_cThread, "list", rb_thread_list, 0);
    04182     rb_define_singleton_method(rb_cThread, "abort_on_exception", rb_thread_s_abort_exc, 0);
    04183     rb_define_singleton_method(rb_cThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1);
    04184 #if THREAD_DEBUG < 0
    04185     rb_define_singleton_method(rb_cThread, "DEBUG", rb_thread_s_debug, 0);
    04186     rb_define_singleton_method(rb_cThread, "DEBUG=", rb_thread_s_debug_set, 1);
    04187 #endif
    04188
    04189     rb_define_method(rb_cThread, "initialize", thread_initialize, -2);
    04190     rb_define_method(rb_cThread, "raise", thread_raise_m, -1);
    04191     rb_define_method(rb_cThread, "join", thread_join_m, -1);
    04192     rb_define_method(rb_cThread, "value", thread_value, 0);
    04193     rb_define_method(rb_cThread, "kill", rb_thread_kill, 0);
    04194     rb_define_method(rb_cThread, "terminate", rb_thread_kill, 0);
    04195     rb_define_method(rb_cThread, "exit", rb_thread_kill, 0);
    04196     rb_define_method(rb_cThread, "run", rb_thread_run, 0);
    04197     rb_define_method(rb_cThread, "wakeup", rb_thread_wakeup, 0);
    04198     rb_define_method(rb_cThread, "[]", rb_thread_aref, 1);
    04199     rb_define_method(rb_cThread, "[]=", rb_thread_aset, 2);
    04200     rb_define_method(rb_cThread, "key?", rb_thread_key_p, 1);
    04201     rb_define_method(rb_cThread, "keys", rb_thread_keys, 0);
    04202     rb_define_method(rb_cThread, "priority", rb_thread_priority, 0);
    04203     rb_define_method(rb_cThread, "priority=", rb_thread_priority_set, 1);
    04204     rb_define_method(rb_cThread, "status", rb_thread_status, 0);
    04205     rb_define_method(rb_cThread, "alive?", rb_thread_alive_p, 0);
    04206     rb_define_method(rb_cThread, "stop?", rb_thread_stop_p, 0);
    04207     rb_define_method(rb_cThread, "abort_on_exception", rb_thread_abort_exc, 0);
    04208     rb_define_method(rb_cThread, "abort_on_exception=", rb_thread_abort_exc_set, 1);
    04209     rb_define_method(rb_cThread, "safe_level", rb_thread_safe_level, 0);
    04210     rb_define_method(rb_cThread, "group", rb_thread_group, 0);
    04211     rb_define_method(rb_cThread, "backtrace", rb_thread_backtrace_m, 0);
    04212
    04213     rb_define_method(rb_cThread, "inspect", rb_thread_inspect, 0);
    04214
    04215     cThGroup = rb_define_class("ThreadGroup", rb_cObject);
    04216     rb_define_alloc_func(cThGroup, thgroup_s_alloc);
    04217     rb_define_method(cThGroup, "list", thgroup_list, 0);
    04218     rb_define_method(cThGroup, "enclose", thgroup_enclose, 0);
    04219     rb_define_method(cThGroup, "enclosed?", thgroup_enclosed_p, 0);
    04220     rb_define_method(cThGroup, "add", thgroup_add, 1);
    04221
    04222     {
    04223         rb_thread_t *th = GET_THREAD();
    04224         th->thgroup = th->vm->thgroup_default = rb_obj_alloc(cThGroup);
    04225         rb_define_const(cThGroup, "Default", th->thgroup);
    04226     }
    04227
    04228     rb_cMutex = rb_define_class("Mutex", rb_cObject);
    04229     rb_define_alloc_func(rb_cMutex, mutex_alloc);
    04230     rb_define_method(rb_cMutex, "initialize", mutex_initialize, 0);
    04231     rb_define_method(rb_cMutex, "locked?", rb_mutex_locked_p, 0);
    04232     rb_define_method(rb_cMutex, "try_lock", rb_mutex_trylock, 0);
    04233     rb_define_method(rb_cMutex, "lock", rb_mutex_lock, 0);
    04234     rb_define_method(rb_cMutex, "unlock", rb_mutex_unlock, 0);
    04235     rb_define_method(rb_cMutex, "sleep", mutex_sleep, -1);
    04236
    04237     recursive_key = rb_intern("__recursive_key__");
    04238     rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError);
    04239
    04240     /* trace */
    04241     rb_define_global_function("set_trace_func", set_trace_func, 1);
    04242     rb_define_method(rb_cThread, "set_trace_func", thread_set_trace_func_m, 1);
    04243     rb_define_method(rb_cThread, "add_trace_func", thread_add_trace_func_m, 1);
    04244
    04245     /* init thread core */
    04246     {
    04247         /* main thread setting */
    04248         {
    04249             /* acquire global vm lock */
    04250             rb_thread_lock_t *lp = &GET_THREAD()->vm->global_vm_lock;
    04251             native_mutex_initialize(lp);
    04252             native_mutex_lock(lp);
    04253             native_mutex_initialize(&GET_THREAD()->interrupt_lock);
    04254         }
    04255     }
    04256
    04257     rb_thread_create_timer_thread();
    04258
    04259     (void)native_mutex_trylock;
    04260     (void)ruby_thread_set_native;
    04261 }
    04262
    04263 int
    04264 ruby_native_thread_p(void)
    04265 {
    04266     rb_thread_t *th = ruby_thread_from_native();
    04267
    04268     return th != 0;
    04269 }
    04270
    04271 static int
    04272 check_deadlock_i(st_data_t key, st_data_t val, int *found)
    04273 {
    04274     VALUE thval = key;
    04275     rb_thread_t *th;
    04276     GetThreadPtr(thval, th);
    04277
    04278     if (th->status != THREAD_STOPPED_FOREVER || RUBY_VM_INTERRUPTED(th) || th->transition_for_lock) {
    04279         *found = 1;
    04280     }
    04281     else if (th->locking_mutex) {
    04282         mutex_t *mutex;
    04283         GetMutexPtr(th->locking_mutex, mutex);
    04284
    04285         native_mutex_lock(&mutex->lock);
    04286         if (mutex->th == th || (!mutex->th && mutex->cond_notified)) {
    04287             *found = 1;
    04288         }
    04289         native_mutex_unlock(&mutex->lock);
    04290     }
    04291
    04292     return (*found) ? ST_STOP : ST_CONTINUE;
    04293 }
    04294
    04295 #if 0 /* for debug */
    04296 static int
    04297 debug_i(st_data_t key, st_data_t val, int *found)
    04298 {
    04299     VALUE thval = key;
    04300     rb_thread_t *th;
    04301     GetThreadPtr(thval, th);
    04302
    04303     printf("th:%p %d %d %d", th, th->status, th->interrupt_flag, th->transition_for_lock);
    04304     if (th->locking_mutex) {
    04305         mutex_t *mutex;
    04306         GetMutexPtr(th->locking_mutex, mutex);
    04307
    04308         native_mutex_lock(&mutex->lock);
    04309         printf(" %p %d\n", mutex->th, mutex->cond_notified);
    04310         native_mutex_unlock(&mutex->lock);
    04311     }
    04312     else puts("");
    04313
    04314     return ST_CONTINUE;
    04315 }
    04316 #endif
    04317
    04318 static void
    04319 rb_check_deadlock(rb_vm_t *vm)
    04320 {
    04321     int found = 0;
    04322
    04323     if (vm_living_thread_num(vm) > vm->sleeper) return;
    04324     if (vm_living_thread_num(vm) < vm->sleeper) rb_bug("sleeper must not be more than vm_living_thread_num(vm)");
    04325
    04326     st_foreach(vm->living_threads, check_deadlock_i, (st_data_t)&found);
    04327
    04328     if (!found) {
    04329         VALUE argv[2];
    04330         argv[0] = rb_eFatal;
    04331         argv[1] = rb_str_new2("deadlock detected");
    04332 #if 0 /* for debug */
    04333         printf("%d %d %p %p\n", vm->living_threads->num_entries, vm->sleeper, GET_THREAD(), vm->main_thread);
    04334         st_foreach(vm->living_threads, debug_i, (st_data_t)0);
    04335 #endif
    04336         vm->sleeper--;
    04337         rb_threadptr_raise(vm->main_thread, 2, argv);
    04338     }
    04339 }
    04340
    04341 static void
    04342 update_coverage(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
    04343 {
    04344     VALUE coverage = GET_THREAD()->cfp->iseq->coverage;
    04345     if (coverage && RBASIC(coverage)->klass == 0) {
    04346         long line = rb_sourceline() - 1;
    04347         long count;
    04348         if (RARRAY_PTR(coverage)[line] == Qnil) {
    04349             rb_bug("bug");
    04350         }
    04351         count = FIX2LONG(RARRAY_PTR(coverage)[line]) + 1;
    04352         if (POSFIXABLE(count)) {
    04353             RARRAY_PTR(coverage)[line] = LONG2FIX(count);
    04354         }
    04355     }
    04356 }
    04357
    04358 VALUE
    04359 rb_get_coverages(void)
    04360 {
    04361     return GET_VM()->coverages;
    04362 }
    04363
    04364 void
    04365 rb_set_coverages(VALUE coverages)
    04366 {
    04367     GET_VM()->coverages = coverages;
    04368     rb_add_event_hook(update_coverage, RUBY_EVENT_COVERAGE, Qnil);
    04369 }
    04370
    04371 void
    04372 rb_reset_coverages(void)
    04373 {
    04374     GET_VM()->coverages = Qfalse;
    04375     rb_remove_event_hook(update_coverage);
    04376 }
    04377