ruby-changes:11567
From: nobu <ko1@a...>
Date: Sat, 18 Apr 2009 18:26:07 +0900 (JST)
Subject: [ruby-changes:11567] Ruby:r23201 (ruby_1_8): * eval.c (rb_thread_remove): stops timer thread unless other
nobu 2009-04-18 18:25:55 +0900 (Sat, 18 Apr 2009) New Revision: 23201 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=23201 Log: * eval.c (rb_thread_remove): stops timer thread unless other threads exist. [ruby-core:18444] Modified files: branches/ruby_1_8/ChangeLog branches/ruby_1_8/eval.c branches/ruby_1_8/version.h Index: ruby_1_8/ChangeLog =================================================================== --- ruby_1_8/ChangeLog (revision 23200) +++ ruby_1_8/ChangeLog (revision 23201) @@ -1,3 +1,8 @@ +Sat Apr 18 18:25:53 2009 Nobuyoshi Nakada <nobu@r...> + + * eval.c (rb_thread_remove): stops timer thread unless other + threads exist. [ruby-core:18444] + Thu Apr 9 11:11:10 2009 Yukihiro Matsumoto <matz@r...> * ext/nkf/nkf.c: RDoc typo fixed. [ruby-core:23170] Index: ruby_1_8/version.h =================================================================== --- ruby_1_8/version.h (revision 23200) +++ ruby_1_8/version.h (revision 23201) @@ -1,7 +1,7 @@ #define RUBY_VERSION "1.8.8" -#define RUBY_RELEASE_DATE "2009-04-09" +#define RUBY_RELEASE_DATE "2009-04-18" #define RUBY_VERSION_CODE 188 -#define RUBY_RELEASE_CODE 20090409 +#define RUBY_RELEASE_CODE 20090418 #define RUBY_PATCHLEVEL -1 #define RUBY_VERSION_MAJOR 1 @@ -9,7 +9,7 @@ #define RUBY_VERSION_TEENY 8 #define RUBY_RELEASE_YEAR 2009 #define RUBY_RELEASE_MONTH 4 -#define RUBY_RELEASE_DAY 9 +#define RUBY_RELEASE_DAY 18 #ifdef RUBY_EXTERN RUBY_EXTERN const char ruby_version[]; Index: ruby_1_8/eval.c =================================================================== --- ruby_1_8/eval.c (revision 23200) +++ ruby_1_8/eval.c (revision 23201) @@ -10976,6 +10976,13 @@ rb_thread_die(th); th->prev->next = th->next; th->next->prev = th->prev; + +#if defined(_THREAD_SAFE) || defined(HAVE_SETITIMER) + /* if this is the last ruby thread, stop timer signals */ + if (th->next == th->prev && th->next == main_thread) { + rb_thread_stop_timer(); + } +#endif } static int @@ -12347,30 +12354,58 @@ /* cause EINTR */ } -static pthread_t time_thread; +#define PER_NANO 1000000000 +static struct timespec * +get_ts(struct timespec *to, long ns) +{ + struct timeval tv; + +#ifdef CLOCK_MONOTONIC + if (clock_gettime(CLOCK_MONOTONIC, to) != 0) +#endif + { + gettimeofday(&tv, NULL); + to->tv_sec = tv.tv_sec; + to->tv_nsec = tv.tv_usec * 1000; + } + if ((to->tv_nsec += ns) >= PER_NANO) { + to->tv_sec += to->tv_nsec / PER_NANO; + to->tv_nsec %= PER_NANO; + } + return to; +} + +static struct timer_thread { + pthread_cond_t cond; + pthread_mutex_t lock; + pthread_t thread; +} time_thread = {PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER}; + +#define safe_mutex_lock(lock) \ + (pthread_mutex_lock(lock), \ + pthread_cleanup_push((void (*)_((void *)))pthread_mutex_unlock, lock)) + static void* thread_timer(dummy) void *dummy; { + struct timer_thread *running = ((void **)dummy)[0]; + pthread_cond_t *start = ((void **)dummy)[1]; + struct timespec to; + int err; + sigset_t all_signals; sigfillset(&all_signals); pthread_sigmask(SIG_BLOCK, &all_signals, 0); - for (;;) { -#ifdef HAVE_NANOSLEEP - struct timespec req, rem; + safe_mutex_lock(&running->lock); + pthread_cond_signal(start); - req.tv_sec = 0; - req.tv_nsec = 10000000; - nanosleep(&req, &rem); -#else - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 10000; - select(0, NULL, NULL, NULL, &tv); -#endif +#define WAIT_FOR_10MS() \ + pthread_cond_timedwait(&running->cond, &running->lock, get_ts(&to, PER_NANO/100)) + while ((err = WAIT_FOR_10MS()) == EINTR || err == ETIMEDOUT) { if (!rb_thread_critical) { rb_thread_pending = 1; if (rb_trap_immediate) { @@ -12378,16 +12413,39 @@ } } } + + pthread_cleanup_pop(1); + + return NULL; } void rb_thread_start_timer() { + void *args[2]; + static pthread_cond_t start = PTHREAD_COND_INITIALIZER; + + if (!thread_init) return; + args[0] = &time_thread; + args[1] = &start; + safe_mutex_lock(&time_thread.lock); + if (pthread_create(&time_thread.thread, 0, thread_timer, args) == 0) { + thread_init = 1; + pthread_atfork(0, 0, rb_thread_stop_timer); + pthread_cond_wait(&start, &time_thread.lock); + } + pthread_cleanup_pop(1); } void rb_thread_stop_timer() { + if (!thread_init) return; + safe_mutex_lock(&time_thread.lock); + pthread_cond_signal(&time_thread.cond); + pthread_cleanup_pop(1); + pthread_join(time_thread.thread, NULL); + thread_init = 0; } #elif defined(HAVE_SETITIMER) static void @@ -12408,11 +12466,12 @@ { struct itimerval tval; - if (!thread_init) return; + if (thread_init) return; tval.it_interval.tv_sec = 0; tval.it_interval.tv_usec = 10000; tval.it_value = tval.it_interval; setitimer(ITIMER_VIRTUAL, &tval, NULL); + thread_init = 1; } void @@ -12425,6 +12484,7 @@ tval.it_interval.tv_usec = 0; tval.it_value = tval.it_interval; setitimer(ITIMER_VIRTUAL, &tval, NULL); + thread_init = 0; } #else /* !(_THREAD_SAFE || HAVE_SETITIMER) */ int rb_thread_tick = THREAD_TICK; @@ -12487,7 +12547,6 @@ } if (!thread_init) { - thread_init = 1; #if defined(HAVE_SETITIMER) || defined(_THREAD_SAFE) #if defined(POSIX_SIGNAL) posix_signal(SIGVTALRM, catch_timer); @@ -12495,12 +12554,8 @@ signal(SIGVTALRM, catch_timer); #endif -#ifdef _THREAD_SAFE - pthread_create(&time_thread, 0, thread_timer, 0); -#else rb_thread_start_timer(); #endif -#endif } if (THREAD_SAVE_CONTEXT(curr_thread)) { -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/