xthread 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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: