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
00028 static void native_mutex_lock(pthread_mutex_t *lock);
00029 static void native_mutex_unlock(pthread_mutex_t *lock);
00030 static int native_mutex_trylock(pthread_mutex_t *lock);
00031 static void native_mutex_initialize(pthread_mutex_t *lock);
00032 static void native_mutex_destroy(pthread_mutex_t *lock);
00033 static void native_cond_signal(rb_thread_cond_t *cond);
00034 static void native_cond_broadcast(rb_thread_cond_t *cond);
00035 static void native_cond_wait(rb_thread_cond_t *cond, pthread_mutex_t *mutex);
00036 static void native_cond_initialize(rb_thread_cond_t *cond, int flags);
00037 static void native_cond_destroy(rb_thread_cond_t *cond);
00038 static pthread_t timer_thread_id;
00039
00040 #define RB_CONDATTR_CLOCK_MONOTONIC 1
00041
00042 #if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(HAVE_CLOCKID_T) && \
00043 defined(CLOCK_REALTIME) && defined(CLOCK_MONOTONIC) && defined(HAVE_CLOCK_GETTIME)
00044 #define USE_MONOTONIC_COND 1
00045 #else
00046 #define USE_MONOTONIC_COND 0
00047 #endif
00048
00049 static void
00050 gvl_acquire_common(rb_vm_t *vm)
00051 {
00052 if (vm->gvl.acquired) {
00053
00054 vm->gvl.waiting++;
00055 if (vm->gvl.waiting == 1) {
00056
00057 rb_thread_wakeup_timer_thread();
00058 }
00059
00060 while (vm->gvl.acquired) {
00061 native_cond_wait(&vm->gvl.cond, &vm->gvl.lock);
00062 }
00063
00064 vm->gvl.waiting--;
00065
00066 if (vm->gvl.need_yield) {
00067 vm->gvl.need_yield = 0;
00068 native_cond_signal(&vm->gvl.switch_cond);
00069 }
00070 }
00071
00072 vm->gvl.acquired = 1;
00073 }
00074
00075 static void
00076 gvl_acquire(rb_vm_t *vm, rb_thread_t *th)
00077 {
00078 native_mutex_lock(&vm->gvl.lock);
00079 gvl_acquire_common(vm);
00080 native_mutex_unlock(&vm->gvl.lock);
00081 }
00082
00083 static void
00084 gvl_release_common(rb_vm_t *vm)
00085 {
00086 vm->gvl.acquired = 0;
00087 if (vm->gvl.waiting > 0)
00088 native_cond_signal(&vm->gvl.cond);
00089 }
00090
00091 static void
00092 gvl_release(rb_vm_t *vm)
00093 {
00094 native_mutex_lock(&vm->gvl.lock);
00095 gvl_release_common(vm);
00096 native_mutex_unlock(&vm->gvl.lock);
00097 }
00098
00099 static void
00100 gvl_yield(rb_vm_t *vm, rb_thread_t *th)
00101 {
00102 native_mutex_lock(&vm->gvl.lock);
00103
00104 gvl_release_common(vm);
00105
00106
00107 if (UNLIKELY(vm->gvl.wait_yield)) {
00108 while (vm->gvl.wait_yield)
00109 native_cond_wait(&vm->gvl.switch_wait_cond, &vm->gvl.lock);
00110 goto acquire;
00111 }
00112
00113 if (vm->gvl.waiting > 0) {
00114
00115 vm->gvl.need_yield = 1;
00116 vm->gvl.wait_yield = 1;
00117 while (vm->gvl.need_yield)
00118 native_cond_wait(&vm->gvl.switch_cond, &vm->gvl.lock);
00119 vm->gvl.wait_yield = 0;
00120 }
00121 else {
00122 native_mutex_unlock(&vm->gvl.lock);
00123 sched_yield();
00124 native_mutex_lock(&vm->gvl.lock);
00125 }
00126
00127 native_cond_broadcast(&vm->gvl.switch_wait_cond);
00128 acquire:
00129 gvl_acquire_common(vm);
00130 native_mutex_unlock(&vm->gvl.lock);
00131 }
00132
00133 static void
00134 gvl_init(rb_vm_t *vm)
00135 {
00136 native_mutex_initialize(&vm->gvl.lock);
00137 native_cond_initialize(&vm->gvl.cond, RB_CONDATTR_CLOCK_MONOTONIC);
00138 native_cond_initialize(&vm->gvl.switch_cond, RB_CONDATTR_CLOCK_MONOTONIC);
00139 native_cond_initialize(&vm->gvl.switch_wait_cond, RB_CONDATTR_CLOCK_MONOTONIC);
00140 vm->gvl.acquired = 0;
00141 vm->gvl.waiting = 0;
00142 vm->gvl.need_yield = 0;
00143 }
00144
00145 static void
00146 gvl_destroy(rb_vm_t *vm)
00147 {
00148 native_cond_destroy(&vm->gvl.switch_wait_cond);
00149 native_cond_destroy(&vm->gvl.switch_cond);
00150 native_cond_destroy(&vm->gvl.cond);
00151 native_mutex_destroy(&vm->gvl.lock);
00152 }
00153
00154 static void
00155 gvl_atfork(rb_vm_t *vm)
00156 {
00157 gvl_init(vm);
00158 gvl_acquire(vm, GET_THREAD());
00159 }
00160
00161 #define NATIVE_MUTEX_LOCK_DEBUG 0
00162
00163 static void
00164 mutex_debug(const char *msg, pthread_mutex_t *lock)
00165 {
00166 if (NATIVE_MUTEX_LOCK_DEBUG) {
00167 int r;
00168 static pthread_mutex_t dbglock = PTHREAD_MUTEX_INITIALIZER;
00169
00170 if ((r = pthread_mutex_lock(&dbglock)) != 0) {exit(EXIT_FAILURE);}
00171 fprintf(stdout, "%s: %p\n", msg, (void *)lock);
00172 if ((r = pthread_mutex_unlock(&dbglock)) != 0) {exit(EXIT_FAILURE);}
00173 }
00174 }
00175
00176 static void
00177 native_mutex_lock(pthread_mutex_t *lock)
00178 {
00179 int r;
00180 mutex_debug("lock", lock);
00181 if ((r = pthread_mutex_lock(lock)) != 0) {
00182 rb_bug_errno("pthread_mutex_lock", r);
00183 }
00184 }
00185
00186 static void
00187 native_mutex_unlock(pthread_mutex_t *lock)
00188 {
00189 int r;
00190 mutex_debug("unlock", lock);
00191 if ((r = pthread_mutex_unlock(lock)) != 0) {
00192 rb_bug_errno("pthread_mutex_unlock", r);
00193 }
00194 }
00195
00196 static inline int
00197 native_mutex_trylock(pthread_mutex_t *lock)
00198 {
00199 int r;
00200 mutex_debug("trylock", lock);
00201 if ((r = pthread_mutex_trylock(lock)) != 0) {
00202 if (r == EBUSY) {
00203 return EBUSY;
00204 }
00205 else {
00206 rb_bug_errno("pthread_mutex_trylock", r);
00207 }
00208 }
00209 return 0;
00210 }
00211
00212 static void
00213 native_mutex_initialize(pthread_mutex_t *lock)
00214 {
00215 int r = pthread_mutex_init(lock, 0);
00216 mutex_debug("init", lock);
00217 if (r != 0) {
00218 rb_bug_errno("pthread_mutex_init", r);
00219 }
00220 }
00221
00222 static void
00223 native_mutex_destroy(pthread_mutex_t *lock)
00224 {
00225 int r = pthread_mutex_destroy(lock);
00226 mutex_debug("destroy", lock);
00227 if (r != 0) {
00228 rb_bug_errno("pthread_mutex_destroy", r);
00229 }
00230 }
00231
00232 static void
00233 native_cond_initialize(rb_thread_cond_t *cond, int flags)
00234 {
00235 int r;
00236 pthread_condattr_t attr;
00237
00238 pthread_condattr_init(&attr);
00239
00240 #if USE_MONOTONIC_COND
00241 cond->clockid = CLOCK_REALTIME;
00242 if (flags & RB_CONDATTR_CLOCK_MONOTONIC) {
00243 r = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
00244 if (r == 0) {
00245 cond->clockid = CLOCK_MONOTONIC;
00246 }
00247 }
00248 #endif
00249
00250 r = pthread_cond_init(&cond->cond, &attr);
00251 pthread_condattr_destroy(&attr);
00252 if (r != 0) {
00253 rb_bug_errno("pthread_cond_init", r);
00254 }
00255
00256 return;
00257 }
00258
00259 static void
00260 native_cond_destroy(rb_thread_cond_t *cond)
00261 {
00262 int r = pthread_cond_destroy(&cond->cond);
00263 if (r != 0) {
00264 rb_bug_errno("pthread_cond_destroy", r);
00265 }
00266 }
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278 static void
00279 native_cond_signal(rb_thread_cond_t *cond)
00280 {
00281 int r;
00282 do {
00283 r = pthread_cond_signal(&cond->cond);
00284 } while (r == EAGAIN);
00285 if (r != 0) {
00286 rb_bug_errno("pthread_cond_signal", r);
00287 }
00288 }
00289
00290 static void
00291 native_cond_broadcast(rb_thread_cond_t *cond)
00292 {
00293 int r;
00294 do {
00295 r = pthread_cond_broadcast(&cond->cond);
00296 } while (r == EAGAIN);
00297 if (r != 0) {
00298 rb_bug_errno("native_cond_broadcast", r);
00299 }
00300 }
00301
00302 static void
00303 native_cond_wait(rb_thread_cond_t *cond, pthread_mutex_t *mutex)
00304 {
00305 int r = pthread_cond_wait(&cond->cond, mutex);
00306 if (r != 0) {
00307 rb_bug_errno("pthread_cond_wait", r);
00308 }
00309 }
00310
00311 static int
00312 native_cond_timedwait(rb_thread_cond_t *cond, pthread_mutex_t *mutex, struct timespec *ts)
00313 {
00314 int r;
00315
00316
00317
00318
00319
00320
00321
00322 do {
00323 r = pthread_cond_timedwait(&cond->cond, mutex, ts);
00324 } while (r == EINTR);
00325
00326 if (r != 0 && r != ETIMEDOUT) {
00327 rb_bug_errno("pthread_cond_timedwait", r);
00328 }
00329
00330 return r;
00331 }
00332
00333 #if SIZEOF_TIME_T == SIZEOF_LONG
00334 typedef unsigned long unsigned_time_t;
00335 #elif SIZEOF_TIME_T == SIZEOF_INT
00336 typedef unsigned int unsigned_time_t;
00337 #elif SIZEOF_TIME_T == SIZEOF_LONG_LONG
00338 typedef unsigned LONG_LONG unsigned_time_t;
00339 #else
00340 # error cannot find integer type which size is same as time_t.
00341 #endif
00342
00343 #define TIMET_MAX (~(time_t)0 <= 0 ? (time_t)((~(unsigned_time_t)0) >> 1) : (time_t)(~(unsigned_time_t)0))
00344
00345 static struct timespec
00346 native_cond_timeout(rb_thread_cond_t *cond, struct timespec timeout_rel)
00347 {
00348 int ret;
00349 struct timeval tv;
00350 struct timespec timeout;
00351 struct timespec now;
00352
00353 #if USE_MONOTONIC_COND
00354 if (cond->clockid == CLOCK_MONOTONIC) {
00355 ret = clock_gettime(cond->clockid, &now);
00356 if (ret != 0)
00357 rb_sys_fail("clock_gettime()");
00358 goto out;
00359 }
00360
00361 if (cond->clockid != CLOCK_REALTIME)
00362 rb_bug("unsupported clockid %d", cond->clockid);
00363 #endif
00364
00365 ret = gettimeofday(&tv, 0);
00366 if (ret != 0)
00367 rb_sys_fail(0);
00368 now.tv_sec = tv.tv_sec;
00369 now.tv_nsec = tv.tv_usec * 1000;
00370
00371 #if USE_MONOTONIC_COND
00372 out:
00373 #endif
00374 timeout.tv_sec = now.tv_sec;
00375 timeout.tv_nsec = now.tv_nsec;
00376 timeout.tv_sec += timeout_rel.tv_sec;
00377 timeout.tv_nsec += timeout_rel.tv_nsec;
00378
00379 if (timeout.tv_nsec >= 1000*1000*1000) {
00380 timeout.tv_sec++;
00381 timeout.tv_nsec -= 1000*1000*1000;
00382 }
00383
00384 if (timeout.tv_sec < now.tv_sec)
00385 timeout.tv_sec = TIMET_MAX;
00386
00387 return timeout;
00388 }
00389
00390 #define native_cleanup_push pthread_cleanup_push
00391 #define native_cleanup_pop pthread_cleanup_pop
00392 #ifdef HAVE_SCHED_YIELD
00393 #define native_thread_yield() (void)sched_yield()
00394 #else
00395 #define native_thread_yield() ((void)0)
00396 #endif
00397
00398 #if defined(SIGVTALRM) && !defined(__CYGWIN__) && !defined(__SYMBIAN32__)
00399 #define USE_SIGNAL_THREAD_LIST 1
00400 #endif
00401 #ifdef USE_SIGNAL_THREAD_LIST
00402 static void add_signal_thread_list(rb_thread_t *th);
00403 static void remove_signal_thread_list(rb_thread_t *th);
00404 static rb_thread_lock_t signal_thread_list_lock;
00405 #endif
00406
00407 static pthread_key_t ruby_native_thread_key;
00408
00409 static void
00410 null_func(int i)
00411 {
00412
00413 }
00414
00415 static rb_thread_t *
00416 ruby_thread_from_native(void)
00417 {
00418 return pthread_getspecific(ruby_native_thread_key);
00419 }
00420
00421 static int
00422 ruby_thread_set_native(rb_thread_t *th)
00423 {
00424 return pthread_setspecific(ruby_native_thread_key, th) == 0;
00425 }
00426
00427 static void native_thread_init(rb_thread_t *th);
00428
00429 void
00430 Init_native_thread(void)
00431 {
00432 rb_thread_t *th = GET_THREAD();
00433
00434 pthread_key_create(&ruby_native_thread_key, NULL);
00435 th->thread_id = pthread_self();
00436 native_thread_init(th);
00437 #ifdef USE_SIGNAL_THREAD_LIST
00438 native_mutex_initialize(&signal_thread_list_lock);
00439 #endif
00440 posix_signal(SIGVTALRM, null_func);
00441 }
00442
00443 static void
00444 native_thread_init(rb_thread_t *th)
00445 {
00446 native_cond_initialize(&th->native_thread_data.sleep_cond, RB_CONDATTR_CLOCK_MONOTONIC);
00447 ruby_thread_set_native(th);
00448 }
00449
00450 static void
00451 native_thread_destroy(rb_thread_t *th)
00452 {
00453 native_cond_destroy(&th->native_thread_data.sleep_cond);
00454 }
00455
00456 #define USE_THREAD_CACHE 0
00457
00458 #if USE_THREAD_CACHE
00459 static rb_thread_t *register_cached_thread_and_wait(void);
00460 #endif
00461
00462 #if defined HAVE_PTHREAD_GETATTR_NP || defined HAVE_PTHREAD_ATTR_GET_NP
00463 #define STACKADDR_AVAILABLE 1
00464 #elif defined HAVE_PTHREAD_GET_STACKADDR_NP && defined HAVE_PTHREAD_GET_STACKSIZE_NP
00465 #define STACKADDR_AVAILABLE 1
00466 #elif defined HAVE_THR_STKSEGMENT || defined HAVE_PTHREAD_STACKSEG_NP
00467 #define STACKADDR_AVAILABLE 1
00468 #elif defined HAVE_PTHREAD_GETTHRDS_NP
00469 #define STACKADDR_AVAILABLE 1
00470 #endif
00471
00472 #ifdef STACKADDR_AVAILABLE
00473
00474
00475
00476 static int
00477 get_stack(void **addr, size_t *size)
00478 {
00479 #define CHECK_ERR(expr) \
00480 {int err = (expr); if (err) return err;}
00481 #ifdef HAVE_PTHREAD_GETATTR_NP
00482 pthread_attr_t attr;
00483 size_t guard = 0;
00484 STACK_GROW_DIR_DETECTION;
00485 CHECK_ERR(pthread_getattr_np(pthread_self(), &attr));
00486 # ifdef HAVE_PTHREAD_ATTR_GETSTACK
00487 CHECK_ERR(pthread_attr_getstack(&attr, addr, size));
00488 STACK_DIR_UPPER((void)0, (void)(*addr = (char *)*addr + *size));
00489 # else
00490 CHECK_ERR(pthread_attr_getstackaddr(&attr, addr));
00491 CHECK_ERR(pthread_attr_getstacksize(&attr, size));
00492 # endif
00493 CHECK_ERR(pthread_attr_getguardsize(&attr, &guard));
00494 *size -= guard;
00495 pthread_attr_destroy(&attr);
00496 #elif defined HAVE_PTHREAD_ATTR_GET_NP
00497 pthread_attr_t attr;
00498 CHECK_ERR(pthread_attr_init(&attr));
00499 CHECK_ERR(pthread_attr_get_np(pthread_self(), &attr));
00500 # ifdef HAVE_PTHREAD_ATTR_GETSTACK
00501 CHECK_ERR(pthread_attr_getstack(&attr, addr, size));
00502 STACK_DIR_UPPER((void)0, (void)(*addr = (char *)*addr + *size));
00503 # else
00504 CHECK_ERR(pthread_attr_getstackaddr(&attr, addr));
00505 CHECK_ERR(pthread_attr_getstacksize(&attr, size));
00506 STACK_DIR_UPPER((void)0, (void)(*addr = (char *)*addr + *size));
00507 # endif
00508 pthread_attr_destroy(&attr);
00509 #elif (defined HAVE_PTHREAD_GET_STACKADDR_NP && defined HAVE_PTHREAD_GET_STACKSIZE_NP)
00510 pthread_t th = pthread_self();
00511 *addr = pthread_get_stackaddr_np(th);
00512 *size = pthread_get_stacksize_np(th);
00513 #elif defined HAVE_THR_STKSEGMENT || defined HAVE_PTHREAD_STACKSEG_NP
00514 stack_t stk;
00515 # if defined HAVE_THR_STKSEGMENT
00516 CHECK_ERR(thr_stksegment(&stk));
00517 # else
00518 CHECK_ERR(pthread_stackseg_np(pthread_self(), &stk));
00519 # endif
00520 *addr = stk.ss_sp;
00521 *size = stk.ss_size;
00522 #elif defined HAVE_PTHREAD_GETTHRDS_NP
00523 pthread_t th = pthread_self();
00524 struct __pthrdsinfo thinfo;
00525 char reg[256];
00526 int regsiz=sizeof(reg);
00527 CHECK_ERR(pthread_getthrds_np(&th, PTHRDSINFO_QUERY_ALL,
00528 &thinfo, sizeof(thinfo),
00529 ®, ®siz));
00530 *addr = thinfo.__pi_stackaddr;
00531 *size = thinfo.__pi_stacksize;
00532 STACK_DIR_UPPER((void)0, (void)(*addr = (char *)*addr + *size));
00533 #else
00534 #error STACKADDR_AVAILABLE is defined but not implemented.
00535 #endif
00536 return 0;
00537 #undef CHECK_ERR
00538 }
00539 #endif
00540
00541 static struct {
00542 rb_thread_id_t id;
00543 size_t stack_maxsize;
00544 VALUE *stack_start;
00545 #ifdef __ia64
00546 VALUE *register_stack_start;
00547 #endif
00548 } native_main_thread;
00549
00550 #ifdef STACK_END_ADDRESS
00551 extern void *STACK_END_ADDRESS;
00552 #endif
00553
00554 #undef ruby_init_stack
00555 void
00556 ruby_init_stack(volatile VALUE *addr
00557 #ifdef __ia64
00558 , void *bsp
00559 #endif
00560 )
00561 {
00562 native_main_thread.id = pthread_self();
00563 #ifdef STACK_END_ADDRESS
00564 native_main_thread.stack_start = STACK_END_ADDRESS;
00565 #else
00566 if (!native_main_thread.stack_start ||
00567 STACK_UPPER((VALUE *)(void *)&addr,
00568 native_main_thread.stack_start > addr,
00569 native_main_thread.stack_start < addr)) {
00570 native_main_thread.stack_start = (VALUE *)addr;
00571 }
00572 #endif
00573 #ifdef __ia64
00574 if (!native_main_thread.register_stack_start ||
00575 (VALUE*)bsp < native_main_thread.register_stack_start) {
00576 native_main_thread.register_stack_start = (VALUE*)bsp;
00577 }
00578 #endif
00579 {
00580 size_t size = 0;
00581 size_t space = 0;
00582 #if defined(STACKADDR_AVAILABLE)
00583 void* stackaddr;
00584 STACK_GROW_DIR_DETECTION;
00585 get_stack(&stackaddr, &size);
00586 space = STACK_DIR_UPPER((char *)addr - (char *)stackaddr, (char *)stackaddr - (char *)addr);
00587 #elif defined(HAVE_GETRLIMIT)
00588 struct rlimit rlim;
00589 if (getrlimit(RLIMIT_STACK, &rlim) == 0) {
00590 size = (size_t)rlim.rlim_cur;
00591 }
00592 space = size > 5 * 1024 * 1024 ? 1024 * 1024 : size / 5;
00593 #endif
00594 native_main_thread.stack_maxsize = size - space;
00595 }
00596 }
00597
00598 #define CHECK_ERR(expr) \
00599 {int err = (expr); if (err) {rb_bug_errno(#expr, err);}}
00600
00601 static int
00602 native_thread_init_stack(rb_thread_t *th)
00603 {
00604 rb_thread_id_t curr = pthread_self();
00605
00606 if (pthread_equal(curr, native_main_thread.id)) {
00607 th->machine_stack_start = native_main_thread.stack_start;
00608 th->machine_stack_maxsize = native_main_thread.stack_maxsize;
00609 }
00610 else {
00611 #ifdef STACKADDR_AVAILABLE
00612 void *start;
00613 size_t size;
00614
00615 if (get_stack(&start, &size) == 0) {
00616 th->machine_stack_start = start;
00617 th->machine_stack_maxsize = size;
00618 }
00619 #else
00620 rb_raise(rb_eNotImpError, "ruby engine can initialize only in the main thread");
00621 #endif
00622 }
00623 #ifdef __ia64
00624 th->machine_register_stack_start = native_main_thread.register_stack_start;
00625 th->machine_stack_maxsize /= 2;
00626 th->machine_register_stack_maxsize = th->machine_stack_maxsize;
00627 #endif
00628 return 0;
00629 }
00630
00631 #ifndef __CYGWIN__
00632 #define USE_NATIVE_THREAD_INIT 1
00633 #endif
00634
00635 static void *
00636 thread_start_func_1(void *th_ptr)
00637 {
00638 #if USE_THREAD_CACHE
00639 thread_start:
00640 #endif
00641 {
00642 rb_thread_t *th = th_ptr;
00643 #if !defined USE_NATIVE_THREAD_INIT
00644 VALUE stack_start;
00645 #endif
00646
00647 #if defined USE_NATIVE_THREAD_INIT
00648 native_thread_init_stack(th);
00649 #endif
00650 native_thread_init(th);
00651
00652 #if defined USE_NATIVE_THREAD_INIT
00653 thread_start_func_2(th, th->machine_stack_start, rb_ia64_bsp());
00654 #else
00655 thread_start_func_2(th, &stack_start, rb_ia64_bsp());
00656 #endif
00657 }
00658 #if USE_THREAD_CACHE
00659 if (1) {
00660
00661 rb_thread_t *th;
00662 if ((th = register_cached_thread_and_wait()) != 0) {
00663 th_ptr = (void *)th;
00664 th->thread_id = pthread_self();
00665 goto thread_start;
00666 }
00667 }
00668 #endif
00669 return 0;
00670 }
00671
00672 struct cached_thread_entry {
00673 volatile rb_thread_t **th_area;
00674 rb_thread_cond_t *cond;
00675 struct cached_thread_entry *next;
00676 };
00677
00678
00679 #if USE_THREAD_CACHE
00680 static pthread_mutex_t thread_cache_lock = PTHREAD_MUTEX_INITIALIZER;
00681 struct cached_thread_entry *cached_thread_root;
00682
00683 static rb_thread_t *
00684 register_cached_thread_and_wait(void)
00685 {
00686 rb_thread_cond_t cond = { PTHREAD_COND_INITIALIZER, };
00687 volatile rb_thread_t *th_area = 0;
00688 struct cached_thread_entry *entry =
00689 (struct cached_thread_entry *)malloc(sizeof(struct cached_thread_entry));
00690
00691 struct timeval tv;
00692 struct timespec ts;
00693 gettimeofday(&tv, 0);
00694 ts.tv_sec = tv.tv_sec + 60;
00695 ts.tv_nsec = tv.tv_usec * 1000;
00696
00697 pthread_mutex_lock(&thread_cache_lock);
00698 {
00699 entry->th_area = &th_area;
00700 entry->cond = &cond;
00701 entry->next = cached_thread_root;
00702 cached_thread_root = entry;
00703
00704 native_cond_timedwait(&cond, &thread_cache_lock, &ts);
00705
00706 {
00707 struct cached_thread_entry *e = cached_thread_root;
00708 struct cached_thread_entry *prev = cached_thread_root;
00709
00710 while (e) {
00711 if (e == entry) {
00712 if (prev == cached_thread_root) {
00713 cached_thread_root = e->next;
00714 }
00715 else {
00716 prev->next = e->next;
00717 }
00718 break;
00719 }
00720 prev = e;
00721 e = e->next;
00722 }
00723 }
00724
00725 free(entry);
00726 native_cond_destroy(&cond);
00727 }
00728 pthread_mutex_unlock(&thread_cache_lock);
00729
00730 return (rb_thread_t *)th_area;
00731 }
00732 #endif
00733
00734 static int
00735 use_cached_thread(rb_thread_t *th)
00736 {
00737 int result = 0;
00738 #if USE_THREAD_CACHE
00739 struct cached_thread_entry *entry;
00740
00741 if (cached_thread_root) {
00742 pthread_mutex_lock(&thread_cache_lock);
00743 entry = cached_thread_root;
00744 {
00745 if (cached_thread_root) {
00746 cached_thread_root = entry->next;
00747 *entry->th_area = th;
00748 result = 1;
00749 }
00750 }
00751 if (result) {
00752 native_cond_signal(entry->cond);
00753 }
00754 pthread_mutex_unlock(&thread_cache_lock);
00755 }
00756 #endif
00757 return result;
00758 }
00759
00760 enum {
00761 #ifdef __SYMBIAN32__
00762 RUBY_STACK_MIN_LIMIT = 64 * 1024,
00763 #else
00764 RUBY_STACK_MIN_LIMIT = 512 * 1024,
00765 #endif
00766 RUBY_STACK_SPACE_LIMIT = 1024 * 1024
00767 };
00768
00769 #ifdef PTHREAD_STACK_MIN
00770 #define RUBY_STACK_MIN ((RUBY_STACK_MIN_LIMIT < PTHREAD_STACK_MIN) ? \
00771 PTHREAD_STACK_MIN * 2 : RUBY_STACK_MIN_LIMIT)
00772 #else
00773 #define RUBY_STACK_MIN (RUBY_STACK_MIN_LIMIT)
00774 #endif
00775 #define RUBY_STACK_SPACE (RUBY_STACK_MIN/5 > RUBY_STACK_SPACE_LIMIT ? \
00776 RUBY_STACK_SPACE_LIMIT : RUBY_STACK_MIN/5)
00777
00778 static int
00779 native_thread_create(rb_thread_t *th)
00780 {
00781 int err = 0;
00782
00783 if (use_cached_thread(th)) {
00784 thread_debug("create (use cached thread): %p\n", (void *)th);
00785 }
00786 else {
00787 pthread_attr_t attr;
00788 const size_t stack_size = RUBY_STACK_MIN;
00789 const size_t space = RUBY_STACK_SPACE;
00790
00791 th->machine_stack_maxsize = stack_size - space;
00792 #ifdef __ia64
00793 th->machine_stack_maxsize /= 2;
00794 th->machine_register_stack_maxsize = th->machine_stack_maxsize;
00795 #endif
00796
00797 CHECK_ERR(pthread_attr_init(&attr));
00798
00799 #ifdef PTHREAD_STACK_MIN
00800 thread_debug("create - stack size: %lu\n", (unsigned long)stack_size);
00801 CHECK_ERR(pthread_attr_setstacksize(&attr, stack_size));
00802 #endif
00803
00804 #ifdef HAVE_PTHREAD_ATTR_SETINHERITSCHED
00805 CHECK_ERR(pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED));
00806 #endif
00807 CHECK_ERR(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
00808
00809 err = pthread_create(&th->thread_id, &attr, thread_start_func_1, th);
00810 thread_debug("create: %p (%d)\n", (void *)th, err);
00811 CHECK_ERR(pthread_attr_destroy(&attr));
00812 }
00813 return err;
00814 }
00815
00816 static void
00817 native_thread_join(pthread_t th)
00818 {
00819 int err = pthread_join(th, 0);
00820 if (err) {
00821 rb_raise(rb_eThreadError, "native_thread_join() failed (%d)", err);
00822 }
00823 }
00824
00825
00826 #if USE_NATIVE_THREAD_PRIORITY
00827
00828 static void
00829 native_thread_apply_priority(rb_thread_t *th)
00830 {
00831 #if defined(_POSIX_PRIORITY_SCHEDULING) && (_POSIX_PRIORITY_SCHEDULING > 0)
00832 struct sched_param sp;
00833 int policy;
00834 int priority = 0 - th->priority;
00835 int max, min;
00836 pthread_getschedparam(th->thread_id, &policy, &sp);
00837 max = sched_get_priority_max(policy);
00838 min = sched_get_priority_min(policy);
00839
00840 if (min > priority) {
00841 priority = min;
00842 }
00843 else if (max < priority) {
00844 priority = max;
00845 }
00846
00847 sp.sched_priority = priority;
00848 pthread_setschedparam(th->thread_id, policy, &sp);
00849 #else
00850
00851 #endif
00852 }
00853
00854 #endif
00855
00856 static void
00857 ubf_pthread_cond_signal(void *ptr)
00858 {
00859 rb_thread_t *th = (rb_thread_t *)ptr;
00860 thread_debug("ubf_pthread_cond_signal (%p)\n", (void *)th);
00861 native_cond_signal(&th->native_thread_data.sleep_cond);
00862 }
00863
00864 static void
00865 native_sleep(rb_thread_t *th, struct timeval *timeout_tv)
00866 {
00867 struct timespec timeout;
00868 pthread_mutex_t *lock = &th->interrupt_lock;
00869 rb_thread_cond_t *cond = &th->native_thread_data.sleep_cond;
00870
00871 if (timeout_tv) {
00872 struct timespec timeout_rel;
00873
00874 timeout_rel.tv_sec = timeout_tv->tv_sec;
00875 timeout_rel.tv_nsec = timeout_tv->tv_usec * 1000;
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885 if (timeout_rel.tv_sec > 100000000) {
00886 timeout_rel.tv_sec = 100000000;
00887 timeout_rel.tv_nsec = 0;
00888 }
00889
00890 timeout = native_cond_timeout(cond, timeout_rel);
00891 }
00892
00893 GVL_UNLOCK_BEGIN();
00894 {
00895 pthread_mutex_lock(lock);
00896 th->unblock.func = ubf_pthread_cond_signal;
00897 th->unblock.arg = th;
00898
00899 if (RUBY_VM_INTERRUPTED(th)) {
00900
00901 thread_debug("native_sleep: interrupted before sleep\n");
00902 }
00903 else {
00904 if (!timeout_tv)
00905 native_cond_wait(cond, lock);
00906 else
00907 native_cond_timedwait(cond, lock, &timeout);
00908 }
00909 th->unblock.func = 0;
00910 th->unblock.arg = 0;
00911
00912 pthread_mutex_unlock(lock);
00913 }
00914 GVL_UNLOCK_END();
00915
00916 thread_debug("native_sleep done\n");
00917 }
00918
00919 #ifdef USE_SIGNAL_THREAD_LIST
00920 struct signal_thread_list {
00921 rb_thread_t *th;
00922 struct signal_thread_list *prev;
00923 struct signal_thread_list *next;
00924 };
00925
00926 static struct signal_thread_list signal_thread_list_anchor = {
00927 0, 0, 0,
00928 };
00929
00930 #define FGLOCK(lock, body) do { \
00931 native_mutex_lock(lock); \
00932 { \
00933 body; \
00934 } \
00935 native_mutex_unlock(lock); \
00936 } while (0)
00937
00938 #if 0
00939 static void
00940 print_signal_list(char *str)
00941 {
00942 struct signal_thread_list *list =
00943 signal_thread_list_anchor.next;
00944 thread_debug("list (%s)> ", str);
00945 while(list){
00946 thread_debug("%p (%p), ", list->th, list->th->thread_id);
00947 list = list->next;
00948 }
00949 thread_debug("\n");
00950 }
00951 #endif
00952
00953 static void
00954 add_signal_thread_list(rb_thread_t *th)
00955 {
00956 if (!th->native_thread_data.signal_thread_list) {
00957 FGLOCK(&signal_thread_list_lock, {
00958 struct signal_thread_list *list =
00959 malloc(sizeof(struct signal_thread_list));
00960
00961 if (list == 0) {
00962 fprintf(stderr, "[FATAL] failed to allocate memory\n");
00963 exit(EXIT_FAILURE);
00964 }
00965
00966 list->th = th;
00967
00968 list->prev = &signal_thread_list_anchor;
00969 list->next = signal_thread_list_anchor.next;
00970 if (list->next) {
00971 list->next->prev = list;
00972 }
00973 signal_thread_list_anchor.next = list;
00974 th->native_thread_data.signal_thread_list = list;
00975 });
00976 }
00977 }
00978
00979 static void
00980 remove_signal_thread_list(rb_thread_t *th)
00981 {
00982 if (th->native_thread_data.signal_thread_list) {
00983 FGLOCK(&signal_thread_list_lock, {
00984 struct signal_thread_list *list =
00985 (struct signal_thread_list *)
00986 th->native_thread_data.signal_thread_list;
00987
00988 list->prev->next = list->next;
00989 if (list->next) {
00990 list->next->prev = list->prev;
00991 }
00992 th->native_thread_data.signal_thread_list = 0;
00993 list->th = 0;
00994 free(list);
00995 });
00996 }
00997 }
00998
00999 static void
01000 ubf_select_each(rb_thread_t *th)
01001 {
01002 thread_debug("ubf_select_each (%p)\n", (void *)th->thread_id);
01003 if (th) {
01004 pthread_kill(th->thread_id, SIGVTALRM);
01005 }
01006 }
01007
01008 static void
01009 ubf_select(void *ptr)
01010 {
01011 rb_thread_t *th = (rb_thread_t *)ptr;
01012 add_signal_thread_list(th);
01013 if (pthread_self() != timer_thread_id)
01014 rb_thread_wakeup_timer_thread();
01015 ubf_select_each(th);
01016 }
01017
01018 static void
01019 ping_signal_thread_list(void) {
01020 if (signal_thread_list_anchor.next) {
01021 FGLOCK(&signal_thread_list_lock, {
01022 struct signal_thread_list *list;
01023
01024 list = signal_thread_list_anchor.next;
01025 while (list) {
01026 ubf_select_each(list->th);
01027 list = list->next;
01028 }
01029 });
01030 }
01031 }
01032
01033 static int
01034 check_signal_thread_list(void)
01035 {
01036 if (signal_thread_list_anchor.next)
01037 return 1;
01038 else
01039 return 0;
01040 }
01041 #else
01042 static void add_signal_thread_list(rb_thread_t *th) { }
01043 static void remove_signal_thread_list(rb_thread_t *th) { }
01044 #define ubf_select 0
01045 static void ping_signal_thread_list(void) { return; }
01046 static int check_signal_thread_list(void) { return 0; }
01047 #endif
01048
01049 static int timer_thread_pipe[2] = {-1, -1};
01050 static int timer_thread_pipe_owner_process;
01051
01052 #define TT_DEBUG 0
01053
01054 #define WRITE_CONST(fd, str) (void)(write((fd),(str),sizeof(str)-1)<0)
01055
01056
01057 void
01058 rb_thread_wakeup_timer_thread(void)
01059 {
01060 ssize_t result;
01061
01062
01063 if (timer_thread_pipe_owner_process == getpid()) {
01064 const char *buff = "!";
01065 retry:
01066 if ((result = write(timer_thread_pipe[1], buff, 1)) <= 0) {
01067 switch (errno) {
01068 case EINTR: goto retry;
01069 case EAGAIN:
01070 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
01071 case EWOULDBLOCK:
01072 #endif
01073 break;
01074 default:
01075 rb_async_bug_errno("rb_thread_wakeup_timer_thread - write", errno);
01076 }
01077 }
01078 if (TT_DEBUG) WRITE_CONST(2, "rb_thread_wakeup_timer_thread: write\n");
01079 }
01080 else {
01081
01082 }
01083 }
01084
01085
01086 static void
01087 consume_communication_pipe(void)
01088 {
01089 #define CCP_READ_BUFF_SIZE 1024
01090
01091 static char buff[CCP_READ_BUFF_SIZE];
01092 ssize_t result;
01093
01094 retry:
01095 result = read(timer_thread_pipe[0], buff, CCP_READ_BUFF_SIZE);
01096 if (result < 0) {
01097 switch (errno) {
01098 case EINTR: goto retry;
01099 default:
01100 rb_async_bug_errno("consume_communication_pipe: read\n", errno);
01101 }
01102 }
01103 }
01104
01105 static void
01106 close_communication_pipe(void)
01107 {
01108 if (close(timer_thread_pipe[0]) < 0) {
01109 rb_bug_errno("native_stop_timer_thread - close(ttp[0])", errno);
01110 }
01111 if (close(timer_thread_pipe[1]) < 0) {
01112 rb_bug_errno("native_stop_timer_thread - close(ttp[1])", errno);
01113 }
01114 timer_thread_pipe[0] = timer_thread_pipe[1] = -1;
01115 }
01116
01117
01118
01119
01120 #define TIME_QUANTUM_USEC (100 * 1000)
01121
01122 static void *
01123 thread_timer(void *p)
01124 {
01125 rb_global_vm_lock_t *gvl = (rb_global_vm_lock_t *)p;
01126 int result;
01127 struct timeval timeout;
01128
01129 if (TT_DEBUG) WRITE_CONST(2, "start timer thread\n");
01130
01131 while (system_working > 0) {
01132 fd_set rfds;
01133 int need_polling;
01134
01135
01136 ping_signal_thread_list();
01137 timer_thread_function(0);
01138 need_polling = check_signal_thread_list();
01139
01140 if (TT_DEBUG) WRITE_CONST(2, "tick\n");
01141
01142
01143 FD_ZERO(&rfds);
01144 FD_SET(timer_thread_pipe[0], &rfds);
01145
01146 if (gvl->waiting > 0 || need_polling) {
01147 timeout.tv_sec = 0;
01148 timeout.tv_usec = TIME_QUANTUM_USEC;
01149
01150
01151 result = select(timer_thread_pipe[0] + 1, &rfds, 0, 0, &timeout);
01152 }
01153 else {
01154
01155 result = select(timer_thread_pipe[0] + 1, &rfds, 0, 0, 0);
01156 }
01157
01158 if (result == 0) {
01159
01160 }
01161 else if (result > 0) {
01162 consume_communication_pipe();
01163 }
01164 else {
01165 switch (errno) {
01166 case EBADF:
01167 case EINVAL:
01168 case ENOMEM:
01169 case EFAULT:
01170 rb_async_bug_errno("thread_timer: select", errno);
01171 default:
01172 ;
01173 }
01174 }
01175 }
01176
01177 if (TT_DEBUG) WRITE_CONST(2, "finish timer thread\n");
01178 return NULL;
01179 }
01180
01181 static void
01182 rb_thread_create_timer_thread(void)
01183 {
01184 rb_enable_interrupt();
01185
01186 if (!timer_thread_id) {
01187 pthread_attr_t attr;
01188 int err;
01189
01190 pthread_attr_init(&attr);
01191 #ifdef PTHREAD_STACK_MIN
01192 if (PTHREAD_STACK_MIN < 4096 * 3) {
01193
01194
01195
01196
01197 pthread_attr_setstacksize(&attr,
01198 4096 * 3 + (THREAD_DEBUG ? BUFSIZ : 0));
01199 }
01200 else {
01201 pthread_attr_setstacksize(&attr,
01202 PTHREAD_STACK_MIN + (THREAD_DEBUG ? BUFSIZ : 0));
01203 }
01204 #endif
01205
01206
01207 if (timer_thread_pipe_owner_process != getpid()) {
01208 if (timer_thread_pipe[0] != -1) {
01209
01210 close_communication_pipe();
01211 }
01212
01213 err = pipe(timer_thread_pipe);
01214 if (err != 0) {
01215 rb_bug_errno("thread_timer: Failed to create communication pipe for timer thread", errno);
01216 }
01217 rb_update_max_fd(timer_thread_pipe[0]);
01218 rb_update_max_fd(timer_thread_pipe[1]);
01219 #if defined(HAVE_FCNTL) && defined(F_GETFL) && defined(F_SETFL)
01220 {
01221 int oflags;
01222 #if defined(O_NONBLOCK)
01223 oflags = fcntl(timer_thread_pipe[1], F_GETFL);
01224 oflags |= O_NONBLOCK;
01225 fcntl(timer_thread_pipe[1], F_SETFL, oflags);
01226 #endif
01227 #if defined(FD_CLOEXEC)
01228 oflags = fcntl(timer_thread_pipe[0], F_GETFD);
01229 fcntl(timer_thread_pipe[0], F_SETFD, oflags | FD_CLOEXEC);
01230 oflags = fcntl(timer_thread_pipe[1], F_GETFD);
01231 fcntl(timer_thread_pipe[1], F_SETFD, oflags | FD_CLOEXEC);
01232 #endif
01233 }
01234 #endif
01235
01236
01237 timer_thread_pipe_owner_process = getpid();
01238 }
01239
01240
01241 if (timer_thread_id) {
01242 rb_bug("rb_thread_create_timer_thread: Timer thread was already created\n");
01243 }
01244 err = pthread_create(&timer_thread_id, &attr, thread_timer, &GET_VM()->gvl);
01245 if (err != 0) {
01246 fprintf(stderr, "[FATAL] Failed to create timer thread (errno: %d)\n", err);
01247 exit(EXIT_FAILURE);
01248 }
01249 pthread_attr_destroy(&attr);
01250 }
01251
01252 rb_disable_interrupt();
01253 }
01254
01255 static int
01256 native_stop_timer_thread(int close_anyway)
01257 {
01258 int stopped;
01259 stopped = --system_working <= 0;
01260
01261 if (TT_DEBUG) fprintf(stderr, "stop timer thread\n");
01262 if (stopped) {
01263
01264 rb_thread_wakeup_timer_thread();
01265 native_thread_join(timer_thread_id);
01266 if (TT_DEBUG) fprintf(stderr, "joined timer thread\n");
01267 timer_thread_id = 0;
01268
01269
01270 if (close_anyway) {
01271
01272
01273
01274
01275
01276
01277
01278
01279 }
01280 }
01281 return stopped;
01282 }
01283
01284 static void
01285 native_reset_timer_thread(void)
01286 {
01287 if (TT_DEBUG) fprintf(stderr, "reset timer thread\n");
01288 }
01289
01290 #ifdef HAVE_SIGALTSTACK
01291 int
01292 ruby_stack_overflowed_p(const rb_thread_t *th, const void *addr)
01293 {
01294 void *base;
01295 size_t size;
01296 const size_t water_mark = 1024 * 1024;
01297 STACK_GROW_DIR_DETECTION;
01298
01299 if (th) {
01300 size = th->machine_stack_maxsize;
01301 base = (char *)th->machine_stack_start - STACK_DIR_UPPER(0, size);
01302 }
01303 #ifdef STACKADDR_AVAILABLE
01304 else if (get_stack(&base, &size) == 0) {
01305 STACK_DIR_UPPER((void)(base = (char *)base + size), (void)0);
01306 }
01307 #endif
01308 else {
01309 return 0;
01310 }
01311 size /= 5;
01312 if (size > water_mark) size = water_mark;
01313 if (IS_STACK_DIR_UPPER()) {
01314 if (size > ~(size_t)base+1) size = ~(size_t)base+1;
01315 if (addr > base && addr <= (void *)((char *)base + size)) return 1;
01316 }
01317 else {
01318 if (size > (size_t)base) size = (size_t)base;
01319 if (addr > (void *)((char *)base - size) && addr <= base) return 1;
01320 }
01321 return 0;
01322 }
01323 #endif
01324
01325 int
01326 rb_reserved_fd_p(int fd)
01327 {
01328 if (fd == timer_thread_pipe[0] ||
01329 fd == timer_thread_pipe[1]) {
01330 return 1;
01331 }
01332 else {
01333 return 0;
01334 }
01335 }
01336
01337 #endif
01338