polyphony 0.34 → 0.36

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ Exception.__disable_sanitized_backtrace__ = true
7
+
8
+ timers = 10.times.map do
9
+ spin do
10
+ t = Gyro::Timer.new(1, 1)
11
+ t.await
12
+ end
13
+ end
14
+
15
+ sleep 0.1
16
+ GC.start
17
+ sleep 0.1
data/ext/gyro/async.c CHANGED
@@ -4,8 +4,10 @@ struct Gyro_Async {
4
4
  struct ev_async ev_async;
5
5
  struct ev_loop *ev_loop;
6
6
  int active;
7
+ VALUE self;
7
8
  VALUE fiber;
8
9
  VALUE value;
10
+ VALUE selector;
9
11
  };
10
12
 
11
13
  VALUE cGyro_Async = Qnil;
@@ -18,12 +20,16 @@ static void Gyro_Async_mark(void *ptr) {
18
20
  if (async->value != Qnil) {
19
21
  rb_gc_mark(async->value);
20
22
  }
23
+ if (async->selector != Qnil) {
24
+ rb_gc_mark(async->selector);
25
+ }
21
26
  }
22
27
 
23
28
  static void Gyro_Async_free(void *ptr) {
24
29
  struct Gyro_Async *async = ptr;
25
30
  if (async->active) {
26
- printf("Async watcher garbage collected while still active!\n");
31
+ ev_clear_pending(async->ev_loop, &async->ev_async);
32
+ ev_async_stop(async->ev_loop, &async->ev_async);
27
33
  }
28
34
  xfree(async);
29
35
  }
@@ -35,26 +41,42 @@ static size_t Gyro_Async_size(const void *ptr) {
35
41
  static const rb_data_type_t Gyro_Async_type = {
36
42
  "Gyro_Async",
37
43
  {Gyro_Async_mark, Gyro_Async_free, Gyro_Async_size,},
38
- 0, 0,
39
- RUBY_TYPED_FREE_IMMEDIATELY,
44
+ 0, 0, 0
40
45
  };
41
46
 
42
47
  static VALUE Gyro_Async_allocate(VALUE klass) {
43
- struct Gyro_Async *async = (struct Gyro_Async *)xmalloc(sizeof(struct Gyro_Async));
48
+ struct Gyro_Async *async = ALLOC(struct Gyro_Async);
44
49
  return TypedData_Wrap_Struct(klass, &Gyro_Async_type, async);
45
50
  }
46
51
 
47
- void Gyro_Async_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, int revents) {
48
- struct Gyro_Async *async = (struct Gyro_Async*)ev_async;
52
+ inline void Gyro_Async_activate(struct Gyro_Async *async) {
53
+ if (async->active) return;
49
54
 
50
- ev_async_stop(async->ev_loop, ev_async);
55
+ async->active = 1;
56
+ async->fiber = rb_fiber_current();
57
+ async->selector = Thread_current_event_selector();
58
+ async->ev_loop = Gyro_Selector_ev_loop(async->selector);
59
+ Gyro_Selector_add_active_watcher(async->selector, async->self);
60
+ ev_async_start(async->ev_loop, &async->ev_async);
61
+ }
62
+
63
+ inline void Gyro_Async_deactivate(struct Gyro_Async *async) {
64
+ if (!async->active) return;
65
+
66
+ ev_async_stop(async->ev_loop, &async->ev_async);
67
+ Gyro_Selector_remove_active_watcher(async->selector, async->self);
51
68
  async->active = 0;
69
+ async->ev_loop = 0;
70
+ async->selector = Qnil;
71
+ async->fiber = Qnil;
72
+ async->value = Qnil;
73
+ }
52
74
 
53
- if (async->fiber != Qnil) {
54
- Gyro_schedule_fiber(async->fiber, async->value);
55
- async->fiber = Qnil;
56
- async->value = Qnil;
57
- }
75
+ void Gyro_Async_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, int revents) {
76
+ struct Gyro_Async *async = (struct Gyro_Async*)ev_async;
77
+
78
+ Fiber_make_runnable(async->fiber, async->value);
79
+ Gyro_Async_deactivate(async);
58
80
  }
