diff options
Diffstat (limited to 'ext/monitor')
| -rw-r--r-- | ext/monitor/depend | 5 | ||||
| -rw-r--r-- | ext/monitor/lib/monitor.rb | 10 | ||||
| -rw-r--r-- | ext/monitor/monitor.c | 156 |
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 |
