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.
Files changed (7) hide show
  1. data/extconf.rb +3 -0
  2. data/fiber_mon.c +674 -0
  3. data/fiber_mon.h +32 -0
  4. data/lib/fiber-mon.rb +257 -0
  5. data/xthread.h +65 -0
  6. metadata +28 -9
  7. data/fiber-mon.rb +0 -252
data/extconf.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+
3
+ create_makefile("fiber_mon")
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: 27
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.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: 2010-10-28 00:00:00 +09:00
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
- - fiber-mon.rb
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