Ensure fiber scheduler re-acquires mutex when interrupted from sleep. (#12158)
[Bug #20907]
This commit is contained in:
parent
31997661e4
commit
a8c2d5e7be
Notes:
git
2024-11-23 23:54:31 +00:00
Merged-By: ioquatix <samuel@codeotaku.com>
@ -182,4 +182,32 @@ class TestFiberScheduler < Test::Unit::TestCase
|
|||||||
thread.join
|
thread.join
|
||||||
signaller.join
|
signaller.join
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_condition_variable
|
||||||
|
condition_variable = ::Thread::ConditionVariable.new
|
||||||
|
mutex = ::Thread::Mutex.new
|
||||||
|
|
||||||
|
error = nil
|
||||||
|
|
||||||
|
thread = Thread.new do
|
||||||
|
Thread.current.report_on_exception = false
|
||||||
|
|
||||||
|
scheduler = Scheduler.new
|
||||||
|
Fiber.set_scheduler scheduler
|
||||||
|
|
||||||
|
fiber = Fiber.schedule do
|
||||||
|
begin
|
||||||
|
mutex.synchronize do
|
||||||
|
condition_variable.wait(mutex)
|
||||||
|
end
|
||||||
|
rescue => error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
fiber.raise(RuntimeError)
|
||||||
|
end
|
||||||
|
|
||||||
|
thread.join
|
||||||
|
assert_kind_of RuntimeError, error
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -548,48 +548,54 @@ rb_mutex_abandon_all(rb_mutex_t *mutexes)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static VALUE
|
struct rb_mutex_sleep_arguments {
|
||||||
rb_mutex_sleep_forever(VALUE self)
|
VALUE self;
|
||||||
{
|
VALUE timeout;
|
||||||
rb_thread_sleep_deadly_allow_spurious_wakeup(self, Qnil, 0);
|
};
|
||||||
return Qnil;
|
|
||||||
}
|
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_mutex_wait_for(VALUE time)
|
mutex_sleep_begin(VALUE _arguments)
|
||||||
{
|
{
|
||||||
rb_hrtime_t *rel = (rb_hrtime_t *)time;
|
struct rb_mutex_sleep_arguments *arguments = (struct rb_mutex_sleep_arguments *)_arguments;
|
||||||
/* permit spurious check */
|
VALUE timeout = arguments->timeout;
|
||||||
return RBOOL(sleep_hrtime(GET_THREAD(), *rel, 0));
|
VALUE woken = Qtrue;
|
||||||
|
|
||||||
|
VALUE scheduler = rb_fiber_scheduler_current();
|
||||||
|
if (scheduler != Qnil) {
|
||||||
|
rb_fiber_scheduler_kernel_sleep(scheduler, timeout);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (NIL_P(timeout)) {
|
||||||
|
rb_thread_sleep_deadly_allow_spurious_wakeup(arguments->self, Qnil, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
struct timeval timeout_value = rb_time_interval(timeout);
|
||||||
|
rb_hrtime_t relative_timeout = rb_timeval2hrtime(&timeout_value);
|
||||||
|
/* permit spurious check */
|
||||||
|
woken = RBOOL(sleep_hrtime(GET_THREAD(), relative_timeout, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return woken;
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_mutex_sleep(VALUE self, VALUE timeout)
|
rb_mutex_sleep(VALUE self, VALUE timeout)
|
||||||
{
|
{
|
||||||
struct timeval t;
|
|
||||||
VALUE woken = Qtrue;
|
|
||||||
|
|
||||||
if (!NIL_P(timeout)) {
|
if (!NIL_P(timeout)) {
|
||||||
t = rb_time_interval(timeout);
|
// Validate the argument:
|
||||||
|
rb_time_interval(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
rb_mutex_unlock(self);
|
rb_mutex_unlock(self);
|
||||||
time_t beg = time(0);
|
time_t beg = time(0);
|
||||||
|
|
||||||
VALUE scheduler = rb_fiber_scheduler_current();
|
struct rb_mutex_sleep_arguments arguments = {
|
||||||
if (scheduler != Qnil) {
|
.self = self,
|
||||||
rb_fiber_scheduler_kernel_sleep(scheduler, timeout);
|
.timeout = timeout,
|
||||||
mutex_lock_uninterruptible(self);
|
};
|
||||||
}
|
|
||||||
else {
|
VALUE woken = rb_ensure(mutex_sleep_begin, (VALUE)&arguments, mutex_lock_uninterruptible, self);
|
||||||
if (NIL_P(timeout)) {
|
|
||||||
rb_ensure(rb_mutex_sleep_forever, self, mutex_lock_uninterruptible, self);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
rb_hrtime_t rel = rb_timeval2hrtime(&t);
|
|
||||||
woken = rb_ensure(rb_mutex_wait_for, (VALUE)&rel, mutex_lock_uninterruptible, self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RUBY_VM_CHECK_INTS_BLOCKING(GET_EC());
|
RUBY_VM_CHECK_INTS_BLOCKING(GET_EC());
|
||||||
if (!woken) return Qnil;
|
if (!woken) return Qnil;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user