monitor-synchronize-use-c-implementation.patch

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

Download (4.6 KB)

View differences:

ext/monitor/extconf.rb
1
require 'mkmf'
2
target = "monitor_mixin"
3

  
4
create_makefile(target)
ext/monitor/monitor_mixin.c
1
/**********************************************************************
2

  
3
  monitor_mixin.c -
4

  
5
  $Author: Brian Gugliemetti $
6
  created at: Wed Apr 27 14:51:06 CST 2011
7

  
8
  All the files in this distribution are covered under the Ruby's
9
  license (see the file COPYING).
10

  
11
**********************************************************************/
12

  
13
#include "ruby.h"
14

  
15
static VALUE rb_mon_enter _((VALUE monitor));
16
static VALUE rb_mon_exit _((VALUE monitor));
17
static VALUE rb_mon_check_owner _((VALUE monitor));
18
static VALUE rb_mon_synchronize _((VALUE monitor, VALUE (*func)(VALUE arg), VALUE arg));
19
void Init_monitor_mixin _((void));
20

  
21
VALUE rb_mMonitorMixin;
22

  
23
/*
24
 * MonitorMixin methods
25
 */
26

  
27
VALUE
28
rb_mon_check_owner(VALUE monitor)
29
{
30
	VALUE mon_owner = rb_ivar_get(monitor, rb_intern("@mon_owner"));
31
	VALUE th = rb_thread_current();
32
	if (mon_owner != th)
33
	{
34
		rb_raise(rb_eThreadError, "current thread not owner");
35
	}
36
}
37

  
38
/*
39
 * call-seq:
40
 *   monitor_mixin.mon_enter -> int
41
 *
42
 * Returns number of times the monitor has entered.
43
 */
44

  
45
VALUE
46
rb_mon_enter(VALUE monitor)
47
{
48
	VALUE mon_owner = rb_ivar_get(monitor, rb_intern("@mon_owner"));
49
	VALUE mon_mutex = rb_ivar_get(monitor, rb_intern("@mon_mutex"));
50
	VALUE mon_count;
51
	ID mon_count_id;
52

  
53
	VALUE th = rb_thread_current();
54

  
55
	if (mon_owner != th)
56
	{
57
		rb_mutex_lock(mon_mutex);
58
		rb_ivar_set(monitor, rb_intern("@mon_owner"), th);
59
	}
60
	mon_count = rb_ivar_get(monitor, mon_count_id = rb_intern("@mon_count"));
61
	rb_ivar_set(monitor, mon_count_id, mon_count = INT2NUM(NUM2INT(mon_count) + 1));
62
	return mon_count;
63
}
64

  
65
VALUE
66
rb_mon_exit_no_check(VALUE monitor)
67
{
68
	VALUE mon_count;
69
	VALUE mon_mutex;
70
	ID mon_count_id;
71

  
72
	mon_count = rb_ivar_get(monitor, mon_count_id = rb_intern("@mon_count"));
73
	rb_ivar_set(monitor, mon_count_id, mon_count = INT2NUM(NUM2INT(mon_count) - 1));
74
	if(mon_count == INT2NUM(0))
75
	{
76
		rb_ivar_set(monitor, rb_intern("@mon_owner"), Qnil);
77
		mon_mutex = rb_ivar_get(monitor, rb_intern("@mon_mutex"));
78
		rb_mutex_unlock(mon_mutex);
79
	}
80
	return mon_count;
81
}
82

  
83
VALUE
84
rb_mon_exit(VALUE monitor)
85
{
86
	rb_mon_check_owner(monitor);
87
	return rb_mon_exit_no_check(monitor);
88
}
89

  
90
VALUE
91
mon_synchronize(VALUE monitor, VALUE (*func)(VALUE arg), VALUE arg)
92
{
93
    rb_mon_enter(monitor);
94
    return rb_ensure(func, arg, rb_mon_exit_no_check, monitor);
95
}
96

  
97
VALUE
98
rb_mon_synchronize(VALUE monitor)
99
{
100
	return mon_synchronize(monitor, rb_yield, Qnil);
101
}
102

  
103
void
104
Init_monitor_mixin()
105
{
106
	rb_mMonitorMixin = rb_define_module("MonitorMixin");
107
    rb_define_method(rb_mMonitorMixin, "mon_check_owner", rb_mon_check_owner, 0);
108
    rb_define_method(rb_mMonitorMixin, "mon_enter", rb_mon_enter, 0);
109
    rb_define_method(rb_mMonitorMixin, "mon_exit", rb_mon_exit, 0);
110
    rb_define_method(rb_mMonitorMixin, "mon_synchronize", rb_mon_synchronize, 0);
111
}
lib/monitor.rb
43 43
=end
44 44

  
45 45
require 'thread'
46
require 'monitor_mixin.so'
46 47

  
47 48
#
48 49
# Adds monitor functionality to an arbitrary object by mixing the module with
......
167 168
  # For backward compatibility
168 169
  alias try_mon_enter mon_try_enter
169 170

  
170
  #
171
  # Enters exclusive section.
172
  #
173
  def mon_enter
174
    if @mon_owner != Thread.current
175
      @mon_mutex.lock
176
      @mon_owner = Thread.current
177
    end
178
    @mon_count += 1
179
  end
180

  
181
  #
182
  # Leaves exclusive section.
183
  #
184
  def mon_exit
185
    mon_check_owner
186
    @mon_count -=1
187
    if @mon_count == 0
188
      @mon_owner = nil
189
      @mon_mutex.unlock
190
    end
191
  end
192

  
193
  #
194
  # Enters exclusive section and executes the block.  Leaves the exclusive
195
  # section automatically when the block exits.  See example under
196
  # +MonitorMixin+.
197
  #
198
  def mon_synchronize
199
    mon_enter
200
    begin
201
      yield
202
    ensure
203
      mon_exit
204
    end
205
  end
206 171
  alias synchronize mon_synchronize
207 172

  
208 173
  #
......
226 191
    @mon_mutex = Mutex.new
227 192
  end
228 193

  
229
  def mon_check_owner
230
    if @mon_owner != Thread.current
231
      raise ThreadError, "current thread not owner"
232
    end
233
  end
234

  
235 194
  def mon_enter_for_cond(count)
236 195
    @mon_owner = Thread.current
237 196
    @mon_count = count