thread_pthread.c

Go to the documentation of this file.
00001 /* -*-c-*- */
00002 /**********************************************************************
00003 
00004   thread_pthread.c -
00005 
00006   $Author: nagachika $
00007 
00008   Copyright (C) 2004-2007 Koichi Sasada
00009 
00010 **********************************************************************/
00011 
00012 #ifdef THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
00013 
00014 #include "gc.h"
00015 
00016 #ifdef HAVE_SYS_RESOURCE_H
00017 #include <sys/resource.h>
00018 #endif
00019 #ifdef HAVE_THR_STKSEGMENT
00020 #include <thread.h>
00021 #endif
00022 #if HAVE_FCNTL_H
00023 #include <fcntl.h>
00024 #elif HAVE_SYS_FCNTL_H
00025 #include <sys/fcntl.h>
00026 #endif
00027 #ifdef HAVE_SYS_PRCTL_H
00028 #include <sys/prctl.h>
00029 #endif
00030 #if defined(__native_client__) && defined(NACL_NEWLIB)
00031 # include "nacl/select.h"
00032 #endif
00033 #if defined(HAVE_SYS_TIME_H)
00034 #include <sys/time.h>
00035 #endif
00036 
00037 static void native_mutex_lock(pthread_mutex_t *lock);
00038 static void native_mutex_unlock(pthread_mutex_t *lock);
00039 static int native_mutex_trylock(pthread_mutex_t *lock);
00040 static void native_mutex_initialize(pthread_mutex_t *lock);
00041 static void native_mutex_destroy(pthread_mutex_t *lock);
00042 static void native_cond_signal(rb_nativethread_cond_t *cond);
00043 static void native_cond_broadcast(rb_nativethread_cond_t *cond);
00044 static void native_cond_wait(rb_nativethread_cond_t *cond, pthread_mutex_t *mutex);
00045 static void native_cond_initialize(rb_nativethread_cond_t *cond, int flags);
00046 static void native_cond_destroy(rb_nativethread_cond_t *cond);
00047 static void rb_thread_wakeup_timer_thread_low(void);
00048 static pthread_t timer_thread_id;
00049 
00050 #define RB_CONDATTR_CLOCK_MONOTONIC 1
00051 
00052 #if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(HAVE_CLOCKID_T) && \
00053     defined(CLOCK_REALTIME) && defined(CLOCK_MONOTONIC) && \
00054     defined(HAVE_CLOCK_GETTIME) && defined(HAVE_PTHREAD_CONDATTR_INIT)
00055 #define USE_MONOTONIC_COND 1
00056 #else
00057 #define USE_MONOTONIC_COND 0
00058 #endif
00059 
00060 #if defined(HAVE_POLL) && defined(HAVE_FCNTL) && defined(F_GETFL) && defined(F_SETFL) && defined(O_NONBLOCK) && !defined(__native_client__)
00061 /* The timer thread sleeps while only one Ruby thread is running. */
00062 # define USE_SLEEPY_TIMER_THREAD 1
00063 #else
00064 # define USE_SLEEPY_TIMER_THREAD 0
00065 #endif
00066 
00067 static void
00068 gvl_acquire_common(rb_vm_t *vm)
00069 {
00070     if (vm->gvl.acquired) {
00071 
00072         vm->gvl.waiting++;
00073         if (vm->gvl.waiting == 1) {
00074             /*
00075              * Wake up timer thread iff timer thread is slept.
00076              * When timer thread is polling mode, we don't want to
00077              * make confusing timer thread interval time.
00078              */
00079             rb_thread_wakeup_timer_thread_low();
00080         }
00081 
00082         while (vm->gvl.acquired) {
00083             native_cond_wait(&vm->gvl.cond, &vm->gvl.lock);
00084         }
00085 
00086         vm->gvl.waiting--;
00087 
00088         if (vm->gvl.need_yield) {
00089             vm->gvl.need_yield = 0;
00090             native_cond_signal(&vm->gvl.switch_cond);
00091         }
00092     }
00093 
00094     vm->gvl.acquired = 1;
00095 }
00096 
00097 static void
00098 gvl_acquire(rb_vm_t *vm, rb_thread_t *th)
00099 {
00100     native_mutex_lock(&vm->gvl.lock);
00101     gvl_acquire_common(vm);
00102     native_mutex_unlock(&vm->gvl.lock);
00103 }
00104 
00105 static void
00106 gvl_release_common(rb_vm_t *vm)
00107 {
00108     vm->gvl.acquired = 0;
00109     if (vm->gvl.waiting > 0)
00110         native_cond_signal(&vm->gvl.cond);
00111 }
00112 
00113 static void
00114 gvl_release(rb_vm_t *vm)
00115 {
00116     native_mutex_lock(&vm->gvl.lock);
00117     gvl_release_common(vm);
00118     native_mutex_unlock(&vm->gvl.lock);
00119 }
00120 
00121 static void
00122 gvl_yield(rb_vm_t *vm, rb_thread_t *th)
00123 {
00124     native_mutex_lock(&vm->gvl.lock);
00125 
00126     gvl_release_common(vm);
00127 
00128     /* An another thread is processing GVL yield. */
00129     if (UNLIKELY(vm->gvl.wait_yield)) {
00130         while (vm->gvl.wait_yield)
00131             native_cond_wait(&vm->gvl.switch_wait_cond, &vm->gvl.lock);
00132         goto acquire;
00133     }
00134 
00135     if (vm->gvl.waiting > 0) {
00136         /* Wait until another thread task take GVL. */
00137         vm->gvl.need_yield = 1;
00138         vm->gvl.wait_yield = 1;
00139         while (vm->gvl.need_yield)
00140             native_cond_wait(&vm->gvl.switch_cond, &vm->gvl.lock);
00141         vm->gvl.wait_yield = 0;
00142     }
00143     else {
00144         native_mutex_unlock(&vm->gvl.lock);
00145         sched_yield();
00146         native_mutex_lock(&vm->gvl.lock);
00147     }
00148 
00149     native_cond_broadcast(&vm->gvl.switch_wait_cond);
00150   acquire:
00151     gvl_acquire_common(vm);
00152     native_mutex_unlock(&vm->gvl.lock);
00153 }
00154 
00155 static void
00156 gvl_init(rb_vm_t *vm)
00157 {
00158     native_mutex_initialize(&vm->gvl.lock);
00159     native_cond_initialize(&vm->gvl.cond, RB_CONDATTR_CLOCK_MONOTONIC);
00160     native_cond_initialize(&vm->gvl.switch_cond, RB_CONDATTR_CLOCK_MONOTONIC);
00161     native_cond_initialize(&vm->gvl.switch_wait_cond, RB_CONDATTR_CLOCK_MONOTONIC);
00162     vm->gvl.acquired = 0;
00163     vm->gvl.waiting = 0;
00164     vm->gvl.need_yield = 0;
00165     vm->gvl.wait_yield = 0;
00166 }
00167 
00168 static void
00169 gvl_destroy(rb_vm_t *vm)
00170 {
00171     native_cond_destroy(&vm->gvl.switch_wait_cond);
00172     native_cond_destroy(&vm->gvl.switch_cond);
00173     native_cond_destroy(&vm->gvl.cond);
00174     native_mutex_destroy(&vm->gvl.lock);
00175 }
00176 
00177 static void
00178 gvl_atfork(rb_vm_t *vm)
00179 {
00180     gvl_init(vm);
00181     gvl_acquire(vm, GET_THREAD());
00182 }
00183 
00184 #define NATIVE_MUTEX_LOCK_DEBUG 0
00185 
00186 static void
00187 mutex_debug(const char *msg, pthread_mutex_t *lock)
00188 {
00189     if (NATIVE_MUTEX_LOCK_DEBUG) {
00190         int r;
00191         static pthread_mutex_t dbglock = PTHREAD_MUTEX_INITIALIZER;
00192 
00193         if ((r = pthread_mutex_lock(&dbglock)) != 0) {exit(EXIT_FAILURE);}
00194         fprintf(stdout, "%s: %p\n", msg, (void *)lock);
00195         if ((r = pthread_mutex_unlock(&dbglock)) != 0) {exit(EXIT_FAILURE);}
00196     }
00197 }
00198 
00199 static void
00200 native_mutex_lock(pthread_mutex_t *lock)
00201 {
00202     int r;
00203     mutex_debug("lock", lock);
00204     if ((r = pthread_mutex_lock(lock)) != 0) {
00205         rb_bug_errno("pthread_mutex_lock", r);
00206     }
00207 }
00208 
00209 static void
00210 native_mutex_unlock(pthread_mutex_t *lock)
00211 {
00212     int r;
00213     mutex_debug("unlock", lock);
00214     if ((r = pthread_mutex_unlock(lock)) != 0) {
00215         rb_bug_errno("pthread_mutex_unlock", r);
00216     }
00217 }
00218 
00219 static inline int
00220 native_mutex_trylock(pthread_mutex_t *lock)
00221 {
00222     int r;
00223     mutex_debug("trylock", lock);
00224     if ((r = pthread_mutex_trylock(lock)) != 0) {
00225         if (r == EBUSY) {
00226             return EBUSY;
00227         }
00228         else {
00229             rb_bug_errno("pthread_mutex_trylock", r);
00230         }
00231     }
00232     return 0;
00233 }
00234 
00235 static void
00236 native_mutex_initialize(pthread_mutex_t *lock)
00237 {
00238     int r = pthread_mutex_init(lock, 0);
00239     mutex_debug("init", lock);
00240     if (r != 0) {
00241         rb_bug_errno("pthread_mutex_init", r);
00242     }
00243 }
00244 
00245 static void
00246 native_mutex_destroy(pthread_mutex_t *lock)
00247 {
00248     int r = pthread_mutex_destroy(lock);
00249     mutex_debug("destroy", lock);
00250     if (r != 0) {
00251         rb_bug_errno("pthread_mutex_destroy", r);
00252     }
00253 }
00254 
00255 static void
00256 native_cond_initialize(rb_nativethread_cond_t *cond, int flags)
00257 {
00258 #ifdef HAVE_PTHREAD_COND_INIT
00259     int r;
00260 # if USE_MONOTONIC_COND
00261     pthread_condattr_t attr;
00262 
00263     pthread_condattr_init(&attr);
00264 
00265     cond->clockid = CLOCK_REALTIME;
00266     if (flags & RB_CONDATTR_CLOCK_MONOTONIC) {
00267         r = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
00268         if (r == 0) {
00269             cond->clockid = CLOCK_MONOTONIC;
00270         }
00271     }
00272 
00273     r = pthread_cond_init(&cond->cond, &attr);
00274     pthread_condattr_destroy(&attr);
00275 # else
00276     r = pthread_cond_init(&cond->cond, NULL);
00277 # endif
00278     if (r != 0) {
00279         rb_bug_errno("pthread_cond_init", r);
00280     }
00281 
00282     return;
00283 #endif
00284 }
00285 
00286 static void
00287 native_cond_destroy(rb_nativethread_cond_t *cond)
00288 {
00289 #ifdef HAVE_PTHREAD_COND_INIT
00290     int r = pthread_cond_destroy(&cond->cond);
00291     if (r != 0) {
00292         rb_bug_errno("pthread_cond_destroy", r);
00293     }
00294 #endif
00295 }
00296 
00297 /*
00298  * In OS X 10.7 (Lion), pthread_cond_signal and pthread_cond_broadcast return
00299  * EAGAIN after retrying 8192 times.  You can see them in the following page:
00300  *
00301  * http://www.opensource.apple.com/source/Libc/Libc-763.11/pthreads/pthread_cond.c
00302  *
00303  * The following native_cond_signal and native_cond_broadcast functions
00304  * need to retrying until pthread functions don't return EAGAIN.
00305  */
00306 
00307 static void
00308 native_cond_signal(rb_nativethread_cond_t *cond)
00309 {
00310     int r;
00311     do {
00312         r = pthread_cond_signal(&cond->cond);
00313     } while (r == EAGAIN);
00314     if (r != 0) {
00315         rb_bug_errno("pthread_cond_signal", r);
00316     }
00317 }
00318 
00319 static void
00320 native_cond_broadcast(rb_nativethread_cond_t *cond)
00321 {
00322     int r;
00323     do {
00324         r = pthread_cond_broadcast(&cond->cond);
00325     } while (r == EAGAIN);
00326     if (r != 0) {
00327         rb_bug_errno("native_cond_broadcast", r);
00328     }
00329 }
00330 
00331 static void
00332 native_cond_wait(rb_nativethread_cond_t *cond, pthread_mutex_t *mutex)
00333 {
00334     int r = pthread_cond_wait(&cond->cond, mutex);
00335     if (r != 0) {
00336         rb_bug_errno("pthread_cond_wait", r);
00337     }
00338 }
00339 
00340 static int
00341 native_cond_timedwait(rb_nativethread_cond_t *cond, pthread_mutex_t *mutex, struct timespec *ts)
00342 {
00343     int r;
00344 
00345     /*
00346      * An old Linux may return EINTR. Even though POSIX says
00347      *   "These functions shall not return an error code of [EINTR]".
00348      *   http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_cond_timedwait.html
00349      * Let's hide it from arch generic code.
00350      */
00351     do {
00352         r = pthread_cond_timedwait(&cond->cond, mutex, ts);
00353     } while (r == EINTR);
00354 
00355     if (r != 0 && r != ETIMEDOUT) {
00356         rb_bug_errno("pthread_cond_timedwait", r);
00357     }
00358 
00359     return r;
00360 }
00361 
00362 static struct timespec
00363 native_cond_timeout(rb_nativethread_cond_t *cond, struct timespec timeout_rel)
00364 {
00365     int ret;
00366     struct timeval tv;
00367     struct timespec timeout;
00368     struct timespec now;
00369 
00370 #if USE_MONOTONIC_COND
00371     if (cond->clockid == CLOCK_MONOTONIC) {
00372         ret = clock_gettime(cond->clockid, &now);
00373         if (ret != 0)
00374             rb_sys_fail("clock_gettime()");
00375         goto out;
00376     }
00377 
00378     if (cond->clockid != CLOCK_REALTIME)
00379         rb_bug("unsupported clockid %"PRIdVALUE, (SIGNED_VALUE)cond->clockid);
00380 #endif
00381 
00382     ret = gettimeofday(&tv, 0);
00383     if (ret != 0)
00384         rb_sys_fail(0);
00385     now.tv_sec = tv.tv_sec;
00386     now.tv_nsec = tv.tv_usec * 1000;
00387 
00388 #if USE_MONOTONIC_COND
00389   out:
00390 #endif
00391     timeout.tv_sec = now.tv_sec;
00392     timeout.tv_nsec = now.tv_nsec;
00393     timeout.tv_sec += timeout_rel.tv_sec;
00394     timeout.tv_nsec += timeout_rel.tv_nsec;
00395 
00396     if (timeout.tv_nsec >= 1000*1000*1000) {
00397         timeout.tv_sec++;
00398         timeout.tv_nsec -= 1000*1000*1000;
00399     }
00400 
00401     if (timeout.tv_sec < now.tv_sec)
00402         timeout.tv_sec = TIMET_MAX;
00403 
00404     return timeout;
00405 }
00406 
00407 #define native_cleanup_push pthread_cleanup_push
00408 #define native_cleanup_pop  pthread_cleanup_pop
00409 #ifdef HAVE_SCHED_YIELD
00410 #define native_thread_yield() (void)sched_yield()
00411 #else
00412 #define native_thread_yield() ((void)0)
00413 #endif
00414 
00415 #if defined(SIGVTALRM) && !defined(__CYGWIN__) && !defined(__SYMBIAN32__)
00416 #define USE_SIGNAL_THREAD_LIST 1
00417 #endif
00418 #ifdef USE_SIGNAL_THREAD_LIST
00419 static void add_signal_thread_list(rb_thread_t *th);
00420 static void remove_signal_thread_list(rb_thread_t *th);
00421 static rb_nativethread_lock_t signal_thread_list_lock;
00422 #endif
00423 
00424 static pthread_key_t ruby_native_thread_key;
00425 
00426 static void
00427 null_func(int i)
00428 {
00429     /* null */
00430 }
00431 
00432 static rb_thread_t *
00433 ruby_thread_from_native(void)
00434 {
00435     return pthread_getspecific(ruby_native_thread_key);
00436 }
00437 
00438 static int
00439 ruby_thread_set_native(rb_thread_t *th)
00440 {
00441     return pthread_setspecific(ruby_native_thread_key, th) == 0;
00442 }
00443 
00444 static void native_thread_init(rb_thread_t *th);
00445 
00446 void
00447 Init_native_thread(void)
00448 {
00449     rb_thread_t *th = GET_THREAD();
00450 
00451     pthread_key_create(&ruby_native_thread_key, NULL);
00452     th->thread_id = pthread_self();
00453     native_thread_init(th);
00454 #ifdef USE_SIGNAL_THREAD_LIST
00455     native_mutex_initialize(&signal_thread_list_lock);
00456 #endif
00457 #ifndef __native_client__
00458     posix_signal(SIGVTALRM, null_func);
00459 #endif
00460 }
00461 
00462 static void
00463 native_thread_init(rb_thread_t *th)
00464 {
00465     native_cond_initialize(&th->native_thread_data.sleep_cond, RB_CONDATTR_CLOCK_MONOTONIC);
00466     ruby_thread_set_native(th);
00467 }
00468 
00469 static void
00470 native_thread_destroy(rb_thread_t *th)
00471 {
00472     native_cond_destroy(&th->native_thread_data.sleep_cond);
00473 }
00474 
00475 #ifndef USE_THREAD_CACHE
00476 #define USE_THREAD_CACHE 0
00477 #endif
00478 
00479 #if USE_THREAD_CACHE
00480 static rb_thread_t *register_cached_thread_and_wait(void);
00481 #endif
00482 
00483 #if defined HAVE_PTHREAD_GETATTR_NP || defined HAVE_PTHREAD_ATTR_GET_NP
00484 #define STACKADDR_AVAILABLE 1
00485 #elif defined HAVE_PTHREAD_GET_STACKADDR_NP && defined HAVE_PTHREAD_GET_STACKSIZE_NP
00486 #define STACKADDR_AVAILABLE 1
00487 #undef MAINSTACKADDR_AVAILABLE
00488 #define MAINSTACKADDR_AVAILABLE 1
00489 void *pthread_get_stackaddr_np(pthread_t);
00490 size_t pthread_get_stacksize_np(pthread_t);
00491 #elif defined HAVE_THR_STKSEGMENT || defined HAVE_PTHREAD_STACKSEG_NP
00492 #define STACKADDR_AVAILABLE 1
00493 #elif defined HAVE_PTHREAD_GETTHRDS_NP
00494 #define STACKADDR_AVAILABLE 1
00495 #elif defined __ia64 && defined _HPUX_SOURCE
00496 #include <sys/dyntune.h>
00497 
00498 #define STACKADDR_AVAILABLE 1
00499 
00500 /*
00501  * Do not lower the thread's stack to PTHREAD_STACK_MIN,
00502  * otherwise one would receive a 'sendsig: useracc failed.'
00503  * and a coredump.
00504  */
00505 #undef PTHREAD_STACK_MIN
00506 
00507 #define HAVE_PTHREAD_ATTR_GET_NP 1
00508 #undef HAVE_PTHREAD_ATTR_GETSTACK
00509 
00510 /*
00511  * As the PTHREAD_STACK_MIN is undefined and
00512  * noone touches the default stacksize,
00513  * it is just fine to use the default.
00514  */
00515 #define pthread_attr_get_np(thid, attr) 0
00516 
00517 /*
00518  * Using value of sp is very rough... To make it more real,
00519  * addr would need to be aligned to vps_pagesize.
00520  * The vps_pagesize is 'Default user page size (kBytes)'
00521  * and could be retrieved by gettune().
00522  */
00523 static int
00524 hpux_attr_getstackaddr(const pthread_attr_t *attr, void **addr)
00525 {
00526     static uint64_t pagesize;
00527     size_t size;
00528 
00529     if (!pagesize) {
00530         if (gettune("vps_pagesize", &pagesize)) {
00531             pagesize = 16;
00532         }
00533         pagesize *= 1024;
00534     }
00535     pthread_attr_getstacksize(attr, &size);
00536     *addr = (void *)((size_t)((char *)_Asm_get_sp() - size) & ~(pagesize - 1));
00537     return 0;
00538 }
00539 #define pthread_attr_getstackaddr(attr, addr) hpux_attr_getstackaddr(attr, addr)
00540 #endif
00541 
00542 #ifndef MAINSTACKADDR_AVAILABLE
00543 # ifdef STACKADDR_AVAILABLE
00544 #   define MAINSTACKADDR_AVAILABLE 1
00545 # else
00546 #   define MAINSTACKADDR_AVAILABLE 0
00547 # endif
00548 #endif
00549 #if MAINSTACKADDR_AVAILABLE && !defined(get_main_stack)
00550 # define get_main_stack(addr, size) get_stack(addr, size)
00551 #endif
00552 
00553 #ifdef STACKADDR_AVAILABLE
00554 /*
00555  * Get the initial address and size of current thread's stack
00556  */
00557 static int
00558 get_stack(void **addr, size_t *size)
00559 {
00560 #define CHECK_ERR(expr)                         \
00561     {int err = (expr); if (err) return err;}
00562 #ifdef HAVE_PTHREAD_GETATTR_NP /* Linux */
00563     pthread_attr_t attr;
00564     size_t guard = 0;
00565     STACK_GROW_DIR_DETECTION;
00566     CHECK_ERR(pthread_getattr_np(pthread_self(), &attr));
00567 # ifdef HAVE_PTHREAD_ATTR_GETSTACK
00568     CHECK_ERR(pthread_attr_getstack(&attr, addr, size));
00569     STACK_DIR_UPPER((void)0, (void)(*addr = (char *)*addr + *size));
00570 # else
00571     CHECK_ERR(pthread_attr_getstackaddr(&attr, addr));
00572     CHECK_ERR(pthread_attr_getstacksize(&attr, size));
00573 # endif
00574     CHECK_ERR(pthread_attr_getguardsize(&attr, &guard));
00575     *size -= guard;
00576     pthread_attr_destroy(&attr);
00577 #elif defined HAVE_PTHREAD_ATTR_GET_NP /* FreeBSD, DragonFly BSD, NetBSD */
00578     pthread_attr_t attr;
00579     CHECK_ERR(pthread_attr_init(&attr));
00580     CHECK_ERR(pthread_attr_get_np(pthread_self(), &attr));
00581 # ifdef HAVE_PTHREAD_ATTR_GETSTACK
00582     CHECK_ERR(pthread_attr_getstack(&attr, addr, size));
00583 # else
00584     CHECK_ERR(pthread_attr_getstackaddr(&attr, addr));
00585     CHECK_ERR(pthread_attr_getstacksize(&attr, size));
00586 # endif
00587     STACK_DIR_UPPER((void)0, (void)(*addr = (char *)*addr + *size));
00588     pthread_attr_destroy(&attr);
00589 #elif (defined HAVE_PTHREAD_GET_STACKADDR_NP && defined HAVE_PTHREAD_GET_STACKSIZE_NP) /* MacOS X */
00590     pthread_t th = pthread_self();
00591     *addr = pthread_get_stackaddr_np(th);
00592     *size = pthread_get_stacksize_np(th);
00593 #elif defined HAVE_THR_STKSEGMENT || defined HAVE_PTHREAD_STACKSEG_NP
00594     stack_t stk;
00595 # if defined HAVE_THR_STKSEGMENT /* Solaris */
00596     CHECK_ERR(thr_stksegment(&stk));
00597 # else /* OpenBSD */
00598     CHECK_ERR(pthread_stackseg_np(pthread_self(), &stk));
00599 # endif
00600     *addr = stk.ss_sp;
00601     *size = stk.ss_size;
00602 #elif defined HAVE_PTHREAD_GETTHRDS_NP /* AIX */
00603     pthread_t th = pthread_self();
00604     struct __pthrdsinfo thinfo;
00605     char reg[256];
00606     int regsiz=sizeof(reg);
00607     CHECK_ERR(pthread_getthrds_np(&th, PTHRDSINFO_QUERY_ALL,
00608                                    &thinfo, sizeof(thinfo),
00609                                    &reg, &regsiz));
00610     *addr = thinfo.__pi_stackaddr;
00611     *size = thinfo.__pi_stacksize;
00612     STACK_DIR_UPPER((void)0, (void)(*addr = (char *)*addr + *size));
00613 #else
00614 #error STACKADDR_AVAILABLE is defined but not implemented.
00615 #endif
00616     return 0;
00617 #undef CHECK_ERR
00618 }
00619 #endif
00620 
00621 static struct {
00622     rb_nativethread_id_t id;
00623     size_t stack_maxsize;
00624     VALUE *stack_start;
00625 #ifdef __ia64
00626     VALUE *register_stack_start;
00627 #endif
00628 } native_main_thread;
00629 
00630 #ifdef STACK_END_ADDRESS
00631 extern void *STACK_END_ADDRESS;
00632 #endif
00633 
00634 enum {
00635     RUBY_STACK_SPACE_LIMIT = 1024 * 1024, /* 1024KB */
00636     RUBY_STACK_SPACE_RATIO = 5
00637 };
00638 
00639 static size_t
00640 space_size(size_t stack_size)
00641 {
00642     size_t space_size = stack_size / RUBY_STACK_SPACE_RATIO;
00643     if (space_size > RUBY_STACK_SPACE_LIMIT) {
00644         return RUBY_STACK_SPACE_LIMIT;
00645     }
00646     else {
00647         return space_size;
00648     }
00649 }
00650 
00651 #undef ruby_init_stack
00652 /* Set stack bottom of Ruby implementation.
00653  *
00654  * You must call this function before any heap allocation by Ruby implementation.
00655  * Or GC will break living objects */
00656 void
00657 ruby_init_stack(volatile VALUE *addr
00658 #ifdef __ia64
00659     , void *bsp
00660 #endif
00661     )
00662 {
00663     native_main_thread.id = pthread_self();
00664 #if MAINSTACKADDR_AVAILABLE
00665     if (native_main_thread.stack_maxsize) return;
00666     {
00667         void* stackaddr;
00668         size_t size;
00669         if (get_main_stack(&stackaddr, &size) == 0) {
00670             native_main_thread.stack_maxsize = size;
00671             native_main_thread.stack_start = stackaddr;
00672             return;
00673         }
00674     }
00675 #endif
00676 #ifdef STACK_END_ADDRESS
00677     native_main_thread.stack_start = STACK_END_ADDRESS;
00678 #else
00679     if (!native_main_thread.stack_start ||
00680         STACK_UPPER((VALUE *)(void *)&addr,
00681                     native_main_thread.stack_start > addr,
00682                     native_main_thread.stack_start < addr)) {
00683         native_main_thread.stack_start = (VALUE *)addr;
00684     }
00685 #endif
00686 #ifdef __ia64
00687     if (!native_main_thread.register_stack_start ||
00688         (VALUE*)bsp < native_main_thread.register_stack_start) {
00689         native_main_thread.register_stack_start = (VALUE*)bsp;
00690     }
00691 #endif
00692     {
00693 #if defined(HAVE_GETRLIMIT)
00694 #if defined(PTHREAD_STACK_DEFAULT)
00695 # if PTHREAD_STACK_DEFAULT < RUBY_STACK_SPACE*5
00696 #  error "PTHREAD_STACK_DEFAULT is too small"
00697 # endif
00698         size_t size = PTHREAD_STACK_DEFAULT;
00699 #else
00700         size_t size = RUBY_VM_THREAD_VM_STACK_SIZE;
00701 #endif
00702         size_t space;
00703         int pagesize = getpagesize();
00704         struct rlimit rlim;
00705         STACK_GROW_DIR_DETECTION;
00706         if (getrlimit(RLIMIT_STACK, &rlim) == 0) {
00707             size = (size_t)rlim.rlim_cur;
00708         }
00709         addr = native_main_thread.stack_start;
00710         if (IS_STACK_DIR_UPPER()) {
00711             space = ((size_t)((char *)addr + size) / pagesize) * pagesize - (size_t)addr;
00712         }
00713         else {
00714             space = (size_t)addr - ((size_t)((char *)addr - size) / pagesize + 1) * pagesize;
00715         }
00716         native_main_thread.stack_maxsize = space;
00717 #endif
00718     }
00719 
00720     /* If addr is out of range of main-thread stack range estimation,  */
00721     /* it should be on co-routine (alternative stack). [Feature #2294] */
00722     {
00723         void *start, *end;
00724         STACK_GROW_DIR_DETECTION;
00725 
00726         if (IS_STACK_DIR_UPPER()) {
00727             start = native_main_thread.stack_start;
00728             end = (char *)native_main_thread.stack_start + native_main_thread.stack_maxsize;
00729         }
00730         else {
00731             start = (char *)native_main_thread.stack_start - native_main_thread.stack_maxsize;
00732             end = native_main_thread.stack_start;
00733         }
00734 
00735         if ((void *)addr < start || (void *)addr > end) {
00736             /* out of range */
00737             native_main_thread.stack_start = (VALUE *)addr;
00738             native_main_thread.stack_maxsize = 0; /* unknown */
00739         }
00740     }
00741 }
00742 
00743 #define CHECK_ERR(expr) \
00744     {int err = (expr); if (err) {rb_bug_errno(#expr, err);}}
00745 
00746 static int
00747 native_thread_init_stack(rb_thread_t *th)
00748 {
00749     rb_nativethread_id_t curr = pthread_self();
00750 
00751     if (pthread_equal(curr, native_main_thread.id)) {
00752         th->machine.stack_start = native_main_thread.stack_start;
00753         th->machine.stack_maxsize = native_main_thread.stack_maxsize;
00754     }
00755     else {
00756 #ifdef STACKADDR_AVAILABLE
00757         void *start;
00758         size_t size;
00759 
00760         if (get_stack(&start, &size) == 0) {
00761             th->machine.stack_start = start;
00762             th->machine.stack_maxsize = size;
00763         }
00764 #elif defined get_stack_of
00765         if (!th->machine.stack_maxsize) {
00766             native_mutex_lock(&th->interrupt_lock);
00767             native_mutex_unlock(&th->interrupt_lock);
00768         }
00769 #else
00770         rb_raise(rb_eNotImpError, "ruby engine can initialize only in the main thread");
00771 #endif
00772     }
00773 #ifdef __ia64
00774     th->machine.register_stack_start = native_main_thread.register_stack_start;
00775     th->machine.stack_maxsize /= 2;
00776     th->machine.register_stack_maxsize = th->machine.stack_maxsize;
00777 #endif
00778     return 0;
00779 }
00780 
00781 #ifndef __CYGWIN__
00782 #define USE_NATIVE_THREAD_INIT 1
00783 #endif
00784 
00785 static void *
00786 thread_start_func_1(void *th_ptr)
00787 {
00788 #if USE_THREAD_CACHE
00789   thread_start:
00790 #endif
00791     {
00792         rb_thread_t *th = th_ptr;
00793 #if !defined USE_NATIVE_THREAD_INIT
00794         VALUE stack_start;
00795 #endif
00796 
00797 #if defined USE_NATIVE_THREAD_INIT
00798         native_thread_init_stack(th);
00799 #endif
00800         native_thread_init(th);
00801         /* run */
00802 #if defined USE_NATIVE_THREAD_INIT
00803         thread_start_func_2(th, th->machine.stack_start, rb_ia64_bsp());
00804 #else
00805         thread_start_func_2(th, &stack_start, rb_ia64_bsp());
00806 #endif
00807     }
00808 #if USE_THREAD_CACHE
00809     if (1) {
00810         /* cache thread */
00811         rb_thread_t *th;
00812         if ((th = register_cached_thread_and_wait()) != 0) {
00813             th_ptr = (void *)th;
00814             th->thread_id = pthread_self();
00815             goto thread_start;
00816         }
00817     }
00818 #endif
00819     return 0;
00820 }
00821 
00822 struct cached_thread_entry {
00823     volatile rb_thread_t **th_area;
00824     rb_nativethread_cond_t *cond;
00825     struct cached_thread_entry *next;
00826 };
00827 
00828 
00829 #if USE_THREAD_CACHE
00830 static pthread_mutex_t thread_cache_lock = PTHREAD_MUTEX_INITIALIZER;
00831 struct cached_thread_entry *cached_thread_root;
00832 
00833 static rb_thread_t *
00834 register_cached_thread_and_wait(void)
00835 {
00836     rb_nativethread_cond_t cond = { PTHREAD_COND_INITIALIZER, };
00837     volatile rb_thread_t *th_area = 0;
00838     struct timeval tv;
00839     struct timespec ts;
00840     struct cached_thread_entry *entry =
00841       (struct cached_thread_entry *)malloc(sizeof(struct cached_thread_entry));
00842 
00843     if (entry == 0) {
00844         return 0; /* failed -> terminate thread immediately */
00845     }
00846 
00847     gettimeofday(&tv, 0);
00848     ts.tv_sec = tv.tv_sec + 60;
00849     ts.tv_nsec = tv.tv_usec * 1000;
00850 
00851     pthread_mutex_lock(&thread_cache_lock);
00852     {
00853         entry->th_area = &th_area;
00854         entry->cond = &cond;
00855         entry->next = cached_thread_root;
00856         cached_thread_root = entry;
00857 
00858         native_cond_timedwait(&cond, &thread_cache_lock, &ts);
00859 
00860         {
00861             struct cached_thread_entry *e, **prev = &cached_thread_root;
00862 
00863             while ((e = *prev) != 0) {
00864                 if (e == entry) {
00865                     *prev = e->next;
00866                     break;
00867                 }
00868                 prev = &e->next;
00869             }
00870         }
00871 
00872         free(entry); /* ok */
00873         native_cond_destroy(&cond);
00874     }
00875     pthread_mutex_unlock(&thread_cache_lock);
00876 
00877     return (rb_thread_t *)th_area;
00878 }
00879 #endif
00880 
00881 static int
00882 use_cached_thread(rb_thread_t *th)
00883 {
00884     int result = 0;
00885 #if USE_THREAD_CACHE
00886     struct cached_thread_entry *entry;
00887 
00888     if (cached_thread_root) {
00889         pthread_mutex_lock(&thread_cache_lock);
00890         entry = cached_thread_root;
00891         {
00892             if (cached_thread_root) {
00893                 cached_thread_root = entry->next;
00894                 *entry->th_area = th;
00895                 result = 1;
00896             }
00897         }
00898         if (result) {
00899             native_cond_signal(entry->cond);
00900         }
00901         pthread_mutex_unlock(&thread_cache_lock);
00902     }
00903 #endif
00904     return result;
00905 }
00906 
00907 static int
00908 native_thread_create(rb_thread_t *th)
00909 {
00910     int err = 0;
00911 
00912     if (use_cached_thread(th)) {
00913         thread_debug("create (use cached thread): %p\n", (void *)th);
00914     }
00915     else {
00916 #ifdef HAVE_PTHREAD_ATTR_INIT
00917         pthread_attr_t attr;
00918         pthread_attr_t *const attrp = &attr;
00919 #else
00920         pthread_attr_t *const attrp = NULL;
00921 #endif
00922         const size_t stack_size = th->vm->default_params.thread_machine_stack_size;
00923         const size_t space = space_size(stack_size);
00924 
00925         th->machine.stack_maxsize = stack_size - space;
00926 #ifdef __ia64
00927         th->machine.stack_maxsize /= 2;
00928         th->machine.register_stack_maxsize = th->machine.stack_maxsize;
00929 #endif
00930 
00931 #ifdef HAVE_PTHREAD_ATTR_INIT
00932         CHECK_ERR(pthread_attr_init(&attr));
00933 
00934 # ifdef PTHREAD_STACK_MIN
00935         thread_debug("create - stack size: %lu\n", (unsigned long)stack_size);
00936         CHECK_ERR(pthread_attr_setstacksize(&attr, stack_size));
00937 # endif
00938 
00939 # ifdef HAVE_PTHREAD_ATTR_SETINHERITSCHED
00940         CHECK_ERR(pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED));
00941 # endif
00942         CHECK_ERR(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
00943 #endif
00944 #ifdef get_stack_of
00945         native_mutex_lock(&th->interrupt_lock);
00946 #endif
00947         err = pthread_create(&th->thread_id, attrp, thread_start_func_1, th);
00948 #ifdef get_stack_of
00949         if (!err) {
00950             get_stack_of(th->thread_id,
00951                          &th->machine.stack_start,
00952                          &th->machine.stack_maxsize);
00953         }
00954         native_mutex_unlock(&th->interrupt_lock);
00955 #endif
00956         thread_debug("create: %p (%d)\n", (void *)th, err);
00957 #ifdef HAVE_PTHREAD_ATTR_INIT
00958         CHECK_ERR(pthread_attr_destroy(&attr));
00959 #endif
00960     }
00961     return err;
00962 }
00963 
00964 static void
00965 native_thread_join(pthread_t th)
00966 {
00967     int err = pthread_join(th, 0);
00968     if (err) {
00969         rb_raise(rb_eThreadError, "native_thread_join() failed (%d)", err);
00970     }
00971 }
00972 
00973 
00974 #if USE_NATIVE_THREAD_PRIORITY
00975 
00976 static void
00977 native_thread_apply_priority(rb_thread_t *th)
00978 {
00979 #if defined(_POSIX_PRIORITY_SCHEDULING) && (_POSIX_PRIORITY_SCHEDULING > 0)
00980     struct sched_param sp;
00981     int policy;
00982     int priority = 0 - th->priority;
00983     int max, min;
00984     pthread_getschedparam(th->thread_id, &policy, &sp);
00985     max = sched_get_priority_max(policy);
00986     min = sched_get_priority_min(policy);
00987 
00988     if (min > priority) {
00989         priority = min;
00990     }
00991     else if (max < priority) {
00992         priority = max;
00993     }
00994 
00995     sp.sched_priority = priority;
00996     pthread_setschedparam(th->thread_id, policy, &sp);
00997 #else
00998     /* not touched */
00999 #endif
01000 }
01001 
01002 #endif /* USE_NATIVE_THREAD_PRIORITY */
01003 
01004 static int
01005 native_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout, rb_thread_t *th)
01006 {
01007     return rb_fd_select(n, readfds, writefds, exceptfds, timeout);
01008 }
01009 
01010 static void
01011 ubf_pthread_cond_signal(void *ptr)
01012 {
01013     rb_thread_t *th = (rb_thread_t *)ptr;
01014     thread_debug("ubf_pthread_cond_signal (%p)\n", (void *)th);
01015     native_cond_signal(&th->native_thread_data.sleep_cond);
01016 }
01017 
01018 static void
01019 native_sleep(rb_thread_t *th, struct timeval *timeout_tv)
01020 {
01021     struct timespec timeout;
01022     pthread_mutex_t *lock = &th->interrupt_lock;
01023     rb_nativethread_cond_t *cond = &th->native_thread_data.sleep_cond;
01024 
01025     if (timeout_tv) {
01026         struct timespec timeout_rel;
01027 
01028         timeout_rel.tv_sec = timeout_tv->tv_sec;
01029         timeout_rel.tv_nsec = timeout_tv->tv_usec * 1000;
01030 
01031         /* Solaris cond_timedwait() return EINVAL if an argument is greater than
01032          * current_time + 100,000,000.  So cut up to 100,000,000.  This is
01033          * considered as a kind of spurious wakeup.  The caller to native_sleep
01034          * should care about spurious wakeup.
01035          *
01036          * See also [Bug #1341] [ruby-core:29702]
01037          * http://download.oracle.com/docs/cd/E19683-01/816-0216/6m6ngupgv/index.html
01038          */
01039         if (timeout_rel.tv_sec > 100000000) {
01040             timeout_rel.tv_sec = 100000000;
01041             timeout_rel.tv_nsec = 0;
01042         }
01043 
01044         timeout = native_cond_timeout(cond, timeout_rel);
01045     }
01046 
01047     GVL_UNLOCK_BEGIN();
01048     {
01049         pthread_mutex_lock(lock);
01050         th->unblock.func = ubf_pthread_cond_signal;
01051         th->unblock.arg = th;
01052 
01053         if (RUBY_VM_INTERRUPTED(th)) {
01054             /* interrupted.  return immediate */
01055             thread_debug("native_sleep: interrupted before sleep\n");
01056         }
01057         else {
01058             if (!timeout_tv)
01059                 native_cond_wait(cond, lock);
01060             else
01061                 native_cond_timedwait(cond, lock, &timeout);
01062         }
01063         th->unblock.func = 0;
01064         th->unblock.arg = 0;
01065 
01066         pthread_mutex_unlock(lock);
01067     }
01068     GVL_UNLOCK_END();
01069 
01070     thread_debug("native_sleep done\n");
01071 }
01072 
01073 #ifdef USE_SIGNAL_THREAD_LIST
01074 struct signal_thread_list {
01075     rb_thread_t *th;
01076     struct signal_thread_list *prev;
01077     struct signal_thread_list *next;
01078 };
01079 
01080 static struct signal_thread_list signal_thread_list_anchor = {
01081     0, 0, 0,
01082 };
01083 
01084 #define FGLOCK(lock, body) do { \
01085     native_mutex_lock(lock); \
01086     { \
01087         body; \
01088     } \
01089     native_mutex_unlock(lock); \
01090 } while (0)
01091 
01092 #if 0 /* for debug */
01093 static void
01094 print_signal_list(char *str)
01095 {
01096     struct signal_thread_list *list =
01097       signal_thread_list_anchor.next;
01098     thread_debug("list (%s)> ", str);
01099     while (list) {
01100         thread_debug("%p (%p), ", list->th, list->th->thread_id);
01101         list = list->next;
01102     }
01103     thread_debug("\n");
01104 }
01105 #endif
01106 
01107 static void
01108 add_signal_thread_list(rb_thread_t *th)
01109 {
01110     if (!th->native_thread_data.signal_thread_list) {
01111         FGLOCK(&signal_thread_list_lock, {
01112             struct signal_thread_list *list =
01113               malloc(sizeof(struct signal_thread_list));
01114 
01115             if (list == 0) {
01116                 fprintf(stderr, "[FATAL] failed to allocate memory\n");
01117                 exit(EXIT_FAILURE);
01118             }
01119 
01120             list->th = th;
01121 
01122             list->prev = &signal_thread_list_anchor;
01123             list->next = signal_thread_list_anchor.next;
01124             if (list->next) {
01125                 list->next->prev = list;
01126             }
01127             signal_thread_list_anchor.next = list;
01128             th->native_thread_data.signal_thread_list = list;
01129         });
01130     }
01131 }
01132 
01133 static void
01134 remove_signal_thread_list(rb_thread_t *th)
01135 {
01136     if (th->native_thread_data.signal_thread_list) {
01137         FGLOCK(&signal_thread_list_lock, {
01138             struct signal_thread_list *list =
01139               (struct signal_thread_list *)
01140                 th->native_thread_data.signal_thread_list;
01141 
01142             list->prev->next = list->next;
01143             if (list->next) {
01144                 list->next->prev = list->prev;
01145             }
01146             th->native_thread_data.signal_thread_list = 0;
01147             list->th = 0;
01148             free(list); /* ok */
01149         });
01150     }
01151 }
01152 
01153 static void
01154 ubf_select_each(rb_thread_t *th)
01155 {
01156     thread_debug("ubf_select_each (%p)\n", (void *)th->thread_id);
01157     if (th) {
01158         pthread_kill(th->thread_id, SIGVTALRM);
01159     }
01160 }
01161 
01162 static void
01163 ubf_select(void *ptr)
01164 {
01165     rb_thread_t *th = (rb_thread_t *)ptr;
01166     add_signal_thread_list(th);
01167 
01168     /*
01169      * ubf_select_each() doesn't guarantee to wake up the target thread.
01170      * Therefore, we need to activate timer thread when called from
01171      * Thread#kill etc.
01172      * In the other hands, we shouldn't call rb_thread_wakeup_timer_thread()
01173      * if running on timer thread because it may make endless wakeups.
01174      */
01175     if (pthread_self() != timer_thread_id)
01176         rb_thread_wakeup_timer_thread();
01177     ubf_select_each(th);
01178 }
01179 
01180 static void
01181 ping_signal_thread_list(void)
01182 {
01183     if (signal_thread_list_anchor.next) {
01184         FGLOCK(&signal_thread_list_lock, {
01185             struct signal_thread_list *list;
01186 
01187             list = signal_thread_list_anchor.next;
01188             while (list) {
01189                 ubf_select_each(list->th);
01190                 list = list->next;
01191             }
01192         });
01193     }
01194 }
01195 
01196 static int
01197 check_signal_thread_list(void)
01198 {
01199     if (signal_thread_list_anchor.next)
01200         return 1;
01201     else
01202         return 0;
01203 }
01204 #else /* USE_SIGNAL_THREAD_LIST */
01205 #define add_signal_thread_list(th) (void)(th)
01206 #define remove_signal_thread_list(th) (void)(th)
01207 #define ubf_select 0
01208 static void ping_signal_thread_list(void) { return; }
01209 static int check_signal_thread_list(void) { return 0; }
01210 #endif /* USE_SIGNAL_THREAD_LIST */
01211 
01212 #define TT_DEBUG 0
01213 #define WRITE_CONST(fd, str) (void)(write((fd),(str),sizeof(str)-1)<0)
01214 
01215 /* 100ms.  10ms is too small for user level thread scheduling
01216  * on recent Linux (tested on 2.6.35)
01217  */
01218 #define TIME_QUANTUM_USEC (100 * 1000)
01219 
01220 #if USE_SLEEPY_TIMER_THREAD
01221 static int timer_thread_pipe[2] = {-1, -1};
01222 static int timer_thread_pipe_low[2] = {-1, -1}; /* low priority */
01223 static int timer_thread_pipe_owner_process;
01224 
01225 /* only use signal-safe system calls here */
01226 static void
01227 rb_thread_wakeup_timer_thread_fd(int fd)
01228 {
01229     ssize_t result;
01230 
01231     /* already opened */
01232     if (timer_thread_pipe_owner_process == getpid()) {
01233         const char *buff = "!";
01234       retry:
01235         if ((result = write(fd, buff, 1)) <= 0) {
01236             switch (errno) {
01237               case EINTR: goto retry;
01238               case EAGAIN:
01239 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
01240               case EWOULDBLOCK:
01241 #endif
01242                 break;
01243               default:
01244                 rb_async_bug_errno("rb_thread_wakeup_timer_thread - write", errno);
01245             }
01246         }
01247         if (TT_DEBUG) WRITE_CONST(2, "rb_thread_wakeup_timer_thread: write\n");
01248     }
01249     else {
01250         /* ignore wakeup */
01251     }
01252 }
01253 
01254 void
01255 rb_thread_wakeup_timer_thread(void)
01256 {
01257     rb_thread_wakeup_timer_thread_fd(timer_thread_pipe[1]);
01258 }
01259 
01260 static void
01261 rb_thread_wakeup_timer_thread_low(void)
01262 {
01263     rb_thread_wakeup_timer_thread_fd(timer_thread_pipe_low[1]);
01264 }
01265 
01266 /* VM-dependent API is not available for this function */
01267 static void
01268 consume_communication_pipe(int fd)
01269 {
01270 #define CCP_READ_BUFF_SIZE 1024
01271     /* buffer can be shared because no one refers to them. */
01272     static char buff[CCP_READ_BUFF_SIZE];
01273     ssize_t result;
01274 
01275     while (1) {
01276         result = read(fd, buff, sizeof(buff));
01277         if (result == 0) {
01278             return;
01279         }
01280         else if (result < 0) {
01281             switch (errno) {
01282             case EINTR:
01283                 continue; /* retry */
01284             case EAGAIN:
01285                 return;
01286             default:
01287                 rb_async_bug_errno("consume_communication_pipe: read\n", errno);
01288             }
01289         }
01290     }
01291 }
01292 
01293 static void
01294 close_communication_pipe(int pipes[2])
01295 {
01296     if (close(pipes[0]) < 0) {
01297         rb_bug_errno("native_stop_timer_thread - close(ttp[0])", errno);
01298     }
01299     if (close(pipes[1]) < 0) {
01300         rb_bug_errno("native_stop_timer_thread - close(ttp[1])", errno);
01301     }
01302     pipes[0] = pipes[1] = -1;
01303 }
01304 
01305 static void
01306 set_nonblock(int fd)
01307 {
01308     int oflags;
01309     int err;
01310 
01311     oflags = fcntl(fd, F_GETFL);
01312     if (oflags == -1)
01313         rb_sys_fail(0);
01314     oflags |= O_NONBLOCK;
01315     err = fcntl(fd, F_SETFL, oflags);
01316     if (err == -1)
01317         rb_sys_fail(0);
01318 }
01319 
01320 static void
01321 setup_communication_pipe_internal(int pipes[2])
01322 {
01323     int err;
01324 
01325     if (pipes[0] != -1) {
01326         /* close pipe of parent process */
01327         close_communication_pipe(pipes);
01328     }
01329 
01330     err = rb_cloexec_pipe(pipes);
01331     if (err != 0) {
01332         rb_bug_errno("setup_communication_pipe: Failed to create communication pipe for timer thread", errno);
01333     }
01334     rb_update_max_fd(pipes[0]);
01335     rb_update_max_fd(pipes[1]);
01336     set_nonblock(pipes[0]);
01337     set_nonblock(pipes[1]);
01338 }
01339 
01340 /* communication pipe with timer thread and signal handler */
01341 static void
01342 setup_communication_pipe(void)
01343 {
01344     if (timer_thread_pipe_owner_process == getpid()) {
01345         /* already set up. */
01346         return;
01347     }
01348     setup_communication_pipe_internal(timer_thread_pipe);
01349     setup_communication_pipe_internal(timer_thread_pipe_low);
01350 
01351     /* validate pipe on this process */
01352     timer_thread_pipe_owner_process = getpid();
01353 }
01354 
01361 static inline void
01362 timer_thread_sleep(rb_global_vm_lock_t* gvl)
01363 {
01364     int result;
01365     int need_polling;
01366     struct pollfd pollfds[2];
01367 
01368     pollfds[0].fd = timer_thread_pipe[0];
01369     pollfds[0].events = POLLIN;
01370     pollfds[1].fd = timer_thread_pipe_low[0];
01371     pollfds[1].events = POLLIN;
01372 
01373     need_polling = check_signal_thread_list();
01374 
01375     if (gvl->waiting > 0 || need_polling) {
01376         /* polling (TIME_QUANTUM_USEC usec) */
01377         result = poll(pollfds, 1, TIME_QUANTUM_USEC/1000);
01378     }
01379     else {
01380         /* wait (infinite) */
01381         result = poll(pollfds, numberof(pollfds), -1);
01382     }
01383 
01384     if (result == 0) {
01385         /* maybe timeout */
01386     }
01387     else if (result > 0) {
01388         consume_communication_pipe(timer_thread_pipe[0]);
01389         consume_communication_pipe(timer_thread_pipe_low[0]);
01390     }
01391     else { /* result < 0 */
01392         switch (errno) {
01393         case EBADF:
01394         case EINVAL:
01395         case ENOMEM: /* from Linux man */
01396         case EFAULT: /* from FreeBSD man */
01397             rb_async_bug_errno("thread_timer: select", errno);
01398         default:
01399             /* ignore */;
01400         }
01401     }
01402 }
01403 
01404 #else /* USE_SLEEPY_TIMER_THREAD */
01405 # define PER_NANO 1000000000
01406 void rb_thread_wakeup_timer_thread(void) {}
01407 static void rb_thread_wakeup_timer_thread_low(void) {}
01408 
01409 static pthread_mutex_t timer_thread_lock;
01410 static rb_nativethread_cond_t timer_thread_cond;
01411 
01412 static inline void
01413 timer_thread_sleep(rb_global_vm_lock_t* unused)
01414 {
01415     struct timespec ts;
01416     ts.tv_sec = 0;
01417     ts.tv_nsec = TIME_QUANTUM_USEC * 1000;
01418     ts = native_cond_timeout(&timer_thread_cond, ts);
01419 
01420     native_cond_timedwait(&timer_thread_cond, &timer_thread_lock, &ts);
01421 }
01422 #endif /* USE_SLEEPY_TIMER_THREAD */
01423 
01424 #if defined(__linux__) && defined(PR_SET_NAME)
01425 # undef SET_THREAD_NAME
01426 # define SET_THREAD_NAME(name) prctl(PR_SET_NAME, name)
01427 #elif !defined(SET_THREAD_NAME)
01428 # define SET_THREAD_NAME(name) (void)0
01429 #endif
01430 
01431 static void *
01432 thread_timer(void *p)
01433 {
01434     rb_global_vm_lock_t *gvl = (rb_global_vm_lock_t *)p;
01435 
01436     if (TT_DEBUG) WRITE_CONST(2, "start timer thread\n");
01437 
01438     SET_THREAD_NAME("ruby-timer-thr");
01439 
01440 #if !USE_SLEEPY_TIMER_THREAD
01441     native_mutex_initialize(&timer_thread_lock);
01442     native_cond_initialize(&timer_thread_cond, RB_CONDATTR_CLOCK_MONOTONIC);
01443     native_mutex_lock(&timer_thread_lock);
01444 #endif
01445     while (system_working > 0) {
01446 
01447         /* timer function */
01448         ping_signal_thread_list();
01449         timer_thread_function(0);
01450 
01451         if (TT_DEBUG) WRITE_CONST(2, "tick\n");
01452 
01453         /* wait */
01454         timer_thread_sleep(gvl);
01455     }
01456 #if !USE_SLEEPY_TIMER_THREAD
01457     native_mutex_unlock(&timer_thread_lock);
01458     native_cond_destroy(&timer_thread_cond);
01459     native_mutex_destroy(&timer_thread_lock);
01460 #endif
01461 
01462     if (TT_DEBUG) WRITE_CONST(2, "finish timer thread\n");
01463     return NULL;
01464 }
01465 
01466 static void
01467 rb_thread_create_timer_thread(void)
01468 {
01469     if (!timer_thread_id) {
01470         int err;
01471 #ifdef HAVE_PTHREAD_ATTR_INIT
01472         pthread_attr_t attr;
01473 
01474         err = pthread_attr_init(&attr);
01475         if (err != 0) {
01476             fprintf(stderr, "[FATAL] Failed to initialize pthread attr: %s\n", strerror(err));
01477             exit(EXIT_FAILURE);
01478         }
01479 # ifdef PTHREAD_STACK_MIN
01480         {
01481             const size_t min_size = (4096 * 4);
01482             /* Allocate the machine stack for the timer thread
01483              * at least 16KB (4 pages).  FreeBSD 8.2 AMD64 causes
01484              * machine stack overflow only with PTHREAD_STACK_MIN.
01485              */
01486             size_t stack_size = PTHREAD_STACK_MIN; /* may be dynamic, get only once */
01487             if (stack_size < min_size) stack_size = min_size;
01488             if (THREAD_DEBUG) stack_size += BUFSIZ;
01489             pthread_attr_setstacksize(&attr, stack_size);
01490         }
01491 # endif
01492 #endif
01493 
01494 #if USE_SLEEPY_TIMER_THREAD
01495         setup_communication_pipe();
01496 #endif /* USE_SLEEPY_TIMER_THREAD */
01497 
01498         /* create timer thread */
01499         if (timer_thread_id) {
01500             rb_bug("rb_thread_create_timer_thread: Timer thread was already created\n");
01501         }
01502 #ifdef HAVE_PTHREAD_ATTR_INIT
01503         err = pthread_create(&timer_thread_id, &attr, thread_timer, &GET_VM()->gvl);
01504 #else
01505         err = pthread_create(&timer_thread_id, NULL, thread_timer, &GET_VM()->gvl);
01506 #endif
01507         if (err != 0) {
01508             fprintf(stderr, "[FATAL] Failed to create timer thread: %s\n", strerror(err));
01509             exit(EXIT_FAILURE);
01510         }
01511 #ifdef HAVE_PTHREAD_ATTR_INIT
01512         pthread_attr_destroy(&attr);
01513 #endif
01514     }
01515 }
01516 
01517 static int
01518 native_stop_timer_thread(int close_anyway)
01519 {
01520     int stopped;
01521     stopped = --system_working <= 0;
01522 
01523     if (TT_DEBUG) fprintf(stderr, "stop timer thread\n");
01524     if (stopped) {
01525         /* join */
01526         rb_thread_wakeup_timer_thread();
01527         native_thread_join(timer_thread_id);
01528         if (TT_DEBUG) fprintf(stderr, "joined timer thread\n");
01529         timer_thread_id = 0;
01530 
01531         /* close communication pipe */
01532         if (close_anyway) {
01533             /* TODO: Uninstall all signal handlers or mask all signals.
01534              *       This pass is cleaning phase (terminate ruby process).
01535              *       To avoid such race, we skip to close communication
01536              *       pipe.  OS will close it at process termination.
01537              *       It may not good practice, but pragmatic.
01538              *       We remain it is TODO.
01539              */
01540             /* close_communication_pipe(); */
01541         }
01542     }
01543     return stopped;
01544 }
01545 
01546 static void
01547 native_reset_timer_thread(void)
01548 {
01549     if (TT_DEBUG)  fprintf(stderr, "reset timer thread\n");
01550 }
01551 
01552 #ifdef HAVE_SIGALTSTACK
01553 int
01554 ruby_stack_overflowed_p(const rb_thread_t *th, const void *addr)
01555 {
01556     void *base;
01557     size_t size;
01558     const size_t water_mark = 1024 * 1024;
01559     STACK_GROW_DIR_DETECTION;
01560 
01561 #ifdef STACKADDR_AVAILABLE
01562     if (get_stack(&base, &size) == 0) {
01563 # ifdef __APPLE__
01564         if (pthread_equal(th->thread_id, native_main_thread.id)) {
01565             struct rlimit rlim;
01566             if (getrlimit(RLIMIT_STACK, &rlim) == 0 && rlim.rlim_cur > size) {
01567                 size = (size_t)rlim.rlim_cur;
01568             }
01569         }
01570 # endif
01571         base = (char *)base + STACK_DIR_UPPER(+size, -size);
01572     }
01573     else
01574 #endif
01575     if (th) {
01576         size = th->machine.stack_maxsize;
01577         base = (char *)th->machine.stack_start - STACK_DIR_UPPER(0, size);
01578     }
01579     else {
01580         return 0;
01581     }
01582     size /= RUBY_STACK_SPACE_RATIO;
01583     if (size > water_mark) size = water_mark;
01584     if (IS_STACK_DIR_UPPER()) {
01585         if (size > ~(size_t)base+1) size = ~(size_t)base+1;
01586         if (addr > base && addr <= (void *)((char *)base + size)) return 1;
01587     }
01588     else {
01589         if (size > (size_t)base) size = (size_t)base;
01590         if (addr > (void *)((char *)base - size) && addr <= base) return 1;
01591     }
01592     return 0;
01593 }
01594 #endif
01595 
01596 int
01597 rb_reserved_fd_p(int fd)
01598 {
01599 #if USE_SLEEPY_TIMER_THREAD
01600     if (fd == timer_thread_pipe[0]     ||
01601         fd == timer_thread_pipe[1]     ||
01602         fd == timer_thread_pipe_low[0] ||
01603         fd == timer_thread_pipe_low[1]) {
01604         return 1;
01605     }
01606     else {
01607         return 0;
01608     }
01609 #else
01610     return 0;
01611 #endif
01612 }
01613 
01614 rb_nativethread_id_t
01615 rb_nativethread_self(void)
01616 {
01617     return pthread_self();
01618 }
01619 
01620 #endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */
01621 

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7