summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-07-08 10:58:03 +0000
committershyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-07-08 10:58:03 +0000
commita563f713984b84305d92b99c547a7e48c33ea2f7 (patch)
tree1a40f233ef49e4142a2ade4d10bd4a1cd67e3726
parent4b4ac8ac64ffaa6de94ac254ce1c6aea2b743269 (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--ChangeLog5
-rw-r--r--eval.c93
-rw-r--r--version.h8
3 files changed, 83 insertions, 23 deletions
diff --git a/ChangeLog b/ChangeLog
index 9f73a79404..8ebb356a06 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/eval.c b/eval.c
index 6bb34f3857..8d1c5e378c 100644
--- a/eval.c
+++ b/eval.c
@@ -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)) {
diff --git a/version.h b/version.h
index 6f152bf4a3..5ecd36daed 100644
--- a/version.h
+++ b/version.h
@@ -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[];