Ruby 2.1.5p273(2014-11-13revision48405)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

thread_pthread.c
Go to the documentation of this file.
1 /* -*-c-*- */
2 /**********************************************************************
3
4 thread_pthread.c -
5
6 $Author: nagachika $
7
8 Copyright (C) 2004-2007 Koichi Sasada
9
10 **********************************************************************/
11
12 #ifdef THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
13
14 #include "gc.h"
15
16 #ifdef HAVE_SYS_RESOURCE_H
17 #include <sys/resource.h>
18 #endif
19 #ifdef HAVE_THR_STKSEGMENT
20 #include <thread.h>
21 #endif
22 #if HAVE_FCNTL_H
23 #include <fcntl.h>
24 #elif HAVE_SYS_FCNTL_H
25 #include <sys/fcntl.h>
26 #endif
27 #ifdef HAVE_SYS_PRCTL_H
28 #include <sys/prctl.h>
29 #endif
30 #if defined(__native_client__) && defined(NACL_NEWLIB)
31 # include "nacl/select.h"
32 #endif
33 #if defined(HAVE_SYS_TIME_H)
34 #include <sys/time.h>
35 #endif
36
37 static void native_mutex_lock(pthread_mutex_t *lock);
38 static void native_mutex_unlock(pthread_mutex_t *lock);
39 static int native_mutex_trylock(pthread_mutex_t *lock);
40 static void native_mutex_initialize(pthread_mutex_t *lock);
41 static void native_mutex_destroy(pthread_mutex_t *lock);
42 static void native_cond_signal(rb_nativethread_cond_t *cond);
43 static void native_cond_broadcast(rb_nativethread_cond_t *cond);
44 static void native_cond_wait(rb_nativethread_cond_t *cond, pthread_mutex_t *mutex);
45 static void native_cond_initialize(rb_nativethread_cond_t *cond, int flags);
46 static void native_cond_destroy(rb_nativethread_cond_t *cond);
47 static void rb_thread_wakeup_timer_thread_low(void);
48 static pthread_t timer_thread_id;
49
50 #define RB_CONDATTR_CLOCK_MONOTONIC 1
51
52 #if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(HAVE_CLOCKID_T) && \
53 defined(CLOCK_REALTIME) && defined(CLOCK_MONOTONIC) && \
54 defined(HAVE_CLOCK_GETTIME) && defined(HAVE_PTHREAD_CONDATTR_INIT)
55 #define USE_MONOTONIC_COND 1
56 #else
57 #define USE_MONOTONIC_COND 0
58 #endif
59
60 #if defined(HAVE_POLL) && defined(HAVE_FCNTL) && defined(F_GETFL) && defined(F_SETFL) && defined(O_NONBLOCK) && !defined(__native_client__)
61 /* The timer thread sleeps while only one Ruby thread is running. */
62 # define USE_SLEEPY_TIMER_THREAD 1
63 #else
64 # define USE_SLEEPY_TIMER_THREAD 0
65 #endif
66
67 static void
68 gvl_acquire_common(rb_vm_t *vm)
69 {
70 if (vm->gvl.acquired) {
71
72 vm->gvl.waiting++;
73 if (vm->gvl.waiting == 1) {
74 /*
75 * Wake up timer thread iff timer thread is slept.
76 * When timer thread is polling mode, we don't want to
77 * make confusing timer thread interval time.
78 */
79 rb_thread_wakeup_timer_thread_low();
80 }
81
82 while (vm->gvl.acquired) {
83 native_cond_wait(&vm->gvl.cond, &vm->gvl.lock);
84 }
85
86 vm->gvl.waiting--;
87
88 if (vm->gvl.need_yield) {
89 vm->gvl.need_yield = 0;
90 native_cond_signal(&vm->gvl.switch_cond);
91 }
92 }
93
94 vm->gvl.acquired = 1;
95 }
96
97 static void
98 gvl_acquire(rb_vm_t *vm, rb_thread_t *th)
99 {
100 native_mutex_lock(&vm->gvl.lock);
101 gvl_acquire_common(vm);
102 native_mutex_unlock(&vm->gvl.lock);
103 }
104
105 static void
106 gvl_release_common(rb_vm_t *vm)
107 {
108 vm->gvl.acquired = 0;
109 if (vm->gvl.waiting > 0)
110 native_cond_signal(&vm->gvl.cond);
111 }
112
113 static void
114 gvl_release(rb_vm_t *vm)
115 {
116 native_mutex_lock(&vm->gvl.lock);
117 gvl_release_common(vm);
118 native_mutex_unlock(&vm->gvl.lock);
119 }
120
121 static void
122 gvl_yield(rb_vm_t *vm, rb_thread_t *th)
123 {
124 native_mutex_lock(&vm->gvl.lock);
125
126 gvl_release_common(vm);
127
128 /* An another thread is processing GVL yield. */
129 if (UNLIKELY(vm->gvl.wait_yield)) {
130 while (vm->gvl.wait_yield)
131 native_cond_wait(&vm->gvl.switch_wait_cond, &vm->gvl.lock);
132 goto acquire;
133 }
134
135 if (vm->gvl.waiting > 0) {
136 /* Wait until another thread task take GVL. */
137 vm->gvl.need_yield = 1;
138 vm->gvl.wait_yield = 1;
139 while (vm->gvl.need_yield)
140 native_cond_wait(&vm->gvl.switch_cond, &vm->gvl.lock);
141 vm->gvl.wait_yield = 0;
142 }
143 else {
144 native_mutex_unlock(&vm->gvl.lock);
145 sched_yield();
146 native_mutex_lock(&vm->gvl.lock);
147 }
148
149 native_cond_broadcast(&vm->gvl.switch_wait_cond);
150 acquire:
151 gvl_acquire_common(vm);
152 native_mutex_unlock(&vm->gvl.lock);
153 }
154
155 static void
156 gvl_init(rb_vm_t *vm)
157 {
158 native_mutex_initialize(&vm->gvl.lock);
159 native_cond_initialize(&vm->gvl.cond, RB_CONDATTR_CLOCK_MONOTONIC);
160 native_cond_initialize(&vm->gvl.switch_cond, RB_CONDATTR_CLOCK_MONOTONIC);
161 native_cond_initialize(&vm->gvl.switch_wait_cond, RB_CONDATTR_CLOCK_MONOTONIC);
162 vm->gvl.acquired = 0;
163 vm->gvl.waiting = 0;
164 vm->gvl.need_yield = 0;
165 vm->gvl.wait_yield = 0;
166 }
167
168 static void
169 gvl_destroy(rb_vm_t *vm)
170 {
171 native_cond_destroy(&vm->gvl.switch_wait_cond);
172 native_cond_destroy(&vm->gvl.switch_cond);
173 native_cond_destroy(&vm->gvl.cond);
174 native_mutex_destroy(&vm->gvl.lock);
175 }
176
177 static void
178 gvl_atfork(rb_vm_t *vm)
179 {
180 gvl_init(vm);
181 gvl_acquire(vm, GET_THREAD());
182 }
183
184 #define NATIVE_MUTEX_LOCK_DEBUG 0
185
186 static void
187 mutex_debug(const char *msg, pthread_mutex_t *lock)
188 {
189 if (NATIVE_MUTEX_LOCK_DEBUG) {
190 int r;
191 static pthread_mutex_t dbglock = PTHREAD_MUTEX_INITIALIZER;
192
193 if ((r = pthread_mutex_lock(&dbglock)) != 0) {exit(EXIT_FAILURE);}
194 fprintf(stdout, "%s: %p\n", msg, (void *)lock);
195 if ((r = pthread_mutex_unlock(&dbglock)) != 0) {exit(EXIT_FAILURE);}
196 }
197 }
198
199 static void
200 native_mutex_lock(pthread_mutex_t *lock)
201 {
202 int r;
203 mutex_debug("lock", lock);
204 if ((r = pthread_mutex_lock(lock)) != 0) {
205 rb_bug_errno("pthread_mutex_lock", r);
206 }
207 }
208
209 static void
210 native_mutex_unlock(pthread_mutex_t *lock)
211 {
212 int r;
213 mutex_debug("unlock", lock);
214 if ((r = pthread_mutex_unlock(lock)) != 0) {
215 rb_bug_errno("pthread_mutex_unlock", r);
216 }
217 }
218
219 static inline int
220 native_mutex_trylock(pthread_mutex_t *lock)
221 {
222 int r;
223 mutex_debug("trylock", lock);
224 if ((r = pthread_mutex_trylock(lock)) != 0) {
225 if (r == EBUSY) {
226 return EBUSY;
227 }
228 else {
229 rb_bug_errno("pthread_mutex_trylock", r);
230 }
231 }
232 return 0;
233 }
234
235 static void
236 native_mutex_initialize(pthread_mutex_t *lock)
237 {
238 int r = pthread_mutex_init(lock, 0);
239 mutex_debug("init", lock);
240 if (r != 0) {
241 rb_bug_errno("pthread_mutex_init", r);
242 }
243 }
244
245 static void
246 native_mutex_destroy(pthread_mutex_t *lock)
247 {
248 int r = pthread_mutex_destroy(lock);
249 mutex_debug("destroy", lock);
250 if (r != 0) {
251 rb_bug_errno("pthread_mutex_destroy", r);
252 }
253 }
254
255 static void
256 native_cond_initialize(rb_nativethread_cond_t *cond, int flags)
257 {
258 #ifdef HAVE_PTHREAD_COND_INIT
259 int r;
260 # if USE_MONOTONIC_COND
261 pthread_condattr_t attr;
262
263 pthread_condattr_init(&attr);
264
265 cond->clockid = CLOCK_REALTIME;
266 if (flags & RB_CONDATTR_CLOCK_MONOTONIC) {
267 r = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
268 if (r == 0) {
269 cond->clockid = CLOCK_MONOTONIC;
270 }
271 }
272
273 r = pthread_cond_init(&cond->cond, &attr);
274 pthread_condattr_destroy(&attr);
275 # else
276 r = pthread_cond_init(&cond->cond, NULL);
277 # endif
278 if (r != 0) {
279 rb_bug_errno("pthread_cond_init", r);
280 }
281
282 return;
283 #endif
284 }
285
286 static void
287 native_cond_destroy(rb_nativethread_cond_t *cond)
288 {
289 #ifdef HAVE_PTHREAD_COND_INIT
290 int r = pthread_cond_destroy(&cond->cond);
291 if (r != 0) {
292 rb_bug_errno("pthread_cond_destroy", r);
293 }
294 #endif
295 }
296
297 /*
298 * In OS X 10.7 (Lion), pthread_cond_signal and pthread_cond_broadcast return
299 * EAGAIN after retrying 8192 times. You can see them in the following page:
300 *
301 * http://www.opensource.apple.com/source/Libc/Libc-763.11/pthreads/pthread_cond.c
302 *
303 * The following native_cond_signal and native_cond_broadcast functions
304 * need to retrying until pthread functions don't return EAGAIN.
305 */
306
307 static void
308 native_cond_signal(rb_nativethread_cond_t *cond)
309 {
310 int r;
311 do {
312 r = pthread_cond_signal(&cond->cond);
313 } while (r == EAGAIN);
314 if (r != 0) {
315 rb_bug_errno("pthread_cond_signal", r);
316 }
317 }
318
319 static void
320 native_cond_broadcast(rb_nativethread_cond_t *cond)
321 {
322 int r;
323 do {
324 r = pthread_cond_broadcast(&cond->cond);
325 } while (r == EAGAIN);
326 if (r != 0) {
327 rb_bug_errno("native_cond_broadcast", r);
328 }
329 }
330
331 static void
332 native_cond_wait(rb_nativethread_cond_t *cond, pthread_mutex_t *mutex)
333 {
334 int r = pthread_cond_wait(&cond->cond, mutex);
335 if (r != 0) {
336 rb_bug_errno("pthread_cond_wait", r);
337 }
338 }
339
340 static int
341 native_cond_timedwait(rb_nativethread_cond_t *cond, pthread_mutex_t *mutex, struct timespec *ts)
342 {
343 int r;
344
345 /*
346 * An old Linux may return EINTR. Even though POSIX says
347 * "These functions shall not return an error code of [EINTR]".
348 * http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_cond_timedwait.html
349 * Let's hide it from arch generic code.
350 */
351 do {
352 r = pthread_cond_timedwait(&cond->cond, mutex, ts);
353 } while (r == EINTR);
354
355 if (r != 0 && r != ETIMEDOUT) {
356 rb_bug_errno("pthread_cond_timedwait", r);
357 }
358
359 return r;
360 }
361
362 static struct timespec
363 native_cond_timeout(rb_nativethread_cond_t *cond, struct timespec timeout_rel)
364 {
365 int ret;
366 struct timeval tv;
367 struct timespec timeout;
368 struct timespec now;
369
370 #if USE_MONOTONIC_COND
371 if (cond->clockid == CLOCK_MONOTONIC) {
372 ret = clock_gettime(cond->clockid, &now);
373 if (ret != 0)
374 rb_sys_fail("clock_gettime()");
375 goto out;
376 }
377
378 if (cond->clockid != CLOCK_REALTIME)
379 rb_bug("unsupported clockid %"PRIdVALUE, (SIGNED_VALUE)cond->clockid);
380 #endif
381
382 ret = gettimeofday(&tv, 0);
383 if (ret != 0)
384 rb_sys_fail(0);
385 now.tv_sec = tv.tv_sec;
386 now.tv_nsec = tv.tv_usec * 1000;
387
388 #if USE_MONOTONIC_COND
389 out:
390 #endif
391 timeout.tv_sec = now.tv_sec;
392 timeout.tv_nsec = now.tv_nsec;
393 timeout.tv_sec += timeout_rel.tv_sec;
394 timeout.tv_nsec += timeout_rel.tv_nsec;
395
396 if (timeout.tv_nsec >= 1000*1000*1000) {
397 timeout.tv_sec++;
398 timeout.tv_nsec -= 1000*1000*1000;
399 }
400
401 if (timeout.tv_sec < now.tv_sec)
402 timeout.tv_sec = TIMET_MAX;
403
404 return timeout;
405 }
406
407 #define native_cleanup_push pthread_cleanup_push
408 #define native_cleanup_pop pthread_cleanup_pop
409 #ifdef HAVE_SCHED_YIELD
410 #define native_thread_yield() (void)sched_yield()
411 #else
412 #define native_thread_yield() ((void)0)
413 #endif
414
415 #if defined(SIGVTALRM) && !defined(__CYGWIN__) && !defined(__SYMBIAN32__)
416 #define USE_SIGNAL_THREAD_LIST 1
417 #endif
418 #ifdef USE_SIGNAL_THREAD_LIST
419 static void add_signal_thread_list(rb_thread_t *th);
420 static void remove_signal_thread_list(rb_thread_t *th);
421 static rb_nativethread_lock_t signal_thread_list_lock;
422 #endif
423
424 static pthread_key_t ruby_native_thread_key;
425
426 static void
427 null_func(int i)
428 {
429 /* null */
430 }
431
432 static rb_thread_t *
433 ruby_thread_from_native(void)
434 {
435 return pthread_getspecific(ruby_native_thread_key);
436 }
437
438 static int
439 ruby_thread_set_native(rb_thread_t *th)
440 {
441 return pthread_setspecific(ruby_native_thread_key, th) == 0;
442 }
443
444 static void native_thread_init(rb_thread_t *th);
445
446 void
447 Init_native_thread(void)
448 {
449 rb_thread_t *th = GET_THREAD();
450
451 pthread_key_create(&ruby_native_thread_key, NULL);
452 th->thread_id = pthread_self();
453 native_thread_init(th);
454 #ifdef USE_SIGNAL_THREAD_LIST
455 native_mutex_initialize(&signal_thread_list_lock);
456 #endif
457 #ifndef __native_client__
458 posix_signal(SIGVTALRM, null_func);
459 #endif
460 }
461
462 static void
463 native_thread_init(rb_thread_t *th)
464 {
465 native_cond_initialize(&th->native_thread_data.sleep_cond, RB_CONDATTR_CLOCK_MONOTONIC);
466 ruby_thread_set_native(th);
467 }
468
469 static void
470 native_thread_destroy(rb_thread_t *th)
471 {
472 native_cond_destroy(&th->native_thread_data.sleep_cond);
473 }
474
475 #ifndef USE_THREAD_CACHE
476 #define USE_THREAD_CACHE 0
477 #endif
478
479 #if USE_THREAD_CACHE
480 static rb_thread_t *register_cached_thread_and_wait(void);
481 #endif
482
483 #if defined HAVE_PTHREAD_GETATTR_NP || defined HAVE_PTHREAD_ATTR_GET_NP
484 #define STACKADDR_AVAILABLE 1
485 #elif defined HAVE_PTHREAD_GET_STACKADDR_NP && defined HAVE_PTHREAD_GET_STACKSIZE_NP
486 #define STACKADDR_AVAILABLE 1
487 #undef MAINSTACKADDR_AVAILABLE
488 #define MAINSTACKADDR_AVAILABLE 1
489 void *pthread_get_stackaddr_np(pthread_t);
490 size_t pthread_get_stacksize_np(pthread_t);
491 #elif defined HAVE_THR_STKSEGMENT || defined HAVE_PTHREAD_STACKSEG_NP
492 #define STACKADDR_AVAILABLE 1
493 #elif defined HAVE_PTHREAD_GETTHRDS_NP
494 #define STACKADDR_AVAILABLE 1
495 #elif defined __ia64 && defined _HPUX_SOURCE
496 #include <sys/dyntune.h>
497
498 #define STACKADDR_AVAILABLE 1
499
500 /*
501 * Do not lower the thread's stack to PTHREAD_STACK_MIN,
502 * otherwise one would receive a 'sendsig: useracc failed.'
503 * and a coredump.
504 */
505 #undef PTHREAD_STACK_MIN
506
507 #define HAVE_PTHREAD_ATTR_GET_NP 1
508 #undef HAVE_PTHREAD_ATTR_GETSTACK
509
510 /*
511 * As the PTHREAD_STACK_MIN is undefined and
512 * noone touches the default stacksize,
513 * it is just fine to use the default.
514 */
515 #define pthread_attr_get_np(thid, attr) 0
516
517 /*
518 * Using value of sp is very rough... To make it more real,
519 * addr would need to be aligned to vps_pagesize.
520 * The vps_pagesize is 'Default user page size (kBytes)'
521 * and could be retrieved by gettune().
522 */
523 static int
524 hpux_attr_getstackaddr(const pthread_attr_t *attr, void **addr)
525 {
526 static uint64_t pagesize;
527 size_t size;
528
529 if (!pagesize) {
530 if (gettune("vps_pagesize", &pagesize)) {
531 pagesize = 16;
532 }
533 pagesize *= 1024;
534 }
535 pthread_attr_getstacksize(attr, &size);
536 *addr = (void *)((size_t)((char *)_Asm_get_sp() - size) & ~(pagesize - 1));
537 return 0;
538 }
539 #define pthread_attr_getstackaddr(attr, addr) hpux_attr_getstackaddr(attr, addr)
540 #endif
541
542 #ifndef MAINSTACKADDR_AVAILABLE
543 # ifdef STACKADDR_AVAILABLE
544 # define MAINSTACKADDR_AVAILABLE 1
545 # else
546 # define MAINSTACKADDR_AVAILABLE 0
547 # endif
548 #endif
549 #if MAINSTACKADDR_AVAILABLE && !defined(get_main_stack)
550 # define get_main_stack(addr, size) get_stack(addr, size)
551 #endif
552
553 #ifdef STACKADDR_AVAILABLE
554 /*
555 * Get the initial address and size of current thread's stack
556 */
557 static int
558 get_stack(void **addr, size_t *size)
559 {
560 #define CHECK_ERR(expr) \
561 {int err = (expr); if (err) return err;}
562 #ifdef HAVE_PTHREAD_GETATTR_NP /* Linux */
563 pthread_attr_t attr;
564 size_t guard = 0;
565 STACK_GROW_DIR_DETECTION;
566 CHECK_ERR(pthread_getattr_np(pthread_self(), &attr));
567 # ifdef HAVE_PTHREAD_ATTR_GETSTACK
568 CHECK_ERR(pthread_attr_getstack(&attr, addr, size));
569 STACK_DIR_UPPER((void)0, (void)(*addr = (char *)*addr + *size));
570 # else
571 CHECK_ERR(pthread_attr_getstackaddr(&attr, addr));
572 CHECK_ERR(pthread_attr_getstacksize(&attr, size));
573 # endif
574 CHECK_ERR(pthread_attr_getguardsize(&attr, &guard));
575 *size -= guard;
576 pthread_attr_destroy(&attr);
577 #elif defined HAVE_PTHREAD_ATTR_GET_NP /* FreeBSD, DragonFly BSD, NetBSD */
578 pthread_attr_t attr;
579 CHECK_ERR(pthread_attr_init(&attr));
580 CHECK_ERR(pthread_attr_get_np(pthread_self(), &attr));
581 # ifdef HAVE_PTHREAD_ATTR_GETSTACK
582 CHECK_ERR(pthread_attr_getstack(&attr, addr, size));
583 # else
584 CHECK_ERR(pthread_attr_getstackaddr(&attr, addr));
585 CHECK_ERR(pthread_attr_getstacksize(&attr, size));
586 # endif
587 STACK_DIR_UPPER((void)0, (void)(*addr = (char *)*addr + *size));
588 pthread_attr_destroy(&attr);
589 #elif (defined HAVE_PTHREAD_GET_STACKADDR_NP && defined HAVE_PTHREAD_GET_STACKSIZE_NP) /* MacOS X */
590 pthread_t th = pthread_self();
591 *addr = pthread_get_stackaddr_np(th);
592 *size = pthread_get_stacksize_np(th);
593 #elif defined HAVE_THR_STKSEGMENT || defined HAVE_PTHREAD_STACKSEG_NP
594 stack_t stk;
595 # if defined HAVE_THR_STKSEGMENT /* Solaris */
596 CHECK_ERR(thr_stksegment(&stk));
597 # else /* OpenBSD */
598 CHECK_ERR(pthread_stackseg_np(pthread_self(), &stk));
599 # endif
600 *addr = stk.ss_sp;
601 *size = stk.ss_size;
602 #elif defined HAVE_PTHREAD_GETTHRDS_NP /* AIX */
603 pthread_t th = pthread_self();
604 struct __pthrdsinfo thinfo;
605 char reg[256];
606 int regsiz=sizeof(reg);
607 CHECK_ERR(pthread_getthrds_np(&th, PTHRDSINFO_QUERY_ALL,
608 &thinfo, sizeof(thinfo),
609 &reg, &regsiz));
610 *addr = thinfo.__pi_stackaddr;
611 *size = thinfo.__pi_stacksize;
612 STACK_DIR_UPPER((void)0, (void)(*addr = (char *)*addr + *size));
613 #else
614 #error STACKADDR_AVAILABLE is defined but not implemented.
615 #endif
616 return 0;
617 #undef CHECK_ERR
618 }
619 #endif
620
621 static struct {
622 rb_nativethread_id_t id;
623 size_t stack_maxsize;
624 VALUE *stack_start;
625 #ifdef __ia64
626 VALUE *register_stack_start;
627 #endif
628 } native_main_thread;
629
630 #ifdef STACK_END_ADDRESS
631 extern void *STACK_END_ADDRESS;
632 #endif
633
634 enum {
635 RUBY_STACK_SPACE_LIMIT = 1024 * 1024, /* 1024KB */
636 RUBY_STACK_SPACE_RATIO = 5
637 };
638
639 static size_t
640 space_size(size_t stack_size)
641 {
642 size_t space_size = stack_size / RUBY_STACK_SPACE_RATIO;
643 if (space_size > RUBY_STACK_SPACE_LIMIT) {
644 return RUBY_STACK_SPACE_LIMIT;
645 }
646 else {
647 return space_size;
648 }
649 }
650
651 #undef ruby_init_stack
652 /* Set stack bottom of Ruby implementation.
653 *
654 * You must call this function before any heap allocation by Ruby implementation.
655 * Or GC will break living objects */
656 void
657 ruby_init_stack(volatile VALUE *addr
658 #ifdef __ia64
659 , void *bsp
660 #endif
661 )
662 {
663 native_main_thread.id = pthread_self();
664 #if MAINSTACKADDR_AVAILABLE
665 if (native_main_thread.stack_maxsize) return;
666 {
667 void* stackaddr;
668 size_t size;
669 if (get_main_stack(&stackaddr, &size) == 0) {
670 native_main_thread.stack_maxsize = size;
671 native_main_thread.stack_start = stackaddr;
672 return;
673 }
674 }
675 #endif
676 #ifdef STACK_END_ADDRESS
677 native_main_thread.stack_start = STACK_END_ADDRESS;
678 #else
679 if (!native_main_thread.stack_start ||
680 STACK_UPPER((VALUE *)(void *)&addr,
681 native_main_thread.stack_start > addr,
682 native_main_thread.stack_start < addr)) {
683 native_main_thread.stack_start = (VALUE *)addr;
684 }
685 #endif
686 #ifdef __ia64
687 if (!native_main_thread.register_stack_start ||
688 (VALUE*)bsp < native_main_thread.register_stack_start) {
689 native_main_thread.register_stack_start = (VALUE*)bsp;
690 }
691 #endif
692 {
693 #if defined(HAVE_GETRLIMIT)
694 #if defined(PTHREAD_STACK_DEFAULT)
695 # if PTHREAD_STACK_DEFAULT < RUBY_STACK_SPACE*5
696 # error "PTHREAD_STACK_DEFAULT is too small"
697 # endif
698 size_t size = PTHREAD_STACK_DEFAULT;
699 #else
700 size_t size = RUBY_VM_THREAD_VM_STACK_SIZE;
701 #endif
702 size_t space;
703 int pagesize = getpagesize();
704 struct rlimit rlim;
705 STACK_GROW_DIR_DETECTION;
706 if (getrlimit(RLIMIT_STACK, &rlim) == 0) {
707 size = (size_t)rlim.rlim_cur;
708 }
709 addr = native_main_thread.stack_start;
710 if (IS_STACK_DIR_UPPER()) {
711 space = ((size_t)((char *)addr + size) / pagesize) * pagesize - (size_t)addr;
712 }
713 else {
714 space = (size_t)addr - ((size_t)((char *)addr - size) / pagesize + 1) * pagesize;
715 }
716 native_main_thread.stack_maxsize = space;
717 #endif
718 }
719
720 /* If addr is out of range of main-thread stack range estimation, */
721 /* it should be on co-routine (alternative stack). [Feature #2294] */
722 {
723 void *start, *end;
724 STACK_GROW_DIR_DETECTION;
725
726 if (IS_STACK_DIR_UPPER()) {
727 start = native_main_thread.stack_start;
728 end = (char *)native_main_thread.stack_start + native_main_thread.stack_maxsize;
729 }
730 else {
731 start = (char *)native_main_thread.stack_start - native_main_thread.stack_maxsize;
732 end = native_main_thread.stack_start;
733 }
734
735 if ((void *)addr < start || (void *)addr > end) {
736 /* out of range */
737 native_main_thread.stack_start = (VALUE *)addr;
738 native_main_thread.stack_maxsize = 0; /* unknown */
739 }
740 }
741 }
742
743 #define CHECK_ERR(expr) \
744 {int err = (expr); if (err) {rb_bug_errno(#expr, err);}}
745
746 static int
747 native_thread_init_stack(rb_thread_t *th)
748 {
749 rb_nativethread_id_t curr = pthread_self();
750
751 if (pthread_equal(curr, native_main_thread.id)) {
752 th->machine.stack_start = native_main_thread.stack_start;
753 th->machine.stack_maxsize = native_main_thread.stack_maxsize;
754 }
755 else {
756 #ifdef STACKADDR_AVAILABLE
757 void *start;
758 size_t size;
759
760 if (get_stack(&start, &size) == 0) {
761 th->machine.stack_start = start;
762 th->machine.stack_maxsize = size;
763 }
764 #elif defined get_stack_of
765 if (!th->machine.stack_maxsize) {
766 native_mutex_lock(&th->interrupt_lock);
767 native_mutex_unlock(&th->interrupt_lock);
768 }
769 #else
770 rb_raise(rb_eNotImpError, "ruby engine can initialize only in the main thread");
771 #endif
772 }
773 #ifdef __ia64
774 th->machine.register_stack_start = native_main_thread.register_stack_start;
775 th->machine.stack_maxsize /= 2;
776 th->machine.register_stack_maxsize = th->machine.stack_maxsize;
777 #endif
778 return 0;
779 }
780
781 #ifndef __CYGWIN__
782 #define USE_NATIVE_THREAD_INIT 1
783 #endif
784
785 static void *
786 thread_start_func_1(void *th_ptr)
787 {
788 #if USE_THREAD_CACHE
789 thread_start:
790 #endif
791 {
792 rb_thread_t *th = th_ptr;
793 #if !defined USE_NATIVE_THREAD_INIT
794 VALUE stack_start;
795 #endif
796
797 #if defined USE_NATIVE_THREAD_INIT
798 native_thread_init_stack(th);
799 #endif
800 native_thread_init(th);
801 /* run */
802 #if defined USE_NATIVE_THREAD_INIT
803 thread_start_func_2(th, th->machine.stack_start, rb_ia64_bsp());
804 #else
805 thread_start_func_2(th, &stack_start, rb_ia64_bsp());
806 #endif
807 }
808 #if USE_THREAD_CACHE
809 if (1) {
810 /* cache thread */
811 rb_thread_t *th;
812 if ((th = register_cached_thread_and_wait()) != 0) {
813 th_ptr = (void *)th;
814 th->thread_id = pthread_self();
815 goto thread_start;
816 }
817 }
818 #endif
819 return 0;
820 }
821
822 struct cached_thread_entry {
823 volatile rb_thread_t **th_area;
824 rb_nativethread_cond_t *cond;
825 struct cached_thread_entry *next;
826 };
827
828
829 #if USE_THREAD_CACHE
830 static pthread_mutex_t thread_cache_lock = PTHREAD_MUTEX_INITIALIZER;
831 struct cached_thread_entry *cached_thread_root;
832
833 static rb_thread_t *
834 register_cached_thread_and_wait(void)
835 {
836 rb_nativethread_cond_t cond = { PTHREAD_COND_INITIALIZER, };
837 volatile rb_thread_t *th_area = 0;
838 struct timeval tv;
839 struct timespec ts;
840 struct cached_thread_entry *entry =
841 (struct cached_thread_entry *)malloc(sizeof(struct cached_thread_entry));
842
843 if (entry == 0) {
844 return 0; /* failed -> terminate thread immediately */
845 }
846
847 gettimeofday(&tv, 0);
848 ts.tv_sec = tv.tv_sec + 60;
849 ts.tv_nsec = tv.tv_usec * 1000;
850
851 pthread_mutex_lock(&thread_cache_lock);
852 {
853 entry->th_area = &th_area;
854 entry->cond = &cond;
855 entry->next = cached_thread_root;
856 cached_thread_root = entry;
857
858 native_cond_timedwait(&cond, &thread_cache_lock, &ts);
859
860 {
861 struct cached_thread_entry *e, **prev = &cached_thread_root;
862
863 while ((e = *prev) != 0) {
864 if (e == entry) {
865 *prev = e->next;
866 break;
867 }
868 prev = &e->next;
869 }
870 }
871
872 free(entry); /* ok */
873 native_cond_destroy(&cond);
874 }
875 pthread_mutex_unlock(&thread_cache_lock);
876
877 return (rb_thread_t *)th_area;
878 }
879 #endif
880
881 static int
882 use_cached_thread(rb_thread_t *th)
883 {
884 int result = 0;
885 #if USE_THREAD_CACHE
886 struct cached_thread_entry *entry;
887
888 if (cached_thread_root) {
889 pthread_mutex_lock(&thread_cache_lock);
890 entry = cached_thread_root;
891 {
892 if (cached_thread_root) {
893 cached_thread_root = entry->next;
894 *entry->th_area = th;
895 result = 1;
896 }
897 }
898 if (result) {
899 native_cond_signal(entry->cond);
900 }
901 pthread_mutex_unlock(&thread_cache_lock);
902 }
903 #endif
904 return result;
905 }
906
907 static int
908 native_thread_create(rb_thread_t *th)
909 {
910 int err = 0;
911
912 if (use_cached_thread(th)) {
913 thread_debug("create (use cached thread): %p\n", (void *)th);
914 }
915 else {
916 #ifdef HAVE_PTHREAD_ATTR_INIT
917 pthread_attr_t attr;
918 pthread_attr_t *const attrp = &attr;
919 #else
920 pthread_attr_t *const attrp = NULL;
921 #endif
922 const size_t stack_size = th->vm->default_params.thread_machine_stack_size;
923 const size_t space = space_size(stack_size);
924
925 th->machine.stack_maxsize = stack_size - space;
926 #ifdef __ia64
927 th->machine.stack_maxsize /= 2;
928 th->machine.register_stack_maxsize = th->machine.stack_maxsize;
929 #endif
930
931 #ifdef HAVE_PTHREAD_ATTR_INIT
932 CHECK_ERR(pthread_attr_init(&attr));
933
934 # ifdef PTHREAD_STACK_MIN
935 thread_debug("create - stack size: %lu\n", (unsigned long)stack_size);
936 CHECK_ERR(pthread_attr_setstacksize(&attr, stack_size));
937 # endif
938
939 # ifdef HAVE_PTHREAD_ATTR_SETINHERITSCHED
940 CHECK_ERR(pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED));
941 # endif
942 CHECK_ERR(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
943 #endif
944 #ifdef get_stack_of
945 native_mutex_lock(&th->interrupt_lock);
946 #endif
947 err = pthread_create(&th->thread_id, attrp, thread_start_func_1, th);
948 #ifdef get_stack_of
949 if (!err) {
950 get_stack_of(th->thread_id,
951 &th->machine.stack_start,
952 &th->machine.stack_maxsize);
953 }
954 native_mutex_unlock(&th->interrupt_lock);
955 #endif
956 thread_debug("create: %p (%d)\n", (void *)th, err);
957 #ifdef HAVE_PTHREAD_ATTR_INIT
958 CHECK_ERR(pthread_attr_destroy(&attr));
959 #endif
960 }
961 return err;
962 }
963
964 static void
965 native_thread_join(pthread_t th)
966 {
967 int err = pthread_join(th, 0);
968 if (err) {
969 rb_raise(rb_eThreadError, "native_thread_join() failed (%d)", err);
970 }
971 }
972
973
974 #if USE_NATIVE_THREAD_PRIORITY
975
976 static void
977 native_thread_apply_priority(rb_thread_t *th)
978 {
979 #if defined(_POSIX_PRIORITY_SCHEDULING) && (_POSIX_PRIORITY_SCHEDULING > 0)
980 struct sched_param sp;
981 int policy;
982 int priority = 0 - th->priority;
983 int max, min;
984 pthread_getschedparam(th->thread_id, &policy, &sp);
985 max = sched_get_priority_max(policy);
986 min = sched_get_priority_min(policy);
987
988 if (min > priority) {
989 priority = min;
990 }
991 else if (max < priority) {
992 priority = max;
993 }
994
995 sp.sched_priority = priority;
996 pthread_setschedparam(th->thread_id, policy, &sp);
997 #else
998 /* not touched */
999 #endif
1000 }
1001
1002 #endif /* USE_NATIVE_THREAD_PRIORITY */
1003
1004 static int
1005 native_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout, rb_thread_t *th)
1006 {
1007 return rb_fd_select(n, readfds, writefds, exceptfds, timeout);
1008 }
1009
1010 static void
1011 ubf_pthread_cond_signal(void *ptr)
1012 {
1013 rb_thread_t *th = (rb_thread_t *)ptr;
1014 thread_debug("ubf_pthread_cond_signal (%p)\n", (void *)th);
1015 native_cond_signal(&th->native_thread_data.sleep_cond);
1016 }
1017
1018 static void
1019 native_sleep(rb_thread_t *th, struct timeval *timeout_tv)
1020 {
1021 struct timespec timeout;
1022 pthread_mutex_t *lock = &th->interrupt_lock;
1023 rb_nativethread_cond_t *cond = &th->native_thread_data.sleep_cond;
1024
1025 if (timeout_tv) {
1026 struct timespec timeout_rel;
1027
1028 timeout_rel.tv_sec = timeout_tv->tv_sec;
1029 timeout_rel.tv_nsec = timeout_tv->tv_usec * 1000;
1030
1031 /* Solaris cond_timedwait() return EINVAL if an argument is greater than
1032 * current_time + 100,000,000. So cut up to 100,000,000. This is
1033 * considered as a kind of spurious wakeup. The caller to native_sleep
1034 * should care about spurious wakeup.
1035 *
1036 * See also [Bug #1341] [ruby-core:29702]
1037 * http://download.oracle.com/docs/cd/E19683-01/816-0216/6m6ngupgv/index.html
1038 */
1039 if (timeout_rel.tv_sec > 100000000) {
1040 timeout_rel.tv_sec = 100000000;
1041 timeout_rel.tv_nsec = 0;
1042 }
1043
1044 timeout = native_cond_timeout(cond, timeout_rel);
1045 }
1046
1047 GVL_UNLOCK_BEGIN();
1048 {
1049 pthread_mutex_lock(lock);
1050 th->unblock.func = ubf_pthread_cond_signal;
1051 th->unblock.arg = th;
1052
1053 if (RUBY_VM_INTERRUPTED(th)) {
1054 /* interrupted. return immediate */
1055 thread_debug("native_sleep: interrupted before sleep\n");
1056 }
1057 else {
1058 if (!timeout_tv)
1059 native_cond_wait(cond, lock);
1060 else
1061 native_cond_timedwait(cond, lock, &timeout);
1062 }
1063 th->unblock.func = 0;
1064 th->unblock.arg = 0;
1065
1066 pthread_mutex_unlock(lock);
1067 }
1068 GVL_UNLOCK_END();
1069
1070 thread_debug("native_sleep done\n");
1071 }
1072
1073 #ifdef USE_SIGNAL_THREAD_LIST
1074 struct signal_thread_list {
1075 rb_thread_t *th;
1076 struct signal_thread_list *prev;
1077 struct signal_thread_list *next;
1078 };
1079
1080 static struct signal_thread_list signal_thread_list_anchor = {
1081 0, 0, 0,
1082 };
1083
1084 #define FGLOCK(lock, body) do { \
1085 native_mutex_lock(lock); \
1086 { \
1087 body; \
1088 } \
1089 native_mutex_unlock(lock); \
1090 } while (0)
1091
1092 #if 0 /* for debug */
1093 static void
1094 print_signal_list(char *str)
1095 {
1096 struct signal_thread_list *list =
1097 signal_thread_list_anchor.next;
1098 thread_debug("list (%s)> ", str);
1099 while (list) {
1100 thread_debug("%p (%p), ", list->th, list->th->thread_id);
1101 list = list->next;
1102 }
1103 thread_debug("\n");
1104 }
1105 #endif
1106
1107 static void
1108 add_signal_thread_list(rb_thread_t *th)
1109 {
1110 if (!th->native_thread_data.signal_thread_list) {
1111 FGLOCK(&signal_thread_list_lock, {
1112 struct signal_thread_list *list =
1113 malloc(sizeof(struct signal_thread_list));
1114
1115 if (list == 0) {
1116 fprintf(stderr, "[FATAL] failed to allocate memory\n");
1117 exit(EXIT_FAILURE);
1118 }
1119
1120 list->th = th;
1121
1122 list->prev = &signal_thread_list_anchor;
1123 list->next = signal_thread_list_anchor.next;
1124 if (list->next) {
1125 list->next->prev = list;
1126 }
1127 signal_thread_list_anchor.next = list;
1128 th->native_thread_data.signal_thread_list = list;
1129 });
1130 }
1131 }
1132
1133 static void
1134 remove_signal_thread_list(rb_thread_t *th)
1135 {
1136 if (th->native_thread_data.signal_thread_list) {
1137 FGLOCK(&signal_thread_list_lock, {
1138 struct signal_thread_list *list =
1139 (struct signal_thread_list *)
1140 th->native_thread_data.signal_thread_list;
1141
1142 list->prev->next = list->next;
1143 if (list->next) {
1144 list->next->prev = list->prev;
1145 }
1146 th->native_thread_data.signal_thread_list = 0;
1147 list->th = 0;
1148 free(list); /* ok */
1149 });
1150 }
1151 }
1152
1153 static void
1154 ubf_select_each(rb_thread_t *th)
1155 {
1156 thread_debug("ubf_select_each (%p)\n", (void *)th->thread_id);
1157 if (th) {
1158 pthread_kill(th->thread_id, SIGVTALRM);
1159 }
1160 }
1161
1162 static void
1163 ubf_select(void *ptr)
1164 {
1165 rb_thread_t *th = (rb_thread_t *)ptr;
1166 add_signal_thread_list(th);
1167
1168 /*
1169 * ubf_select_each() doesn't guarantee to wake up the target thread.
1170 * Therefore, we need to activate timer thread when called from
1171 * Thread#kill etc.
1172 * In the other hands, we shouldn't call rb_thread_wakeup_timer_thread()
1173 * if running on timer thread because it may make endless wakeups.
1174 */
1175 if (pthread_self() != timer_thread_id)
1176 rb_thread_wakeup_timer_thread();
1177 ubf_select_each(th);
1178 }
1179
1180 static void
1181 ping_signal_thread_list(void)
1182 {
1183 if (signal_thread_list_anchor.next) {
1184 FGLOCK(&signal_thread_list_lock, {
1185 struct signal_thread_list *list;
1186
1187 list = signal_thread_list_anchor.next;
1188 while (list) {
1189 ubf_select_each(list->th);
1190 list = list->next;
1191 }
1192 });
1193 }
1194 }
1195
1196 static int
1197 check_signal_thread_list(void)
1198 {
1199 if (signal_thread_list_anchor.next)
1200 return 1;
1201 else
1202 return 0;
1203 }
1204 #else /* USE_SIGNAL_THREAD_LIST */
1205 #define add_signal_thread_list(th) (void)(th)
1206 #define remove_signal_thread_list(th) (void)(th)
1207 #define ubf_select 0
1208 static void ping_signal_thread_list(void) { return; }
1209 static int check_signal_thread_list(void) { return 0; }
1210 #endif /* USE_SIGNAL_THREAD_LIST */
1211
1212 #define TT_DEBUG 0
1213 #define WRITE_CONST(fd, str) (void)(write((fd),(str),sizeof(str)-1)<0)
1214
1215 /* 100ms. 10ms is too small for user level thread scheduling
1216 * on recent Linux (tested on 2.6.35)
1217 */
1218 #define TIME_QUANTUM_USEC (100 * 1000)
1219
1220 #if USE_SLEEPY_TIMER_THREAD
1221 static int timer_thread_pipe[2] = {-1, -1};
1222 static int timer_thread_pipe_low[2] = {-1, -1}; /* low priority */
1223 static int timer_thread_pipe_owner_process;
1224
1225 /* only use signal-safe system calls here */
1226 static void
1227 rb_thread_wakeup_timer_thread_fd(int fd)
1228 {
1229 ssize_t result;
1230
1231 /* already opened */
1232 if (timer_thread_pipe_owner_process == getpid()) {
1233 const char *buff = "!";
1234 retry:
1235 if ((result = write(fd, buff, 1)) <= 0) {
1236 switch (errno) {
1237 case EINTR: goto retry;
1238 case EAGAIN:
1239 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
1240 case EWOULDBLOCK:
1241 #endif
1242 break;
1243 default:
1244 rb_async_bug_errno("rb_thread_wakeup_timer_thread - write", errno);
1245 }
1246 }
1247 if (TT_DEBUG) WRITE_CONST(2, "rb_thread_wakeup_timer_thread: write\n");
1248 }
1249 else {
1250 /* ignore wakeup */
1251 }
1252 }
1253
1254 void
1255 rb_thread_wakeup_timer_thread(void)
1256 {
1257 rb_thread_wakeup_timer_thread_fd(timer_thread_pipe[1]);
1258 }
1259
1260 static void
1261 rb_thread_wakeup_timer_thread_low(void)
1262 {
1263 rb_thread_wakeup_timer_thread_fd(timer_thread_pipe_low[1]);
1264 }
1265
1266 /* VM-dependent API is not available for this function */
1267 static void
1268 consume_communication_pipe(int fd)
1269 {
1270 #define CCP_READ_BUFF_SIZE 1024
1271 /* buffer can be shared because no one refers to them. */
1272 static char buff[CCP_READ_BUFF_SIZE];
1273 ssize_t result;
1274
1275 while (1) {
1276 result = read(fd, buff, sizeof(buff));
1277 if (result == 0) {
1278 return;
1279 }
1280 else if (result < 0) {
1281 switch (errno) {
1282 case EINTR:
1283 continue; /* retry */
1284 case EAGAIN:
1285 return;
1286 default:
1287 rb_async_bug_errno("consume_communication_pipe: read\n", errno);
1288 }
1289 }
1290 }
1291 }
1292
1293 static void
1294 close_communication_pipe(int pipes[2])
1295 {
1296 if (close(pipes[0]) < 0) {
1297 rb_bug_errno("native_stop_timer_thread - close(ttp[0])", errno);
1298 }
1299 if (close(pipes[1]) < 0) {
1300 rb_bug_errno("native_stop_timer_thread - close(ttp[1])", errno);
1301 }
1302 pipes[0] = pipes[1] = -1;
1303 }
1304
1305 static void
1306 set_nonblock(int fd)
1307 {
1308 int oflags;
1309 int err;
1310
1311 oflags = fcntl(fd, F_GETFL);
1312 if (oflags == -1)
1313 rb_sys_fail(0);
1314 oflags |= O_NONBLOCK;
1315 err = fcntl(fd, F_SETFL, oflags);
1316 if (err == -1)
1317 rb_sys_fail(0);
1318 }
1319
1320 static void
1321 setup_communication_pipe_internal(int pipes[2])
1322 {
1323 int err;
1324
1325 if (pipes[0] != -1) {
1326 /* close pipe of parent process */
1327 close_communication_pipe(pipes);
1328 }
1329
1330 err = rb_cloexec_pipe(pipes);
1331 if (err != 0) {
1332 rb_bug_errno("setup_communication_pipe: Failed to create communication pipe for timer thread", errno);
1333 }
1334 rb_update_max_fd(pipes[0]);
1335 rb_update_max_fd(pipes[1]);
1336 set_nonblock(pipes[0]);
1337 set_nonblock(pipes[1]);
1338 }
1339
1340 /* communication pipe with timer thread and signal handler */
1341 static void
1342 setup_communication_pipe(void)
1343 {
1344 if (timer_thread_pipe_owner_process == getpid()) {
1345 /* already set up. */
1346 return;
1347 }
1348 setup_communication_pipe_internal(timer_thread_pipe);
1349 setup_communication_pipe_internal(timer_thread_pipe_low);
1350
1351 /* validate pipe on this process */
1352 timer_thread_pipe_owner_process = getpid();
1353 }
1354
1361 static inline void
1362 timer_thread_sleep(rb_global_vm_lock_t* gvl)
1363 {
1364 int result;
1365 int need_polling;
1366 struct pollfd pollfds[2];
1367
1368 pollfds[0].fd = timer_thread_pipe[0];
1369 pollfds[0].events = POLLIN;
1370 pollfds[1].fd = timer_thread_pipe_low[0];
1371 pollfds[1].events = POLLIN;
1372
1373 need_polling = check_signal_thread_list();
1374
1375 if (gvl->waiting > 0 || need_polling) {
1376 /* polling (TIME_QUANTUM_USEC usec) */
1377 result = poll(pollfds, 1, TIME_QUANTUM_USEC/1000);
1378 }
1379 else {
1380 /* wait (infinite) */
1381 result = poll(pollfds, numberof(pollfds), -1);
1382 }
1383
1384 if (result == 0) {
1385 /* maybe timeout */
1386 }
1387 else if (result > 0) {
1388 consume_communication_pipe(timer_thread_pipe[0]);
1389 consume_communication_pipe(timer_thread_pipe_low[0]);
1390 }
1391 else { /* result < 0 */
1392 switch (errno) {
1393 case EBADF:
1394 case EINVAL:
1395 case ENOMEM: /* from Linux man */
1396 case EFAULT: /* from FreeBSD man */
1397 rb_async_bug_errno("thread_timer: select", errno);
1398 default:
1399 /* ignore */;
1400 }
1401 }
1402 }
1403
1404 #else /* USE_SLEEPY_TIMER_THREAD */
1405 # define PER_NANO 1000000000
1406 void rb_thread_wakeup_timer_thread(void) {}
1407 static void rb_thread_wakeup_timer_thread_low(void) {}
1408
1409 static pthread_mutex_t timer_thread_lock;
1410 static rb_nativethread_cond_t timer_thread_cond;
1411
1412 static inline void
1413 timer_thread_sleep(rb_global_vm_lock_t* unused)
1414 {
1415 struct timespec ts;
1416 ts.tv_sec = 0;
1417 ts.tv_nsec = TIME_QUANTUM_USEC * 1000;
1418 ts = native_cond_timeout(&timer_thread_cond, ts);
1419
1420 native_cond_timedwait(&timer_thread_cond, &timer_thread_lock, &ts);
1421 }
1422 #endif /* USE_SLEEPY_TIMER_THREAD */
1423
1424 #if defined(__linux__) && defined(PR_SET_NAME)
1425 # undef SET_THREAD_NAME
1426 # define SET_THREAD_NAME(name) prctl(PR_SET_NAME, name)
1427 #elif !defined(SET_THREAD_NAME)
1428 # define SET_THREAD_NAME(name) (void)0
1429 #endif
1430
1431 static void *
1432 thread_timer(void *p)
1433 {
1434 rb_global_vm_lock_t *gvl = (rb_global_vm_lock_t *)p;
1435
1436 if (TT_DEBUG) WRITE_CONST(2, "start timer thread\n");
1437
1438 SET_THREAD_NAME("ruby-timer-thr");
1439
1440 #if !USE_SLEEPY_TIMER_THREAD
1441 native_mutex_initialize(&timer_thread_lock);
1442 native_cond_initialize(&timer_thread_cond, RB_CONDATTR_CLOCK_MONOTONIC);
1443 native_mutex_lock(&timer_thread_lock);
1444 #endif
1445 while (system_working > 0) {
1446
1447 /* timer function */
1448 ping_signal_thread_list();
1449 timer_thread_function(0);
1450
1451 if (TT_DEBUG) WRITE_CONST(2, "tick\n");
1452
1453 /* wait */
1454 timer_thread_sleep(gvl);
1455 }
1456 #if !USE_SLEEPY_TIMER_THREAD
1457 native_mutex_unlock(&timer_thread_lock);
1458 native_cond_destroy(&timer_thread_cond);
1459 native_mutex_destroy(&timer_thread_lock);
1460 #endif
1461
1462 if (TT_DEBUG) WRITE_CONST(2, "finish timer thread\n");
1463 return NULL;
1464 }
1465
1466 static void
1467 rb_thread_create_timer_thread(void)
1468 {
1469 if (!timer_thread_id) {
1470 int err;
1471 #ifdef HAVE_PTHREAD_ATTR_INIT
1472 pthread_attr_t attr;
1473
1474 err = pthread_attr_init(&attr);
1475 if (err != 0) {
1476 fprintf(stderr, "[FATAL] Failed to initialize pthread attr: %s\n", strerror(err));
1477 exit(EXIT_FAILURE);
1478 }
1479 # ifdef PTHREAD_STACK_MIN
1480 {
1481 const size_t min_size = (4096 * 4);
1482 /* Allocate the machine stack for the timer thread
1483 * at least 16KB (4 pages). FreeBSD 8.2 AMD64 causes
1484 * machine stack overflow only with PTHREAD_STACK_MIN.
1485 */
1486 size_t stack_size = PTHREAD_STACK_MIN; /* may be dynamic, get only once */
1487 if (stack_size < min_size) stack_size = min_size;
1488 if (THREAD_DEBUG) stack_size += BUFSIZ;
1489 pthread_attr_setstacksize(&attr, stack_size);
1490 }
1491 # endif
1492 #endif
1493
1494 #if USE_SLEEPY_TIMER_THREAD
1495 setup_communication_pipe();
1496 #endif /* USE_SLEEPY_TIMER_THREAD */
1497
1498 /* create timer thread */
1499 if (timer_thread_id) {
1500 rb_bug("rb_thread_create_timer_thread: Timer thread was already created\n");
1501 }
1502 #ifdef HAVE_PTHREAD_ATTR_INIT
1503 err = pthread_create(&timer_thread_id, &attr, thread_timer, &GET_VM()->gvl);
1504 #else
1505 err = pthread_create(&timer_thread_id, NULL, thread_timer, &GET_VM()->gvl);
1506 #endif
1507 if (err != 0) {
1508 fprintf(stderr, "[FATAL] Failed to create timer thread: %s\n", strerror(err));
1509 exit(EXIT_FAILURE);
1510 }
1511 #ifdef HAVE_PTHREAD_ATTR_INIT
1512 pthread_attr_destroy(&attr);
1513 #endif
1514 }
1515 }
1516
1517 static int
1518 native_stop_timer_thread(int close_anyway)
1519 {
1520 int stopped;
1521 stopped = --system_working <= 0;
1522
1523 if (TT_DEBUG) fprintf(stderr, "stop timer thread\n");
1524 if (stopped) {
1525 /* join */
1526 rb_thread_wakeup_timer_thread();
1527 native_thread_join(timer_thread_id);
1528 if (TT_DEBUG) fprintf(stderr, "joined timer thread\n");
1529 timer_thread_id = 0;
1530
1531 /* close communication pipe */
1532 if (close_anyway) {
1533 /* TODO: Uninstall all signal handlers or mask all signals.
1534 * This pass is cleaning phase (terminate ruby process).
1535 * To avoid such race, we skip to close communication
1536 * pipe. OS will close it at process termination.
1537 * It may not good practice, but pragmatic.
1538 * We remain it is TODO.
1539 */
1540 /* close_communication_pipe(); */
1541 }
1542 }
1543 return stopped;
1544 }
1545
1546 static void
1547 native_reset_timer_thread(void)
1548 {
1549 if (TT_DEBUG) fprintf(stderr, "reset timer thread\n");
1550 }
1551
1552 #ifdef HAVE_SIGALTSTACK
1553 int
1554 ruby_stack_overflowed_p(const rb_thread_t *th, const void *addr)
1555 {
1556 void *base;
1557 size_t size;
1558 const size_t water_mark = 1024 * 1024;
1559 STACK_GROW_DIR_DETECTION;
1560
1561 #ifdef STACKADDR_AVAILABLE
1562 if (get_stack(&base, &size) == 0) {
1563 # ifdef __APPLE__
1564 if (pthread_equal(th->thread_id, native_main_thread.id)) {
1565 struct rlimit rlim;
1566 if (getrlimit(RLIMIT_STACK, &rlim) == 0 && rlim.rlim_cur > size) {
1567 size = (size_t)rlim.rlim_cur;
1568 }
1569 }
1570 # endif
1571 base = (char *)base + STACK_DIR_UPPER(+size, -size);
1572 }
1573 else
1574 #endif
1575 if (th) {
1576 size = th->machine.stack_maxsize;
1577 base = (char *)th->machine.stack_start - STACK_DIR_UPPER(0, size);
1578 }
1579 else {
1580 return 0;
1581 }
1582 size /= RUBY_STACK_SPACE_RATIO;
1583 if (size > water_mark) size = water_mark;
1584 if (IS_STACK_DIR_UPPER()) {
1585 if (size > ~(size_t)base+1) size = ~(size_t)base+1;
1586 if (addr > base && addr <= (void *)((char *)base + size)) return 1;
1587 }
1588 else {
1589 if (size > (size_t)base) size = (size_t)base;
1590 if (addr > (void *)((char *)base - size) && addr <= base) return 1;
1591 }
1592 return 0;
1593 }
1594 #endif
1595
1596 int
1597 rb_reserved_fd_p(int fd)
1598 {
1599 #if USE_SLEEPY_TIMER_THREAD
1600 if (fd == timer_thread_pipe[0] ||
1601 fd == timer_thread_pipe[1] ||
1602 fd == timer_thread_pipe_low[0] ||
1603 fd == timer_thread_pipe_low[1]) {
1604 return 1;
1605 }
1606 else {
1607 return 0;
1608 }
1609 #else
1610 return 0;
1611 #endif
1612 }
1613
1614 rb_nativethread_id_t
1615 rb_nativethread_self(void)
1616 {
1617 return pthread_self();
1618 }
1619
1620 #endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */
cond
#define cond(node)
Definition: ripper.c:427
native_thread_data_struct::sleep_cond
rb_nativethread_cond_t sleep_cond
Definition: thread_pthread.h:30
rb_nativethread_self
RUBY_SYMBOL_EXPORT_BEGIN rb_nativethread_id_t rb_nativethread_self()
rb_thread_struct::vm
rb_vm_t * vm
Definition: vm_core.h:526
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:327
gettimeofday
int gettimeofday(struct timeval *, struct timezone *)
Definition: win32.c:4307
rb_global_vm_lock_struct::wait_yield
int wait_yield
Definition: thread_pthread.h:53
rb_update_max_fd
void rb_update_max_fd(int fd)
Definition: io.c:183
rb_global_vm_lock_struct::waiting
volatile unsigned long waiting
Definition: thread_pthread.h:46
max
static int max(int a, int b)
Definition: strftime.c:141
native_thread_data_struct::signal_thread_list
void * signal_thread_list
Definition: thread_pthread.h:29
rb_unblock_callback::func
rb_unblock_function_t * func
Definition: vm_core.h:500
THREAD_DEBUG
#define THREAD_DEBUG
Definition: thread.c:74
rb_global_vm_lock_struct::switch_cond
rb_nativethread_cond_t switch_cond
Definition: thread_pthread.h:50
CLOCK_MONOTONIC
#define CLOCK_MONOTONIC
Definition: win32.h:129
id
const int id
Definition: nkf.c:209
timeval::tv_sec
long tv_sec
Definition: ossl_asn1.c:17
fcntl
int fcntl(int, int,...)
Definition: win32.c:4085
rb_async_bug_errno
void rb_async_bug_errno(const char *mesg, int errno_arg)
Definition: error.c:371
STACK_UPPER
#define STACK_UPPER(x, a, b)
Definition: gc.h:74
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
gc.h
rb_nativethread_lock_t
pthread_mutex_t rb_nativethread_lock_t
Definition: thread_pthread.h:19
system_working
static volatile int system_working
Definition: thread.c:95
rb_thread_struct
Definition: vm_core.h:524
rb_thread_struct::machine
struct rb_thread_struct::@169 machine
timespec::tv_sec
time_t tv_sec
Definition: missing.h:51
posix_signal
sighandler_t posix_signal(int signum, sighandler_t handler)
Definition: missing-pips.c:43
uint64_t
unsigned long long uint64_t
Definition: sha2.h:102
rb_fdset_t
fd_set rb_fdset_t
Definition: intern.h:348
thread.h
RUBY_VM_THREAD_VM_STACK_SIZE
#define RUBY_VM_THREAD_VM_STACK_SIZE
Definition: vm_core.h:431
rb_thread_wakeup_timer_thread
void rb_thread_wakeup_timer_thread(void)
getrlimit
int getrlimit(int resource, struct rlimit *rlp)
Definition: missing-pips.c:48
F_SETFL
#define F_SETFL
Definition: win32.h:622
timeval::tv_usec
long tv_usec
Definition: ossl_asn1.c:18
PRIdVALUE
#define PRIdVALUE
Definition: ruby.h:132
timespec::tv_nsec
long tv_nsec
Definition: missing.h:52
UNLIKELY
#define UNLIKELY(x)
Definition: vm_core.h:109
msg
static char msg[50]
Definition: strerror.c:8
thread_debug
#define thread_debug
Definition: thread.c:210
if
if((ID)(DISPID) nameid!=nameid)
Definition: win32ole.c:770
err
int err
Definition: win32.c:114
EXIT_FAILURE
#define EXIT_FAILURE
Definition: eval_intern.h:24
GVL_UNLOCK_BEGIN
#define GVL_UNLOCK_BEGIN()
Definition: thread.c:136
rb_global_vm_lock_struct::cond
rb_nativethread_cond_t cond
Definition: thread_pthread.h:47
numberof
#define numberof(array)
Definition: etc.c:595
select.h
timeval
Definition: ossl_asn1.c:16
errno
int errno
STACK_DIR_UPPER
#define STACK_DIR_UPPER(a, b)
Definition: gc.h:82
CLOCK_REALTIME
#define CLOCK_REALTIME
Definition: win32.h:128
rb_nativethread_id_t
pthread_t rb_nativethread_id_t
Definition: thread_pthread.h:18
malloc
#define malloc
Definition: ripper.c:96
pthread_kill
int pthread_kill(pthread_t thread, int sig)
Definition: missing-pips.c:37
GVL_UNLOCK_END
#define GVL_UNLOCK_END()
Definition: thread.c:141
VALUE
unsigned long VALUE
Definition: ruby.h:88
STACK_GROW_DIR_DETECTION
#define STACK_GROW_DIR_DETECTION
Definition: gc.h:81
result
static VALUE result
Definition: nkf.c:40
Init_native_thread
void Init_native_thread(void)
rb_bug_errno
void rb_bug_errno(const char *mesg, int errno_arg)
Definition: error.c:350
clock_gettime
int clock_gettime(clockid_t, struct timespec *)
Definition: win32.c:4319
ruby_init_stack
void ruby_init_stack(volatile VALUE *)
rb_thread_cond_struct
Definition: thread_pthread.h:21
rb_global_vm_lock_struct::switch_wait_cond
rb_nativethread_cond_t switch_wait_cond
Definition: thread_pthread.h:51
timer_thread_function
static void timer_thread_function(void *)
Definition: thread.c:3825
rb_thread_struct::priority
int priority
Definition: vm_core.h:564
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:1976
rb_reserved_fd_p
int rb_reserved_fd_p(int fd)
WRITE_CONST
#define WRITE_CONST(fd, str)
Definition: error.c:368
rb_cloexec_pipe
int rb_cloexec_pipe(int fildes[2])
Definition: io.c:286
thread_start_func_2
#define thread_start_func_2(th, st, rst)
Definition: thread.c:214
size
int size
Definition: encoding.c:49
rb_vm_struct::default_params
struct rb_vm_struct::@168 default_params
rb_thread_struct::stack_start
VALUE * stack_start
Definition: vm_core.h:621
rb_thread_struct::unblock
struct rb_unblock_callback unblock
Definition: vm_core.h:589
rb_unblock_callback::arg
void * arg
Definition: vm_core.h:501
rb_fd_select
#define rb_fd_select(n, rfds, wfds, efds, timeout)
Definition: intern.h:361
rb_thread_struct::thread_id
rb_nativethread_id_t thread_id
Definition: vm_core.h:561
strerror
RUBY_EXTERN char * strerror(int)
Definition: strerror.c:11
O_NONBLOCK
#define O_NONBLOCK
Definition: win32.h:626
list
struct rb_encoding_entry * list
Definition: encoding.c:47
ETIMEDOUT
#define ETIMEDOUT
Definition: win32.h:584
rb_thread_struct::native_thread_data
native_thread_data_t native_thread_data
Definition: vm_core.h:566
EWOULDBLOCK
#define EWOULDBLOCK
Definition: rubysocket.h:126
rb_vm_struct::thread_machine_stack_size
size_t thread_machine_stack_size
Definition: vm_core.h:421
thread_start
static VALUE thread_start(VALUE klass, VALUE args)
Definition: thread.c:713
timespec
Definition: missing.h:50
rb_thread_cond_struct::cond
pthread_cond_t cond
Definition: thread_pthread.h:22
rb_eNotImpError
VALUE rb_eNotImpError
Definition: error.c:558
rb_vm_struct::gvl
rb_global_vm_lock_t gvl
Definition: vm_core.h:351
rb_global_vm_lock_struct::acquired
unsigned long acquired
Definition: thread_pthread.h:42
rb_vm_struct
Definition: vm_core.h:348
RUBY_VM_INTERRUPTED
#define RUBY_VM_INTERRUPTED(th)
Definition: vm_core.h:963
rb_global_vm_lock_struct::need_yield
int need_yield
Definition: thread_pthread.h:52
rb_thread_struct::interrupt_lock
rb_nativethread_lock_t interrupt_lock
Definition: vm_core.h:587
rb_global_vm_lock_struct::lock
pthread_mutex_t lock
Definition: thread_pthread.h:43
rb_thread_struct::stack_maxsize
size_t stack_maxsize
Definition: vm_core.h:623
NULL
#define NULL
Definition: _sdbm.c:103
GET_THREAD
static rb_thread_t * GET_THREAD(void)
Definition: vm_core.h:927
rb_global_vm_lock_struct
Definition: thread_pthread.h:40
free
free(psz)
rb_eThreadError
VALUE rb_eThreadError
Definition: eval.c:730
IS_STACK_DIR_UPPER
#define IS_STACK_DIR_UPPER()
Definition: gc.h:84
SIGNED_VALUE
#define SIGNED_VALUE
Definition: ruby.h:90
GET_VM
#define GET_VM()
Definition: vm_core.h:920