summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwyhaines <wyhaines@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-02-03 16:09:35 +0000
committerwyhaines <wyhaines@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-02-03 16:09:35 +0000
commiteda0a8e2d912c25d6d47da4a28f508bd8e80c104 (patch)
treeeb3c71b89c5272bf25c989f6d48e4c288d3c8439
parentfdbf2bb474d7c1922fb66d433de21bfa99b2d471 (diff)
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
-rw-r--r--ChangeLog4
-rw-r--r--eval.c103
-rw-r--r--version.h10
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 <khaines@ruby-lang.org>
+
+ * eval.c: Backport #1743 [ruby-core:24203]; stops timer thread unless other threads exist.
+
Wed Jan 28 04:00:00 2010 Kirk Haines <khaines@ruby-lang.org>
* 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,14 +12153,8 @@ 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
}
if (THREAD_SAVE_CONTEXT(curr_thread)) {
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[];