xthread 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (C) 2010 Keiju Ishitsuka. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
data/cond.c ADDED
@@ -0,0 +1,152 @@
1
+ /************************************************
2
+
3
+ cond.c -
4
+
5
+ Copyright (C) 2011 Keiju Ishitsuka
6
+ Copyright (C) 2011 Penta Advanced Laboratories, Inc.
7
+
8
+ ************************************************/
9
+
10
+ #include "ruby.h"
11
+
12
+ #include "xthread.h"
13
+
14
+ VALUE rb_cXThreadConditionVariable;
15
+
16
+ typedef struct rb_xthread_cond_struct
17
+ {
18
+ VALUE waiters;
19
+ /* VALUE waiters_mutex; */
20
+ } xthread_cond_t;
21
+
22
+ #define GetXThreadCondPtr(obj, tobj) \
23
+ TypedData_Get_Struct((obj), xthread_cond_t, &xthread_cond_data_type, (tobj))
24
+
25
+ static void
26
+ xthread_cond_mark(void *ptr)
27
+ {
28
+ xthread_cond_t *cv = (xthread_cond_t*)ptr;
29
+
30
+ rb_gc_mark(cv->waiters);
31
+ /* rb_gc_mark(cv->waiters_mutex); */
32
+ }
33
+
34
+ static void
35
+ xthread_cond_free(void *ptr)
36
+ {
37
+ ruby_xfree(ptr);
38
+ }
39
+
40
+ static size_t
41
+ xthread_cond_memsize(const void *ptr)
42
+ {
43
+ return ptr ? sizeof(xthread_cond_t) : 0;
44
+ }
45
+
46
+ static const rb_data_type_t xthread_cond_data_type = {
47
+ "xthread_cond",
48
+ {xthread_cond_mark, xthread_cond_free, xthread_cond_memsize,},
49
+ };
50
+
51
+ static VALUE
52
+ xthread_cond_alloc(VALUE klass)
53
+ {
54
+ VALUE volatile obj;
55
+ xthread_cond_t *cv;
56
+
57
+ obj = TypedData_Make_Struct(klass, xthread_cond_t,
58
+ &xthread_cond_data_type, cv);
59
+ cv->waiters = rb_xthread_fifo_new();
60
+ /* cv->waiters_mutex = rb_mutex_new(); */
61
+ return obj;
62
+ }
63
+
64
+ /*
65
+ * call-seq:
66
+ * ConditionVariable.new -> condition_variable
67
+ *
68
+ * Creates a new ConditionVariable
69
+ */
70
+ static VALUE
71
+ xthread_cond_initialize(VALUE self)
72
+ {
73
+ return self;
74
+ }
75
+
76
+ VALUE
77
+ rb_xthread_cond_new(void)
78
+ {
79
+ return xthread_cond_alloc(rb_cXThreadConditionVariable);
80
+ }
81
+
82
+ VALUE
83
+ rb_xthread_cond_wait(VALUE self, VALUE mutex, VALUE timeout)
84
+ {
85
+ xthread_cond_t *cv;
86
+ VALUE th = rb_thread_current();
87
+
88
+ GetXThreadCondPtr(self, cv);
89
+
90
+ /* rb_mutex_lock(cv->waiters_mutex); */
91
+ rb_xthread_fifo_push(cv->waiters, th);
92
+ /* rb_mutex_unlock(cv->waiters_mutex); */
93
+
94
+ rb_mutex_sleep(mutex, timeout);
95
+
96
+ return self;
97
+ }
98
+
99
+ static VALUE
100
+ xthread_cond_wait(int argc, VALUE *argv, VALUE self)
101
+ {
102
+ VALUE mutex;
103
+ VALUE timeout;
104
+
105
+ rb_scan_args(argc, argv, "11", &mutex, &timeout);
106
+ return rb_xthread_cond_wait(self, mutex, timeout);
107
+ }
108
+
109
+ VALUE
110
+ rb_xthread_cond_signal(VALUE self)
111
+ {
112
+ VALUE th;
113
+ xthread_cond_t *cv;
114
+ GetXThreadCondPtr(self, cv);
115
+
116
+ /* rb_mutex_lock(cv->waiters_mutex); */
117
+ th = rb_xthread_fifo_pop(cv->waiters);
118
+ /* rb_mutex_unlock(cv->waiters_mutex); */
119
+ if (th != Qnil) {
120
+ rb_thread_wakeup(th);
121
+ }
122
+
123
+ return self;
124
+ }
125
+
126
+ VALUE
127
+ rb_xthread_cond_broadcast(VALUE self)
128
+ {
129
+ xthread_cond_t *cv;
130
+ VALUE waiters0;
131
+ VALUE th;
132
+
133
+ GetXThreadCondPtr(self, cv);
134
+
135
+ while ((th = rb_xthread_fifo_pop(cv->waiters)) != Qnil) {
136
+ rb_thread_wakeup(th);
137
+ }
138
+
139
+ return self;
140
+ }
141
+
142
+ void
143
+ Init_XThreadCond(void)
144
+ {
145
+ rb_cXThreadConditionVariable =
146
+ rb_define_class_under(rb_mXThread, "ConditionVariable", rb_cObject);
147
+ rb_define_alloc_func(rb_cXThreadConditionVariable, xthread_cond_alloc);
148
+ rb_define_method(rb_cXThreadConditionVariable, "initialize", xthread_cond_initialize, 0);
149
+ rb_define_method(rb_cXThreadConditionVariable, "wait", xthread_cond_wait, -1);
150
+ rb_define_method(rb_cXThreadConditionVariable, "signal", rb_xthread_cond_signal, 0);
151
+ rb_define_method(rb_cXThreadConditionVariable, "broadcast", rb_xthread_cond_broadcast, 0);
152
+ }
data/extconf.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'mkmf'
2
+
3
+ create_makefile("xthread")
4
+
data/fifo.c ADDED
@@ -0,0 +1,269 @@
1
+ /**********************************************************************
2
+
3
+ fifo.c -
4
+
5
+ Copyright (C) 2011 Keiju Ishitsuka
6
+ Copyright (C) 2011 Penta Advanced Laboratories, Inc.
7
+
8
+ **********************************************************************/
9
+
10
+ #include "ruby.h"
11
+
12
+ #include "xthread.h"
13
+
14
+ #define FIFO_DEFAULT_CAPA 16
15
+
16
+ VALUE rb_mXThread;
17
+ VALUE rb_cXThreadFifo;
18
+
19
+ typedef struct rb_xthread_fifo_struct
20
+ {
21
+ long push;
22
+ long pop;
23
+ long capa;
24
+
25
+ VALUE *elements;
26
+ } xthread_fifo_t;
27
+
28
+ #define GetXThreadFifoPtr(obj, tobj) \
29
+ TypedData_Get_Struct((obj), xthread_fifo_t, &xthread_fifo_data_type, (tobj))
30
+
31
+ static void
32
+ xthread_fifo_mark(void *ptr)
33
+ {
34
+ xthread_fifo_t *fifo = (xthread_fifo_t*)ptr;
35
+
36
+ if (fifo->push < fifo->capa) {
37
+ long i;
38
+ for (i = fifo->pop; i < fifo->push; i++) {
39
+ rb_gc_mark(fifo->elements[i]);
40
+ }
41
+ }
42
+ else {
43
+ long i;
44
+ for (i = 0; i < fifo->push - fifo->capa; i++) {
45
+ rb_gc_mark(fifo->elements[i]);
46
+ }
47
+
48
+ for (i = fifo->pop; i < fifo->capa; i++) {
49
+ rb_gc_mark(fifo->elements[i]);
50
+ }
51
+ }
52
+ }
53
+
54
+ static void
55
+ xthread_fifo_free(void *ptr)
56
+ {
57
+ xthread_fifo_t *fifo = (xthread_fifo_t*)ptr;
58
+
59
+ ruby_xfree(fifo->elements);
60
+ ruby_xfree(ptr);
61
+ }
62
+
63
+ static size_t
64
+ xthread_fifo_memsize(const void *ptr)
65
+ {
66
+ xthread_fifo_t *fifo = (xthread_fifo_t*)ptr;
67
+
68
+ return ptr ? sizeof(xthread_fifo_t) + fifo->capa * sizeof(VALUE): 0;
69
+ }
70
+
71
+ static const rb_data_type_t xthread_fifo_data_type = {
72
+ "xthread_fifo",
73
+ {xthread_fifo_mark, xthread_fifo_free, xthread_fifo_memsize,},
74
+ };
75
+
76
+ static VALUE
77
+ xthread_fifo_alloc(VALUE klass)
78
+ {
79
+ VALUE volatile obj;
80
+ xthread_fifo_t *fifo;
81
+
82
+ obj = TypedData_Make_Struct(klass, xthread_fifo_t, &xthread_fifo_data_type, fifo);
83
+
84
+ fifo->push = 0;
85
+ fifo->pop = 0;
86
+
87
+ fifo->capa = FIFO_DEFAULT_CAPA;
88
+ fifo->elements = NULL;
89
+
90
+ return obj;
91
+ }
92
+
93
+ static void
94
+ xthread_fifo_resize_double_capa(xthread_fifo_t *fifo)
95
+ {
96
+ long new_capa = fifo->capa * 2;
97
+
98
+ REALLOC_N(fifo->elements, VALUE, new_capa);
99
+
100
+ if (fifo->push > fifo->capa) {
101
+ if (fifo->capa - fifo->pop <= fifo->push - fifo->capa) {
102
+ MEMCPY(&fifo->elements[fifo->pop + fifo->capa],
103
+ &fifo->elements[fifo->pop], VALUE, fifo->capa - fifo->pop);
104
+ fifo->pop += fifo->capa;
105
+ fifo->push += fifo->capa;
106
+ }
107
+ else {
108
+ MEMCPY(&fifo->elements[fifo->capa],
109
+ fifo->elements, VALUE, fifo->push - fifo->capa);
110
+ }
111
+ }
112
+ fifo->capa = new_capa;
113
+ }
114
+
115
+ static VALUE
116
+ xthread_fifo_initialize(VALUE self)
117
+ {
118
+ xthread_fifo_t *fifo;
119
+ GetXThreadFifoPtr(self, fifo);
120
+
121
+ fifo->elements = ALLOC_N(VALUE, fifo->capa);
122
+ return self;
123
+ }
124
+
125
+ VALUE
126
+ rb_xthread_fifo_new(void)
127
+ {
128
+ VALUE self;
129
+ self = xthread_fifo_alloc(rb_cXThreadFifo);
130
+ xthread_fifo_initialize(self);
131
+ return self;
132
+ }
133
+
134
+ VALUE
135
+ rb_xthread_fifo_push(VALUE self, VALUE item)
136
+ {
137
+ xthread_fifo_t *fifo;
138
+ int signal_p = 0;
139
+
140
+ GetXThreadFifoPtr(self, fifo);
141
+
142
+ if (fifo->push < fifo->capa) {
143
+ fifo->elements[fifo->push++] = item;
144
+ return self;
145
+ }
146
+
147
+ if (fifo->push - fifo->capa < fifo->pop) {
148
+ fifo->elements[fifo->push - fifo->capa] = item;
149
+ fifo->push++;
150
+ return self;
151
+ }
152
+
153
+ xthread_fifo_resize_double_capa(fifo);
154
+ return rb_xthread_fifo_push(self, item);
155
+ }
156
+
157
+ VALUE
158
+ rb_xthread_fifo_pop(VALUE self)
159
+ {
160
+ xthread_fifo_t *fifo;
161
+ VALUE item;
162
+
163
+ GetXThreadFifoPtr(self, fifo);
164
+
165
+ if (fifo->push == fifo->pop)
166
+ return Qnil;
167
+
168
+ item = fifo->elements[fifo->pop++];
169
+ if(fifo->pop >= fifo->capa) {
170
+ fifo->pop -= fifo->capa;
171
+ fifo->push -= fifo->capa;
172
+ }
173
+ return item;
174
+ }
175
+
176
+ VALUE
177
+ rb_xthread_fifo_empty_p(VALUE self)
178
+ {
179
+ xthread_fifo_t *fifo;
180
+ GetXThreadFifoPtr(self, fifo);
181
+
182
+ if (fifo->push == fifo->pop)
183
+ return Qtrue;
184
+ return Qfalse;
185
+ }
186
+
187
+ VALUE
188
+ rb_xthread_fifo_clear(VALUE self)
189
+ {
190
+ xthread_fifo_t *fifo;
191
+ GetXThreadFifoPtr(self, fifo);
192
+
193
+ fifo->push = 0;
194
+ fifo->pop = 0;
195
+ return self;
196
+ }
197
+
198
+ VALUE
199
+ rb_xthread_fifo_length(VALUE self)
200
+ {
201
+ xthread_fifo_t *fifo;
202
+ GetXThreadFifoPtr(self, fifo);
203
+
204
+ return LONG2NUM(fifo->push - fifo->pop);
205
+ }
206
+
207
+ VALUE
208
+ rb_xthread_fifo_to_a(VALUE self)
209
+ {
210
+ VALUE ary;
211
+ xthread_fifo_t *fifo;
212
+ GetXThreadFifoPtr(self, fifo);
213
+
214
+ ary = rb_ary_new2(fifo->push - fifo->pop);
215
+
216
+ if (fifo->push < fifo->capa) {
217
+ long i;
218
+ for (i = fifo->pop; i < fifo->push; i++) {
219
+ rb_ary_push(ary, fifo->elements[i]);
220
+ }
221
+ }
222
+ else {
223
+ long i;
224
+ for (i = 0; i < fifo->push - fifo->capa; i++) {
225
+ rb_ary_push(ary, fifo->elements[i]);
226
+ }
227
+
228
+ for (i = fifo->pop; i < fifo->capa; i++) {
229
+ rb_ary_push(ary, fifo->elements[i]);
230
+ }
231
+ }
232
+ return ary;
233
+ }
234
+
235
+ VALUE
236
+ rb_xthread_fifo_inspect(VALUE self)
237
+ {
238
+ xthread_fifo_t *fifo;
239
+ VALUE str;
240
+
241
+ GetXThreadFifoPtr(self, fifo);
242
+
243
+ str = rb_sprintf("<%s ", rb_obj_classname(self), (void*)self);
244
+ rb_str_append(str, rb_inspect(rb_xthread_fifo_to_a(self)));
245
+ rb_str_cat2(str, ">");
246
+ return str;
247
+ }
248
+
249
+ void
250
+ Init_XThreadFifo()
251
+ {
252
+ rb_cXThreadFifo = rb_define_class_under(rb_mXThread, "Fifo", rb_cObject);
253
+
254
+ rb_define_alloc_func(rb_cXThreadFifo, xthread_fifo_alloc);
255
+ rb_define_method(rb_cXThreadFifo, "initialize", xthread_fifo_initialize, 0);
256
+ rb_define_method(rb_cXThreadFifo, "pop", rb_xthread_fifo_pop, 0);
257
+ rb_define_alias(rb_cXThreadFifo, "shift", "pop");
258
+ rb_define_alias(rb_cXThreadFifo, "deq", "pop");
259
+ rb_define_method(rb_cXThreadFifo, "push", rb_xthread_fifo_push, 1);
260
+ rb_define_alias(rb_cXThreadFifo, "<<", "push");
261
+ rb_define_alias(rb_cXThreadFifo, "enq", "push");
262
+ rb_define_method(rb_cXThreadFifo, "empty?", rb_xthread_fifo_empty_p, 0);
263
+ rb_define_method(rb_cXThreadFifo, "clear", rb_xthread_fifo_clear, 0);
264
+ rb_define_method(rb_cXThreadFifo, "length", rb_xthread_fifo_length, 0);
265
+ rb_define_alias(rb_cXThreadFifo, "size", "length");
266
+ rb_define_method(rb_cXThreadFifo, "to_a", rb_xthread_fifo_to_a, 0);
267
+ rb_define_method(rb_cXThreadFifo, "inspect", rb_xthread_fifo_inspect, 0);
268
+
269
+ }
@@ -0,0 +1,282 @@
1
+ =begin
2
+
3
+ = xthread/monitor.rb
4
+
5
+ This Monitor is using XThread::ConditionVariable.
6
+
7
+ Original by monitor.rb
8
+ Copyright (C) 2001 Shugo Maeda <shugo@ruby-lang.org>
9
+
10
+ This library is distributed under the terms of the Ruby license.
11
+ You can freely distribute/modify this library.
12
+
13
+ == example
14
+
15
+ This is a simple example.
16
+
17
+ require 'monitor.rb'
18
+
19
+ buf = []
20
+ buf.extend(MonitorMixin)
21
+ empty_cond = buf.new_cond
22
+
23
+ # consumer
24
+ Thread.start do
25
+ loop do
26
+ buf.synchronize do
27
+ empty_cond.wait_while { buf.empty? }
28
+ print buf.shift
29
+ end
30
+ end
31
+ end
32
+
33
+ # producer
34
+ while line = ARGF.gets
35
+ buf.synchronize do
36
+ buf.push(line)
37
+ empty_cond.signal
38
+ end
39
+ end
40
+
41
+ The consumer thread waits for the producer thread to push a line
42
+ to buf while buf.empty?, and the producer thread (main thread)
43
+ reads a line from ARGF and push it to buf, then call
44
+ empty_cond.signal.
45
+
46
+ =end
47
+
48
+ require 'xthread'
49
+
50
+ #
51
+ # Adds monitor functionality to an arbitrary object by mixing the module with
52
+ # +include+. For example:
53
+ #
54
+ # require 'monitor'
55
+ #
56
+ # buf = []
57
+ # buf.extend(MonitorMixin)
58
+ # empty_cond = buf.new_cond
59
+ #
60
+ # # consumer
61
+ # Thread.start do
62
+ # loop do
63
+ # buf.synchronize do
64
+ # empty_cond.wait_while { buf.empty? }
65
+ # print buf.shift
66
+ # end
67
+ # end
68
+ # end
69
+ #
70
+ # # producer
71
+ # while line = ARGF.gets
72
+ # buf.synchronize do
73
+ # buf.push(line)
74
+ # empty_cond.signal
75
+ # end
76
+ # end
77
+ #
78
+ # The consumer thread waits for the producer thread to push a line
79
+ # to buf while buf.empty?, and the producer thread (main thread)
80
+ # reads a line from ARGF and push it to buf, then call
81
+ # empty_cond.signal.
82
+ #
83
+ module XThread
84
+ module RBMonitorMixin
85
+ #
86
+ # FIXME: This isn't documented in Nutshell.
87
+ #
88
+ # Since MonitorMixin.new_cond returns a ConditionVariable, and the example
89
+ # above calls while_wait and signal, this class should be documented.
90
+ #
91
+ class RBConditionVariable
92
+ class Timeout < Exception; end
93
+
94
+ #
95
+ # Releases the lock held in the associated monitor and waits; reacquires the lock on wakeup.
96
+ #
97
+ # If +timeout+ is given, this method returns after +timeout+ seconds passed,
98
+ # even if no other thread doesn't signal.
99
+ #
100
+ def wait(timeout = nil)
101
+ @monitor.__send__(:mon_check_owner)
102
+ count = @monitor.__send__(:mon_exit_for_cond)
103
+ begin
104
+ @cond.wait(@monitor.instance_variable_get("@mon_mutex"), timeout)
105
+ return true
106
+ ensure
107
+ @monitor.__send__(:mon_enter_for_cond, count)
108
+ end
109
+ end
110
+
111
+ #
112
+ # Calls wait repeatedly while the given block yields a truthy value.
113
+ #
114
+ def wait_while
115
+ while yield
116
+ wait
117
+ end
118
+ end
119
+
120
+ #
121
+ # Calls wait repeatedly until the given block yields a truthy value.
122
+ #
123
+ def wait_until
124
+ until yield
125
+ wait
126
+ end
127
+ end
128
+
129
+ #
130
+ # Wakes up the first thread in line waiting for this lock.
131
+ #
132
+ def signal
133
+ @monitor.__send__(:mon_check_owner)
134
+ @cond.signal
135
+ end
136
+
137
+ #
138
+ # Wakes up all threads waiting for this lock.
139
+ #
140
+ def broadcast
141
+ @monitor.__send__(:mon_check_owner)
142
+ @cond.broadcast
143
+ end
144
+
145
+ private
146
+
147
+ def initialize(monitor)
148
+ @monitor = monitor
149
+ @cond = ::XThread::ConditionVariable.new
150
+ end
151
+ end
152
+
153
+ def self.extend_object(obj)
154
+ super(obj)
155
+ obj.__send__(:mon_initialize)
156
+ end
157
+
158
+ #
159
+ # Attempts to enter exclusive section. Returns +false+ if lock fails.
160
+ #
161
+ def mon_try_enter
162
+ if @mon_owner != Thread.current
163
+ unless @mon_mutex.try_lock
164
+ return false
165
+ end
166
+ @mon_owner = Thread.current
167
+ end
168
+ @mon_count += 1
169
+ return true
170
+ end
171
+ # For backward compatibility
172
+ alias try_mon_enter mon_try_enter
173
+
174
+ #
175
+ # Enters exclusive section.
176
+ #
177
+ def mon_enter
178
+ if @mon_owner != Thread.current
179
+ @mon_mutex.lock
180
+ @mon_owner = Thread.current
181
+ end
182
+ @mon_count += 1
183
+ end
184
+
185
+ #
186
+ # Leaves exclusive section.
187
+ #
188
+ def mon_exit
189
+ mon_check_owner
190
+ @mon_count -=1
191
+ if @mon_count == 0
192
+ @mon_owner = nil
193
+ @mon_mutex.unlock
194
+ end
195
+ end
196
+
197
+ #
198
+ # Enters exclusive section and executes the block. Leaves the exclusive
199
+ # section automatically when the block exits. See example under
200
+ # +MonitorMixin+.
201
+ #
202
+ def mon_synchronize
203
+ mon_enter
204
+ begin
205
+ yield
206
+ ensure
207
+ mon_exit
208
+ end
209
+ end
210
+ alias synchronize mon_synchronize
211
+
212
+ #
213
+ # Creates a new MonitorMixin::ConditionVariable associated with the
214
+ # receiver.
215
+ #
216
+ def new_cond
217
+ return RBConditionVariable.new(self)
218
+ end
219
+
220
+ private
221
+
222
+ def initialize(*args)
223
+ super
224
+ mon_initialize
225
+ end
226
+
227
+ def mon_initialize
228
+ @mon_owner = nil
229
+ @mon_count = 0
230
+ @mon_mutex = Mutex.new
231
+ end
232
+
233
+ def mon_check_owner
234
+ if @mon_owner != Thread.current
235
+ raise ThreadError, "current thread not owner"
236
+ end
237
+ end
238
+
239
+ def mon_enter_for_cond(count)
240
+ @mon_owner = Thread.current
241
+ @mon_count = count
242
+ end
243
+
244
+ def mon_exit_for_cond
245
+ count = @mon_count
246
+ @mon_owner = nil
247
+ @mon_count = 0
248
+ return count
249
+ end
250
+ end
251
+
252
+ class RBMonitor
253
+ include RBMonitorMixin
254
+ alias try_enter try_mon_enter
255
+ alias enter mon_enter
256
+ alias exit mon_exit
257
+ end
258
+ end
259
+
260
+
261
+ # Documentation comments:
262
+ # - All documentation comes from Nutshell.
263
+ # - MonitorMixin.new_cond appears in the example, but is not documented in
264
+ # Nutshell.
265
+ # - All the internals (internal modules Accessible and Initializable, class
266
+ # ConditionVariable) appear in RDoc. It might be good to hide them, by
267
+ # making them private, or marking them :nodoc:, etc.
268
+ # - The entire example from the RD section at the top is replicated in the RDoc
269
+ # comment for MonitorMixin. Does the RD section need to remain?
270
+ # - RDoc doesn't recognise aliases, so we have mon_synchronize documented, but
271
+ # not synchronize.
272
+ # - mon_owner is in Nutshell, but appears as an accessor in a separate module
273
+ # here, so is hard/impossible to RDoc. Some other useful accessors
274
+ # (mon_count and some queue stuff) are also in this module, and don't appear
275
+ # directly in the RDoc output.
276
+ # - in short, it may be worth changing the code layout in this file to make the
277
+ # documentation easier
278
+
279
+ # Local variables:
280
+ # mode: Ruby
281
+ # tab-width: 8
282
+ # End: