ruby-changes:14706
From: wyhaines <ko1@a...>
Date: Thu, 4 Feb 2010 01:09:52 +0900 (JST)
Subject: [ruby-changes:14706] Ruby:r26561 (ruby_1_8_6): Backport #1743 ; stops timer thread unless other threads exist.
wyhaines 2010-02-04 01:09:35 +0900 (Thu, 04 Feb 2010) New Revision: 26561 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=26561 Log: Backport #1743 [ruby-core:24203]; stops timer thread unless other threads exist. Modified files: branches/ruby_1_8_6/ChangeLog branches/ruby_1_8_6/eval.c branches/ruby_1_8_6/version.h Index: ruby_1_8_6/ChangeLog =================================================================== --- ruby_1_8_6/ChangeLog (revision 26560) +++ ruby_1_8_6/ChangeLog (revision 26561) @@ -1,3 +1,7 @@ +Wed Feb 4 01:06:00 2010 Kirk Haines <khaines@r...> + + * eval.c: Backport #1743 [ruby-core:24203]; stops timer thread unless other threads exist. + Wed Jan 28 04:00:00 2010 Kirk Haines <khaines@r...> * io.c: Backport #2009 [ruby-core:25173]; (rb_io_fptr_finalize): free fptr to avoid memory leaks. Index: ruby_1_8_6/version.h =================================================================== --- ruby_1_8_6/version.h (revision 26560) +++ ruby_1_8_6/version.h (revision 26561) @@ -1,15 +1,15 @@ #define RUBY_VERSION "1.8.6" -#define RUBY_RELEASE_DATE "2010-01-28" +#define RUBY_RELEASE_DATE "2010-02-04" #define RUBY_VERSION_CODE 186 -#define RUBY_RELEASE_CODE 20100128 -#define RUBY_PATCHLEVEL 388 +#define RUBY_RELEASE_CODE 20100204 +#define RUBY_PATCHLEVEL 398 #define RUBY_VERSION_MAJOR 1 #define RUBY_VERSION_MINOR 8 #define RUBY_VERSION_TEENY 6 #define RUBY_RELEASE_YEAR 2010 -#define RUBY_RELEASE_MONTH 1 -#define RUBY_RELEASE_DAY 28 +#define RUBY_RELEASE_MONTH 2 +#define RUBY_RELEASE_DAY 04 #ifdef RUBY_EXTERN RUBY_EXTERN const char ruby_version[]; Index: ruby_1_8_6/eval.c =================================================================== --- ruby_1_8_6/eval.c (revision 26560) +++ ruby_1_8_6/eval.c (revision 26561) @@ -10569,6 +10569,12 @@ 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 @@ -11955,40 +11961,58 @@ /* cause EINTR */ } -static int time_thread_alive_p = 0; -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; { -#ifdef _THREAD_SAFE -#define test_cancel() pthread_testcancel() -#else -#define test_cancel() /* void */ -#endif + 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); - test_cancel(); - req.tv_sec = 0; - req.tv_nsec = 10000000; - nanosleep(&req, &rem); -#else - struct timeval tv; - - test_cancel(); - 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) { @@ -11996,17 +12020,39 @@ } } } -#undef test_cancel + + 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; } void @@ -12047,11 +12093,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 @@ -12064,6 +12111,7 @@ tval.it_interval.tv_usec = 0; tval.it_value = tval.it_interval; setitimer(ITIMER_VIRTUAL, &tval, NULL); + thread_init = 0; } void @@ -12098,7 +12146,6 @@ } if (!thread_init) { - thread_init = 1; #if defined(HAVE_SETITIMER) || defined(_THREAD_SAFE) #if defined(POSIX_SIGNAL) posix_signal(SIGVTALRM, catch_timer); @@ -12106,14 +12153,8 @@ signal(SIGVTALRM, catch_timer); #endif -#ifdef _THREAD_SAFE - pthread_create(&time_thread, 0, thread_timer, 0); - time_thread_alive_p = 1; - pthread_atfork(0, 0, rb_child_atfork); -#else rb_thread_start_timer(); #endif -#endif } if (THREAD_SAVE_CONTEXT(curr_thread)) { -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/