From eda0a8e2d912c25d6d47da4a28f508bd8e80c104 Mon Sep 17 00:00:00 2001 From: wyhaines Date: Wed, 3 Feb 2010 16:09:35 +0000 Subject: Backport #1743 [ruby-core:24203]; stops timer thread unless other threads exist. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_6@26561 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 4 +++ eval.c | 103 +++++++++++++++++++++++++++++++++++++++++++------------------- version.h | 10 +++--- 3 files changed, 81 insertions(+), 36 deletions(-) diff --git a/ChangeLog b/ChangeLog index 74a6c7da5f..479530ccb0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +Wed Feb 4 01:06:00 2010 Kirk Haines + + * eval.c: Backport #1743 [ruby-core:24203]; stops timer thread unless other threads exist. + Wed Jan 28 04:00:00 2010 Kirk Haines * io.c: Backport #2009 [ruby-core:25173]; (rb_io_fptr_finalize): free fptr to avoid memory leaks. diff --git a/eval.c b/eval.c index 188fe8da5d..af63617347 100644 --- a/eval.c +++ b/eval.c @@ -10569,6 +10569,12 @@ rb_thread_remove(th) 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 @@ catch_timer(sig) /* 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 @@ thread_timer(dummy) } } } -#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 @@ rb_thread_start_timer() { 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 @@ rb_thread_stop_timer() 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 @@ rb_thread_start_0(fn, arg, th) } if (!thread_init) { - thread_init = 1; #if defined(HAVE_SETITIMER) || defined(_THREAD_SAFE) #if defined(POSIX_SIGNAL) posix_signal(SIGVTALRM, catch_timer); @@ -12106,13 +12153,7 @@ rb_thread_start_0(fn, arg, th) 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 } diff --git a/version.h b/version.h index dc1589dc1d..e9390f4a0e 100644 --- a/version.h +++ b/version.h @@ -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[]; -- cgit v1.2.3