summaryrefslogtreecommitdiff
path: root/ext/monitor
diff options
context:
space:
mode:
Diffstat (limited to 'ext/monitor')
-rw-r--r--ext/monitor/depend5
-rw-r--r--ext/monitor/lib/monitor.rb10
-rw-r--r--ext/monitor/monitor.c156
3 files changed, 127 insertions, 44 deletions
diff --git a/ext/monitor/depend b/ext/monitor/depend
index 3030da71d0..0c7d54afc8 100644
--- a/ext/monitor/depend
+++ b/ext/monitor/depend
@@ -51,6 +51,7 @@ monitor.o: $(hdrdir)/ruby/internal/attr/noexcept.h
monitor.o: $(hdrdir)/ruby/internal/attr/noinline.h
monitor.o: $(hdrdir)/ruby/internal/attr/nonnull.h
monitor.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+monitor.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
monitor.o: $(hdrdir)/ruby/internal/attr/pure.h
monitor.o: $(hdrdir)/ruby/internal/attr/restrict.h
monitor.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -110,7 +111,6 @@ monitor.o: $(hdrdir)/ruby/internal/intern/enumerator.h
monitor.o: $(hdrdir)/ruby/internal/intern/error.h
monitor.o: $(hdrdir)/ruby/internal/intern/eval.h
monitor.o: $(hdrdir)/ruby/internal/intern/file.h
-monitor.o: $(hdrdir)/ruby/internal/intern/gc.h
monitor.o: $(hdrdir)/ruby/internal/intern/hash.h
monitor.o: $(hdrdir)/ruby/internal/intern/io.h
monitor.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -127,6 +127,7 @@ monitor.o: $(hdrdir)/ruby/internal/intern/re.h
monitor.o: $(hdrdir)/ruby/internal/intern/ruby.h
monitor.o: $(hdrdir)/ruby/internal/intern/select.h
monitor.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+monitor.o: $(hdrdir)/ruby/internal/intern/set.h
monitor.o: $(hdrdir)/ruby/internal/intern/signal.h
monitor.o: $(hdrdir)/ruby/internal/intern/sprintf.h
monitor.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -141,12 +142,12 @@ monitor.o: $(hdrdir)/ruby/internal/memory.h
monitor.o: $(hdrdir)/ruby/internal/method.h
monitor.o: $(hdrdir)/ruby/internal/module.h
monitor.o: $(hdrdir)/ruby/internal/newobj.h
-monitor.o: $(hdrdir)/ruby/internal/rgengc.h
monitor.o: $(hdrdir)/ruby/internal/scan_args.h
monitor.o: $(hdrdir)/ruby/internal/special_consts.h
monitor.o: $(hdrdir)/ruby/internal/static_assert.h
monitor.o: $(hdrdir)/ruby/internal/stdalign.h
monitor.o: $(hdrdir)/ruby/internal/stdbool.h
+monitor.o: $(hdrdir)/ruby/internal/stdckdint.h
monitor.o: $(hdrdir)/ruby/internal/symbol.h
monitor.o: $(hdrdir)/ruby/internal/value.h
monitor.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/monitor/lib/monitor.rb b/ext/monitor/lib/monitor.rb
index 31d6d2b3c4..82d0a75c56 100644
--- a/ext/monitor/lib/monitor.rb
+++ b/ext/monitor/lib/monitor.rb
@@ -143,13 +143,13 @@ module MonitorMixin
private
- def initialize(monitor)
+ def initialize(monitor) # :nodoc:
@monitor = monitor
@cond = Thread::ConditionVariable.new
end
end
- def self.extend_object(obj)
+ def self.extend_object(obj) # :nodoc:
super(obj)
obj.__send__(:mon_initialize)
end
@@ -238,6 +238,8 @@ module MonitorMixin
@mon_data_owner_object_id = self.object_id
end
+ # Ensures that the MonitorMixin is owned by the current thread,
+ # otherwise raises an exception.
def mon_check_owner
@mon_data.mon_check_owner
end
@@ -254,6 +256,10 @@ end
# end
#
class Monitor
+ #
+ # Creates a new MonitorMixin::ConditionVariable associated with the
+ # Monitor object.
+ #
def new_cond
::MonitorMixin::ConditionVariable.new(self)
end
diff --git a/ext/monitor/monitor.c b/ext/monitor/monitor.c
index 10209cf2aa..c43751c4e2 100644
--- a/ext/monitor/monitor.c
+++ b/ext/monitor/monitor.c
@@ -4,28 +4,35 @@
struct rb_monitor {
long count;
- const VALUE owner;
- const VALUE mutex;
+ VALUE owner;
+ VALUE mutex;
};
static void
monitor_mark(void *ptr)
{
struct rb_monitor *mc = ptr;
- rb_gc_mark(mc->owner);
- rb_gc_mark(mc->mutex);
+ rb_gc_mark_movable(mc->owner);
+ rb_gc_mark_movable(mc->mutex);
}
-static size_t
-monitor_memsize(const void *ptr)
+static void
+monitor_compact(void *ptr)
{
- return sizeof(struct rb_monitor);
+ struct rb_monitor *mc = ptr;
+ mc->owner = rb_gc_location(mc->owner);
+ mc->mutex = rb_gc_location(mc->mutex);
}
static const rb_data_type_t monitor_data_type = {
- "monitor",
- {monitor_mark, RUBY_TYPED_DEFAULT_FREE, monitor_memsize,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
+ .wrap_struct_name = "monitor",
+ .function = {
+ .dmark = monitor_mark,
+ .dfree = RUBY_TYPED_DEFAULT_FREE,
+ .dsize = NULL, // Fully embeded
+ .dcompact = monitor_compact,
+ },
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
};
static VALUE
@@ -50,68 +57,124 @@ monitor_ptr(VALUE monitor)
return mc;
}
-static int
-mc_owner_p(struct rb_monitor *mc)
+static bool
+mc_owner_p(struct rb_monitor *mc, VALUE current_fiber)
{
- return mc->owner == rb_fiber_current();
+ return mc->owner == current_fiber;
}
+/*
+ * call-seq:
+ * try_enter -> true or false
+ *
+ * Attempts to enter exclusive section. Returns +false+ if lock fails.
+ */
static VALUE
monitor_try_enter(VALUE monitor)
{
struct rb_monitor *mc = monitor_ptr(monitor);
- if (!mc_owner_p(mc)) {
+ VALUE current_fiber = rb_fiber_current();
+ if (!mc_owner_p(mc, current_fiber)) {
if (!rb_mutex_trylock(mc->mutex)) {
return Qfalse;
}
- RB_OBJ_WRITE(monitor, &mc->owner, rb_fiber_current());
+ RB_OBJ_WRITE(monitor, &mc->owner, current_fiber);
mc->count = 0;
}
mc->count += 1;
return Qtrue;
}
+
+struct monitor_args {
+ VALUE monitor;
+ struct rb_monitor *mc;
+ VALUE current_fiber;
+};
+
+static inline void
+monitor_args_init(struct monitor_args *args, VALUE monitor)
+{
+ args->monitor = monitor;
+ args->mc = monitor_ptr(monitor);
+ args->current_fiber = rb_fiber_current();
+}
+
+static void
+monitor_enter0(struct monitor_args *args)
+{
+ if (!mc_owner_p(args->mc, args->current_fiber)) {
+ rb_mutex_lock(args->mc->mutex);
+ RB_OBJ_WRITE(args->monitor, &args->mc->owner, args->current_fiber);
+ args->mc->count = 0;
+ }
+ args->mc->count++;
+}
+
+/*
+ * call-seq:
+ * enter -> nil
+ *
+ * Enters exclusive section.
+ */
static VALUE
monitor_enter(VALUE monitor)
{
- struct rb_monitor *mc = monitor_ptr(monitor);
- if (!mc_owner_p(mc)) {
- rb_mutex_lock(mc->mutex);
- RB_OBJ_WRITE(monitor, &mc->owner, rb_fiber_current());
- mc->count = 0;
- }
- mc->count++;
+ struct monitor_args args;
+ monitor_args_init(&args, monitor);
+ monitor_enter0(&args);
return Qnil;
}
-static VALUE
-monitor_check_owner(VALUE monitor)
+static inline void
+monitor_check_owner0(struct monitor_args *args)
{
- struct rb_monitor *mc = monitor_ptr(monitor);
- if (!mc_owner_p(mc)) {
+ if (!mc_owner_p(args->mc, args->current_fiber)) {
rb_raise(rb_eThreadError, "current fiber not owner");
}
- return Qnil;
}
+/* :nodoc: */
static VALUE
-monitor_exit(VALUE monitor)
+monitor_check_owner(VALUE monitor)
{
- monitor_check_owner(monitor);
+ struct monitor_args args;
+ monitor_args_init(&args, monitor);
+ monitor_check_owner0(&args);
+ return Qnil;
+}
- struct rb_monitor *mc = monitor_ptr(monitor);
+static void
+monitor_exit0(struct monitor_args *args)
+{
+ monitor_check_owner0(args);
- if (mc->count <= 0) rb_bug("monitor_exit: count:%d\n", (int)mc->count);
- mc->count--;
+ if (args->mc->count <= 0) rb_bug("monitor_exit: count:%d", (int)args->mc->count);
+ args->mc->count--;
- if (mc->count == 0) {
- RB_OBJ_WRITE(monitor, &mc->owner, Qnil);
- rb_mutex_unlock(mc->mutex);
+ if (args->mc->count == 0) {
+ RB_OBJ_WRITE(args->monitor, &args->mc->owner, Qnil);
+ rb_mutex_unlock(args->mc->mutex);
}
+}
+
+/*
+ * call-seq:
+ * exit -> nil
+ *
+ * Leaves exclusive section.
+ */
+static VALUE
+monitor_exit(VALUE monitor)
+{
+ struct monitor_args args;
+ monitor_args_init(&args, monitor);
+ monitor_exit0(&args);
return Qnil;
}
+/* :nodoc: */
static VALUE
monitor_locked_p(VALUE monitor)
{
@@ -119,11 +182,12 @@ monitor_locked_p(VALUE monitor)
return rb_mutex_locked_p(mc->mutex);
}
+/* :nodoc: */
static VALUE
monitor_owned_p(VALUE monitor)
{
struct rb_monitor *mc = monitor_ptr(monitor);
- return (rb_mutex_locked_p(mc->mutex) && mc_owner_p(mc)) ? Qtrue : Qfalse;
+ return rb_mutex_locked_p(mc->mutex) && mc_owner_p(mc, rb_fiber_current()) ? Qtrue : Qfalse;
}
static VALUE
@@ -166,6 +230,7 @@ monitor_enter_for_cond(VALUE v)
return Qnil;
}
+/* :nodoc: */
static VALUE
monitor_wait_for_cond(VALUE monitor, VALUE cond, VALUE timeout)
{
@@ -188,16 +253,27 @@ monitor_sync_body(VALUE monitor)
}
static VALUE
-monitor_sync_ensure(VALUE monitor)
+monitor_sync_ensure(VALUE v_args)
{
- return monitor_exit(monitor);
+ monitor_exit0((struct monitor_args *)v_args);
+ return Qnil;
}
+/*
+ * call-seq:
+ * synchronize { } -> result of the block
+ *
+ * Enters exclusive section and executes the block. Leaves the exclusive
+ * section automatically when the block exits. See example under
+ * +MonitorMixin+.
+ */
static VALUE
monitor_synchronize(VALUE monitor)
{
- monitor_enter(monitor);
- return rb_ensure(monitor_sync_body, monitor, monitor_sync_ensure, monitor);
+ struct monitor_args args;
+ monitor_args_init(&args, monitor);
+ monitor_enter0(&args);
+ return rb_ensure(monitor_sync_body, (VALUE)&args, monitor_sync_ensure, (VALUE)&args);
}
void