59
81
 
60
82
  #define GetGyro_Async(obj, async) \
@@ -64,12 +86,14 @@ static VALUE Gyro_Async_initialize(VALUE self) {
64
86
  struct Gyro_Async *async;
65
87
  GetGyro_Async(self, async);
66
88
 
89
+ async->self = self;
67
90
  async->fiber = Qnil;
68
91
  async->value = Qnil;
92
+ async->selector = Qnil;
69
93
  async->active = 0;
94
+ async->ev_loop = 0;
70
95
 
71
96
  ev_async_init(&async->ev_async, Gyro_Async_callback);
72
- async->ev_loop = 0;
73
97
 
74
98
  return Qnil;
75
99
  }
@@ -79,7 +103,7 @@ static VALUE Gyro_Async_signal(int argc, VALUE *argv, VALUE self) {
79
103
  GetGyro_Async(self, async);
80
104
 
81
105
  if (!async->active) {
82
- // printf("signal! called before await\n");
106
+ // printf("signal called before await\n");
83
107
  return Qnil;
84
108
  }
85
109
 
@@ -91,68 +115,34 @@ static VALUE Gyro_Async_signal(int argc, VALUE *argv, VALUE self) {
91
115
 
92
116
  VALUE Gyro_Async_await(VALUE self) {
93
117
  struct Gyro_Async *async;
94
- VALUE ret;
95
-
96
118
  GetGyro_Async(self, async);
97
119
 
98
- async->fiber = rb_fiber_current();
99
- if (!async->active) {
100
- async->active = 1;
101
- async->ev_loop = Gyro_Selector_current_thread_ev_loop();
102
- ev_async_start(async->ev_loop, &async->ev_async);
103
- }
120
+ Gyro_Async_activate(async);
121
+ VALUE ret = Gyro_switchpoint();
122
+ Gyro_Async_deactivate(async);
104
123
 
105
- ret = Fiber_await();
124
+ TEST_RESUME_EXCEPTION(ret);
106
125
  RB_GC_GUARD(ret);
107
-
108
- if (async->active) {
109
- async->active = 0;
110
- async->fiber = Qnil;
111
- ev_async_stop(async->ev_loop, &async->ev_async);
112
- async->value = Qnil;
113
- }
114
-
115
- // fiber is resumed
116
- if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
117
- return rb_funcall(rb_mKernel, ID_raise, 1, ret);
118
- }
119
- else {
120
- return ret;
121
- }
126
+ return ret;
122
127
  }
123
128
 
124
129
  VALUE Gyro_Async_await_no_raise(VALUE self) {
125
130
  struct Gyro_Async *async;
126
- VALUE ret;
127
-
128
131
  GetGyro_Async(self, async);
129
132
 
130
- async->fiber = rb_fiber_current();
131
- if (!async->active) {
132
- async->active = 1;
133
- async->ev_loop = Gyro_Selector_current_thread_ev_loop();
134
- ev_async_start(async->ev_loop, &async->ev_async);
135
- }
136
-
137
- ret = Fiber_await();
133
+ Gyro_Async_activate(async);
134
+ VALUE ret = Gyro_switchpoint();
135
+ Gyro_Async_deactivate(async);
136
+
138
137
  RB_GC_GUARD(ret);
139
-
140
- if (async->active) {
141
- async->active = 0;
142
- async->fiber = Qnil;
143
- ev_async_stop(async->ev_loop, &async->ev_async);
144
- async->value = Qnil;
145
- }
146
-
147
138
  return ret;
148
139
  }
149
140
 
150
-
151
141
  void Init_Gyro_Async() {
152
142
  cGyro_Async = rb_define_class_under(mGyro, "Async", rb_cData);
153
143
  rb_define_alloc_func(cGyro_Async, Gyro_Async_allocate);
154
144
 
155
145
  rb_define_method(cGyro_Async, "initialize", Gyro_Async_initialize, 0);
156
- rb_define_method(cGyro_Async, "signal!", Gyro_Async_signal, -1);
146
+ rb_define_method(cGyro_Async, "signal", Gyro_Async_signal, -1);
157
147
  rb_define_method(cGyro_Async, "await", Gyro_Async_await, 0);
158
148
  }
data/ext/gyro/child.c CHANGED
@@ -7,6 +7,7 @@ struct Gyro_Child {
7
7
  int pid;
8
8
  VALUE self;
9
9
  VALUE fiber;
10
+ VALUE selector;
10
11
  };
11
12
 
12
13
  static VALUE cGyro_Child = Qnil;
@@ -16,12 +17,16 @@ static void Gyro_Child_mark(void *ptr) {
16
17
  if (child->fiber != Qnil) {
17
18
  rb_gc_mark(child->fiber);
18
19
  }
20
+ if (child->selector != Qnil) {
21
+ rb_gc_mark(child->selector);
22
+ }
19
23
  }
20
24
 
21
25
  static void Gyro_Child_free(void *ptr) {
22
26
  struct Gyro_Child *child = ptr;
23
27
  if (child->active) {
24
- printf("Child watcher garbage collected while still active!\n");
28
+ ev_clear_pending(child->ev_loop, &child->ev_child);
29
+ ev_child_stop(child->ev_loop, &child->ev_child);
25
30
  }
26
31
  xfree(child);
27
32
  }
@@ -33,31 +38,51 @@ static size_t Gyro_Child_size(const void *ptr) {
33
38
  static const rb_data_type_t Gyro_Child_type = {
34
39
  "Gyro_Child",
35
40
  {Gyro_Child_mark, Gyro_Child_free, Gyro_Child_size,},
36
- 0, 0,
37
- RUBY_TYPED_FREE_IMMEDIATELY,
41
+ 0, 0, 0
38
42
  };
39
43
 
40
44
  static VALUE Gyro_Child_allocate(VALUE klass) {
41
- struct Gyro_Child *child = (struct Gyro_Child *)xmalloc(sizeof(struct Gyro_Child));
45
+ struct Gyro_Child *child = ALLOC(struct Gyro_Child);
42
46
  return TypedData_Wrap_Struct(klass, &Gyro_Child_type, child);
43
47
  }
44
48
 
49
+ inline void Gyro_Child_activate(struct Gyro_Child *child) {
50
+ if (child->active) return;
51
+
52
+ child->active = 1;
53
+ child->fiber = rb_fiber_current();
54
+ child->selector = Thread_current_event_selector();
55
+ child->ev_loop = Gyro_Selector_ev_loop(child->selector);
56
+ Gyro_Selector_add_active_watcher(child->selector, child->self);
57
+ ev_child_start(child->ev_loop, &child->ev_child);
58
+ }
59
+
60
+ inline void Gyro_Child_deactivate(struct Gyro_Child *child) {
61
+ if (!child->active) return;
62
+
63
+ ev_child_stop(child->ev_loop, &child->ev_child);
64
+ Gyro_Selector_remove_active_watcher(child->selector, child->self);
65
+ child->active = 0;
66
+ child->ev_loop = 0;
67
+ child->selector = Qnil;
68
+ child->fiber = Qnil;
69
+ }
70
+
71
+ VALUE Gyro_Child_resume_value(struct ev_child *ev_child) {
72
+ int exit_status = ev_child->rstatus >> 8; // weird, why should we do this?
73
+
74
+ return rb_ary_new_from_args(
75
+ 2, INT2NUM(ev_child->rpid), INT2NUM(exit_status)
76
+ );
77
+ }
78
+
45
79
  void Gyro_Child_callback(struct ev_loop *ev_loop, struct ev_child *ev_child, int revents) {
46
80
  struct Gyro_Child *child = (struct Gyro_Child*)ev_child;
47
81
 
48
- child->active = 0;
49
- ev_child_stop(child->ev_loop, ev_child);
82
+ VALUE resume_value = Gyro_Child_resume_value(ev_child);
83
+ Fiber_make_runnable(child->fiber, resume_value);
50
84
 
51
- if (child->fiber != Qnil) {
52
- VALUE fiber = child->fiber;
53
- int exit_status = ev_child->rstatus >> 8; // weird, why should we do this?
54
-
55
- VALUE resume_value = rb_ary_new_from_args(
56
- 2, INT2NUM(ev_child->rpid), INT2NUM(exit_status)
57
- );
58
- child->fiber = Qnil;
59
- Gyro_schedule_fiber(fiber, resume_value);
60
- }
85
+ Gyro_Child_deactivate(child);
61
86
  }
62
87
 
63
88
  #define GetGyro_Child(obj, child) \
@@ -70,8 +95,10 @@ static VALUE Gyro_Child_initialize(VALUE self, VALUE pid) {
70
95
 
71
96
  child->self = self;
72
97
  child->fiber = Qnil;
98
+ child->selector = Qnil;
73
99
  child->pid = NUM2INT(pid);
74
100
  child->active = 0;
101
+ child->ev_loop = 0;
75
102
 
76
103
  ev_child_init(&child->ev_child, Gyro_Child_callback, child->pid, 0);
77
104
 
@@ -80,32 +107,15 @@ static VALUE Gyro_Child_initialize(VALUE self, VALUE pid) {
80
107
 
81
108
  static VALUE Gyro_Child_await(VALUE self) {
82
109
  struct Gyro_Child *child;
83
- VALUE ret;
84
-
85
110
  GetGyro_Child(self, child);
86
111
 
87
- if (child->active)
88
- child->active = 1;
89
- child->fiber = rb_fiber_current();
90
- child->ev_loop = Gyro_Selector_current_thread_ev_loop();
91
- ev_child_start(child->ev_loop, &child->ev_child);
112
+ Gyro_Child_activate(child);
113
+ VALUE ret = Gyro_switchpoint();
114
+ Gyro_Child_deactivate(child);
92
115
 
93
- ret = Fiber_await();
116
+ TEST_RESUME_EXCEPTION(ret);
94
117
  RB_GC_GUARD(ret);
95
-
96
- if (child->active) {
97
- child->active = 0;
98
- child->fiber = Qnil;
99
- ev_child_stop(child->ev_loop, &child->ev_child);
100
- }
101
-
102
- // fiber is resumed, check if resumed value is an exception
103
- if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
104
- return rb_funcall(rb_mKernel, ID_raise, 1, ret);
105
- }
106
- else {
107
- return ret;
108
- }
118
+ return ret;
109
119
  }
110
120
 
111
121
  void Init_Gyro_Child() {
data/ext/gyro/fiber.c ADDED
@@ -0,0 +1,113 @@
1
+ #include "gyro.h"
2
+
3
+ ID ID_fiber_trace;
4
+ ID ID_ivar_auto_async;
5
+ ID ID_ivar_auto_io;
6
+ ID ID_trace_ev_loop_enter;
7
+ ID ID_trace_ev_loop_leave;
8
+ ID ID_trace_run;
9
+ ID ID_trace_runnable;
10
+ ID ID_trace_terminate;
11
+ ID ID_trace_wait;
12
+
13
+ VALUE SYM_dead;
14
+ VALUE SYM_running;
15
+ VALUE SYM_runnable;
16
+ VALUE SYM_waiting;
17
+
18
+ VALUE SYM_fiber_create;
19
+ VALUE SYM_fiber_ev_loop_enter;
20
+ VALUE SYM_fiber_ev_loop_leave;
21
+ VALUE SYM_fiber_run;
22
+ VALUE SYM_fiber_schedule;
23
+ VALUE SYM_fiber_switchpoint;
24
+ VALUE SYM_fiber_terminate;
25
+
26
+ static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self) {
27
+ VALUE arg = (argc == 0) ? Qnil : argv[0];
28
+ VALUE ret = rb_funcall(self, ID_transfer, 1, arg);
29
+
30
+ TEST_RESUME_EXCEPTION(ret);
31
+ RB_GC_GUARD(ret);
32
+ return ret;
33
+ }
34
+
35
+ inline VALUE Fiber_auto_async(VALUE self) {
36
+ VALUE async = rb_ivar_get(self, ID_ivar_auto_async);
37
+ if (async == Qnil) {
38
+ async = rb_funcall(cGyro_Async, ID_new, 0);
39
+ rb_ivar_set(self, ID_ivar_auto_async, async);
40
+ }
41
+ return async;
42
+ }
43
+
44
+ inline VALUE Fiber_auto_io(VALUE self) {
45
+ VALUE io = rb_ivar_get(self, ID_ivar_auto_io);
46
+ if (io == Qnil) {
47
+ io = rb_funcall(cGyro_IO, ID_new, 2, Qnil, Qnil);
48
+ rb_ivar_set(self, ID_ivar_auto_io, io);
49
+ }
50
+ return io;
51
+ }
52
+
53
+ static VALUE Fiber_schedule(int argc, VALUE *argv, VALUE self) {
54
+ VALUE value = (argc == 0) ? Qnil : argv[0];
55
+ Fiber_make_runnable(self, value);
56
+ return self;
57
+ }
58
+
59
+ static VALUE Fiber_state(VALUE self) {
60
+ if (!rb_fiber_alive_p(self) || (rb_ivar_get(self, ID_ivar_running) == Qfalse))
61
+ return SYM_dead;
62
+ if (rb_fiber_current() == self) return SYM_running;
63
+ if (rb_ivar_get(self, ID_runnable) != Qnil) return SYM_runnable;
64
+
65
+ return SYM_waiting;
66
+ }
67
+
68
+ void Fiber_make_runnable(VALUE fiber, VALUE value) {
69
+ VALUE thread = rb_ivar_get(fiber, ID_ivar_thread);
70
+ if (thread != Qnil) {
71
+ Thread_schedule_fiber(thread, fiber, value);
72
+ }
73
+ else {
74
+ rb_warn("No thread set for fiber");
75
+ }
76
+ }
77
+
78
+ void Init_Fiber() {
79
+ VALUE cFiber = rb_const_get(rb_cObject, rb_intern("Fiber"));
80
+ rb_define_method(cFiber, "auto_async", Fiber_auto_async, 0);
81
+ rb_define_method(cFiber, "safe_transfer", Fiber_safe_transfer, -1);
82
+ rb_define_method(cFiber, "schedule", Fiber_schedule, -1);
83
+ rb_define_method(cFiber, "state", Fiber_state, 0);
84
+
85
+ ID_ivar_auto_async = rb_intern("@auto_async");
86
+
87
+ SYM_dead = ID2SYM(rb_intern("dead"));
88
+ SYM_running = ID2SYM(rb_intern("running"));
89
+ SYM_runnable = ID2SYM(rb_intern("runnable"));
90
+ SYM_waiting = ID2SYM(rb_intern("waiting"));
91
+ rb_global_variable(&SYM_dead);
92
+ rb_global_variable(&SYM_running);
93
+ rb_global_variable(&SYM_runnable);
94
+ rb_global_variable(&SYM_waiting);
95
+
96
+ ID_fiber_trace = rb_intern("__fiber_trace__");
97
+
98
+ SYM_fiber_create = ID2SYM(rb_intern("fiber_create"));
99
+ SYM_fiber_ev_loop_enter = ID2SYM(rb_intern("fiber_ev_loop_enter"));
100
+ SYM_fiber_ev_loop_leave = ID2SYM(rb_intern("fiber_ev_loop_leave"));
101
+ SYM_fiber_run = ID2SYM(rb_intern("fiber_run"));
102
+ SYM_fiber_schedule = ID2SYM(rb_intern("fiber_schedule"));
103
+ SYM_fiber_switchpoint = ID2SYM(rb_intern("fiber_switchpoint"));
104
+ SYM_fiber_terminate = ID2SYM(rb_intern("fiber_terminate"));
105
+
106
+ rb_global_variable(&SYM_fiber_create);
107
+ rb_global_variable(&SYM_fiber_ev_loop_enter);
108
+ rb_global_variable(&SYM_fiber_ev_loop_leave);
109
+ rb_global_variable(&SYM_fiber_run);
110
+ rb_global_variable(&SYM_fiber_schedule);
111
+ rb_global_variable(&SYM_fiber_switchpoint);
112
+ rb_global_variable(&SYM_fiber_terminate);
113
+ }