00001
00002
00003
00004
00005
00006
00007
00008
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
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
00076
00077
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
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
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
00299
00300
00301
00302
00303
00304
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
00347
00348
00349
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
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
00502
00503
00504
00505 #undef PTHREAD_STACK_MIN
00506
00507 #define HAVE_PTHREAD_ATTR_GET_NP 1
00508 #undef HAVE_PTHREAD_ATTR_GETSTACK
00509
00510
00511
00512
00513
00514
00515 #define pthread_attr_get_np(thid, attr) 0
00516
00517
00518
00519
00520
00521
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
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
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
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)
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
00596 CHECK_ERR(thr_stksegment(&stk));
00597 # else
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
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 ®, ®siz));
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,
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
00653
00654
00655
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
00721
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
00737 native_main_thread.stack_start = (VALUE *)addr;
00738 native_main_thread.stack_maxsize = 0;
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
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
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;
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);
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
00999 #endif
01000 }
01001
01002 #endif
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
01032
01033
01034
01035
01036
01037
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
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
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);
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
01170
01171
01172
01173
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
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
01211
01212 #define TT_DEBUG 0
01213 #define WRITE_CONST(fd, str) (void)(write((fd),(str),sizeof(str)-1)<0)
01214
01215
01216
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};
01223 static int timer_thread_pipe_owner_process;
01224
01225
01226 static void
01227 rb_thread_wakeup_timer_thread_fd(int fd)
01228 {
01229 ssize_t result;
01230
01231
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
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
01267 static void
01268 consume_communication_pipe(int fd)
01269 {
01270 #define CCP_READ_BUFF_SIZE 1024
01271
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;
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
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
01341 static void
01342 setup_communication_pipe(void)
01343 {
01344 if (timer_thread_pipe_owner_process == getpid()) {
01345
01346 return;
01347 }
01348 setup_communication_pipe_internal(timer_thread_pipe);
01349 setup_communication_pipe_internal(timer_thread_pipe_low);
01350
01351
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
01377 result = poll(pollfds, 1, TIME_QUANTUM_USEC/1000);
01378 }
01379 else {
01380
01381 result = poll(pollfds, numberof(pollfds), -1);
01382 }
01383
01384 if (result == 0) {
01385
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 {
01392 switch (errno) {
01393 case EBADF:
01394 case EINVAL:
01395 case ENOMEM:
01396 case EFAULT:
01397 rb_async_bug_errno("thread_timer: select", errno);
01398 default:
01399 ;
01400 }
01401 }
01402 }
01403
01404 #else
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
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
01448 ping_signal_thread_list();
01449 timer_thread_function(0);
01450
01451 if (TT_DEBUG) WRITE_CONST(2, "tick\n");
01452
01453
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
01483
01484
01485
01486 size_t stack_size = PTHREAD_STACK_MIN;
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
01497
01498
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
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
01532 if (close_anyway) {
01533
01534
01535
01536
01537
01538
01539
01540
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
01621