fiber-mon 0.1.0 → 0.2.0
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/extconf.rb +3 -0
- data/fiber_mon.c +674 -0
- data/fiber_mon.h +32 -0
- data/lib/fiber-mon.rb +257 -0
- data/xthread.h +65 -0
- metadata +28 -9
- data/fiber-mon.rb +0 -252
data/extconf.rb
ADDED
data/fiber_mon.c
ADDED
@@ -0,0 +1,674 @@
|
|
1
|
+
/**********************************************************************
|
2
|
+
|
3
|
+
fiber-mon.c -
|
4
|
+
Copyright (C) 2010-2011 Keiju ISHITSUKA
|
5
|
+
(Penta Advanced Labrabries, Co.,Ltd)
|
6
|
+
|
7
|
+
**********************************************************************/
|
8
|
+
|
9
|
+
#include "ruby.h"
|
10
|
+
|
11
|
+
#include "xthread.h"
|
12
|
+
#include "fiber_mon.h"
|
13
|
+
|
14
|
+
VALUE rb_cFiberMon;
|
15
|
+
VALUE rb_cFiberMonMonitor;
|
16
|
+
VALUE rb_cFiberMonConditionVariable;
|
17
|
+
|
18
|
+
typedef struct rb_fibermon_struct
|
19
|
+
{
|
20
|
+
long started;
|
21
|
+
VALUE current_fib;
|
22
|
+
VALUE entries;
|
23
|
+
|
24
|
+
VALUE obsolate_mon;
|
25
|
+
} fibermon_t;
|
26
|
+
|
27
|
+
#define GetFiberMonPtr(obj, tobj) \
|
28
|
+
TypedData_Get_Struct((obj), fibermon_t, &fibermon_data_type, (tobj))
|
29
|
+
|
30
|
+
static void
|
31
|
+
fibermon_mark(void *ptr)
|
32
|
+
{
|
33
|
+
fibermon_t *mon = (fibermon_t*)ptr;
|
34
|
+
|
35
|
+
rb_gc_mark(mon->current_fib);
|
36
|
+
rb_gc_mark(mon->entries);
|
37
|
+
rb_gc_mark(mon->obsolate_mon);
|
38
|
+
}
|
39
|
+
|
40
|
+
static void
|
41
|
+
fibermon_free(void *ptr)
|
42
|
+
{
|
43
|
+
ruby_xfree(ptr);
|
44
|
+
}
|
45
|
+
|
46
|
+
static size_t
|
47
|
+
fibermon_memsize(const void *ptr)
|
48
|
+
{
|
49
|
+
return ptr ? sizeof(fibermon_t) : 0;
|
50
|
+
}
|
51
|
+
|
52
|
+
static const rb_data_type_t fibermon_data_type = {
|
53
|
+
"fibermon",
|
54
|
+
{fibermon_mark, fibermon_free, fibermon_memsize,},
|
55
|
+
};
|
56
|
+
|
57
|
+
static VALUE
|
58
|
+
fibermon_alloc(VALUE klass)
|
59
|
+
{
|
60
|
+
VALUE volatile obj;
|
61
|
+
fibermon_t *mon;
|
62
|
+
|
63
|
+
obj = TypedData_Make_Struct(klass, fibermon_t, &fibermon_data_type, mon);
|
64
|
+
|
65
|
+
mon->started = 0;
|
66
|
+
mon->current_fib = Qnil;
|
67
|
+
mon->entries = rb_xthread_queue_new();
|
68
|
+
|
69
|
+
mon->obsolate_mon = Qnil;
|
70
|
+
return obj;
|
71
|
+
}
|
72
|
+
|
73
|
+
static VALUE fibermon_start(VALUE);
|
74
|
+
|
75
|
+
static VALUE
|
76
|
+
fibermon_initialize(VALUE self)
|
77
|
+
{
|
78
|
+
fibermon_t *mon;
|
79
|
+
GetFiberMonPtr(self, mon);
|
80
|
+
|
81
|
+
if (!mon->started) {
|
82
|
+
rb_thread_create(fibermon_start, (void *)self);
|
83
|
+
mon->started = 1;
|
84
|
+
}
|
85
|
+
return self;
|
86
|
+
}
|
87
|
+
|
88
|
+
static VALUE
|
89
|
+
fibermon_mon_start(VALUE self)
|
90
|
+
{
|
91
|
+
fibermon_t *mon;
|
92
|
+
GetFiberMonPtr(self, mon);
|
93
|
+
|
94
|
+
rb_warn("This api is old interface. You don't need call this method.");
|
95
|
+
}
|
96
|
+
|
97
|
+
|
98
|
+
VALUE
|
99
|
+
rb_fibermon_new(void)
|
100
|
+
{
|
101
|
+
VALUE mon;
|
102
|
+
mon = fibermon_alloc(rb_cFiberMon);
|
103
|
+
fibermon_initialize(mon);
|
104
|
+
}
|
105
|
+
|
106
|
+
VALUE
|
107
|
+
rb_fibermon_current(VALUE self)
|
108
|
+
{
|
109
|
+
fibermon_t *mon;
|
110
|
+
GetFiberMonPtr(self, mon);
|
111
|
+
|
112
|
+
return mon->current_fib;
|
113
|
+
}
|
114
|
+
|
115
|
+
VALUE rb_fibermon_monitor_new(VALUE);
|
116
|
+
|
117
|
+
static VALUE
|
118
|
+
rb_fibermon_obsolate_mon(VALUE self)
|
119
|
+
{
|
120
|
+
fibermon_t *mon;
|
121
|
+
GetFiberMonPtr(self, mon);
|
122
|
+
|
123
|
+
if (NIL_P(mon->obsolate_mon)) {
|
124
|
+
mon->obsolate_mon = rb_fibermon_monitor_new(self);
|
125
|
+
}
|
126
|
+
return mon->obsolate_mon;
|
127
|
+
}
|
128
|
+
|
129
|
+
/*
|
130
|
+
static VALUE
|
131
|
+
fibermon_start_cond_wait(VALUE self)
|
132
|
+
{
|
133
|
+
fibermon_t *mon;
|
134
|
+
GetFiberMonPtr(self, mon);
|
135
|
+
|
136
|
+
return rb_xthread_cond_wait(mon->wait_resume_cv, mon->wait_resume_mx, Qnil);
|
137
|
+
}
|
138
|
+
*/
|
139
|
+
|
140
|
+
static VALUE
|
141
|
+
fibermon_start_fib_resume(VALUE self)
|
142
|
+
{
|
143
|
+
fibermon_t *mon;
|
144
|
+
|
145
|
+
GetFiberMonPtr(self, mon);
|
146
|
+
rb_fiber_resume(mon->current_fib, 0, NULL);
|
147
|
+
}
|
148
|
+
|
149
|
+
static VALUE
|
150
|
+
fibermon_start_fib_ensure(VALUE self)
|
151
|
+
{
|
152
|
+
fibermon_t *mon;
|
153
|
+
|
154
|
+
GetFiberMonPtr(self, mon);
|
155
|
+
mon->current_fib = Qnil;
|
156
|
+
return Qnil;
|
157
|
+
}
|
158
|
+
|
159
|
+
static VALUE
|
160
|
+
fibermon_start_fiber_creation(VALUE x, VALUE arg)
|
161
|
+
{
|
162
|
+
rb_proc_call(rb_ary_entry(arg, 0), rb_ary_entry(arg, 1));
|
163
|
+
}
|
164
|
+
|
165
|
+
static VALUE
|
166
|
+
fibermon_start(VALUE self)
|
167
|
+
{
|
168
|
+
fibermon_t *mon;
|
169
|
+
VALUE block;
|
170
|
+
|
171
|
+
GetFiberMonPtr(self, mon);
|
172
|
+
|
173
|
+
while(1) {
|
174
|
+
VALUE entry;
|
175
|
+
|
176
|
+
entry = rb_xthread_queue_pop(mon->entries);
|
177
|
+
if (CLASS_OF(entry) == rb_cProc) {
|
178
|
+
VALUE arg = rb_ary_new3(2, entry, rb_ary_new3(1, self));
|
179
|
+
|
180
|
+
mon->current_fib =
|
181
|
+
rb_fiber_new(fibermon_start_fiber_creation, (VALUE)arg);
|
182
|
+
}
|
183
|
+
else {
|
184
|
+
mon->current_fib = entry;
|
185
|
+
}
|
186
|
+
rb_ensure(fibermon_start_fib_resume, (VALUE)self,
|
187
|
+
fibermon_start_fib_ensure, (VALUE)self);
|
188
|
+
}
|
189
|
+
return self;
|
190
|
+
}
|
191
|
+
|
192
|
+
VALUE
|
193
|
+
rb_fibermon_entry_fiber(VALUE self, VALUE fib)
|
194
|
+
{
|
195
|
+
fibermon_t *mon;
|
196
|
+
GetFiberMonPtr(self, mon);
|
197
|
+
|
198
|
+
rb_xthread_queue_push(mon->entries, fib);
|
199
|
+
}
|
200
|
+
|
201
|
+
|
202
|
+
static VALUE
|
203
|
+
fibermon_entry(int argc, VALUE *argv, VALUE self)
|
204
|
+
{
|
205
|
+
VALUE block;
|
206
|
+
VALUE proc;
|
207
|
+
|
208
|
+
rb_scan_args(argc, argv, "01&", &proc, &block);
|
209
|
+
if (NIL_P(proc)) {
|
210
|
+
proc = block;
|
211
|
+
}
|
212
|
+
|
213
|
+
return rb_fibermon_entry_fiber(self, proc);
|
214
|
+
}
|
215
|
+
|
216
|
+
VALUE rb_fibermon_monitor_wait_cond(VALUE);
|
217
|
+
|
218
|
+
static VALUE
|
219
|
+
fibermon_yield_obso(VALUE self)
|
220
|
+
{
|
221
|
+
fibermon_t *mon;
|
222
|
+
GetFiberMonPtr(self, mon);
|
223
|
+
|
224
|
+
if (!rb_fibermon_monitor_valid_owner_p(mon->obsolate_mon)) {
|
225
|
+
return rb_fiber_yield(0, NULL);
|
226
|
+
}
|
227
|
+
else {
|
228
|
+
return rb_fibermon_monitor_wait_cond(mon->obsolate_mon);
|
229
|
+
}
|
230
|
+
}
|
231
|
+
|
232
|
+
VALUE
|
233
|
+
rb_fibermon_yield(VALUE self)
|
234
|
+
{
|
235
|
+
fibermon_t *mon;
|
236
|
+
GetFiberMonPtr(self, mon);
|
237
|
+
|
238
|
+
rb_xthread_queue_push(mon->entries, mon->current_fib);
|
239
|
+
|
240
|
+
if (NIL_P(mon->obsolate_mon)) {
|
241
|
+
return rb_fiber_yield(0, NULL);
|
242
|
+
}
|
243
|
+
else {
|
244
|
+
return fibermon_yield_obso(self);
|
245
|
+
}
|
246
|
+
}
|
247
|
+
|
248
|
+
VALUE
|
249
|
+
rb_fibermon_new_mon(VALUE self)
|
250
|
+
{
|
251
|
+
return rb_fibermon_monitor_new(self);
|
252
|
+
}
|
253
|
+
|
254
|
+
VALUE rb_fibermon_cond_new(VALUE);
|
255
|
+
|
256
|
+
VALUE
|
257
|
+
rb_fibermon_new_cv(VALUE self)
|
258
|
+
{
|
259
|
+
|
260
|
+
rb_warn("This api is old interface. You can use FiberMon#new_mon and FiberMon::Monitor#new_cv.");
|
261
|
+
|
262
|
+
return rb_fibermon_cond_new(rb_fibermon_obsolate_mon(self));
|
263
|
+
}
|
264
|
+
|
265
|
+
VALUE rb_fibermon_monitor_synchronize(VALUE, VALUE (*)(VALUE), VALUE);
|
266
|
+
|
267
|
+
VALUE
|
268
|
+
rb_fibermon_synchronize(VALUE self)
|
269
|
+
{
|
270
|
+
VALUE mon;
|
271
|
+
|
272
|
+
rb_warn("This api is old interface. You can use FiberMon#new_mon and FiberMon::Monitor#synchronize.");
|
273
|
+
|
274
|
+
mon = rb_fibermon_obsolate_mon(self);
|
275
|
+
return rb_fibermon_monitor_synchronize(mon, rb_yield, mon);
|
276
|
+
}
|
277
|
+
|
278
|
+
typedef struct rb_fibermon_monitor_struct
|
279
|
+
{
|
280
|
+
VALUE fibermon;
|
281
|
+
|
282
|
+
VALUE owner;
|
283
|
+
long count;
|
284
|
+
VALUE mutex;
|
285
|
+
} fibermon_monitor_t;
|
286
|
+
|
287
|
+
#define GetFiberMonMonitorPtr(obj, tobj) \
|
288
|
+
TypedData_Get_Struct((obj), fibermon_monitor_t, \
|
289
|
+
&fibermon_monitor_data_type, (tobj))
|
290
|
+
|
291
|
+
#define FIBERMON_MONITOR_CHECK_OWNER(obj) \
|
292
|
+
{ \
|
293
|
+
fibermon_monitor_t *mon; \
|
294
|
+
VALUE th = rb_thread_current(); \
|
295
|
+
GetFiberMonMonitorPtr(obj, mon); \
|
296
|
+
if (mon->owner != th) { \
|
297
|
+
rb_raise(rb_eThreadError, "current thread not owner"); \
|
298
|
+
} \
|
299
|
+
}
|
300
|
+
|
301
|
+
static void
|
302
|
+
fibermon_monitor_mark(void *ptr)
|
303
|
+
{
|
304
|
+
fibermon_monitor_t *mon = (fibermon_monitor_t*)ptr;
|
305
|
+
|
306
|
+
rb_gc_mark(mon->fibermon);
|
307
|
+
rb_gc_mark(mon->owner);
|
308
|
+
rb_gc_mark(mon->mutex);
|
309
|
+
}
|
310
|
+
|
311
|
+
static void
|
312
|
+
fibermon_monitor_free(void *ptr)
|
313
|
+
{
|
314
|
+
ruby_xfree(ptr);
|
315
|
+
}
|
316
|
+
|
317
|
+
static size_t
|
318
|
+
fibermon_monitor_memsize(const void *ptr)
|
319
|
+
{
|
320
|
+
return ptr ? sizeof(fibermon_monitor_t) : 0;
|
321
|
+
}
|
322
|
+
|
323
|
+
static const rb_data_type_t fibermon_monitor_data_type = {
|
324
|
+
"fibermon_monitor",
|
325
|
+
{fibermon_monitor_mark, fibermon_monitor_free, fibermon_monitor_memsize,},
|
326
|
+
};
|
327
|
+
|
328
|
+
static VALUE
|
329
|
+
fibermon_monitor_alloc(VALUE klass)
|
330
|
+
{
|
331
|
+
VALUE volatile obj;
|
332
|
+
fibermon_monitor_t *mon;
|
333
|
+
|
334
|
+
obj = TypedData_Make_Struct(klass, fibermon_monitor_t,
|
335
|
+
&fibermon_monitor_data_type, mon);
|
336
|
+
mon->fibermon = Qnil;
|
337
|
+
mon->owner = Qnil;
|
338
|
+
mon->count = 0;
|
339
|
+
mon->mutex = rb_mutex_new();
|
340
|
+
|
341
|
+
return obj;
|
342
|
+
}
|
343
|
+
|
344
|
+
static VALUE
|
345
|
+
fibermon_monitor_initialize(VALUE self, VALUE fibermon)
|
346
|
+
{
|
347
|
+
fibermon_monitor_t *mon;
|
348
|
+
GetFiberMonMonitorPtr(self, mon);
|
349
|
+
|
350
|
+
mon->fibermon = fibermon;
|
351
|
+
|
352
|
+
return self;
|
353
|
+
}
|
354
|
+
|
355
|
+
VALUE
|
356
|
+
rb_fibermon_monitor_new(VALUE fibermon)
|
357
|
+
{
|
358
|
+
VALUE mon;
|
359
|
+
|
360
|
+
mon = fibermon_monitor_alloc(rb_cFiberMonMonitor);
|
361
|
+
fibermon_monitor_initialize(mon, fibermon);
|
362
|
+
return mon;
|
363
|
+
}
|
364
|
+
|
365
|
+
VALUE
|
366
|
+
rb_fibermon_monitor_valid_owner_p(VALUE self)
|
367
|
+
{
|
368
|
+
fibermon_monitor_t *mon;
|
369
|
+
VALUE th = rb_thread_current();
|
370
|
+
|
371
|
+
GetFiberMonMonitorPtr(self, mon);
|
372
|
+
|
373
|
+
if (mon->owner == th) {
|
374
|
+
return Qtrue;
|
375
|
+
}
|
376
|
+
else {
|
377
|
+
return Qfalse;
|
378
|
+
}
|
379
|
+
}
|
380
|
+
|
381
|
+
VALUE
|
382
|
+
rb_fibermon_monitor_try_enter(VALUE self)
|
383
|
+
{
|
384
|
+
fibermon_monitor_t *mon;
|
385
|
+
VALUE th = rb_thread_current();
|
386
|
+
|
387
|
+
GetFiberMonMonitorPtr(self, mon);
|
388
|
+
|
389
|
+
if (mon->owner != th) {
|
390
|
+
if (rb_mutex_trylock(mon->mutex) == Qfalse) {
|
391
|
+
return Qfalse;
|
392
|
+
}
|
393
|
+
mon->owner = th;
|
394
|
+
}
|
395
|
+
mon->count++;
|
396
|
+
return Qtrue;
|
397
|
+
}
|
398
|
+
|
399
|
+
VALUE
|
400
|
+
rb_fibermon_monitor_enter(VALUE self)
|
401
|
+
{
|
402
|
+
fibermon_monitor_t *mon;
|
403
|
+
VALUE th = rb_thread_current();
|
404
|
+
|
405
|
+
GetFiberMonMonitorPtr(self, mon);
|
406
|
+
if (mon->owner != th) {
|
407
|
+
rb_mutex_lock(mon->mutex);
|
408
|
+
mon->owner = th;
|
409
|
+
}
|
410
|
+
mon->count += 1;
|
411
|
+
}
|
412
|
+
|
413
|
+
VALUE
|
414
|
+
rb_fibermon_monitor_exit(VALUE self)
|
415
|
+
{
|
416
|
+
fibermon_monitor_t *mon;
|
417
|
+
VALUE th = rb_thread_current();
|
418
|
+
|
419
|
+
GetFiberMonMonitorPtr(self, mon);
|
420
|
+
|
421
|
+
FIBERMON_MONITOR_CHECK_OWNER(self);
|
422
|
+
mon->count--;
|
423
|
+
if(mon->count == 0) {
|
424
|
+
mon->owner = Qnil;
|
425
|
+
rb_mutex_unlock(mon->mutex);
|
426
|
+
}
|
427
|
+
}
|
428
|
+
|
429
|
+
VALUE
|
430
|
+
rb_fibermon_monitor_synchronize(VALUE self, VALUE (*func)(VALUE), VALUE arg)
|
431
|
+
{
|
432
|
+
rb_fibermon_monitor_enter(self);
|
433
|
+
return rb_ensure(func, arg, rb_fibermon_monitor_exit, self);
|
434
|
+
}
|
435
|
+
|
436
|
+
static VALUE
|
437
|
+
fibermon_monitor_synchronize(VALUE self)
|
438
|
+
{
|
439
|
+
return rb_fibermon_monitor_synchronize(self, rb_yield, self);
|
440
|
+
}
|
441
|
+
|
442
|
+
VALUE
|
443
|
+
rb_fibermon_monitor_new_cond(VALUE self)
|
444
|
+
{
|
445
|
+
rb_fibermon_cond_new(self);
|
446
|
+
}
|
447
|
+
|
448
|
+
static VALUE
|
449
|
+
rb_fibermon_monitor_entry_fiber(VALUE self, VALUE fiber)
|
450
|
+
{
|
451
|
+
fibermon_monitor_t *mon;
|
452
|
+
GetFiberMonMonitorPtr(self, mon);
|
453
|
+
|
454
|
+
return rb_fibermon_entry_fiber(mon->fibermon, fiber);
|
455
|
+
}
|
456
|
+
|
457
|
+
struct fibermon_monitor_wait_cond_arg {
|
458
|
+
fibermon_monitor_t *mon;
|
459
|
+
long count;
|
460
|
+
};
|
461
|
+
|
462
|
+
static VALUE
|
463
|
+
rb_fibermon_monitor_wait_cond_yield(VALUE dummy)
|
464
|
+
{
|
465
|
+
return rb_fiber_yield(0, NULL);
|
466
|
+
}
|
467
|
+
|
468
|
+
VALUE
|
469
|
+
rb_fibermon_monitor_wait_cond_ensure(struct fibermon_monitor_wait_cond_arg *arg)
|
470
|
+
{
|
471
|
+
fibermon_monitor_t *mon = arg->mon;
|
472
|
+
|
473
|
+
rb_mutex_lock(mon->mutex);
|
474
|
+
mon->owner = rb_thread_current();
|
475
|
+
mon->count = arg->count;
|
476
|
+
}
|
477
|
+
|
478
|
+
VALUE
|
479
|
+
rb_fibermon_monitor_wait_cond(VALUE self)
|
480
|
+
{
|
481
|
+
fibermon_monitor_t *mon;
|
482
|
+
struct fibermon_monitor_wait_cond_arg arg;
|
483
|
+
|
484
|
+
GetFiberMonMonitorPtr(self, mon);
|
485
|
+
arg.count = mon->count;
|
486
|
+
mon->owner = Qnil;
|
487
|
+
mon->count = 0;
|
488
|
+
rb_mutex_unlock(mon->mutex);
|
489
|
+
|
490
|
+
arg.mon = mon;
|
491
|
+
rb_ensure(rb_fibermon_monitor_wait_cond_yield, Qnil,
|
492
|
+
rb_fibermon_monitor_wait_cond_ensure, (VALUE)&arg);
|
493
|
+
}
|
494
|
+
|
495
|
+
typedef struct rb_fibermon_cond_struct
|
496
|
+
{
|
497
|
+
VALUE monitor;
|
498
|
+
VALUE waitings;
|
499
|
+
|
500
|
+
} fibermon_cond_t;
|
501
|
+
|
502
|
+
#define GetFiberMonCondPtr(obj, tobj) \
|
503
|
+
TypedData_Get_Struct((obj), fibermon_cond_t, \
|
504
|
+
&fibermon_cond_data_type, (tobj))
|
505
|
+
|
506
|
+
static void
|
507
|
+
fibermon_cond_mark(void *ptr)
|
508
|
+
{
|
509
|
+
fibermon_cond_t *cv = (fibermon_cond_t*)ptr;
|
510
|
+
|
511
|
+
rb_gc_mark(cv->monitor);
|
512
|
+
rb_gc_mark(cv->waitings);
|
513
|
+
}
|
514
|
+
|
515
|
+
static void
|
516
|
+
fibermon_cond_free(void *ptr)
|
517
|
+
{
|
518
|
+
ruby_xfree(ptr);
|
519
|
+
}
|
520
|
+
|
521
|
+
static size_t
|
522
|
+
fibermon_cond_memsize(const void *ptr)
|
523
|
+
{
|
524
|
+
return ptr ? sizeof(fibermon_cond_t) : 0;
|
525
|
+
}
|
526
|
+
|
527
|
+
static const rb_data_type_t fibermon_cond_data_type = {
|
528
|
+
"fibermon_cond",
|
529
|
+
{fibermon_cond_mark, fibermon_cond_free, fibermon_cond_memsize,},
|
530
|
+
};
|
531
|
+
|
532
|
+
static VALUE
|
533
|
+
fibermon_cond_alloc(VALUE klass)
|
534
|
+
{
|
535
|
+
VALUE volatile obj;
|
536
|
+
fibermon_cond_t *cv;
|
537
|
+
|
538
|
+
obj = TypedData_Make_Struct(klass, fibermon_cond_t,
|
539
|
+
&fibermon_cond_data_type, cv);
|
540
|
+
|
541
|
+
cv->monitor = Qnil;
|
542
|
+
cv->waitings = rb_xthread_fifo_new();
|
543
|
+
|
544
|
+
return obj;
|
545
|
+
}
|
546
|
+
|
547
|
+
static VALUE
|
548
|
+
fibermon_cond_initialize(VALUE self, VALUE monitor)
|
549
|
+
{
|
550
|
+
fibermon_cond_t *cv;
|
551
|
+
GetFiberMonCondPtr(self, cv);
|
552
|
+
|
553
|
+
cv->monitor = monitor;
|
554
|
+
return self;
|
555
|
+
}
|
556
|
+
|
557
|
+
VALUE
|
558
|
+
rb_fibermon_cond_new(VALUE monitor)
|
559
|
+
{
|
560
|
+
VALUE cv;
|
561
|
+
|
562
|
+
cv = fibermon_cond_alloc(rb_cFiberMonConditionVariable);
|
563
|
+
fibermon_cond_initialize(cv, monitor);
|
564
|
+
return cv;
|
565
|
+
}
|
566
|
+
|
567
|
+
VALUE
|
568
|
+
rb_fibermon_cond_signal(VALUE self)
|
569
|
+
{
|
570
|
+
fibermon_cond_t *cv;
|
571
|
+
VALUE fb;
|
572
|
+
|
573
|
+
GetFiberMonCondPtr(self, cv);
|
574
|
+
|
575
|
+
fb = rb_xthread_fifo_pop(cv->waitings);
|
576
|
+
if (!NIL_P(fb)) {
|
577
|
+
rb_fibermon_monitor_entry_fiber(cv->monitor, fb);
|
578
|
+
}
|
579
|
+
return self;
|
580
|
+
}
|
581
|
+
|
582
|
+
VALUE
|
583
|
+
rb_fibermon_cond_broadcast(VALUE self)
|
584
|
+
{
|
585
|
+
fibermon_cond_t *cv;
|
586
|
+
VALUE fb;
|
587
|
+
|
588
|
+
GetFiberMonCondPtr(self, cv);
|
589
|
+
|
590
|
+
while (!NIL_P(fb = rb_xthread_fifo_pop(cv->waitings))) {
|
591
|
+
rb_fibermon_monitor_entry_fiber(cv->monitor, fb);
|
592
|
+
}
|
593
|
+
return self;
|
594
|
+
}
|
595
|
+
|
596
|
+
VALUE
|
597
|
+
rb_fibermon_cond_wait(VALUE self)
|
598
|
+
{
|
599
|
+
fibermon_cond_t *cv;
|
600
|
+
VALUE fb;
|
601
|
+
|
602
|
+
GetFiberMonCondPtr(self, cv);
|
603
|
+
rb_xthread_fifo_push(cv->waitings, rb_fiber_current());
|
604
|
+
|
605
|
+
return rb_fibermon_monitor_wait_cond(cv->monitor);
|
606
|
+
}
|
607
|
+
|
608
|
+
VALUE
|
609
|
+
rb_fibermon_cond_wait_until(VALUE self)
|
610
|
+
{
|
611
|
+
while(!RTEST(rb_yield(Qnil))) {
|
612
|
+
rb_fibermon_cond_wait(self);
|
613
|
+
}
|
614
|
+
return self;
|
615
|
+
}
|
616
|
+
|
617
|
+
VALUE
|
618
|
+
rb_fibermon_cond_wait_while(VALUE self)
|
619
|
+
{
|
620
|
+
while(RTEST(rb_yield(Qnil))) {
|
621
|
+
rb_fibermon_cond_wait(self);
|
622
|
+
}
|
623
|
+
return self;
|
624
|
+
}
|
625
|
+
|
626
|
+
Init_fiber_mon()
|
627
|
+
{
|
628
|
+
rb_cFiberMon = rb_define_class("FiberMon", rb_cObject);
|
629
|
+
rb_define_alloc_func(rb_cFiberMon, fibermon_alloc);
|
630
|
+
rb_define_method(rb_cFiberMon, "initialize", fibermon_initialize, 0);
|
631
|
+
rb_define_method(rb_cFiberMon, "current", rb_fibermon_current, 0);
|
632
|
+
rb_define_method(rb_cFiberMon, "mon_start", fibermon_mon_start, 0);
|
633
|
+
rb_define_alias(rb_cFiberMon, "start", "mon_start");
|
634
|
+
rb_define_method(rb_cFiberMon, "entry_fiber", fibermon_entry, -1);
|
635
|
+
rb_define_alias(rb_cFiberMon, "entry", "entry_fiber");
|
636
|
+
rb_define_method(rb_cFiberMon, "yield", rb_fibermon_yield, 0);
|
637
|
+
rb_define_method(rb_cFiberMon, "new_mon", rb_fibermon_new_mon, 0);
|
638
|
+
rb_define_method(rb_cFiberMon, "new_cv", rb_fibermon_new_cv, 0);
|
639
|
+
rb_define_alias(rb_cFiberMon, "new_cond", "new_cv");
|
640
|
+
rb_define_method(rb_cFiberMon, "synchronize", rb_fibermon_synchronize, 0);
|
641
|
+
|
642
|
+
rb_cFiberMonMonitor =
|
643
|
+
rb_define_class_under(rb_cFiberMon, "Monitor", rb_cObject);
|
644
|
+
rb_define_alloc_func(rb_cFiberMonMonitor, fibermon_monitor_alloc);
|
645
|
+
rb_define_method(rb_cFiberMonMonitor, "iniialize",
|
646
|
+
fibermon_monitor_initialize, 1);
|
647
|
+
rb_define_method(rb_cFiberMonMonitor, "try_enter",
|
648
|
+
rb_fibermon_monitor_try_enter, 0);
|
649
|
+
rb_define_method(rb_cFiberMonMonitor, "enter",
|
650
|
+
rb_fibermon_monitor_enter, 0);
|
651
|
+
rb_define_method(rb_cFiberMonMonitor, "exit",
|
652
|
+
rb_fibermon_monitor_exit, 0);
|
653
|
+
rb_define_method(rb_cFiberMonMonitor, "synchronize",
|
654
|
+
fibermon_monitor_synchronize, 0);
|
655
|
+
rb_define_method(rb_cFiberMonMonitor, "new_cond",
|
656
|
+
rb_fibermon_monitor_new_cond, 0);
|
657
|
+
rb_define_alias(rb_cFiberMonMonitor, "new_cv", "new_cond");
|
658
|
+
|
659
|
+
rb_cFiberMonConditionVariable =
|
660
|
+
rb_define_class_under(rb_cFiberMon, "ConditionVariable", rb_cObject);
|
661
|
+
rb_define_alloc_func(rb_cFiberMonConditionVariable, fibermon_cond_alloc);
|
662
|
+
rb_define_method(rb_cFiberMonConditionVariable, "iniialize",
|
663
|
+
fibermon_cond_initialize, 1);
|
664
|
+
rb_define_method(rb_cFiberMonConditionVariable, "signal",
|
665
|
+
rb_fibermon_cond_signal, 0);
|
666
|
+
rb_define_method(rb_cFiberMonConditionVariable, "broadcast",
|
667
|
+
rb_fibermon_cond_broadcast, 0);
|
668
|
+
rb_define_method(rb_cFiberMonConditionVariable, "wait",
|
669
|
+
rb_fibermon_cond_wait, 0);
|
670
|
+
rb_define_method(rb_cFiberMonConditionVariable, "wait_until",
|
671
|
+
rb_fibermon_cond_wait_until, 0);
|
672
|
+
rb_define_method(rb_cFiberMonConditionVariable, "wait_while",
|
673
|
+
rb_fibermon_cond_wait_while, 0);
|
674
|
+
}
|
data/fiber_mon.h
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
/**********************************************************************
|
2
|
+
|
3
|
+
fiber-mon.h -
|
4
|
+
Copyright (C) 2010-2011 Keiju ISHITSUKA
|
5
|
+
(Penta Advanced Labrabries, Co.,Ltd)
|
6
|
+
|
7
|
+
**********************************************************************/
|
8
|
+
|
9
|
+
RUBY_EXTERN VALUE rb_cFiberMon;
|
10
|
+
RUBY_EXTERN VALUE rb_cFiberMonMonitor;
|
11
|
+
RUBY_EXTERN VALUE rb_cFiberMonConditionVariable;
|
12
|
+
|
13
|
+
RUBY_EXTERN VALUE rb_fibermon_new(void);
|
14
|
+
RUBY_EXTERN VALUE rb_fibermon_current(VALUE);
|
15
|
+
RUBY_EXTERN VALUE rb_fibermon_entry_fiber(VALUE, VALUE);
|
16
|
+
RUBY_EXTERN VALUE rb_fibermon_yield(VALUE);
|
17
|
+
RUBY_EXTERN VALUE rb_fibermon_new_mon(VALUE);
|
18
|
+
|
19
|
+
RUBY_EXTERN VALUE rb_fibermon_monitor_new(VALUE);
|
20
|
+
RUBY_EXTERN VALUE rb_fibermon_monitor_valid_owner_p(VALUE);
|
21
|
+
RUBY_EXTERN VALUE rb_fibermon_monitor_try_enter(VALUE);
|
22
|
+
RUBY_EXTERN VALUE rb_fibermon_monitor_enter(VALUE);
|
23
|
+
RUBY_EXTERN VALUE rb_fibermon_monitor_exit(VALUE);
|
24
|
+
RUBY_EXTERN VALUE rb_fibermon_monitor_synchronize(VALUE, VALUE (*)(VALUE), VALUE);
|
25
|
+
RUBY_EXTERN VALUE rb_fibermon_monitor_new_cond(VALUE);
|
26
|
+
|
27
|
+
RUBY_EXTERN VALUE rb_fibermon_cond_new(VALUE);
|
28
|
+
RUBY_EXTERN VALUE rb_fibermon_cond_signal(VALUE);
|
29
|
+
RUBY_EXTERN VALUE rb_fibermon_cond_broadcast(VALUE);
|
30
|
+
RUBY_EXTERN VALUE rb_fibermon_cond_wait(VALUE);
|
31
|
+
RUBY_EXTERN VALUE rb_fibermon_cond_wait_until(VALUE);
|
32
|
+
RUBY_EXTERN VALUE rb_fibermon_cond_wait_while(VALUE);
|
data/lib/fiber-mon.rb
ADDED
@@ -0,0 +1,257 @@
|
|
1
|
+
#
|
2
|
+
# fiber-mon.rb -
|
3
|
+
# Copyright (C) 2010 Keiju ISHITSUKA
|
4
|
+
# (Penta Advanced Labrabries, Co.,Ltd)
|
5
|
+
#
|
6
|
+
|
7
|
+
require "xthread"
|
8
|
+
require "fiber_mon.so"
|
9
|
+
|
10
|
+
require "forwardable"
|
11
|
+
require "monitor"
|
12
|
+
|
13
|
+
class FiberMon
|
14
|
+
class RBFiberMon
|
15
|
+
include MonitorMixin
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
super
|
19
|
+
|
20
|
+
# @mon_mx = Mutex.new
|
21
|
+
# @owner = nil
|
22
|
+
# @mon_mxmx = Mutex.new
|
23
|
+
|
24
|
+
@started = false
|
25
|
+
|
26
|
+
@current = nil
|
27
|
+
|
28
|
+
@entries = []
|
29
|
+
|
30
|
+
@wait_resume = []
|
31
|
+
@wait_resume_mx = ::Mutex.new
|
32
|
+
@wait_resume_cv = ::XThread::ConditionVariable.new
|
33
|
+
|
34
|
+
mon_start
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :current
|
38
|
+
|
39
|
+
def mon_start
|
40
|
+
return if @started
|
41
|
+
@started = true
|
42
|
+
th = Thread.start{
|
43
|
+
loop do
|
44
|
+
@wait_resume_mx.synchronize do
|
45
|
+
while @wait_resume.empty? && @entries.empty?
|
46
|
+
@wait_resume_cv.wait(@wait_resume_mx)
|
47
|
+
end
|
48
|
+
|
49
|
+
if block = @entries.shift
|
50
|
+
@current = Fiber.new{block.call(self)}
|
51
|
+
else
|
52
|
+
@current = @wait_resume.shift
|
53
|
+
end
|
54
|
+
end
|
55
|
+
begin
|
56
|
+
mx = @current.resume if @current
|
57
|
+
# rescue
|
58
|
+
# if $DEBUG
|
59
|
+
# p $!
|
60
|
+
# puts $@
|
61
|
+
# end
|
62
|
+
# raise
|
63
|
+
ensure
|
64
|
+
if mx.kind_of?(Mutex)
|
65
|
+
mx.unlock
|
66
|
+
end
|
67
|
+
@current = nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
}
|
71
|
+
th
|
72
|
+
end
|
73
|
+
alias start mon_start
|
74
|
+
|
75
|
+
def entry_fiber(p0 = nil, &block)
|
76
|
+
p0 = block if block
|
77
|
+
@wait_resume_mx.synchronize do
|
78
|
+
@entries.push p0
|
79
|
+
@wait_resume_cv.signal
|
80
|
+
end
|
81
|
+
end
|
82
|
+
alias entry entry_fiber
|
83
|
+
# alias start entry_fiber
|
84
|
+
|
85
|
+
def yield
|
86
|
+
@wait_resume_mx.synchronize do
|
87
|
+
@wait_resume.push @current
|
88
|
+
@wait_resume_cv.signal
|
89
|
+
end
|
90
|
+
fiber_yield
|
91
|
+
end
|
92
|
+
|
93
|
+
# def synchronize(&block)
|
94
|
+
# @mon_mxmx.synchronize do
|
95
|
+
# @mon_mx.lock
|
96
|
+
# @owner = Thread.current
|
97
|
+
# end
|
98
|
+
# begin
|
99
|
+
# block.call
|
100
|
+
# ensure
|
101
|
+
# @mon_mxmx.synchronize do
|
102
|
+
# @owner = nil
|
103
|
+
# @mon_mx.unlock
|
104
|
+
# end
|
105
|
+
# end
|
106
|
+
# end
|
107
|
+
|
108
|
+
# def fiber_yield
|
109
|
+
# begin
|
110
|
+
# status = nil
|
111
|
+
# @mon_mxmx.synchronize do
|
112
|
+
# if status = @owner == Thread.current && @mon_mx.locked?
|
113
|
+
# @mon_mx.unlock
|
114
|
+
# @owner = nil
|
115
|
+
# end
|
116
|
+
# end
|
117
|
+
# Fiber.yield
|
118
|
+
# rescue
|
119
|
+
# Log::debug_exception(self)
|
120
|
+
# ensure
|
121
|
+
# @mon_mxmx.synchronize do
|
122
|
+
# if status
|
123
|
+
# @owner = Thread.current
|
124
|
+
# @mon_mx.lock
|
125
|
+
# end
|
126
|
+
# end
|
127
|
+
# end
|
128
|
+
# end
|
129
|
+
|
130
|
+
def fiber_yield
|
131
|
+
begin
|
132
|
+
mon_check_owner
|
133
|
+
rescue
|
134
|
+
return Fiber.yield
|
135
|
+
end
|
136
|
+
if (count = mon_exit_for_cond) > 0
|
137
|
+
begin
|
138
|
+
Fiber.yield @mon_mutex
|
139
|
+
ensure
|
140
|
+
@mon_mutex.lock
|
141
|
+
end
|
142
|
+
else
|
143
|
+
Fiber.yield
|
144
|
+
end
|
145
|
+
mon_enter_for_cond(count)
|
146
|
+
end
|
147
|
+
|
148
|
+
def new_mon
|
149
|
+
Monitor.new(self)
|
150
|
+
end
|
151
|
+
|
152
|
+
def new_cv
|
153
|
+
ConditionVariable.new(self)
|
154
|
+
end
|
155
|
+
alias new_cond new_cv
|
156
|
+
|
157
|
+
def entry_wait_resume(*fbs)
|
158
|
+
@wait_resume_mx.synchronize do
|
159
|
+
@wait_resume.concat(fbs)
|
160
|
+
@wait_resume_cv.signal
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
class Monitor<::Monitor
|
165
|
+
extend Forwardable
|
166
|
+
|
167
|
+
def initialize(fibmon)
|
168
|
+
super()
|
169
|
+
@fibmon = fibmon
|
170
|
+
end
|
171
|
+
|
172
|
+
def_delegator :@fibmon, :entry_wait_resume
|
173
|
+
def_delegator :@fibmon, :current
|
174
|
+
|
175
|
+
def new_cv
|
176
|
+
ConditionVariable.new(self)
|
177
|
+
end
|
178
|
+
|
179
|
+
def fiber_yield
|
180
|
+
begin
|
181
|
+
mon_check_owner
|
182
|
+
rescue
|
183
|
+
return Fiber.yield
|
184
|
+
end
|
185
|
+
if (count = mon_exit_for_cond) > 0
|
186
|
+
begin
|
187
|
+
Fiber.yield @mon_mutex
|
188
|
+
ensure
|
189
|
+
@mon_mutex.lock
|
190
|
+
end
|
191
|
+
else
|
192
|
+
Fiber.yield
|
193
|
+
end
|
194
|
+
mon_enter_for_cond(count)
|
195
|
+
end
|
196
|
+
|
197
|
+
alias yield fiber_yield
|
198
|
+
end
|
199
|
+
|
200
|
+
class ConditionVariable
|
201
|
+
def initialize(monitor)
|
202
|
+
@mon = monitor
|
203
|
+
|
204
|
+
@waitings = []
|
205
|
+
@waitings_mx = Mutex.new
|
206
|
+
end
|
207
|
+
|
208
|
+
def synchronize(&block)
|
209
|
+
@waitings_mx.synchronize(&block)
|
210
|
+
end
|
211
|
+
|
212
|
+
def signal(&block)
|
213
|
+
@waitings_mx.synchronize do
|
214
|
+
if block_given?
|
215
|
+
yield
|
216
|
+
end
|
217
|
+
|
218
|
+
if fb = @waitings.shift
|
219
|
+
@mon.entry_wait_resume(fb)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def broadcast(&block)
|
225
|
+
@waitings_mx.synchronize do
|
226
|
+
if block_given?
|
227
|
+
yield
|
228
|
+
end
|
229
|
+
|
230
|
+
return if @waitings.empty?
|
231
|
+
fbs, @waitings = @waitings, []
|
232
|
+
@mon.entry_wait_resume(*fbs)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def wait
|
237
|
+
@waitings_mx.synchronize do
|
238
|
+
@waitings.push @mon.current
|
239
|
+
end
|
240
|
+
@mon.fiber_yield
|
241
|
+
end
|
242
|
+
|
243
|
+
def wait_until(&cond)
|
244
|
+
until cond.call
|
245
|
+
wait
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def wait_while(&cond)
|
250
|
+
while cond.call
|
251
|
+
wait
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
end
|
257
|
+
end
|
data/xthread.h
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
/**********************************************************************
|
2
|
+
|
3
|
+
xthread.h -
|
4
|
+
|
5
|
+
Copyright (C) 2011 Keiju Ishitsuka
|
6
|
+
Copyright (C) 2011 Penta Advanced Laboratories, Inc.
|
7
|
+
|
8
|
+
**********************************************************************/
|
9
|
+
|
10
|
+
|
11
|
+
#define XTHREAD_VERSION "0.1.2"
|
12
|
+
|
13
|
+
RUBY_EXTERN VALUE rb_mXThread;
|
14
|
+
RUBY_EXTERN VALUE rb_cXThreadFifo;
|
15
|
+
RUBY_EXTERN VALUE rb_cXThreadConditionVariable;
|
16
|
+
RUBY_EXTERN VALUE rb_cXThreadQueue;
|
17
|
+
RUBY_EXTERN VALUE rb_cXThreadSizedQueue;
|
18
|
+
RUBY_EXTERN VALUE rb_cXThreadMonitor;
|
19
|
+
RUBY_EXTERN VALUE rb_cXThreadMonitorCond;
|
20
|
+
|
21
|
+
|
22
|
+
RUBY_EXTERN VALUE rb_xthread_fifo_new(void);
|
23
|
+
RUBY_EXTERN VALUE rb_xthread_fifo_empty_p(VALUE);
|
24
|
+
RUBY_EXTERN VALUE rb_xthread_fifo_push(VALUE, VALUE);
|
25
|
+
RUBY_EXTERN VALUE rb_xthread_fifo_pop(VALUE);
|
26
|
+
RUBY_EXTERN VALUE rb_xthread_fifo_clear(VALUE);
|
27
|
+
RUBY_EXTERN VALUE rb_xthread_fifo_length(VALUE);
|
28
|
+
|
29
|
+
RUBY_EXTERN VALUE rb_xthread_cond_new(void);
|
30
|
+
RUBY_EXTERN VALUE rb_xthread_cond_signal(VALUE);
|
31
|
+
RUBY_EXTERN VALUE rb_xthread_cond_broadcast(VALUE);
|
32
|
+
RUBY_EXTERN VALUE rb_xthread_cond_wait(VALUE, VALUE, VALUE);
|
33
|
+
|
34
|
+
RUBY_EXTERN VALUE rb_xthread_queue_new(void);
|
35
|
+
RUBY_EXTERN VALUE rb_xthread_queue_push(VALUE, VALUE);
|
36
|
+
RUBY_EXTERN VALUE rb_xthread_queue_pop(VALUE);
|
37
|
+
RUBY_EXTERN VALUE rb_xthread_queue_pop_non_block(VALUE);
|
38
|
+
RUBY_EXTERN VALUE rb_xthread_queue_empty_p(VALUE);
|
39
|
+
RUBY_EXTERN VALUE rb_xthread_queue_clear(VALUE);
|
40
|
+
RUBY_EXTERN VALUE rb_xthread_queue_length(VALUE);
|
41
|
+
|
42
|
+
RUBY_EXTERN VALUE rb_xthread_sized_queue_new(long);
|
43
|
+
RUBY_EXTERN VALUE rb_xthread_sized_queue_max(VALUE);
|
44
|
+
RUBY_EXTERN VALUE rb_xthread_sized_queue_set_max(VALUE, VALUE);
|
45
|
+
RUBY_EXTERN VALUE rb_xthread_sized_queue_push(VALUE, VALUE);
|
46
|
+
RUBY_EXTERN VALUE rb_xthread_sized_queue_pop(VALUE);
|
47
|
+
RUBY_EXTERN VALUE rb_xthread_sized_queue_pop_non_block(VALUE);
|
48
|
+
|
49
|
+
RUBY_EXTERN VALUE rb_xthread_monitor_new(void);
|
50
|
+
RUBY_EXTERN VALUE rb_xthread_monitor_try_enter(VALUE);
|
51
|
+
RUBY_EXTERN VALUE rb_xthread_monitor_enter(VALUE);
|
52
|
+
RUBY_EXTERN VALUE rb_xthread_monitor_exit(VALUE);
|
53
|
+
RUBY_EXTERN VALUE rb_xthread_monitor_synchronize(VALUE, VALUE (*)(VALUE), VALUE);
|
54
|
+
RUBY_EXTERN VALUE rb_xthread_monitor_new_cond(VALUE);
|
55
|
+
|
56
|
+
RUBY_EXTERN VALUE rb_xthread_monitor_cond_new(VALUE);
|
57
|
+
RUBY_EXTERN VALUE rb_xthread_monitor_cond_wait(VALUE, VALUE);
|
58
|
+
RUBY_EXTERN VALUE rb_xthread_monitor_cond_wait_while(VALUE);
|
59
|
+
RUBY_EXTERN VALUE rb_xthread_monitor_cond_wait_until(VALUE);
|
60
|
+
RUBY_EXTERN VALUE rb_xthread_monitor_cond_signal(VALUE);
|
61
|
+
RUBY_EXTERN VALUE rb_xthread_monitor_cond_broadcast(VALUE self);
|
62
|
+
|
63
|
+
|
64
|
+
|
65
|
+
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fiber-mon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 2
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Keiju.Ishitsuka
|
@@ -15,22 +15,41 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-04-10 00:00:00 +09:00
|
19
19
|
default_executable:
|
20
|
-
dependencies:
|
21
|
-
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: xthread
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 29
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 1
|
33
|
+
- 3
|
34
|
+
version: 0.1.3
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
22
37
|
description: |
|
23
38
|
Simple fiber scheduler for Ruby.
|
24
39
|
|
25
40
|
email: keiju@ishitsuka.com
|
26
41
|
executables: []
|
27
42
|
|
28
|
-
extensions:
|
29
|
-
|
43
|
+
extensions:
|
44
|
+
- extconf.rb
|
30
45
|
extra_rdoc_files: []
|
31
46
|
|
32
47
|
files:
|
33
|
-
-
|
48
|
+
- fiber_mon.c
|
49
|
+
- fiber_mon.h
|
50
|
+
- xthread.h
|
51
|
+
- lib/fiber-mon.rb
|
52
|
+
- extconf.rb
|
34
53
|
has_rdoc: true
|
35
54
|
homepage: http://github.com/keiju/fiber-mon
|
36
55
|
licenses: []
|
data/fiber-mon.rb
DELETED
@@ -1,252 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# fiber-mon.rb -
|
3
|
-
# Copyright (C) 2010 Keiju ISHITSUKA
|
4
|
-
# (Penta Advanced Labrabries, Co.,Ltd)
|
5
|
-
#
|
6
|
-
|
7
|
-
require "forwardable"
|
8
|
-
require "monitor"
|
9
|
-
|
10
|
-
class FiberMon
|
11
|
-
include MonitorMixin
|
12
|
-
|
13
|
-
def initialize
|
14
|
-
super
|
15
|
-
|
16
|
-
# @mon_mx = Mutex.new
|
17
|
-
# @owner = nil
|
18
|
-
# @mon_mxmx = Mutex.new
|
19
|
-
|
20
|
-
@started = false
|
21
|
-
|
22
|
-
@current = nil
|
23
|
-
|
24
|
-
@entries = []
|
25
|
-
|
26
|
-
@wait_resume = []
|
27
|
-
@wait_resume_mx = ::Mutex.new
|
28
|
-
@wait_resume_cv = ::ConditionVariable.new
|
29
|
-
|
30
|
-
mon_start
|
31
|
-
end
|
32
|
-
|
33
|
-
attr_reader :current
|
34
|
-
|
35
|
-
def mon_start
|
36
|
-
return if @started
|
37
|
-
@started = true
|
38
|
-
th = Thread.start{
|
39
|
-
loop do
|
40
|
-
@wait_resume_mx.synchronize do
|
41
|
-
while @wait_resume.empty? && @entries.empty?
|
42
|
-
@wait_resume_cv.wait(@wait_resume_mx)
|
43
|
-
end
|
44
|
-
|
45
|
-
if block = @entries.shift
|
46
|
-
@current = Fiber.new{block.call(self)}
|
47
|
-
else
|
48
|
-
@current = @wait_resume.shift
|
49
|
-
end
|
50
|
-
end
|
51
|
-
begin
|
52
|
-
mx = @current.resume if @current
|
53
|
-
# rescue
|
54
|
-
# if $DEBUG
|
55
|
-
# p $!
|
56
|
-
# puts $@
|
57
|
-
# end
|
58
|
-
# raise
|
59
|
-
ensure
|
60
|
-
if mx.kind_of?(Mutex)
|
61
|
-
mx.unlock
|
62
|
-
end
|
63
|
-
@current = nil
|
64
|
-
end
|
65
|
-
end
|
66
|
-
}
|
67
|
-
th
|
68
|
-
end
|
69
|
-
alias start mon_start
|
70
|
-
|
71
|
-
def entry_fiber(p0 = nil, &block)
|
72
|
-
p0 = block if block
|
73
|
-
@wait_resume_mx.synchronize do
|
74
|
-
@entries.push p0
|
75
|
-
@wait_resume_cv.signal
|
76
|
-
end
|
77
|
-
end
|
78
|
-
alias entry entry_fiber
|
79
|
-
# alias start entry_fiber
|
80
|
-
|
81
|
-
def yield
|
82
|
-
@wait_resume_mx.synchronize do
|
83
|
-
@wait_resume.push @current
|
84
|
-
@wait_resume_cv.signal
|
85
|
-
end
|
86
|
-
fiber_yield
|
87
|
-
end
|
88
|
-
|
89
|
-
# def synchronize(&block)
|
90
|
-
# @mon_mxmx.synchronize do
|
91
|
-
# @mon_mx.lock
|
92
|
-
# @owner = Thread.current
|
93
|
-
# end
|
94
|
-
# begin
|
95
|
-
# block.call
|
96
|
-
# ensure
|
97
|
-
# @mon_mxmx.synchronize do
|
98
|
-
# @owner = nil
|
99
|
-
# @mon_mx.unlock
|
100
|
-
# end
|
101
|
-
# end
|
102
|
-
# end
|
103
|
-
|
104
|
-
# def fiber_yield
|
105
|
-
# begin
|
106
|
-
# status = nil
|
107
|
-
# @mon_mxmx.synchronize do
|
108
|
-
# if status = @owner == Thread.current && @mon_mx.locked?
|
109
|
-
# @mon_mx.unlock
|
110
|
-
# @owner = nil
|
111
|
-
# end
|
112
|
-
# end
|
113
|
-
# Fiber.yield
|
114
|
-
# rescue
|
115
|
-
# Log::debug_exception(self)
|
116
|
-
# ensure
|
117
|
-
# @mon_mxmx.synchronize do
|
118
|
-
# if status
|
119
|
-
# @owner = Thread.current
|
120
|
-
# @mon_mx.lock
|
121
|
-
# end
|
122
|
-
# end
|
123
|
-
# end
|
124
|
-
# end
|
125
|
-
|
126
|
-
def fiber_yield
|
127
|
-
begin
|
128
|
-
mon_check_owner
|
129
|
-
rescue
|
130
|
-
return Fiber.yield
|
131
|
-
end
|
132
|
-
if (count = mon_exit_for_cond) > 0
|
133
|
-
begin
|
134
|
-
Fiber.yield @mon_mutex
|
135
|
-
ensure
|
136
|
-
@mon_mutex.lock
|
137
|
-
end
|
138
|
-
else
|
139
|
-
Fiber.yield
|
140
|
-
end
|
141
|
-
mon_enter_for_cond(count)
|
142
|
-
end
|
143
|
-
|
144
|
-
def new_mon
|
145
|
-
Monitor.new(self)
|
146
|
-
end
|
147
|
-
|
148
|
-
def new_cv
|
149
|
-
ConditionVariable.new(self)
|
150
|
-
end
|
151
|
-
alias new_cond new_cv
|
152
|
-
|
153
|
-
def entry_wait_resume(*fbs)
|
154
|
-
@wait_resume_mx.synchronize do
|
155
|
-
@wait_resume.concat(fbs)
|
156
|
-
@wait_resume_cv.signal
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
class Monitor<::Monitor
|
161
|
-
extend Forwardable
|
162
|
-
|
163
|
-
def initialize(fibmon)
|
164
|
-
super()
|
165
|
-
@fibmon = fibmon
|
166
|
-
end
|
167
|
-
|
168
|
-
def_delegator :@fibmon, :entry_wait_resume
|
169
|
-
def_delegator :@fibmon, :current
|
170
|
-
|
171
|
-
def new_cv
|
172
|
-
ConditionVariable.new(self)
|
173
|
-
end
|
174
|
-
|
175
|
-
def fiber_yield
|
176
|
-
begin
|
177
|
-
mon_check_owner
|
178
|
-
rescue
|
179
|
-
return Fiber.yield
|
180
|
-
end
|
181
|
-
if (count = mon_exit_for_cond) > 0
|
182
|
-
begin
|
183
|
-
Fiber.yield @mon_mutex
|
184
|
-
ensure
|
185
|
-
@mon_mutex.lock
|
186
|
-
end
|
187
|
-
else
|
188
|
-
Fiber.yield
|
189
|
-
end
|
190
|
-
mon_enter_for_cond(count)
|
191
|
-
end
|
192
|
-
|
193
|
-
alias yield fiber_yield
|
194
|
-
end
|
195
|
-
|
196
|
-
class ConditionVariable
|
197
|
-
def initialize(monitor)
|
198
|
-
@mon = monitor
|
199
|
-
|
200
|
-
@waitings = []
|
201
|
-
@waitings_mx = Mutex.new
|
202
|
-
end
|
203
|
-
|
204
|
-
def synchronize(&block)
|
205
|
-
@waitings_mx.synchronize(&block)
|
206
|
-
end
|
207
|
-
|
208
|
-
def signal(&block)
|
209
|
-
@waitings_mx.synchronize do
|
210
|
-
if block_given?
|
211
|
-
yield
|
212
|
-
end
|
213
|
-
|
214
|
-
if fb = @waitings.shift
|
215
|
-
@mon.entry_wait_resume(fb)
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
def broadcast(&block)
|
221
|
-
@waitings_mx.synchronize do
|
222
|
-
if block_given?
|
223
|
-
yield
|
224
|
-
end
|
225
|
-
|
226
|
-
return if @waitings.empty?
|
227
|
-
fbs, @waitings = @waitings, []
|
228
|
-
@mon.entry_wait_resume(*fbs)
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
def wait
|
233
|
-
@waitings_mx.synchronize do
|
234
|
-
@waitings.push @mon.current
|
235
|
-
end
|
236
|
-
@mon.fiber_yield
|
237
|
-
end
|
238
|
-
|
239
|
-
def wait_until(&cond)
|
240
|
-
until cond.call
|
241
|
-
wait
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
def wait_while(&cond)
|
246
|
-
while cond.call
|
247
|
-
wait
|
248
|
-
end
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
end
|