Project

General

Profile

Bug #4266 » monitor-synchronize-use-c-implementation.patch

Fix for MonitorMixin/monitor synchronize using similar approach as mutex synchronize patch - briangug (Brian Gugliemetti), 05/05/2011 09:01 AM

View differences:

ext/monitor/extconf.rb
require 'mkmf'
target = "monitor_mixin"
create_makefile(target)
ext/monitor/monitor_mixin.c
/**********************************************************************
monitor_mixin.c -
$Author: Brian Gugliemetti $
created at: Wed Apr 27 14:51:06 CST 2011
All the files in this distribution are covered under the Ruby's
license (see the file COPYING).
**********************************************************************/
#include "ruby.h"
static VALUE rb_mon_enter _((VALUE monitor));
static VALUE rb_mon_exit _((VALUE monitor));
static VALUE rb_mon_check_owner _((VALUE monitor));
static VALUE rb_mon_synchronize _((VALUE monitor, VALUE (*func)(VALUE arg), VALUE arg));
void Init_monitor_mixin _((void));
VALUE rb_mMonitorMixin;
/*
* MonitorMixin methods
*/
VALUE
rb_mon_check_owner(VALUE monitor)
{
VALUE mon_owner = rb_ivar_get(monitor, rb_intern("@mon_owner"));
VALUE th = rb_thread_current();
if (mon_owner != th)
{
rb_raise(rb_eThreadError, "current thread not owner");
}
}
/*
* call-seq:
* monitor_mixin.mon_enter -> int
*
* Returns number of times the monitor has entered.
*/
VALUE
rb_mon_enter(VALUE monitor)
{
VALUE mon_owner = rb_ivar_get(monitor, rb_intern("@mon_owner"));
VALUE mon_mutex = rb_ivar_get(monitor, rb_intern("@mon_mutex"));
VALUE mon_count;
ID mon_count_id;
VALUE th = rb_thread_current();
if (mon_owner != th)
{
rb_mutex_lock(mon_mutex);
rb_ivar_set(monitor, rb_intern("@mon_owner"), th);
}
mon_count = rb_ivar_get(monitor, mon_count_id = rb_intern("@mon_count"));
rb_ivar_set(monitor, mon_count_id, mon_count = INT2NUM(NUM2INT(mon_count) + 1));
return mon_count;
}
VALUE
rb_mon_exit_no_check(VALUE monitor)
{
VALUE mon_count;
VALUE mon_mutex;
ID mon_count_id;
mon_count = rb_ivar_get(monitor, mon_count_id = rb_intern("@mon_count"));
rb_ivar_set(monitor, mon_count_id, mon_count = INT2NUM(NUM2INT(mon_count) - 1));
if(mon_count == INT2NUM(0))
{
rb_ivar_set(monitor, rb_intern("@mon_owner"), Qnil);
mon_mutex = rb_ivar_get(monitor, rb_intern("@mon_mutex"));
rb_mutex_unlock(mon_mutex);
}
return mon_count;
}
VALUE
rb_mon_exit(VALUE monitor)
{
rb_mon_check_owner(monitor);
return rb_mon_exit_no_check(monitor);
}
VALUE
mon_synchronize(VALUE monitor, VALUE (*func)(VALUE arg), VALUE arg)
{
rb_mon_enter(monitor);
return rb_ensure(func, arg, rb_mon_exit_no_check, monitor);
}
VALUE
rb_mon_synchronize(VALUE monitor)
{
return mon_synchronize(monitor, rb_yield, Qnil);
}
void
Init_monitor_mixin()
{
rb_mMonitorMixin = rb_define_module("MonitorMixin");
rb_define_method(rb_mMonitorMixin, "mon_check_owner", rb_mon_check_owner, 0);
rb_define_method(rb_mMonitorMixin, "mon_enter", rb_mon_enter, 0);
rb_define_method(rb_mMonitorMixin, "mon_exit", rb_mon_exit, 0);
rb_define_method(rb_mMonitorMixin, "mon_synchronize", rb_mon_synchronize, 0);
}
lib/monitor.rb
=end
require 'thread'
require 'monitor_mixin.so'
#
# Adds monitor functionality to an arbitrary object by mixing the module with
......
# For backward compatibility
alias try_mon_enter mon_try_enter
#
# Enters exclusive section.
#
def mon_enter
if @mon_owner != Thread.current
@mon_mutex.lock
@mon_owner = Thread.current
end
@mon_count += 1
end
#
# Leaves exclusive section.
#
def mon_exit
mon_check_owner
@mon_count -=1
if @mon_count == 0
@mon_owner = nil
@mon_mutex.unlock
end
end
#
# Enters exclusive section and executes the block. Leaves the exclusive
# section automatically when the block exits. See example under
# +MonitorMixin+.
#
def mon_synchronize
mon_enter
begin
yield
ensure
mon_exit
end
end
alias synchronize mon_synchronize
#
......
@mon_mutex = Mutex.new
end
def mon_check_owner
if @mon_owner != Thread.current
raise ThreadError, "current thread not owner"
end
end
def mon_enter_for_cond(count)
@mon_owner = Thread.current
@mon_count = count
(4-4/4)