polyphony 0.26 → 0.27

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -3
  3. data/CHANGELOG.md +8 -0
  4. data/Gemfile.lock +1 -1
  5. data/TODO.md +34 -14
  6. data/examples/core/xx-mt-scheduler.rb +349 -0
  7. data/examples/core/xx-queue-async.rb +120 -0
  8. data/examples/core/xx-readpartial.rb +18 -0
  9. data/examples/core/xx-thread-selector-sleep.rb +51 -0
  10. data/examples/core/xx-thread-selector-snooze.rb +46 -0
  11. data/examples/core/xx-thread-sleep.rb +17 -0
  12. data/examples/core/xx-thread-snooze.rb +34 -0
  13. data/examples/performance/snooze.rb +5 -5
  14. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +73 -0
  15. data/examples/performance/thread-vs-fiber/polyphony_server.rb +12 -4
  16. data/ext/gyro/async.c +58 -61
  17. data/ext/gyro/child.c +50 -59
  18. data/ext/gyro/gyro.c +84 -192
  19. data/ext/gyro/gyro.h +29 -2
  20. data/ext/gyro/gyro_ext.c +6 -0
  21. data/ext/gyro/io.c +87 -96
  22. data/ext/gyro/queue.c +109 -0
  23. data/ext/gyro/selector.c +117 -0
  24. data/ext/gyro/signal.c +44 -54
  25. data/ext/gyro/socket.c +15 -20
  26. data/ext/gyro/thread.c +203 -0
  27. data/ext/gyro/timer.c +79 -50
  28. data/ext/libev/ev.c +3 -0
  29. data/lib/polyphony.rb +7 -12
  30. data/lib/polyphony/core/global_api.rb +5 -1
  31. data/lib/polyphony/core/throttler.rb +6 -11
  32. data/lib/polyphony/extensions/core.rb +2 -0
  33. data/lib/polyphony/extensions/fiber.rb +11 -13
  34. data/lib/polyphony/extensions/thread.rb +52 -0
  35. data/lib/polyphony/version.rb +1 -1
  36. data/test/helper.rb +8 -3
  37. data/test/test_fiber.rb +2 -2
  38. data/test/test_global_api.rb +4 -5
  39. data/test/test_gyro.rb +3 -2
  40. data/test/test_io.rb +1 -0
  41. data/test/test_supervisor.rb +3 -3
  42. data/test/test_thread.rb +44 -0
  43. data/test/test_throttler.rb +41 -0
  44. data/test/test_timer.rb +13 -7
  45. metadata +17 -6
  46. data/examples/core/xx-thread_cancel.rb +0 -28
  47. data/examples/performance/thread.rb +0 -27
  48. data/lib/polyphony/core/thread.rb +0 -23
