|
Ruby 1.9.2p290(2011-07-09revision32553)
|
00001 /* -*-c-*- */ 00002 /********************************************************************** 00003 00004 thread_pthread.c - 00005 00006 $Author: yugui $ 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 00020 static void native_mutex_lock(pthread_mutex_t *lock); 00021 static void native_mutex_unlock(pthread_mutex_t *lock); 00022 static int native_mutex_trylock(pthread_mutex_t *lock); 00023 static void native_mutex_initialize(pthread_mutex_t *lock); 00024 static void native_mutex_destroy(pthread_mutex_t *lock); 00025 00026 static void native_cond_signal(pthread_cond_t *cond); 00027 static void native_cond_broadcast(pthread_cond_t *cond); 00028 static void native_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); 00029 static void native_cond_initialize(pthread_cond_t *cond); 00030 static void native_cond_destroy(pthread_cond_t *cond); 00031 00032 static void 00033 native_mutex_lock(pthread_mutex_t *lock) 00034 { 00035 int r; 00036 if ((r = pthread_mutex_lock(lock)) != 0) { 00037 rb_bug_errno("pthread_mutex_lock", r); 00038 } 00039 } 00040 00041 static void 00042 native_mutex_unlock(pthread_mutex_t *lock) 00043 { 00044 int r; 00045 if ((r = pthread_mutex_unlock(lock)) != 0) { 00046 rb_bug_errno("pthread_mutex_unlock", r); 00047 } 00048 } 00049 00050 static inline int 00051 native_mutex_trylock(pthread_mutex_t *lock) 00052 { 00053 int r; 00054 if ((r = pthread_mutex_trylock(lock)) != 0) { 00055 if (r == EBUSY) { 00056 return EBUSY; 00057 } 00058 else { 00059 rb_bug_errno("pthread_mutex_trylock", r); 00060 } 00061 } 00062 return 0; 00063 } 00064 00065 static void 00066 native_mutex_initialize(pthread_mutex_t *lock) 00067 { 00068 int r = pthread_mutex_init(lock, 0); 00069 if (r != 0) { 00070 rb_bug_errno("pthread_mutex_init", r); 00071 } 00072 } 00073 00074 #define native_mutex_reinitialize_atfork(lock) (\ 00075 native_mutex_unlock(lock), \ 00076 native_mutex_initialize(lock), \ 00077 native_mutex_lock(lock)) 00078 00079 static void 00080 native_mutex_destroy(pthread_mutex_t *lock) 00081 { 00082 int r = pthread_mutex_destroy(lock); 00083 if (r != 0) { 00084 rb_bug_errno("pthread_mutex_destroy", r); 00085 } 00086 } 00087 00088 static void 00089 native_cond_initialize(pthread_cond_t *cond) 00090 { 00091 int r = pthread_cond_init(cond, 0); 00092 if (r != 0) { 00093 rb_bug_errno("pthread_cond_init", r); 00094 } 00095 } 00096 00097 static void 00098 native_cond_destroy(pthread_cond_t *cond) 00099 { 00100 int r = pthread_cond_destroy(cond); 00101 if (r != 0) { 00102 rb_bug_errno("pthread_cond_destroy", r); 00103 } 00104 } 00105 00106 static void 00107 native_cond_signal(pthread_cond_t *cond) 00108 { 00109 int r = pthread_cond_signal(cond); 00110 if (r != 0) { 00111 rb_bug_errno("pthread_cond_signal", r); 00112 } 00113 } 00114 00115 static void 00116 native_cond_broadcast(pthread_cond_t *cond) 00117 { 00118 int r = pthread_cond_broadcast(cond); 00119 if (r != 0) { 00120 rb_bug_errno("native_cond_broadcast", r); 00121 } 00122 } 00123 00124 static void 00125 native_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 00126 { 00127 int r = pthread_cond_wait(cond, mutex); 00128 if (r != 0) { 00129 rb_bug_errno("pthread_cond_wait", r); 00130 } 00131 } 00132 00133 static int 00134 native_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, struct timespec *ts) 00135 { 00136 int r; 00137 00138 /* 00139 * An old Linux may return EINTR. Even though POSIX says 00140 * "These functions shall not return an error code of [EINTR]". 00141 * http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_cond_timedwait.html 00142 * Let's hide it from arch generic code. 00143 */ 00144 do { 00145 r = pthread_cond_timedwait(cond, mutex, ts); 00146 } while (r == EINTR); 00147 00148 if (r != 0 && r != ETIMEDOUT) { 00149 rb_bug_errno("pthread_cond_timedwait", r); 00150 } 00151 00152 return r; 00153 } 00154 00155 00156 #define native_cleanup_push pthread_cleanup_push 00157 #define native_cleanup_pop pthread_cleanup_pop 00158 #ifdef HAVE_SCHED_YIELD 00159 #define native_thread_yield() (void)sched_yield() 00160 #else 00161 #define native_thread_yield() ((void)0) 00162 #endif 00163 00164 #ifndef __CYGWIN__ 00165 static void add_signal_thread_list(rb_thread_t *th); 00166 #endif 00167 static void remove_signal_thread_list(rb_thread_t *th); 00168 00169 static rb_thread_lock_t signal_thread_list_lock; 00170 00171 static pthread_key_t ruby_native_thread_key; 00172 00173 static void 00174 null_func(int i) 00175 { 00176 /* null */ 00177 } 00178 00179 static rb_thread_t * 00180 ruby_thread_from_native(void) 00181 { 00182 return pthread_getspecific(ruby_native_thread_key); 00183 } 00184 00185 static int 00186 ruby_thread_set_native(rb_thread_t *th) 00187 { 00188 return pthread_setspecific(ruby_native_thread_key, th) == 0; 00189 } 00190 00191 void 00192 Init_native_thread(void) 00193 { 00194 rb_thread_t *th = GET_THREAD(); 00195 00196 pthread_key_create(&ruby_native_thread_key, NULL); 00197 th->thread_id = pthread_self(); 00198 native_cond_initialize(&th->native_thread_data.sleep_cond); 00199 ruby_thread_set_native(th); 00200 native_mutex_initialize(&signal_thread_list_lock); 00201 posix_signal(SIGVTALRM, null_func); 00202 } 00203 00204 static void 00205 native_thread_destroy(rb_thread_t *th) 00206 { 00207 pthread_mutex_destroy(&th->interrupt_lock); 00208 pthread_cond_destroy(&th->native_thread_data.sleep_cond); 00209 } 00210 00211 #define USE_THREAD_CACHE 0 00212 00213 #if STACK_GROW_DIRECTION 00214 #define STACK_GROW_DIR_DETECTION 00215 #define STACK_DIR_UPPER(a,b) STACK_UPPER(0, a, b) 00216 #else 00217 #define STACK_GROW_DIR_DETECTION VALUE stack_grow_dir_detection 00218 #define STACK_DIR_UPPER(a,b) STACK_UPPER(&stack_grow_dir_detection, a, b) 00219 #endif 00220 00221 #if defined HAVE_PTHREAD_GETATTR_NP || defined HAVE_PTHREAD_ATTR_GET_NP 00222 #define STACKADDR_AVAILABLE 1 00223 #elif defined HAVE_PTHREAD_GET_STACKADDR_NP && defined HAVE_PTHREAD_GET_STACKSIZE_NP 00224 #define STACKADDR_AVAILABLE 1 00225 #elif defined HAVE_THR_STKSEGMENT || defined HAVE_PTHREAD_STACKSEG_NP 00226 #define STACKADDR_AVAILABLE 1 00227 #elif defined HAVE_PTHREAD_GETTHRDS_NP 00228 #define STACKADDR_AVAILABLE 1 00229 #endif 00230 00231 #ifdef STACKADDR_AVAILABLE 00232 static int 00233 get_stack(void **addr, size_t *size) 00234 { 00235 #define CHECK_ERR(expr) \ 00236 {int err = (expr); if (err) return err;} 00237 #if defined HAVE_PTHREAD_GETATTR_NP || defined HAVE_PTHREAD_ATTR_GET_NP 00238 pthread_attr_t attr; 00239 size_t guard = 0; 00240 00241 # ifdef HAVE_PTHREAD_GETATTR_NP 00242 CHECK_ERR(pthread_getattr_np(pthread_self(), &attr)); 00243 # ifdef HAVE_PTHREAD_ATTR_GETSTACK 00244 CHECK_ERR(pthread_attr_getstack(&attr, addr, size)); 00245 # else 00246 CHECK_ERR(pthread_attr_getstackaddr(&attr, addr)); 00247 CHECK_ERR(pthread_attr_getstacksize(&attr, size)); 00248 # endif 00249 if (pthread_attr_getguardsize(&attr, &guard) == 0) { 00250 STACK_GROW_DIR_DETECTION; 00251 STACK_DIR_UPPER((void)0, (void)(*addr = (char *)*addr + guard)); 00252 *size -= guard; 00253 } 00254 # else 00255 CHECK_ERR(pthread_attr_init(&attr)); 00256 CHECK_ERR(pthread_attr_get_np(pthread_self(), &attr)); 00257 CHECK_ERR(pthread_attr_getstackaddr(&attr, addr)); 00258 CHECK_ERR(pthread_attr_getstacksize(&attr, size)); 00259 # endif 00260 CHECK_ERR(pthread_attr_getguardsize(&attr, &guard)); 00261 *size -= guard; 00262 pthread_attr_destroy(&attr); 00263 #elif defined HAVE_PTHREAD_GET_STACKADDR_NP && defined HAVE_PTHREAD_GET_STACKSIZE_NP 00264 pthread_t th = pthread_self(); 00265 *addr = pthread_get_stackaddr_np(th); 00266 *size = pthread_get_stacksize_np(th); 00267 #elif defined HAVE_THR_STKSEGMENT || defined HAVE_PTHREAD_STACKSEG_NP 00268 stack_t stk; 00269 # if defined HAVE_THR_STKSEGMENT 00270 CHECK_ERR(thr_stksegment(&stk)); 00271 # else 00272 CHECK_ERR(pthread_stackseg_np(pthread_self(), &stk)); 00273 # endif 00274 *addr = stk.ss_sp; 00275 *size = stk.ss_size; 00276 #elif defined HAVE_PTHREAD_GETTHRDS_NP 00277 pthread_t th = pthread_self(); 00278 struct __pthrdsinfo thinfo; 00279 char reg[256]; 00280 int regsiz=sizeof(reg); 00281 CHECK_ERR(pthread_getthrds_np(&th, PTHRDSINFO_QUERY_ALL, 00282 &thinfo, sizeof(thinfo), 00283 ®, ®siz)); 00284 *addr = thinfo.__pi_stackaddr; 00285 *size = thinfo.__pi_stacksize; 00286 #endif 00287 return 0; 00288 #undef CHECK_ERR 00289 } 00290 #endif 00291 00292 static struct { 00293 rb_thread_id_t id; 00294 size_t stack_maxsize; 00295 VALUE *stack_start; 00296 #ifdef __ia64 00297 VALUE *register_stack_start; 00298 #endif 00299 } native_main_thread; 00300 00301 #ifdef STACK_END_ADDRESS 00302 extern void *STACK_END_ADDRESS; 00303 #endif 00304 00305 #undef ruby_init_stack 00306 void 00307 ruby_init_stack(volatile VALUE *addr 00308 #ifdef __ia64 00309 , void *bsp 00310 #endif 00311 ) 00312 { 00313 native_main_thread.id = pthread_self(); 00314 #ifdef STACK_END_ADDRESS 00315 native_main_thread.stack_start = STACK_END_ADDRESS; 00316 #else 00317 if (!native_main_thread.stack_start || 00318 STACK_UPPER((VALUE *)(void *)&addr, 00319 native_main_thread.stack_start > addr, 00320 native_main_thread.stack_start < addr)) { 00321 native_main_thread.stack_start = (VALUE *)addr; 00322 } 00323 #endif 00324 #ifdef __ia64 00325 if (!native_main_thread.register_stack_start || 00326 (VALUE*)bsp < native_main_thread.register_stack_start) { 00327 native_main_thread.register_stack_start = (VALUE*)bsp; 00328 } 00329 #endif 00330 { 00331 size_t size = 0; 00332 size_t space = 0; 00333 #if defined(HAVE_PTHREAD_ATTR_GET_NP) 00334 void* addr; 00335 get_stack(&addr, &size); 00336 #elif defined(HAVE_GETRLIMIT) 00337 struct rlimit rlim; 00338 if (getrlimit(RLIMIT_STACK, &rlim) == 0) { 00339 size = (size_t)rlim.rlim_cur; 00340 } 00341 #endif 00342 space = size > 5 * 1024 * 1024 ? 1024 * 1024 : size / 5; 00343 native_main_thread.stack_maxsize = size - space; 00344 } 00345 } 00346 00347 #define CHECK_ERR(expr) \ 00348 {int err = (expr); if (err) {rb_bug_errno(#expr, err);}} 00349 00350 static int 00351 native_thread_init_stack(rb_thread_t *th) 00352 { 00353 rb_thread_id_t curr = pthread_self(); 00354 00355 if (pthread_equal(curr, native_main_thread.id)) { 00356 th->machine_stack_start = native_main_thread.stack_start; 00357 th->machine_stack_maxsize = native_main_thread.stack_maxsize; 00358 } 00359 else { 00360 #ifdef STACKADDR_AVAILABLE 00361 void *start; 00362 size_t size; 00363 00364 if (get_stack(&start, &size) == 0) { 00365 th->machine_stack_start = start; 00366 th->machine_stack_maxsize = size; 00367 } 00368 #else 00369 rb_raise(rb_eNotImpError, "ruby engine can initialize only in the main thread"); 00370 #endif 00371 } 00372 #ifdef __ia64 00373 th->machine_register_stack_start = native_main_thread.register_stack_start; 00374 th->machine_stack_maxsize /= 2; 00375 th->machine_register_stack_maxsize = th->machine_stack_maxsize; 00376 #endif 00377 return 0; 00378 } 00379 00380 static void * 00381 thread_start_func_1(void *th_ptr) 00382 { 00383 #if USE_THREAD_CACHE 00384 thread_start: 00385 #endif 00386 { 00387 rb_thread_t *th = th_ptr; 00388 VALUE stack_start; 00389 00390 #ifndef __CYGWIN__ 00391 native_thread_init_stack(th); 00392 #endif 00393 /* run */ 00394 thread_start_func_2(th, &stack_start, rb_ia64_bsp()); 00395 } 00396 #if USE_THREAD_CACHE 00397 if (1) { 00398 /* cache thread */ 00399 rb_thread_t *th; 00400 static rb_thread_t *register_cached_thread_and_wait(void); 00401 if ((th = register_cached_thread_and_wait()) != 0) { 00402 th_ptr = (void *)th; 00403 th->thread_id = pthread_self(); 00404 goto thread_start; 00405 } 00406 } 00407 #endif 00408 return 0; 00409 } 00410 00411 void rb_thread_create_control_thread(void); 00412 00413 struct cached_thread_entry { 00414 volatile rb_thread_t **th_area; 00415 pthread_cond_t *cond; 00416 struct cached_thread_entry *next; 00417 }; 00418 00419 00420 #if USE_THREAD_CACHE 00421 static pthread_mutex_t thread_cache_lock = PTHREAD_MUTEX_INITIALIZER; 00422 struct cached_thread_entry *cached_thread_root; 00423 00424 static rb_thread_t * 00425 register_cached_thread_and_wait(void) 00426 { 00427 pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 00428 volatile rb_thread_t *th_area = 0; 00429 struct cached_thread_entry *entry = 00430 (struct cached_thread_entry *)malloc(sizeof(struct cached_thread_entry)); 00431 00432 struct timeval tv; 00433 struct timespec ts; 00434 gettimeofday(&tv, 0); 00435 ts.tv_sec = tv.tv_sec + 60; 00436 ts.tv_nsec = tv.tv_usec * 1000; 00437 00438 pthread_mutex_lock(&thread_cache_lock); 00439 { 00440 entry->th_area = &th_area; 00441 entry->cond = &cond; 00442 entry->next = cached_thread_root; 00443 cached_thread_root = entry; 00444 00445 pthread_cond_timedwait(&cond, &thread_cache_lock, &ts); 00446 00447 { 00448 struct cached_thread_entry *e = cached_thread_root; 00449 struct cached_thread_entry *prev = cached_thread_root; 00450 00451 while (e) { 00452 if (e == entry) { 00453 if (prev == cached_thread_root) { 00454 cached_thread_root = e->next; 00455 } 00456 else { 00457 prev->next = e->next; 00458 } 00459 break; 00460 } 00461 prev = e; 00462 e = e->next; 00463 } 00464 } 00465 00466 free(entry); /* ok */ 00467 pthread_cond_destroy(&cond); 00468 } 00469 pthread_mutex_unlock(&thread_cache_lock); 00470 00471 return (rb_thread_t *)th_area; 00472 } 00473 #endif 00474 00475 static int 00476 use_cached_thread(rb_thread_t *th) 00477 { 00478 int result = 0; 00479 #if USE_THREAD_CACHE 00480 struct cached_thread_entry *entry; 00481 00482 if (cached_thread_root) { 00483 pthread_mutex_lock(&thread_cache_lock); 00484 entry = cached_thread_root; 00485 { 00486 if (cached_thread_root) { 00487 cached_thread_root = entry->next; 00488 *entry->th_area = th; 00489 result = 1; 00490 } 00491 } 00492 if (result) { 00493 pthread_cond_signal(entry->cond); 00494 } 00495 pthread_mutex_unlock(&thread_cache_lock); 00496 } 00497 #endif 00498 return result; 00499 } 00500 00501 enum { 00502 #ifdef __SYMBIAN32__ 00503 RUBY_STACK_MIN_LIMIT = 64 * 1024, /* 64KB: Let's be slightly more frugal on mobile platform */ 00504 #else 00505 RUBY_STACK_MIN_LIMIT = 512 * 1024, /* 512KB */ 00506 #endif 00507 RUBY_STACK_SPACE_LIMIT = 1024 * 1024 00508 }; 00509 00510 #ifdef PTHREAD_STACK_MIN 00511 #define RUBY_STACK_MIN ((RUBY_STACK_MIN_LIMIT < PTHREAD_STACK_MIN) ? \ 00512 PTHREAD_STACK_MIN * 2 : RUBY_STACK_MIN_LIMIT) 00513 #else 00514 #define RUBY_STACK_MIN (RUBY_STACK_MIN_LIMIT) 00515 #endif 00516 #define RUBY_STACK_SPACE (RUBY_STACK_MIN/5 > RUBY_STACK_SPACE_LIMIT ? \ 00517 RUBY_STACK_SPACE_LIMIT : RUBY_STACK_MIN/5) 00518 00519 static int 00520 native_thread_create(rb_thread_t *th) 00521 { 00522 int err = 0; 00523 00524 if (use_cached_thread(th)) { 00525 thread_debug("create (use cached thread): %p\n", (void *)th); 00526 } 00527 else { 00528 pthread_attr_t attr; 00529 const size_t stack_size = RUBY_STACK_MIN; 00530 const size_t space = RUBY_STACK_SPACE; 00531 00532 th->machine_stack_maxsize = stack_size - space; 00533 #ifdef __ia64 00534 th->machine_stack_maxsize /= 2; 00535 th->machine_register_stack_maxsize = th->machine_stack_maxsize; 00536 #endif 00537 00538 CHECK_ERR(pthread_attr_init(&attr)); 00539 00540 #ifdef PTHREAD_STACK_MIN 00541 thread_debug("create - stack size: %lu\n", (unsigned long)stack_size); 00542 CHECK_ERR(pthread_attr_setstacksize(&attr, stack_size)); 00543 #endif 00544 00545 #ifdef HAVE_PTHREAD_ATTR_SETINHERITSCHED 00546 CHECK_ERR(pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED)); 00547 #endif 00548 CHECK_ERR(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)); 00549 00550 err = pthread_create(&th->thread_id, &attr, thread_start_func_1, th); 00551 thread_debug("create: %p (%d)", (void *)th, err); 00552 CHECK_ERR(pthread_attr_destroy(&attr)); 00553 00554 if (!err) { 00555 pthread_cond_init(&th->native_thread_data.sleep_cond, 0); 00556 } 00557 } 00558 return err; 00559 } 00560 00561 static void 00562 native_thread_join(pthread_t th) 00563 { 00564 int err = pthread_join(th, 0); 00565 if (err) { 00566 rb_raise(rb_eThreadError, "native_thread_join() failed (%d)", err); 00567 } 00568 } 00569 00570 00571 #if USE_NATIVE_THREAD_PRIORITY 00572 00573 static void 00574 native_thread_apply_priority(rb_thread_t *th) 00575 { 00576 #if defined(_POSIX_PRIORITY_SCHEDULING) && (_POSIX_PRIORITY_SCHEDULING > 0) 00577 struct sched_param sp; 00578 int policy; 00579 int priority = 0 - th->priority; 00580 int max, min; 00581 pthread_getschedparam(th->thread_id, &policy, &sp); 00582 max = sched_get_priority_max(policy); 00583 min = sched_get_priority_min(policy); 00584 00585 if (min > priority) { 00586 priority = min; 00587 } 00588 else if (max < priority) { 00589 priority = max; 00590 } 00591 00592 sp.sched_priority = priority; 00593 pthread_setschedparam(th->thread_id, policy, &sp); 00594 #else 00595 /* not touched */ 00596 #endif 00597 } 00598 00599 #endif /* USE_NATIVE_THREAD_PRIORITY */ 00600 00601 static void 00602 ubf_pthread_cond_signal(void *ptr) 00603 { 00604 rb_thread_t *th = (rb_thread_t *)ptr; 00605 thread_debug("ubf_pthread_cond_signal (%p)\n", (void *)th); 00606 pthread_cond_signal(&th->native_thread_data.sleep_cond); 00607 } 00608 00609 #if !defined(__CYGWIN__) && !defined(__SYMBIAN32__) 00610 static void 00611 ubf_select_each(rb_thread_t *th) 00612 { 00613 thread_debug("ubf_select_each (%p)\n", (void *)th->thread_id); 00614 if (th) { 00615 pthread_kill(th->thread_id, SIGVTALRM); 00616 } 00617 } 00618 00619 static void 00620 ubf_select(void *ptr) 00621 { 00622 rb_thread_t *th = (rb_thread_t *)ptr; 00623 add_signal_thread_list(th); 00624 ubf_select_each(th); 00625 } 00626 #else 00627 #define ubf_select 0 00628 #endif 00629 00630 #define PER_NANO 1000000000 00631 00632 static void 00633 native_sleep(rb_thread_t *th, struct timeval *tv) 00634 { 00635 struct timespec ts; 00636 struct timeval tvn; 00637 00638 if (tv) { 00639 gettimeofday(&tvn, NULL); 00640 ts.tv_sec = tvn.tv_sec + tv->tv_sec; 00641 ts.tv_nsec = (tvn.tv_usec + tv->tv_usec) * 1000; 00642 if (ts.tv_nsec >= PER_NANO){ 00643 ts.tv_sec += 1; 00644 ts.tv_nsec -= PER_NANO; 00645 } 00646 } 00647 00648 thread_debug("native_sleep %ld\n", tv ? tv->tv_sec : -1); 00649 GVL_UNLOCK_BEGIN(); 00650 { 00651 pthread_mutex_lock(&th->interrupt_lock); 00652 th->unblock.func = ubf_pthread_cond_signal; 00653 th->unblock.arg = th; 00654 00655 if (RUBY_VM_INTERRUPTED(th)) { 00656 /* interrupted. return immediate */ 00657 thread_debug("native_sleep: interrupted before sleep\n"); 00658 } 00659 else { 00660 if (tv == 0 || ts.tv_sec < tvn.tv_sec /* overflow */ ) { 00661 int r; 00662 thread_debug("native_sleep: pthread_cond_wait start\n"); 00663 r = pthread_cond_wait(&th->native_thread_data.sleep_cond, 00664 &th->interrupt_lock); 00665 if (r) rb_bug_errno("pthread_cond_wait", r); 00666 thread_debug("native_sleep: pthread_cond_wait end\n"); 00667 } 00668 else { 00669 int r; 00670 thread_debug("native_sleep: pthread_cond_timedwait start (%ld, %ld)\n", 00671 (unsigned long)ts.tv_sec, ts.tv_nsec); 00672 r = pthread_cond_timedwait(&th->native_thread_data.sleep_cond, 00673 &th->interrupt_lock, &ts); 00674 if (r && r != ETIMEDOUT) rb_bug_errno("pthread_cond_timedwait", r); 00675 00676 thread_debug("native_sleep: pthread_cond_timedwait end (%d)\n", r); 00677 } 00678 } 00679 th->unblock.func = 0; 00680 th->unblock.arg = 0; 00681 00682 pthread_mutex_unlock(&th->interrupt_lock); 00683 } 00684 GVL_UNLOCK_END(); 00685 00686 thread_debug("native_sleep done\n"); 00687 } 00688 00689 struct signal_thread_list { 00690 rb_thread_t *th; 00691 struct signal_thread_list *prev; 00692 struct signal_thread_list *next; 00693 }; 00694 00695 #ifndef __CYGWIN__ 00696 static struct signal_thread_list signal_thread_list_anchor = { 00697 0, 0, 0, 00698 }; 00699 #endif 00700 00701 #define FGLOCK(lock, body) do { \ 00702 native_mutex_lock(lock); \ 00703 { \ 00704 body; \ 00705 } \ 00706 native_mutex_unlock(lock); \ 00707 } while (0) 00708 00709 #if 0 /* for debug */ 00710 static void 00711 print_signal_list(char *str) 00712 { 00713 struct signal_thread_list *list = 00714 signal_thread_list_anchor.next; 00715 thread_debug("list (%s)> ", str); 00716 while(list){ 00717 thread_debug("%p (%p), ", list->th, list->th->thread_id); 00718 list = list->next; 00719 } 00720 thread_debug("\n"); 00721 } 00722 #endif 00723 00724 #ifndef __CYGWIN__ 00725 static void 00726 add_signal_thread_list(rb_thread_t *th) 00727 { 00728 if (!th->native_thread_data.signal_thread_list) { 00729 FGLOCK(&signal_thread_list_lock, { 00730 struct signal_thread_list *list = 00731 malloc(sizeof(struct signal_thread_list)); 00732 00733 if (list == 0) { 00734 fprintf(stderr, "[FATAL] failed to allocate memory\n"); 00735 exit(1); 00736 } 00737 00738 list->th = th; 00739 00740 list->prev = &signal_thread_list_anchor; 00741 list->next = signal_thread_list_anchor.next; 00742 if (list->next) { 00743 list->next->prev = list; 00744 } 00745 signal_thread_list_anchor.next = list; 00746 th->native_thread_data.signal_thread_list = list; 00747 }); 00748 } 00749 } 00750 #endif 00751 00752 static void 00753 remove_signal_thread_list(rb_thread_t *th) 00754 { 00755 if (th->native_thread_data.signal_thread_list) { 00756 FGLOCK(&signal_thread_list_lock, { 00757 struct signal_thread_list *list = 00758 (struct signal_thread_list *) 00759 th->native_thread_data.signal_thread_list; 00760 00761 list->prev->next = list->next; 00762 if (list->next) { 00763 list->next->prev = list->prev; 00764 } 00765 th->native_thread_data.signal_thread_list = 0; 00766 list->th = 0; 00767 free(list); /* ok */ 00768 }); 00769 } 00770 else { 00771 /* */ 00772 } 00773 } 00774 00775 static pthread_t timer_thread_id; 00776 static pthread_cond_t timer_thread_cond = PTHREAD_COND_INITIALIZER; 00777 static pthread_mutex_t timer_thread_lock = PTHREAD_MUTEX_INITIALIZER; 00778 00779 static struct timespec * 00780 get_ts(struct timespec *ts, unsigned long nsec) 00781 { 00782 struct timeval tv; 00783 gettimeofday(&tv, 0); 00784 ts->tv_sec = tv.tv_sec; 00785 ts->tv_nsec = tv.tv_usec * 1000 + nsec; 00786 if (ts->tv_nsec >= PER_NANO) { 00787 ts->tv_sec++; 00788 ts->tv_nsec -= PER_NANO; 00789 } 00790 return ts; 00791 } 00792 00793 static void * 00794 thread_timer(void *dummy) 00795 { 00796 struct timespec ts; 00797 00798 native_mutex_lock(&timer_thread_lock); 00799 native_cond_broadcast(&timer_thread_cond); 00800 #define WAIT_FOR_10MS() native_cond_timedwait(&timer_thread_cond, &timer_thread_lock, get_ts(&ts, PER_NANO/100)) 00801 while (system_working > 0) { 00802 int err = WAIT_FOR_10MS(); 00803 if (err == ETIMEDOUT); 00804 else if (err == 0) { 00805 if (rb_signal_buff_size() == 0) break; 00806 } 00807 else rb_bug_errno("thread_timer/timedwait", err); 00808 00809 #if !defined(__CYGWIN__) && !defined(__SYMBIAN32__) 00810 if (signal_thread_list_anchor.next) { 00811 FGLOCK(&signal_thread_list_lock, { 00812 struct signal_thread_list *list; 00813 list = signal_thread_list_anchor.next; 00814 while (list) { 00815 ubf_select_each(list->th); 00816 list = list->next; 00817 } 00818 }); 00819 } 00820 #endif 00821 timer_thread_function(dummy); 00822 } 00823 native_mutex_unlock(&timer_thread_lock); 00824 return NULL; 00825 } 00826 00827 static void 00828 rb_thread_create_timer_thread(void) 00829 { 00830 rb_enable_interrupt(); 00831 00832 if (!timer_thread_id) { 00833 pthread_attr_t attr; 00834 int err; 00835 00836 pthread_attr_init(&attr); 00837 #ifdef PTHREAD_STACK_MIN 00838 pthread_attr_setstacksize(&attr, 00839 PTHREAD_STACK_MIN + (THREAD_DEBUG ? BUFSIZ : 0)); 00840 #endif 00841 native_mutex_lock(&timer_thread_lock); 00842 err = pthread_create(&timer_thread_id, &attr, thread_timer, 0); 00843 if (err != 0) { 00844 native_mutex_unlock(&timer_thread_lock); 00845 fprintf(stderr, "[FATAL] Failed to create timer thread (errno: %d)\n", err); 00846 exit(EXIT_FAILURE); 00847 } 00848 native_cond_wait(&timer_thread_cond, &timer_thread_lock); 00849 native_mutex_unlock(&timer_thread_lock); 00850 } 00851 rb_disable_interrupt(); /* only timer thread recieve signal */ 00852 } 00853 00854 static int 00855 native_stop_timer_thread(void) 00856 { 00857 int stopped; 00858 native_mutex_lock(&timer_thread_lock); 00859 stopped = --system_working <= 0; 00860 if (stopped) { 00861 native_cond_signal(&timer_thread_cond); 00862 } 00863 native_mutex_unlock(&timer_thread_lock); 00864 if (stopped) { 00865 native_thread_join(timer_thread_id); 00866 } 00867 return stopped; 00868 } 00869 00870 static void 00871 native_reset_timer_thread(void) 00872 { 00873 timer_thread_id = 0; 00874 } 00875 00876 #ifdef HAVE_SIGALTSTACK 00877 int 00878 ruby_stack_overflowed_p(const rb_thread_t *th, const void *addr) 00879 { 00880 void *base; 00881 size_t size; 00882 const size_t water_mark = 1024 * 1024; 00883 STACK_GROW_DIR_DETECTION; 00884 00885 if (th) { 00886 size = th->machine_stack_maxsize; 00887 base = (char *)th->machine_stack_start - STACK_DIR_UPPER(0, size); 00888 } 00889 #ifdef STACKADDR_AVAILABLE 00890 else if (get_stack(&base, &size) == 0) { 00891 STACK_DIR_UPPER((void)(base = (char *)base + size), (void)0); 00892 } 00893 #endif 00894 else { 00895 return 0; 00896 } 00897 size /= 5; 00898 if (size > water_mark) size = water_mark; 00899 if (STACK_DIR_UPPER(1, 0)) { 00900 if (size > ~(size_t)base+1) size = ~(size_t)base+1; 00901 if (addr > base && addr <= (void *)((char *)base + size)) return 1; 00902 } 00903 else { 00904 if (size > (size_t)base) size = (size_t)base; 00905 if (addr > (void *)((char *)base - size) && addr <= base) return 1; 00906 } 00907 return 0; 00908 } 00909 #endif 00910 00911 #endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */ 00912
1.7.3