зеркало из https://github.com/github/ruby.git
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
This commit is contained in:
Родитель
54b50fbb9c
Коммит
b2ea836ae7
15
ChangeLog
15
ChangeLog
|
@ -1,3 +1,18 @@
|
||||||
|
Sat May 7 02:29:41 2011 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
|
||||||
|
|
||||||
|
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 <kosaki.motohiro@gmail.com>
|
Sat May 7 01:54:21 2011 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
|
||||||
|
|
||||||
* thread_pthread.c (get_ts): add monotonic clock capability.
|
* thread_pthread.c (get_ts): add monotonic clock capability.
|
||||||
|
|
35
thread.c
35
thread.c
|
@ -3336,7 +3336,7 @@ mutex_alloc(VALUE klass)
|
||||||
|
|
||||||
obj = TypedData_Make_Struct(klass, mutex_t, &mutex_data_type, mutex);
|
obj = TypedData_Make_Struct(klass, mutex_t, &mutex_data_type, mutex);
|
||||||
native_mutex_initialize(&mutex->lock);
|
native_mutex_initialize(&mutex->lock);
|
||||||
native_cond_initialize(&mutex->cond, 0);
|
native_cond_initialize(&mutex->cond, RB_CONDATTR_CLOCK_MONOTONIC);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3410,26 +3410,6 @@ rb_mutex_trylock(VALUE self)
|
||||||
return locked;
|
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
|
static int
|
||||||
lock_func(rb_thread_t *th, mutex_t *mutex, int timeout_ms)
|
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);
|
native_mutex_lock(&mutex->lock);
|
||||||
th->transition_for_lock = 0;
|
th->transition_for_lock = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
struct timespec ts;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!mutex->th) {
|
if (!mutex->th) {
|
||||||
mutex->th = th;
|
mutex->th = th;
|
||||||
break;
|
break;
|
||||||
|
@ -3448,8 +3425,14 @@ lock_func(rb_thread_t *th, mutex_t *mutex, int timeout_ms)
|
||||||
|
|
||||||
mutex->cond_waiting++;
|
mutex->cond_waiting++;
|
||||||
if (timeout_ms) {
|
if (timeout_ms) {
|
||||||
ts = init_lock_timeout(timeout_ms);
|
int ret;
|
||||||
ret = native_cond_timedwait(&mutex->cond, &mutex->lock, &ts);
|
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) {
|
if (ret == ETIMEDOUT) {
|
||||||
interrupted = 2;
|
interrupted = 2;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -295,6 +295,41 @@ native_cond_timedwait(rb_thread_cond_t *cond, pthread_mutex_t *mutex, struct tim
|
||||||
return r;
|
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_push pthread_cleanup_push
|
||||||
#define native_cleanup_pop pthread_cleanup_pop
|
#define native_cleanup_pop pthread_cleanup_pop
|
||||||
#ifdef HAVE_SCHED_YIELD
|
#ifdef HAVE_SCHED_YIELD
|
||||||
|
@ -917,49 +952,23 @@ static pthread_t timer_thread_id;
|
||||||
static rb_thread_cond_t timer_thread_cond;
|
static rb_thread_cond_t timer_thread_cond;
|
||||||
static pthread_mutex_t timer_thread_lock = PTHREAD_MUTEX_INITIALIZER;
|
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 *
|
static void *
|
||||||
thread_timer(void *dummy)
|
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_mutex_lock(&timer_thread_lock);
|
||||||
native_cond_broadcast(&timer_thread_cond);
|
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) {
|
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);
|
if (err == ETIMEDOUT);
|
||||||
else if (err == 0 || err == EINTR) {
|
else if (err == 0 || err == EINTR) {
|
||||||
if (rb_signal_buff_size() == 0) break;
|
if (rb_signal_buff_size() == 0) break;
|
||||||
|
|
|
@ -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);
|
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
|
static void
|
||||||
native_cond_initialize(rb_thread_cond_t *cond, int flags)
|
native_cond_initialize(rb_thread_cond_t *cond, int flags)
|
||||||
{
|
{
|
||||||
|
|
Загрузка…
Ссылка в новой задаче