@@ -15,25 +15,48 @@ enum {
15
15
  // void Gyro_del_watcher_ref(VALUE obj);
16
16
  VALUE Gyro_snooze(VALUE self);
17
17
 
18
- VALUE Gyro_run_next_fiber();
19
- VALUE Gyro_await();
20
18
  void Gyro_schedule_fiber(VALUE fiber, VALUE value);
21
19
 
22
20
  int Gyro_ref_count();
23
21
  void Gyro_ref_count_incr();
24
22
  void Gyro_ref_count_decr();
25
23
 
24
+ VALUE Gyro_Async_await(VALUE async);
25
+
26
26
  VALUE IO_read_watcher(VALUE io);
27
27
  VALUE IO_write_watcher(VALUE io);
28
28
  VALUE Gyro_IO_await(VALUE self);
29
29
 
30
+ VALUE Gyro_Selector_run(VALUE self);
31
+
32
+ VALUE Gyro_Timer_await(VALUE self);
33
+
30
34
  int io_setstrbuf(VALUE *str, long len);
31
35
  void io_set_read_length(VALUE str, long n, int shrinkable);
32
36
  VALUE io_enc_str(VALUE str, rb_io_t *fptr);
33
37
 
38
+ struct ev_loop *Gyro_Selector_ev_loop(VALUE selector);
39
+ struct ev_loop *Gyro_Selector_current_thread_ev_loop();
40
+ long Gyro_Selector_pending_count(VALUE self);
41
+
42
+ VALUE Thread_current_event_selector();
43
+ VALUE Thread_ref(VALUE thread);
44
+ VALUE Thread_unref(VALUE thread);
45
+ VALUE Thread_switch_fiber(VALUE thread);
46
+ VALUE Fiber_await();
47
+ VALUE Thread_schedule_fiber(VALUE thread, VALUE fiber);
48
+ VALUE Thread_post_fork(VALUE thread);
49
+
50
+
34
51
  #define OBJ_ID(obj) (NUM2LONG(rb_funcall(obj, rb_intern("object_id"), 0)))
52
+ #define INSPECT(...) (rb_funcall(rb_cObject, rb_intern("p"), __VA_ARGS__))
35
53
 
36
54
  extern VALUE mGyro;
55
+ extern VALUE cGyro_Async;
56
+ extern VALUE cGyro_IO;
57
+ extern VALUE cGyro_Queue;
58
+ extern VALUE cGyro_Selector;
59
+ extern VALUE cGyro_Timer;
37
60
 
38
61
  extern VALUE Gyro_reactor_fiber;
39
62
  extern VALUE Gyro_root_fiber;
@@ -43,8 +66,12 @@ extern ID ID_caller;
43
66
  extern ID ID_clear;
44
67
  extern ID ID_each;
45
68
  extern ID ID_inspect;
69
+ extern ID ID_new;
46
70
  extern ID ID_raise;
47
71
  extern ID ID_scheduled_value;
72
+ extern ID ID_signal_bang;
73
+ extern ID ID_size;
74
+ extern ID ID_switch_fiber;
48
75
  extern ID ID_transfer;
49
76
  extern ID ID_R;
50
77
  extern ID ID_W;
@@ -4,9 +4,12 @@ void Init_Gyro();
4
4
  void Init_Gyro_Async();
5
5
  void Init_Gyro_Child();
6
6
  void Init_Gyro_IO();
7
+ void Init_Gyro_Queue();
8
+ void Init_Gyro_Selector();
7
9
  void Init_Gyro_Signal();
8
10
  void Init_Gyro_Timer();
9
11
  void Init_Socket();
12
+ void Init_Thread();
10
13
 
11
14
  void Init_gyro_ext() {
12
15
  ev_set_allocator(xrealloc);
@@ -15,8 +18,11 @@ void Init_gyro_ext() {
15
18
  Init_Gyro_Async();
16
19
  Init_Gyro_Child();
17
20
  Init_Gyro_IO();
21
+ Init_Gyro_Queue();
22
+ Init_Gyro_Selector();
18
23
  Init_Gyro_Signal();
19
24
  Init_Gyro_Timer();
20
25
 
21
26
  Init_Socket();
27
+ Init_Thread();
22
28
  }
@@ -8,56 +8,36 @@
8
8
 
9
9
  struct Gyro_IO {
10
10
  struct ev_io ev_io;
11
+ struct ev_loop *ev_loop;
11
12
  int active;
12
13
  int event_mask;
13
14
  VALUE fiber;
14
15
  };
15
16
 
16
- static VALUE cGyro_IO = Qnil;
17
+ VALUE cGyro_IO = Qnil;
17
18
 
18
- static VALUE Gyro_IO_allocate(VALUE klass);
19
- static void Gyro_IO_mark(void *ptr);
20
- static void Gyro_IO_free(void *ptr);
21
- static size_t Gyro_IO_size(const void *ptr);
22
-
23
- static VALUE Gyro_IO_initialize(VALUE self, VALUE io, VALUE event_mask);
24
-
25
- void Gyro_IO_callback(struct ev_loop *ev_loop, struct ev_io *io, int revents);
26
-
27
- static int Gyro_IO_symbol2event_mask(VALUE sym);
28
-
29
- // static VALUE IO_gets(int argc, VALUE *argv, VALUE io);
30
- static VALUE IO_read(int argc, VALUE *argv, VALUE io);
31
- static VALUE IO_readpartial(int argc, VALUE *argv, VALUE io);
32
- static VALUE IO_write(int argc, VALUE *argv, VALUE io);
33
- static VALUE IO_write_chevron(VALUE io, VALUE str);
34
-
35
- ID ID_read_watcher;
36
- ID ID_write_watcher;
19
+ ID ID_ivar_read_watcher;
20
+ ID ID_ivar_write_watcher;
37
21
  VALUE SYM_r;
38
22
  VALUE SYM_w;
39
23
 
40
- void Init_Gyro_IO() {
41
- cGyro_IO = rb_define_class_under(mGyro, "IO", rb_cData);
42
- rb_define_alloc_func(cGyro_IO, Gyro_IO_allocate);
43
-
44
- rb_define_method(cGyro_IO, "initialize", Gyro_IO_initialize, 2);
45
- rb_define_method(cGyro_IO, "await", Gyro_IO_await, 0);
24
+ static void Gyro_IO_mark(void *ptr) {
25
+ struct Gyro_IO *io = ptr;
26
+ if (io->fiber != Qnil) {
27
+ rb_gc_mark(io->fiber);
28
+ }
29
+ }
46
30
 
47
- VALUE cIO = rb_const_get(rb_cObject, rb_intern("IO"));
48
- // rb_define_method(cIO, "gets", IO_gets, -1);
49
- rb_define_method(cIO, "read", IO_read, -1);
50
- rb_define_method(cIO, "readpartial", IO_readpartial, -1);
51
- rb_define_method(cIO, "write", IO_write, -1);
52
- rb_define_method(cIO, "write_nonblock", IO_write, -1);
53
- rb_define_method(cIO, "<<", IO_write_chevron, 1);
54
- rb_define_method(cIO, "read_watcher", IO_read_watcher, 0);
55
- rb_define_method(cIO, "write_watcher", IO_write_watcher, 0);
31
+ static void Gyro_IO_free(void *ptr) {
32
+ struct Gyro_IO *io = ptr;
33
+ if (io->active) {
34
+ printf("IO watcher garbage collected while still active!\n");
35
+ }
36
+ xfree(io);
37
+ }
56
38
 
57
- ID_read_watcher = rb_intern("@read_watcher");
58
- ID_write_watcher = rb_intern("@write_watcher");
59
- SYM_r = ID2SYM(rb_intern("r"));
60
- SYM_w = ID2SYM(rb_intern("w"));
39
+ static size_t Gyro_IO_size(const void *ptr) {
40
+ return sizeof(struct Gyro_IO);
61
41
  }
62
42
 
63
43
  static const rb_data_type_t Gyro_IO_type = {
@@ -73,25 +53,42 @@ static VALUE Gyro_IO_allocate(VALUE klass) {
73
53
  return TypedData_Wrap_Struct(klass, &Gyro_IO_type, io);
74
54
  }
75
55
 
76
- static void Gyro_IO_mark(void *ptr) {
77
- struct Gyro_IO *io = ptr;
56
+ static const char * S_IO = "IO";
57
+ static const char * S_to_io = "to_io";
58
+
59
+ void Gyro_IO_callback(struct ev_loop *ev_loop, struct ev_io *ev_io, int revents) {
60
+ struct Gyro_IO *io = (struct Gyro_IO*)ev_io;
61
+
62
+ ev_io_stop(io->ev_loop, ev_io);
63
+ io->active = 0;
64
+
78
65
  if (io->fiber != Qnil) {
79
- rb_gc_mark(io->fiber);
66
+ VALUE fiber = io->fiber;
67
+ io->fiber = Qnil;
68
+ Gyro_schedule_fiber(fiber, Qnil);
80
69
  }
81
70
  }
82
71
 
83
- static void Gyro_IO_free(void *ptr) {
84
- struct Gyro_IO *io = ptr;
85
- ev_io_stop(EV_DEFAULT, &io->ev_io);
86
- xfree(io);
87
- }
72
+ static int Gyro_IO_symbol2event_mask(VALUE sym) {
73
+ ID sym_id;
88
74
 
89
- static size_t Gyro_IO_size(const void *ptr) {
90
- return sizeof(struct Gyro_IO);
91
- }
75
+ if (NIL_P(sym)) {
76
+ return 0;
77
+ }
92
78
 
93
- static const char * S_IO = "IO";
94
- static const char * S_to_io = "to_io";
79
+ sym_id = SYM2ID(sym);
80
+
81
+ if(sym_id == ID_R) {
82
+ return EV_READ;
83
+ } else if(sym_id == ID_W) {
84
+ return EV_WRITE;
85
+ } else if(sym_id == ID_RW) {
86
+ return EV_READ | EV_WRITE;
87
+ } else {
88
+ rb_raise(rb_eArgError, "invalid interest type %s (must be :r, :w, or :rw)",
89
+ RSTRING_PTR(rb_funcall(sym, ID_inspect, 0)));
90
+ }
91
+ }
95
92
 
96
93
  #define GetGyro_IO(obj, io) TypedData_Get_Struct((obj), struct Gyro_IO, &Gyro_IO_type, (io))
97
94
 
@@ -111,19 +108,6 @@ static VALUE Gyro_IO_initialize(VALUE self, VALUE io_obj, VALUE event_mask) {
111
108
  return Qnil;
112
109
  }
113
110
 
114
- void Gyro_IO_callback(struct ev_loop *ev_loop, struct ev_io *ev_io, int revents) {
115
- struct Gyro_IO *io = (struct Gyro_IO*)ev_io;
116
-
117
- ev_io_stop(EV_DEFAULT, ev_io);
118
- io->active = 0;
119
-
120
- if (io->fiber != Qnil) {
121
- VALUE fiber = io->fiber;
122
- io->fiber = Qnil;
123
- Gyro_schedule_fiber(fiber, Qnil);
124
- }
125
- }
126
-
127
111
  VALUE Gyro_IO_await(VALUE self) {
128
112
  struct Gyro_IO *io;
129
113
  VALUE ret;
@@ -132,14 +116,16 @@ VALUE Gyro_IO_await(VALUE self) {
132
116
 
133
117
  io->fiber = rb_fiber_current();
134
118
  io->active = 1;
135
- ev_io_start(EV_DEFAULT, &io->ev_io);
136
- ret = Gyro_await();
119
+ io->ev_loop = Gyro_Selector_current_thread_ev_loop();
120
+ ev_io_start(io->ev_loop, &io->ev_io);
121
+
122
+ ret = Fiber_await();
123
+ RB_GC_GUARD(ret);
137
124
 
138
- // make sure io watcher is stopped
139
- io->fiber = Qnil;
140
125
  if (io->active) {
141
126
  io->active = 0;
142
- ev_io_stop(EV_DEFAULT, &io->ev_io);
127
+ io->fiber = Qnil;
128
+ ev_io_stop(io->ev_loop, &io->ev_io);
143
129
  }
144
130
 
145
131
  // fiber is resumed, check if resumed value is an exception
@@ -151,27 +137,6 @@ VALUE Gyro_IO_await(VALUE self) {
151
137
  }
152
138
  }
153
139
 
154
- static int Gyro_IO_symbol2event_mask(VALUE sym) {
155
- ID sym_id;
156
-
157
- if (NIL_P(sym)) {
158
- return 0;
159
- }
160
-
161
- sym_id = SYM2ID(sym);
162
-
163
- if(sym_id == ID_R) {
164
- return EV_READ;
165
- } else if(sym_id == ID_W) {
166
- return EV_WRITE;
167
- } else if(sym_id == ID_RW) {
168
- return EV_READ | EV_WRITE;
169
- } else {
170
- rb_raise(rb_eArgError, "invalid interest type %s (must be :r, :w, or :rw)",
171
- RSTRING_PTR(rb_funcall(sym, ID_inspect, 0)));
172
- }
173
- }
174
-
175
140
  //////////////////////////////////////////////////////////////////////
176
141
  //////////////////////////////////////////////////////////////////////
177
142
  // the following is copied verbatim from the Ruby source code (io.c)
@@ -436,21 +401,47 @@ static VALUE IO_write_chevron(VALUE io, VALUE str) {
436
401
  }
437
402
 
438
403
  VALUE IO_read_watcher(VALUE self) {
439
- VALUE watcher = rb_ivar_get(self, ID_read_watcher);
404
+ VALUE watcher = rb_ivar_get(self, ID_ivar_read_watcher);
440
405
  if (watcher == Qnil) {
441
406
  VALUE args[] = {self, SYM_r};
442
407
  watcher = rb_class_new_instance(2, args, cGyro_IO);
443
- rb_ivar_set(self, ID_read_watcher, watcher);
408
+ rb_ivar_set(self, ID_ivar_read_watcher, watcher);
444
409
  }
445
410
  return watcher;
446
411
  }
447
412
 
448
413
  VALUE IO_write_watcher(VALUE self) {
449
- VALUE watcher = rb_ivar_get(self, ID_write_watcher);
414
+ VALUE watcher = rb_ivar_get(self, ID_ivar_write_watcher);
450
415
  if (watcher == Qnil) {
451
416
  VALUE args[] = {self, SYM_w};
452
417
  watcher = rb_class_new_instance(2, args, cGyro_IO);
453
- rb_ivar_set(self, ID_write_watcher, watcher);
418
+ rb_ivar_set(self, ID_ivar_write_watcher, watcher);
454
419
  }
455
420
  return watcher;
456
- }
421
+ }
422
+
423
+ void Init_Gyro_IO() {
424
+ cGyro_IO = rb_define_class_under(mGyro, "IO", rb_cData);
425
+ rb_define_alloc_func(cGyro_IO, Gyro_IO_allocate);
426
+
427
+ rb_define_method(cGyro_IO, "initialize", Gyro_IO_initialize, 2);
428
+ rb_define_method(cGyro_IO, "await", Gyro_IO_await, 0);
429
+
430
+ VALUE cIO = rb_const_get(rb_cObject, rb_intern("IO"));
431
+ // rb_define_method(cIO, "gets", IO_gets, -1);
432
+ rb_define_method(cIO, "read", IO_read, -1);
433
+ rb_define_method(cIO, "readpartial", IO_readpartial, -1);
434
+ rb_define_method(cIO, "write", IO_write, -1);
435
+ rb_define_method(cIO, "write_nonblock", IO_write, -1);
436
+ rb_define_method(cIO, "<<", IO_write_chevron, 1);
437
+ rb_define_method(cIO, "read_watcher", IO_read_watcher, 0);
438
+ rb_define_method(cIO, "write_watcher", IO_write_watcher, 0);
439
+
440
+ ID_ivar_read_watcher = rb_intern("@read_watcher");
441
+ ID_ivar_write_watcher = rb_intern("@write_watcher");
442
+ SYM_r = ID2SYM(rb_intern("r"));
443
+ SYM_w = ID2SYM(rb_intern("w"));
444
+
445
+ rb_global_variable(&SYM_r);
446
+ rb_global_variable(&SYM_w);
447
+ }
@@ -0,0 +1,109 @@
1
+ #include "gyro.h"
2
+
3
+ struct Gyro_Queue {
4
+ VALUE self;
5
+ VALUE queue;
6
+ VALUE wait_queue;
7
+ };
8
+
9
+ VALUE cGyro_Queue = Qnil;
10
+
11
+ static void Gyro_Queue_mark(void *ptr) {
12
+ struct Gyro_Queue *queue = ptr;
13
+ if (queue->queue != Qnil) {
14
+ rb_gc_mark(queue->queue);
15
+ }
16
+ if (queue->wait_queue != Qnil) {
17
+ rb_gc_mark(queue->wait_queue);
18
+ }
19
+ }
20
+
21
+ static void Gyro_Queue_free(void *ptr) {
22
+ struct Gyro_Queue *queue = ptr;
23
+ xfree(queue);
24
+ }
25
+
26
+ static size_t Gyro_Queue_size(const void *ptr) {
27
+ return sizeof(struct Gyro_Queue);
28
+ }
29
+
30
+ static const rb_data_type_t Gyro_Queue_type = {
31
+ "Gyro_Queue",
32
+ {Gyro_Queue_mark, Gyro_Queue_free, Gyro_Queue_size,},
33
+ 0, 0,
34
+ RUBY_TYPED_FREE_IMMEDIATELY,
35
+ };
36
+
37
+ static VALUE Gyro_Queue_allocate(VALUE klass) {
38
+ struct Gyro_Queue *queue = (struct Gyro_Queue *)xmalloc(sizeof(struct Gyro_Queue));
39
+ return TypedData_Wrap_Struct(klass, &Gyro_Queue_type, queue);
40
+ }
41
+ #define GetGyro_Queue(obj, queue) \
42
+ TypedData_Get_Struct((obj), struct Gyro_Queue, &Gyro_Queue_type, (queue))
43
+
44
+ static VALUE Gyro_Queue_initialize(VALUE self) {
45
+ struct Gyro_Queue *queue;
46
+ GetGyro_Queue(self, queue);
47
+
48
+ queue->self = self;
49
+ queue->queue = rb_ary_new();
50
+ queue->wait_queue = rb_ary_new();
51
+
52
+ return Qnil;
53
+ }
54
+
55
+ VALUE Gyro_Queue_push(VALUE self, VALUE value) {
56
+ struct Gyro_Queue *queue;
57
+ GetGyro_Queue(self, queue);
58
+
59
+ if (RARRAY_LEN(queue->wait_queue) > 0) {
60
+ VALUE async = rb_ary_shift(queue->wait_queue);
61
+ return rb_funcall(async, ID_signal_bang, 1, value);
62
+ }
63
+
64
+ rb_ary_push(queue->queue, value);
65
+ return self;
66
+ }
67
+
68
+ VALUE Gyro_Queue_shift(VALUE self) {
69
+ struct Gyro_Queue *queue;
70
+ GetGyro_Queue(self, queue);
71
+
72
+ if (RARRAY_LEN(queue->queue) > 0) {
73
+ return rb_ary_shift(queue->queue);
74
+ }
75
+
76
+ VALUE async = rb_funcall(cGyro_Async, ID_new, 0);
77
+ rb_ary_push(queue->wait_queue, async);
78
+ return Gyro_Async_await(async);
79
+ }
80
+
81
+ VALUE Gyro_Queue_shift_all(VALUE self) {
82
+ struct Gyro_Queue *queue;
83
+ GetGyro_Queue(self, queue);
84
+
85
+ if (rb_block_given_p()) {
86
+ while (RARRAY_LEN(queue->queue) > 0) {
87
+ rb_yield(rb_ary_shift(queue->queue));
88
+ }
89
+ }
90
+ else {
91
+ rb_ary_clear(queue->queue);
92
+ }
93
+
94
+ return self;
95
+ }
96
+
97
+ void Init_Gyro_Queue() {
98
+ cGyro_Queue = rb_define_class_under(mGyro, "Queue", rb_cData);
99
+ rb_define_alloc_func(cGyro_Queue, Gyro_Queue_allocate);
100
+
101
+ rb_define_method(cGyro_Queue, "initialize", Gyro_Queue_initialize, 0);
102
+ rb_define_method(cGyro_Queue, "push", Gyro_Queue_push, 1);
103
+ rb_define_method(cGyro_Queue, "<<", Gyro_Queue_push, 1);
104
+
105
+ rb_define_method(cGyro_Queue, "pop", Gyro_Queue_shift, 0);
106
+ rb_define_method(cGyro_Queue, "shift", Gyro_Queue_shift, 0);
107
+
108
+ rb_define_method(cGyro_Queue, "shift_each", Gyro_Queue_shift_all, 0);
109
+ }