fiber-mon 0.1.0 → 0.2.0

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