2 /**********************************************************************
8 Copyright (C) 2004-2007 Koichi Sasada
10 **********************************************************************/
12 #ifdef THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
16 #ifdef HAVE_SYS_RESOURCE_H
17 #include <sys/resource.h>
20 static void native_mutex_lock(pthread_mutex_t
*lock
);
21 static void native_mutex_unlock(pthread_mutex_t
*lock
);
22 static int native_mutex_trylock(pthread_mutex_t
*lock
);
23 static void native_mutex_initialize(pthread_mutex_t
*lock
);
24 static void native_mutex_destroy(pthread_mutex_t
*lock
);
26 static void native_cond_signal(pthread_cond_t
*cond
);
27 static void native_cond_broadcast(pthread_cond_t
*cond
);
28 static void native_cond_wait(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
);
29 static void native_cond_initialize(pthread_cond_t
*cond
);
30 static void native_cond_destroy(pthread_cond_t
*cond
);
33 native_mutex_lock(pthread_mutex_t
*lock
)
36 if ((r
= pthread_mutex_lock(lock
)) != 0) {
37 rb_bug("pthread_mutex_lock: %d", r
);
42 native_mutex_unlock(pthread_mutex_t
*lock
)
45 if ((r
= pthread_mutex_unlock(lock
)) != 0) {
46 rb_bug("native_mutex_unlock return non-zero: %d", r
);
51 native_mutex_trylock(pthread_mutex_t
*lock
)
54 if ((r
= pthread_mutex_trylock(lock
)) != 0) {
59 rb_bug("native_mutex_trylock return non-zero: %d", r
);
66 native_mutex_initialize(pthread_mutex_t
*lock
)
68 int r
= pthread_mutex_init(lock
, 0);
70 rb_bug("native_mutex_initialize return non-zero: %d", r
);
75 native_mutex_destroy(pthread_mutex_t
*lock
)
77 int r
= pthread_mutex_destroy(lock
);
79 rb_bug("native_mutex_destroy return non-zero: %d", r
);
84 native_cond_initialize(pthread_cond_t
*cond
)
86 int r
= pthread_cond_init(cond
, 0);
88 rb_bug("native_cond_initialize return non-zero: %d", r
);
93 native_cond_destroy(pthread_cond_t
*cond
)
95 int r
= pthread_cond_destroy(cond
);
97 rb_bug("native_cond_destroy return non-zero: %d", r
);
102 native_cond_signal(pthread_cond_t
*cond
)
104 pthread_cond_signal(cond
);
108 native_cond_broadcast(pthread_cond_t
*cond
)
110 pthread_cond_broadcast(cond
);
114 native_cond_wait(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
116 pthread_cond_wait(cond
, mutex
);
120 #define native_cleanup_push pthread_cleanup_push
121 #define native_cleanup_pop pthread_cleanup_pop
122 #define native_thread_yield() sched_yield()
125 static void add_signal_thread_list(rb_thread_t
*th
);
127 static void remove_signal_thread_list(rb_thread_t
*th
);
129 static rb_thread_lock_t signal_thread_list_lock
;
131 static pthread_key_t ruby_native_thread_key
;
140 ruby_thread_from_native(void)
142 return pthread_getspecific(ruby_native_thread_key
);
146 ruby_thread_set_native(rb_thread_t
*th
)
148 return pthread_setspecific(ruby_native_thread_key
, th
) == 0;
152 Init_native_thread(void)
154 rb_thread_t
*th
= GET_THREAD();
156 pthread_key_create(&ruby_native_thread_key
, NULL
);
157 th
->thread_id
= pthread_self();
158 native_cond_initialize(&th
->native_thread_data
.sleep_cond
);
159 ruby_thread_set_native(th
);
160 native_mutex_initialize(&signal_thread_list_lock
);
161 posix_signal(SIGVTALRM
, null_func
);
165 native_thread_destroy(rb_thread_t
*th
)
167 pthread_mutex_destroy(&th
->interrupt_lock
);
168 pthread_cond_destroy(&th
->native_thread_data
.sleep_cond
);
171 #define USE_THREAD_CACHE 0
175 size_t stack_maxsize
;
178 VALUE
*register_stack_start
;
180 } native_main_thread
;
182 #ifdef STACK_END_ADDRESS
183 extern void *STACK_END_ADDRESS
;
186 #undef ruby_init_stack
188 ruby_init_stack(VALUE
*addr
194 native_main_thread
.id
= pthread_self();
195 #ifdef STACK_END_ADDRESS
196 native_main_thread
.stack_start
= STACK_END_ADDRESS
;
198 if (!native_main_thread
.stack_start
||
200 native_main_thread
.stack_start
> addr
,
201 native_main_thread
.stack_start
< addr
)) {
202 native_main_thread
.stack_start
= addr
;
206 if (!native_main_thread
.register_stack_start
||
207 (VALUE
*)bsp
< native_main_thread
.register_stack_start
) {
208 native_main_thread
.register_stack_start
= (VALUE
*)bsp
;
211 #ifdef HAVE_GETRLIMIT
215 if (getrlimit(RLIMIT_STACK
, &rlim
) == 0) {
216 unsigned int space
= rlim
.rlim_cur
/5;
218 if (space
> 1024*1024) space
= 1024*1024;
219 native_main_thread
.stack_maxsize
= rlim
.rlim_cur
- space
;
225 #define CHECK_ERR(expr) \
226 {int err = (expr); if (err) {rb_bug("err: %d - %s", err, #expr);}}
229 native_thread_init_stack(rb_thread_t
*th
)
231 rb_thread_id_t curr
= pthread_self();
233 if (pthread_equal(curr
, native_main_thread
.id
)) {
234 th
->machine_stack_start
= native_main_thread
.stack_start
;
235 th
->machine_stack_maxsize
= native_main_thread
.stack_maxsize
;
238 #ifdef HAVE_PTHREAD_GETATTR_NP
241 CHECK_ERR(pthread_getattr_np(curr
, &attr
));
242 # if defined HAVE_PTHREAD_ATTR_GETSTACK
243 CHECK_ERR(pthread_attr_getstack(&attr
, &start
, &th
->machine_stack_maxsize
));
244 # elif defined HAVE_PTHREAD_ATTR_GETSTACKSIZE && defined HAVE_PTHREAD_ATTR_GETSTACKADDR
245 CHECK_ERR(pthread_attr_getstackaddr(&attr
, &start
));
246 CHECK_ERR(pthread_attr_getstacksize(&attr
, &th
->machine_stack_maxsize
));
248 th
->machine_stack_start
= start
;
250 rb_raise(rb_eNotImpError
, "ruby engine can initialize only in the main thread");
254 th
->machine_register_stack_start
= native_main_thread
.register_stack_start
;
255 th
->machine_stack_maxsize
/= 2;
256 th
->machine_register_stack_maxsize
= th
->machine_stack_maxsize
;
262 thread_start_func_1(void *th_ptr
)
268 rb_thread_t
*th
= th_ptr
;
272 thread_start_func_2(th
, &stack_start
, rb_ia64_bsp());
278 static rb_thread_t
*register_cached_thread_and_wait(void);
279 if ((th
= register_cached_thread_and_wait()) != 0) {
281 th
->thread_id
= pthread_self();
289 void rb_thread_create_control_thread(void);
291 struct cached_thread_entry
{
292 volatile rb_thread_t
**th_area
;
293 pthread_cond_t
*cond
;
294 struct cached_thread_entry
*next
;
299 static pthread_mutex_t thread_cache_lock
= PTHREAD_MUTEX_INITIALIZER
;
300 struct cached_thread_entry
*cached_thread_root
;
303 register_cached_thread_and_wait(void)
305 pthread_cond_t cond
= PTHREAD_COND_INITIALIZER
;
306 volatile rb_thread_t
*th_area
= 0;
307 struct cached_thread_entry
*entry
=
308 (struct cached_thread_entry
*)malloc(sizeof(struct cached_thread_entry
));
312 gettimeofday(&tv
, 0);
313 ts
.tv_sec
= tv
.tv_sec
+ 60;
314 ts
.tv_nsec
= tv
.tv_usec
* 1000;
316 pthread_mutex_lock(&thread_cache_lock
);
318 entry
->th_area
= &th_area
;
320 entry
->next
= cached_thread_root
;
321 cached_thread_root
= entry
;
323 pthread_cond_timedwait(&cond
, &thread_cache_lock
, &ts
);
326 struct cached_thread_entry
*e
= cached_thread_root
;
327 struct cached_thread_entry
*prev
= cached_thread_root
;
331 if (prev
== cached_thread_root
) {
332 cached_thread_root
= e
->next
;
335 prev
->next
= e
->next
;
344 free(entry
); /* ok */
345 pthread_cond_destroy(&cond
);
347 pthread_mutex_unlock(&thread_cache_lock
);
349 return (rb_thread_t
*)th_area
;
354 use_cached_thread(rb_thread_t
*th
)
358 struct cached_thread_entry
*entry
;
360 if (cached_thread_root
) {
361 pthread_mutex_lock(&thread_cache_lock
);
362 entry
= cached_thread_root
;
364 if (cached_thread_root
) {
365 cached_thread_root
= entry
->next
;
366 *entry
->th_area
= th
;
371 pthread_cond_signal(entry
->cond
);
373 pthread_mutex_unlock(&thread_cache_lock
);
380 native_thread_create(rb_thread_t
*th
)
384 if (use_cached_thread(th
)) {
385 thread_debug("create (use cached thread): %p\n", th
);
389 size_t stack_size
= 512 * 1024; /* 512KB */
392 #ifdef PTHREAD_STACK_MIN
393 if (stack_size
< PTHREAD_STACK_MIN
) {
394 stack_size
= PTHREAD_STACK_MIN
* 2;
397 space
= stack_size
/5;
398 if (space
> 1024*1024) space
= 1024*1024;
399 th
->machine_stack_maxsize
= stack_size
- space
;
401 th
->machine_stack_maxsize
/= 2;
402 th
->machine_register_stack_maxsize
= th
->machine_stack_maxsize
;
405 CHECK_ERR(pthread_attr_init(&attr
));
407 #ifdef PTHREAD_STACK_MIN
408 thread_debug("create - stack size: %lu\n", (unsigned long)stack_size
);
409 CHECK_ERR(pthread_attr_setstacksize(&attr
, stack_size
));
412 CHECK_ERR(pthread_attr_setinheritsched(&attr
, PTHREAD_INHERIT_SCHED
));
413 CHECK_ERR(pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
));
415 err
= pthread_create(&th
->thread_id
, &attr
, thread_start_func_1
, th
);
416 thread_debug("create: %p (%d)", th
, err
);
417 CHECK_ERR(pthread_attr_destroy(&attr
));
420 pthread_cond_init(&th
->native_thread_data
.sleep_cond
, 0);
423 st_delete_wrap(th
->vm
->living_threads
, th
->self
);
424 th
->status
= THREAD_KILLED
;
425 rb_raise(rb_eThreadError
, "can't create Thread (%d)", err
);
432 native_thread_join(pthread_t th
)
434 int err
= pthread_join(th
, 0);
436 rb_raise(rb_eThreadError
, "native_thread_join() failed (%d)", err
);
441 native_thread_apply_priority(rb_thread_t
*th
)
443 #if defined(_POSIX_PRIORITY_SCHEDULING) && (_POSIX_PRIORITY_SCHEDULING > 0)
444 struct sched_param sp
;
446 int priority
= 0 - th
->priority
;
448 pthread_getschedparam(th
->thread_id
, &policy
, &sp
);
449 max
= sched_get_priority_max(policy
);
450 min
= sched_get_priority_min(policy
);
452 if (min
> priority
) {
455 else if (max
< priority
) {
459 sp
.sched_priority
= priority
;
460 pthread_setschedparam(th
->thread_id
, policy
, &sp
);
467 ubf_pthread_cond_signal(void *ptr
)
469 rb_thread_t
*th
= (rb_thread_t
*)ptr
;
470 thread_debug("ubf_pthread_cond_signal (%p)\n", th
);
471 pthread_cond_signal(&th
->native_thread_data
.sleep_cond
);
476 ubf_select_each(rb_thread_t
*th
)
478 thread_debug("ubf_select_each (%p)\n", (void *)th
->thread_id
);
480 pthread_kill(th
->thread_id
, SIGVTALRM
);
485 ubf_select(void *ptr
)
487 rb_thread_t
*th
= (rb_thread_t
*)ptr
;
488 add_signal_thread_list(th
);
496 native_sleep(rb_thread_t
*th
, struct timeval
*tv
, int deadlockable
)
498 int prev_status
= th
->status
;
503 gettimeofday(&tvn
, NULL
);
504 ts
.tv_sec
= tvn
.tv_sec
+ tv
->tv_sec
;
505 ts
.tv_nsec
= (tvn
.tv_usec
+ tv
->tv_usec
) * 1000;
506 if (ts
.tv_nsec
>= 1000000000){
508 ts
.tv_nsec
-= 1000000000;
512 if (!tv
&& deadlockable
) {
513 th
->status
= THREAD_STOPPED_FOREVER
;
515 rb_check_deadlock(th
->vm
);
518 th
->status
= THREAD_STOPPED
;
521 thread_debug("native_sleep %ld\n", tv
? tv
->tv_sec
: -1);
524 pthread_mutex_lock(&th
->interrupt_lock
);
525 th
->unblock
.func
= ubf_pthread_cond_signal
;
526 th
->unblock
.arg
= th
;
528 if (RUBY_VM_INTERRUPTED(th
)) {
529 /* interrupted. return immediate */
530 thread_debug("native_sleep: interrupted before sleep\n");
533 if (tv
== 0 || ts
.tv_sec
< tvn
.tv_sec
/* overflow */ ) {
535 thread_debug("native_sleep: pthread_cond_wait start\n");
536 r
= pthread_cond_wait(&th
->native_thread_data
.sleep_cond
,
537 &th
->interrupt_lock
);
538 if (r
) rb_bug("pthread_cond_wait: %d", r
);
539 thread_debug("native_sleep: pthread_cond_wait end\n");
543 thread_debug("native_sleep: pthread_cond_timedwait start (%ld, %ld)\n",
544 (unsigned long)ts
.tv_sec
, ts
.tv_nsec
);
545 r
= pthread_cond_timedwait(&th
->native_thread_data
.sleep_cond
,
546 &th
->interrupt_lock
, &ts
);
547 if (r
&& r
!= ETIMEDOUT
) rb_bug("pthread_cond_timedwait: %d", r
);
549 thread_debug("native_sleep: pthread_cond_timedwait end (%d)\n", r
);
552 th
->unblock
.func
= 0;
555 pthread_mutex_unlock(&th
->interrupt_lock
);
558 th
->status
= prev_status
;
559 if (!tv
&& deadlockable
) th
->vm
->sleeper
--;
560 RUBY_VM_CHECK_INTS();
562 thread_debug("native_sleep done\n");
565 struct signal_thread_list
{
567 struct signal_thread_list
*prev
;
568 struct signal_thread_list
*next
;
572 static struct signal_thread_list signal_thread_list_anchor
= {
577 #define FGLOCK(lock, body) do { \
578 native_mutex_lock(lock); \
582 native_mutex_unlock(lock); \
585 #if 0 /* for debug */
587 print_signal_list(char *str
)
589 struct signal_thread_list
*list
=
590 signal_thread_list_anchor
.next
;
591 thread_debug("list (%s)> ", str
);
593 thread_debug("%p (%p), ", list
->th
, list
->th
->thread_id
);
602 add_signal_thread_list(rb_thread_t
*th
)
604 if (!th
->native_thread_data
.signal_thread_list
) {
605 FGLOCK(&signal_thread_list_lock
, {
606 struct signal_thread_list
*list
=
607 malloc(sizeof(struct signal_thread_list
));
610 fprintf(stderr
, "[FATAL] failed to allocate memory\n");
616 list
->prev
= &signal_thread_list_anchor
;
617 list
->next
= signal_thread_list_anchor
.next
;
619 list
->next
->prev
= list
;
621 signal_thread_list_anchor
.next
= list
;
622 th
->native_thread_data
.signal_thread_list
= list
;
629 remove_signal_thread_list(rb_thread_t
*th
)
631 if (th
->native_thread_data
.signal_thread_list
) {
632 FGLOCK(&signal_thread_list_lock
, {
633 struct signal_thread_list
*list
=
634 (struct signal_thread_list
*)
635 th
->native_thread_data
.signal_thread_list
;
637 list
->prev
->next
= list
->next
;
639 list
->next
->prev
= list
->prev
;
641 th
->native_thread_data
.signal_thread_list
= 0;
651 static pthread_t timer_thread_id
;
654 thread_timer(void *dummy
)
656 while (system_working
) {
657 #ifdef HAVE_NANOSLEEP
658 struct timespec req
, rem
;
660 req
.tv_nsec
= 10 * 1000 * 1000; /* 10 ms */
661 nanosleep(&req
, &rem
);
665 tv
.tv_usec
= 10000; /* 10 ms */
666 select(0, NULL
, NULL
, NULL
, &tv
);
669 if (signal_thread_list_anchor
.next
) {
670 FGLOCK(&signal_thread_list_lock
, {
671 struct signal_thread_list
*list
;
672 list
= signal_thread_list_anchor
.next
;
674 ubf_select_each(list
->th
);
680 timer_thread_function(dummy
);
686 rb_thread_create_timer_thread(void)
688 rb_enable_interrupt();
690 if (!timer_thread_id
) {
694 pthread_attr_init(&attr
);
695 #ifdef PTHREAD_STACK_MIN
696 pthread_attr_setstacksize(&attr
,
697 PTHREAD_STACK_MIN
+ (THREAD_DEBUG
? BUFSIZ
: 0));
699 err
= pthread_create(&timer_thread_id
, &attr
, thread_timer
, GET_VM());
701 rb_bug("rb_thread_create_timer_thread: return non-zero (%d)", err
);
704 rb_disable_interrupt(); /* only timer thread recieve signal */
707 #endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */