Feature #4607 » 0001-mutex-fix-silly-last_thread-handling.patch
thread.c | ||
---|---|---|
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 last_thread)
|
||
lock_func(rb_thread_t *th, mutex_t *mutex, int timeout_ms)
|
||
{
|
||
int interrupted = 0;
|
||
#if 0 /* for debug */
|
||
native_thread_yield();
|
||
#endif
|
||
native_mutex_lock(&mutex->lock);
|
||
th->transition_for_lock = 0;
|
||
while (mutex->th || (mutex->th = th, 0)) {
|
||
if (last_thread) {
|
||
interrupted = 2;
|
||
break;
|
||
}
|
||
struct timespec ts;
|
||
int ret;
|
||
mutex->cond_waiting++;
|
||
native_cond_wait(&mutex->cond, &mutex->lock);
|
||
if (timeout_ms) {
|
||
ts = init_lock_timeout(timeout_ms);
|
||
ret = native_cond_timedwait(&mutex->cond, &mutex->lock, &ts);
|
||
if (ret == ETIMEDOUT) {
|
||
interrupted = 2;
|
||
break;
|
||
}
|
||
}
|
||
else {
|
||
native_cond_wait(&mutex->cond, &mutex->lock);
|
||
}
|
||
mutex->cond_notified--;
|
||
if (RUBY_VM_INTERRUPTED(th)) {
|
||
... | ... | |
th->transition_for_lock = 1;
|
||
native_mutex_unlock(&mutex->lock);
|
||
if (interrupted == 2) native_thread_yield();
|
||
#if 0 /* for debug */
|
||
native_thread_yield();
|
||
#endif
|
||
return interrupted;
|
||
}
|
||
... | ... | |
while (mutex->th != th) {
|
||
int interrupted;
|
||
enum rb_thread_status prev_status = th->status;
|
||
int last_thread = 0;
|
||
int timeout_ms = 0;
|
||
struct rb_unblock_callback oldubf;
|
||
set_unblock_function(th, lock_interrupt, mutex, &oldubf);
|
||
th->status = THREAD_STOPPED_FOREVER;
|
||
th->vm->sleeper++;
|
||
th->locking_mutex = self;
|
||
/*
|
||
* Carefully! while some contended threads are in lock_fun(),
|
||
* vm->sleepr is unstable value. we have to avoid both deadlock
|
||
* and busy loop.
|
||
*/
|
||
if (vm_living_thread_num(th->vm) == th->vm->sleeper) {
|
||
last_thread = 1;
|
||
timeout_ms = 100;
|
||
}
|
||
th->transition_for_lock = 1;
|
||
BLOCKING_REGION_CORE({
|
||
interrupted = lock_func(th, mutex, last_thread);
|
||
interrupted = lock_func(th, mutex, timeout_ms);
|
||
});
|
||
th->transition_for_lock = 0;
|
||
remove_signal_thread_list(th);
|
- « Previous
- 1
- 2
- Next »