aboutsummaryrefslogtreecommitdiffstats
path: root/ext/monitor
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2019-10-20 15:45:30 +0900
committerKoichi Sasada <ko1@atdot.net>2019-10-20 15:45:30 +0900
commita236eaa762137d7cb32b8311e0ef9a74bbb0f385 (patch)
treeccf40c23053f1aef9b8445fd8d3e8e4bd816e7a6 /ext/monitor
parenta0a3c701816c2fe4ab6e940c6cf5638756ceb6dc (diff)
downloadruby-a236eaa762137d7cb32b8311e0ef9a74bbb0f385.tar.gz
Native MonitorMixin::ConditionVariable#wait
MonitorMixin::ConditionVariable#wait can be interrupted just after Monitor#exit_for_cond. So implementation in C.
Diffstat (limited to 'ext/monitor')
-rw-r--r--ext/monitor/lib/monitor.rb8
-rw-r--r--ext/monitor/monitor.c57
2 files changed, 43 insertions, 22 deletions
diff --git a/ext/monitor/lib/monitor.rb b/ext/monitor/lib/monitor.rb
index f6b3023dd7..b9ae03649c 100644
--- a/ext/monitor/lib/monitor.rb
+++ b/ext/monitor/lib/monitor.rb
@@ -105,13 +105,7 @@ module MonitorMixin
#
def wait(timeout = nil)
@monitor.mon_check_owner
- count = @monitor.__send__(:exit_for_cond)
- begin
- @cond.wait(@monitor.__send__(:mutex_for_cond), timeout)
- return true
- ensure
- @monitor.__send__(:enter_for_cond, count)
- end
+ @monitor.wait_for_cond(@cond, timeout)
end
#
diff --git a/ext/monitor/monitor.c b/ext/monitor/monitor.c
index cf9e7fe07d..2d399768b2 100644
--- a/ext/monitor/monitor.c
+++ b/ext/monitor/monitor.c
@@ -122,15 +122,6 @@ monitor_check_owner(VALUE monitor)
}
static VALUE
-monitor_enter_for_cond(VALUE monitor, VALUE count)
-{
- struct rb_monitor *mc = monitor_ptr(monitor);
- RB_OBJ_WRITE(monitor, &mc->owner, rb_thread_current());
- mc->count = NUM2LONG(count);
- return Qnil;
-}
-
-static VALUE
monitor_exit_for_cond(VALUE monitor)
{
struct rb_monitor *mc = monitor_ptr(monitor);
@@ -140,11 +131,49 @@ monitor_exit_for_cond(VALUE monitor)
return LONG2NUM(cnt);
}
+struct wait_for_cond_data {
+ VALUE monitor;
+ VALUE cond;
+ VALUE timeout;
+ VALUE count;
+};
+
static VALUE
-monitor_mutex_for_cond(VALUE monitor)
+monitor_wait_for_cond_body(VALUE v)
{
- struct rb_monitor *mc = monitor_ptr(monitor);
- return mc->mutex;
+ struct wait_for_cond_data *data = (struct wait_for_cond_data *)v;
+ struct rb_monitor *mc = monitor_ptr(data->monitor);
+ // cond.wait(monitor.mutex, timeout)
+ rb_funcall(data->cond, rb_intern("wait"), 2, mc->mutex, data->timeout);
+ return Qtrue;
+}
+
+static VALUE
+monitor_enter_for_cond(VALUE v)
+{
+ // assert(rb_mutex_owned_p(mc->mutex) == Qtrue)
+ // but rb_mutex_owned_p is not exported...
+
+ struct wait_for_cond_data *data = (struct wait_for_cond_data *)v;
+ struct rb_monitor *mc = monitor_ptr(data->monitor);
+ RB_OBJ_WRITE(data->monitor, &mc->owner, rb_thread_current());
+ mc->count = NUM2LONG(data->count);
+ return Qnil;
+}
+
+static VALUE
+monitor_wait_for_cond(VALUE monitor, VALUE cond, VALUE timeout)
+{
+ VALUE count = monitor_exit_for_cond(monitor);
+ struct wait_for_cond_data data = {
+ monitor,
+ cond,
+ timeout,
+ count,
+ };
+
+ return rb_ensure(monitor_wait_for_cond_body, (VALUE)&data,
+ monitor_enter_for_cond, (VALUE)&data);
}
static VALUE
@@ -183,7 +212,5 @@ Init_monitor(void)
rb_define_method(rb_cMonitor, "mon_owned?", monitor_owned_p, 0);
/* internal methods for MonitorMixin::ConditionalVariable */
- rb_define_private_method(rb_cMonitor, "enter_for_cond", monitor_enter_for_cond, 1);
- rb_define_private_method(rb_cMonitor, "exit_for_cond", monitor_exit_for_cond, 0);
- rb_define_private_method(rb_cMonitor, "mutex_for_cond", monitor_mutex_for_cond, 0);
+ rb_define_method(rb_cMonitor, "wait_for_cond", monitor_wait_for_cond, 2);
}