From b2ea836ae705cc690d1230476e6eb97e92e7ef52 Mon Sep 17 00:00:00 2001 From: kosaki Date: Fri, 6 May 2011 17:39:32 +0000 Subject: [PATCH] mutex: deadlock check timeout use monotonic time. * thread_pthread.c (native_cond_timeout): new internal api. it calculate a proper time for argument of native_cond_timedwait(). * thread_win32.c (native_cond_timeout): ditto. * thread_pthread.c (thread_timer): use native_cond_timeout() instead of get_ts. * thread.c (lock_func): ditto. * thread_pthread.c (get_ts): removed. use native_cond_timeout(). * thread.c (init_lock_timeout): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@31454 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 15 +++++++++ thread.c | 35 ++++++--------------- thread_pthread.c | 81 +++++++++++++++++++++++++++--------------------- thread_win32.c | 23 ++++++++++++++ 4 files changed, 92 insertions(+), 62 deletions(-) diff --git a/ChangeLog b/ChangeLog index 71c407fefa..5e1e788368 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +Sat May 7 02:29:41 2011 KOSAKI Motohiro + + mutex: deadlock check timeout use monotonic time. + + * thread_pthread.c (native_cond_timeout): new internal api. + it calculate a proper time for argument of native_cond_timedwait(). + * thread_win32.c (native_cond_timeout): ditto. + + * thread_pthread.c (thread_timer): use native_cond_timeout() + instead of get_ts. + * thread.c (lock_func): ditto. + + * thread_pthread.c (get_ts): removed. use native_cond_timeout(). + * thread.c (init_lock_timeout): ditto. + Sat May 7 01:54:21 2011 KOSAKI Motohiro * thread_pthread.c (get_ts): add monotonic clock capability. diff --git a/thread.c b/thread.c index 1e3b957dd8..0bdc4ef6bf 100644 --- a/thread.c +++ b/thread.c @@ -3336,7 +3336,7 @@ mutex_alloc(VALUE klass) obj = TypedData_Make_Struct(klass, mutex_t, &mutex_data_type, mutex); native_mutex_initialize(&mutex->lock); - native_cond_initialize(&mutex->cond, 0); + native_cond_initialize(&mutex->cond, RB_CONDATTR_CLOCK_MONOTONIC); return obj; } @@ -3410,26 +3410,6 @@ rb_mutex_trylock(VALUE self) return locked; } -static struct timespec init_lock_timeout(int timeout_ms) -{ - struct timespec ts; - struct timeval tv; - int ret; - - ret = gettimeofday(&tv, NULL); - if (ret < 0) - rb_sys_fail(0); - - ts.tv_sec = tv.tv_sec; - ts.tv_nsec = tv.tv_usec * 1000 + timeout_ms * 1000 * 1000; - if (ts.tv_nsec >= 1000000000) { - ts.tv_sec++; - ts.tv_nsec -= 1000000000; - } - - return ts; -} - static int lock_func(rb_thread_t *th, mutex_t *mutex, int timeout_ms) { @@ -3438,9 +3418,6 @@ lock_func(rb_thread_t *th, mutex_t *mutex, int timeout_ms) native_mutex_lock(&mutex->lock); th->transition_for_lock = 0; for (;;) { - struct timespec ts; - int ret; - if (!mutex->th) { mutex->th = th; break; @@ -3448,8 +3425,14 @@ lock_func(rb_thread_t *th, mutex_t *mutex, int timeout_ms) mutex->cond_waiting++; if (timeout_ms) { - ts = init_lock_timeout(timeout_ms); - ret = native_cond_timedwait(&mutex->cond, &mutex->lock, &ts); + int ret; + struct timespec timeout_rel; + struct timespec timeout; + + timeout_rel.tv_sec = 0; + timeout_rel.tv_nsec = timeout_ms * 1000 * 1000; + timeout = native_cond_timeout(&mutex->cond, timeout_rel); + ret = native_cond_timedwait(&mutex->cond, &mutex->lock, &timeout); if (ret == ETIMEDOUT) { interrupted = 2; break; diff --git a/thread_pthread.c b/thread_pthread.c index 7d55ba2763..ba2b954388 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -295,6 +295,41 @@ native_cond_timedwait(rb_thread_cond_t *cond, pthread_mutex_t *mutex, struct tim return r; } +static struct timespec +native_cond_timeout(rb_thread_cond_t *cond, struct timespec timeout_rel) +{ + int ret; + struct timeval tv; + struct timespec timeout; + +#if USE_MONOTONIC_COND + if (cond->clockid == CLOCK_MONOTONIC) { + ret = clock_gettime(cond->clockid, &timeout); + if (ret != 0) + rb_sys_fail("clock_gettime()"); + goto out; + } +#endif + + if (cond->clockid != CLOCK_REALTIME) + rb_bug("unsupported clockid %d", cond->clockid); + + ret = gettimeofday(&tv, 0); + if (ret != 0) + rb_sys_fail(0); + timeout.tv_sec = tv.tv_sec; + timeout.tv_nsec = tv.tv_usec * 1000; + + out: + timeout.tv_sec += timeout_rel.tv_sec; + timeout.tv_nsec += timeout_rel.tv_nsec; + if (timeout.tv_nsec >= 1000*1000*1000) { + timeout.tv_sec++; + timeout.tv_nsec -= 1000*1000*1000; + } + return timeout; +} + #define native_cleanup_push pthread_cleanup_push #define native_cleanup_pop pthread_cleanup_pop #ifdef HAVE_SCHED_YIELD @@ -917,49 +952,23 @@ static pthread_t timer_thread_id; static rb_thread_cond_t timer_thread_cond; static pthread_mutex_t timer_thread_lock = PTHREAD_MUTEX_INITIALIZER; -static struct timespec * -get_ts(struct timespec *ts, unsigned long nsec) -{ - int ret; - struct timeval tv; - -#if USE_MONOTONIC_COND - if (timer_thread_cond.clockid == CLOCK_MONOTONIC) { - ret = clock_gettime(CLOCK_MONOTONIC, ts); - if (ret != 0) - rb_sys_fail("clock_gettime(CLOCK_MONOTONIC)"); - goto out; - } -#endif - - if (timer_thread_cond.clockid != CLOCK_REALTIME) - rb_bug("unsupported clockid %d", timer_thread_cond.clockid); - - ret = gettimeofday(&tv, 0); - if (ret != 0) - rb_sys_fail(0); - ts->tv_sec = tv.tv_sec; - ts->tv_nsec = tv.tv_usec * 1000; - - out: - ts->tv_nsec += nsec; - if (ts->tv_nsec >= PER_NANO) { - ts->tv_sec++; - ts->tv_nsec -= PER_NANO; - } - return ts; -} - static void * thread_timer(void *dummy) { - struct timespec ts; + struct timespec timeout_10ms; + + timeout_10ms.tv_sec = 0; + timeout_10ms.tv_nsec = 10 * 1000 * 1000; native_mutex_lock(&timer_thread_lock); native_cond_broadcast(&timer_thread_cond); -#define WAIT_FOR_10MS() native_cond_timedwait(&timer_thread_cond, &timer_thread_lock, get_ts(&ts, PER_NANO/100)) while (system_working > 0) { - int err = WAIT_FOR_10MS(); + int err; + struct timespec timeout; + + timeout = native_cond_timeout(&timer_thread_cond, timeout_10ms); + err = native_cond_timedwait(&timer_thread_cond, &timer_thread_lock, + &timeout); if (err == ETIMEDOUT); else if (err == 0 || err == EINTR) { if (rb_signal_buff_size() == 0) break; diff --git a/thread_win32.c b/thread_win32.c index 287f637911..62f78fd850 100644 --- a/thread_win32.c +++ b/thread_win32.c @@ -489,6 +489,29 @@ native_cond_timedwait(rb_thread_cond_t *cond, rb_thread_lock_t *mutex, struct ti return __cond_timedwait(cond, mutex, timeout_ms); } +static struct timespec +native_cond_timeout(rb_thread_cond_t *cond, struct timespec timeout_rel) +{ + int ret; + struct timeval tv; + struct timespec timeout; + + ret = gettimeofday(&tv, 0); + if (ret != 0) + rb_sys_fail(0); + timeout.tv_sec = tv.tv_sec; + timeout.tv_nsec = tv.tv_usec * 1000; + + timeout.tv_sec += timeout_rel.tv_sec; + timeout.tv_nsec += timeout_rel.tv_nsec; + if (timeout.tv_nsec >= 1000*1000*1000) { + timeout.tv_sec++; + timeout.tv_nsec -= 1000*1000*1000; + } + return timeout; +} + + static void native_cond_initialize(rb_thread_cond_t *cond, int flags) {