Bug #4696 » 0001-new-deadlock-check.patch
thread.c | ||
---|---|---|
rb_thread_lock_t lock;
|
||
rb_thread_cond_t cond;
|
||
struct rb_thread_struct volatile *th;
|
||
volatile int cond_waiting, cond_notified;
|
||
int cond_waiting;
|
||
struct rb_mutex_struct *next_mutex;
|
||
} mutex_t;
|
||
... | ... | |
lock_func(rb_thread_t *th, mutex_t *mutex, int timeout_ms)
|
||
{
|
||
int interrupted = 0;
|
||
int err = 0;
|
||
native_mutex_lock(&mutex->lock);
|
||
th->transition_for_lock = 0;
|
||
mutex->cond_waiting++;
|
||
for (;;) {
|
||
if (!mutex->th) {
|
||
mutex->th = th;
|
||
break;
|
||
}
|
||
if (RUBY_VM_INTERRUPTED(th)) {
|
||
interrupted = 1;
|
||
break;
|
||
}
|
||
if (err == ETIMEDOUT) {
|
||
interrupted = 2;
|
||
break;
|
||
}
|
||
mutex->cond_waiting++;
|
||
if (timeout_ms) {
|
||
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;
|
||
mutex->cond_waiting--;
|
||
break;
|
||
}
|
||
err = native_cond_timedwait(&mutex->cond, &mutex->lock, &timeout);
|
||
}
|
||
else {
|
||
native_cond_wait(&mutex->cond, &mutex->lock);
|
||
}
|
||
mutex->cond_notified--;
|
||
if (RUBY_VM_INTERRUPTED(th)) {
|
||
interrupted = 1;
|
||
break;
|
||
err = 0;
|
||
}
|
||
}
|
||
mutex->cond_waiting--;
|
||
th->transition_for_lock = 1;
|
||
native_mutex_unlock(&mutex->lock);
|
||
... | ... | |
{
|
||
mutex_t *mutex = (mutex_t *)ptr;
|
||
native_mutex_lock(&mutex->lock);
|
||
if (mutex->cond_waiting > 0) {
|
||
if (mutex->cond_waiting > 0)
|
||
native_cond_broadcast(&mutex->cond);
|
||
mutex->cond_notified = mutex->cond_waiting;
|
||
mutex->cond_waiting = 0;
|
||
}
|
||
native_mutex_unlock(&mutex->lock);
|
||
}
|
||
... | ... | |
}
|
||
else {
|
||
mutex->th = 0;
|
||
if (mutex->cond_waiting > 0) {
|
||
/* waiting thread */
|
||
if (mutex->cond_waiting > 0)
|
||
native_cond_signal(&mutex->cond);
|
||
mutex->cond_waiting--;
|
||
mutex->cond_notified++;
|
||
}
|
||
}
|
||
native_mutex_unlock(&mutex->lock);
|
||
... | ... | |
GetMutexPtr(th->locking_mutex, mutex);
|
||
native_mutex_lock(&mutex->lock);
|
||
if (mutex->th == th || (!mutex->th && mutex->cond_notified)) {
|
||
if (mutex->th == th || (!mutex->th && mutex->cond_waiting)) {
|
||
*found = 1;
|
||
}
|
||
native_mutex_unlock(&mutex->lock);
|
||
... | ... | |
return (*found) ? ST_STOP : ST_CONTINUE;
|
||
}
|
||
#if 0 /* for debug */
|
||
#ifdef DEBUG_DEADLOCK_CHECK
|
||
static int
|
||
debug_i(st_data_t key, st_data_t val, int *found)
|
||
{
|
||
... | ... | |
GetMutexPtr(th->locking_mutex, mutex);
|
||
native_mutex_lock(&mutex->lock);
|
||
printf(" %p %d\n", mutex->th, mutex->cond_notified);
|
||
printf(" %p %d\n", mutex->th, mutex->cond_waiting);
|
||
native_mutex_unlock(&mutex->lock);
|
||
}
|
||
else puts("");
|
||
else
|
||
puts("");
|
||
return ST_CONTINUE;
|
||
}
|
||
... | ... | |
VALUE argv[2];
|
||
argv[0] = rb_eFatal;
|
||
argv[1] = rb_str_new2("deadlock detected");
|
||
#if 0 /* for debug */
|
||
#ifdef DEBUG_DEADLOCK_CHECK
|
||
printf("%d %d %p %p\n", vm->living_threads->num_entries, vm->sleeper, GET_THREAD(), vm->main_thread);
|
||
st_foreach(vm->living_threads, debug_i, (st_data_t)0);
|
||
#endif
|