Bug #4266 » monitor-synchronize-use-c-implementation.patch
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
|
- « Previous
- 1
- 2
- 3
- 4
- Next »