diff options
author | shyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-07-08 10:58:03 +0000 |
---|---|---|
committer | shyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-07-08 10:58:03 +0000 |
commit | a563f713984b84305d92b99c547a7e48c33ea2f7 (patch) | |
tree | 1a40f233ef49e4142a2ade4d10bd4a1cd67e3726 | |
parent | 4b4ac8ac64ffaa6de94ac254ce1c6aea2b743269 (diff) |
merge revision(s) 23201:
* eval.c (rb_thread_remove): stops timer thread unless other
threads exist. [ruby-core:18444]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_7@23993 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | eval.c | 93 | ||||
-rw-r--r-- | version.h | 8 |
3 files changed, 83 insertions, 23 deletions
@@ -1,3 +1,8 @@ +Wed Jul 8 19:28:03 2009 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * eval.c (rb_thread_remove): stops timer thread unless other + threads exist. [ruby-core:18444] + Mon Jul 6 16:01:38 2009 Nobuyoshi Nakada <nobu@ruby-lang.org> * eval.c (rb_eval): checks for interrupt, stack and finalizers too. @@ -10869,6 +10869,13 @@ 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 @@ -12238,30 +12245,58 @@ catch_timer(sig) /* 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) { @@ -12269,16 +12304,39 @@ thread_timer(dummy) } } } + + 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 @@ -12299,11 +12357,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 @@ -12316,6 +12375,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; } #else /* !(_THREAD_SAFE || HAVE_SETITIMER) */ int rb_thread_tick = THREAD_TICK; @@ -12339,7 +12399,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); @@ -12347,12 +12406,8 @@ rb_thread_start_0(fn, arg, th) 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)) { @@ -1,15 +1,15 @@ #define RUBY_VERSION "1.8.7" -#define RUBY_RELEASE_DATE "2009-07-06" +#define RUBY_RELEASE_DATE "2009-07-08" #define RUBY_VERSION_CODE 187 -#define RUBY_RELEASE_CODE 20090706 -#define RUBY_PATCHLEVEL 179 +#define RUBY_RELEASE_CODE 20090708 +#define RUBY_PATCHLEVEL 180 #define RUBY_VERSION_MAJOR 1 #define RUBY_VERSION_MINOR 8 #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_YEAR 2009 #define RUBY_RELEASE_MONTH 7 -#define RUBY_RELEASE_DAY 6 +#define RUBY_RELEASE_DAY 8 #ifdef RUBY_EXTERN RUBY_EXTERN const char ruby_version[]; |