polyphony 0.43.10 → 0.45.2

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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -1
  3. data/CHANGELOG.md +37 -0
  4. data/Gemfile.lock +16 -6
  5. data/Rakefile +1 -1
  6. data/TODO.md +15 -10
  7. data/docs/_posts/2020-07-26-polyphony-0.44.md +77 -0
  8. data/docs/api-reference/thread.md +1 -1
  9. data/docs/getting-started/overview.md +14 -14
  10. data/docs/getting-started/tutorial.md +1 -1
  11. data/examples/adapters/redis_client.rb +3 -1
  12. data/examples/adapters/redis_pubsub_perf.rb +11 -8
  13. data/examples/adapters/sequel_mysql.rb +23 -0
  14. data/examples/adapters/sequel_mysql_pool.rb +33 -0
  15. data/examples/adapters/sequel_pg.rb +24 -0
  16. data/examples/core/{02-awaiting-fibers.rb → await.rb} +0 -0
  17. data/examples/core/{xx-channels.rb → channels.rb} +0 -0
  18. data/examples/core/deferring-an-operation.rb +16 -0
  19. data/examples/core/{xx-erlang-style-genserver.rb → erlang-style-genserver.rb} +16 -9
  20. data/examples/core/{xx-forking.rb → forking.rb} +1 -1
  21. data/examples/core/handling-signals.rb +11 -0
  22. data/examples/core/{03-interrupting.rb → interrupt.rb} +0 -0
  23. data/examples/core/{xx-pingpong.rb → pingpong.rb} +7 -5
  24. data/examples/core/{xx-recurrent-timer.rb → recurrent-timer.rb} +1 -1
  25. data/examples/core/{xx-resource_delegate.rb → resource_delegate.rb} +3 -4
  26. data/examples/core/{01-spinning-up-fibers.rb → spin.rb} +1 -1
  27. data/examples/core/{xx-spin_error_backtrace.rb → spin_error_backtrace.rb} +1 -1
  28. data/examples/core/{xx-supervise-process.rb → supervise-process.rb} +8 -5
  29. data/examples/core/supervisor.rb +20 -0
  30. data/examples/core/{xx-thread-sleep.rb → thread-sleep.rb} +0 -0
  31. data/examples/core/{xx-thread_pool.rb → thread_pool.rb} +0 -0
  32. data/examples/core/{xx-throttling.rb → throttling.rb} +0 -0
  33. data/examples/core/{xx-timeout.rb → timeout.rb} +0 -0
  34. data/examples/core/{xx-using-a-mutex.rb → using-a-mutex.rb} +0 -0
  35. data/examples/core/{xx-worker-thread.rb → worker-thread.rb} +2 -2
  36. data/examples/io/{xx-backticks.rb → backticks.rb} +0 -0
  37. data/examples/io/{xx-echo_client.rb → echo_client.rb} +1 -1
  38. data/examples/io/{xx-echo_client_from_stdin.rb → echo_client_from_stdin.rb} +2 -2
  39. data/examples/io/{xx-echo_pipe.rb → echo_pipe.rb} +1 -1
  40. data/examples/io/{xx-echo_server.rb → echo_server.rb} +0 -0
  41. data/examples/io/{xx-echo_server_with_timeout.rb → echo_server_with_timeout.rb} +1 -1
  42. data/examples/io/{xx-echo_stdin.rb → echo_stdin.rb} +0 -0
  43. data/examples/io/{xx-happy-eyeballs.rb → happy-eyeballs.rb} +0 -0
  44. data/examples/io/{xx-httparty.rb → httparty.rb} +4 -13
  45. data/examples/io/{xx-irb.rb → irb.rb} +0 -0
  46. data/examples/io/{xx-net-http.rb → net-http.rb} +0 -0
  47. data/examples/io/{xx-open.rb → open.rb} +0 -0
  48. data/examples/io/pry.rb +18 -0
  49. data/examples/io/rack_server.rb +71 -0
  50. data/examples/io/{xx-system.rb → system.rb} +1 -1
  51. data/examples/io/{xx-tcpserver.rb → tcpserver.rb} +0 -0
  52. data/examples/io/{xx-tcpsocket.rb → tcpsocket.rb} +0 -0
  53. data/examples/io/tunnel.rb +6 -1
  54. data/examples/io/{xx-zip.rb → zip.rb} +0 -0
  55. data/examples/performance/fiber_transfer.rb +2 -1
  56. data/examples/performance/fs_read.rb +5 -6
  57. data/examples/{io/xx-switch.rb → performance/switch.rb} +2 -1
  58. data/examples/performance/thread-vs-fiber/{xx-httparty_multi.rb → httparty_multi.rb} +3 -4
  59. data/examples/performance/thread-vs-fiber/{xx-httparty_threaded.rb → httparty_threaded.rb} +0 -0
  60. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +1 -1
  61. data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -1
  62. data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +1 -1
  63. data/examples/performance/thread-vs-fiber/threaded_server.rb +1 -5
  64. data/examples/performance/thread_pool_perf.rb +6 -7
  65. data/ext/polyphony/backend.h +40 -0
  66. data/ext/polyphony/event.c +3 -3
  67. data/ext/polyphony/extconf.rb +1 -1
  68. data/ext/polyphony/fiber.c +66 -6
  69. data/ext/polyphony/{libev_agent.c → libev_backend.c} +239 -235
  70. data/ext/polyphony/polyphony.c +3 -3
  71. data/ext/polyphony/polyphony.h +15 -23
  72. data/ext/polyphony/polyphony_ext.c +3 -4
  73. data/ext/polyphony/queue.c +25 -12
  74. data/ext/polyphony/ring_buffer.c +0 -1
  75. data/ext/polyphony/thread.c +36 -33
  76. data/lib/polyphony.rb +25 -38
  77. data/lib/polyphony/adapters/fs.rb +1 -1
  78. data/lib/polyphony/adapters/irb.rb +2 -17
  79. data/lib/polyphony/adapters/mysql2.rb +19 -0
  80. data/lib/polyphony/adapters/postgres.rb +5 -5
  81. data/lib/polyphony/adapters/process.rb +2 -2
  82. data/lib/polyphony/adapters/readline.rb +17 -0
  83. data/lib/polyphony/adapters/redis.rb +1 -1
  84. data/lib/polyphony/adapters/sequel.rb +45 -0
  85. data/lib/polyphony/core/exceptions.rb +11 -0
  86. data/lib/polyphony/core/global_api.rb +17 -12
  87. data/lib/polyphony/core/resource_pool.rb +20 -7
  88. data/lib/polyphony/core/sync.rb +46 -8
  89. data/lib/polyphony/core/throttler.rb +1 -1
  90. data/lib/polyphony/extensions/core.rb +38 -25
  91. data/lib/polyphony/extensions/fiber.rb +12 -45
  92. data/lib/polyphony/extensions/io.rb +45 -12
  93. data/lib/polyphony/extensions/openssl.rb +6 -6
  94. data/lib/polyphony/extensions/socket.rb +22 -15
  95. data/lib/polyphony/extensions/thread.rb +6 -5
  96. data/lib/polyphony/net.rb +2 -1
  97. data/lib/polyphony/version.rb +1 -1
  98. data/polyphony.gemspec +7 -3
  99. data/test/helper.rb +1 -1
  100. data/test/{test_agent.rb → test_backend.rb} +22 -22
  101. data/test/test_fiber.rb +28 -11
  102. data/test/test_io.rb +17 -1
  103. data/test/test_kernel.rb +5 -0
  104. data/test/test_resource_pool.rb +50 -16
  105. data/test/test_signal.rb +5 -29
  106. data/test/test_socket.rb +17 -0
  107. data/test/test_sync.rb +52 -0
  108. metadata +126 -98
  109. data/.gitbook.yaml +0 -4
  110. data/examples/adapters/concurrent-ruby.rb +0 -9
  111. data/examples/core/04-handling-signals.rb +0 -19
  112. data/examples/core/xx-agent.rb +0 -102
  113. data/examples/core/xx-at_exit.rb +0 -29
  114. data/examples/core/xx-caller.rb +0 -12
  115. data/examples/core/xx-daemon.rb +0 -14
  116. data/examples/core/xx-deadlock.rb +0 -8
  117. data/examples/core/xx-deferring-an-operation.rb +0 -14
  118. data/examples/core/xx-exception-backtrace.rb +0 -40
  119. data/examples/core/xx-fork-cleanup.rb +0 -22
  120. data/examples/core/xx-fork-spin.rb +0 -42
  121. data/examples/core/xx-fork-terminate.rb +0 -27
  122. data/examples/core/xx-move_on.rb +0 -23
  123. data/examples/core/xx-queue-async.rb +0 -120
  124. data/examples/core/xx-readpartial.rb +0 -18
  125. data/examples/core/xx-signals.rb +0 -16
  126. data/examples/core/xx-sleep-forever.rb +0 -9
  127. data/examples/core/xx-sleeping.rb +0 -25
  128. data/examples/core/xx-snooze-starve.rb +0 -16
  129. data/examples/core/xx-spin-fork.rb +0 -49
  130. data/examples/core/xx-state-machine.rb +0 -51
  131. data/examples/core/xx-stop.rb +0 -20
  132. data/examples/core/xx-supervisors.rb +0 -21
  133. data/examples/core/xx-thread-selector-sleep.rb +0 -51
  134. data/examples/core/xx-thread-selector-snooze.rb +0 -46
  135. data/examples/core/xx-thread-snooze.rb +0 -34
  136. data/examples/core/xx-timer-gc.rb +0 -17
  137. data/examples/core/xx-trace.rb +0 -79
  138. data/examples/performance/xx-array.rb +0 -11
  139. data/examples/performance/xx-fiber-switch.rb +0 -9
  140. data/examples/performance/xx-snooze.rb +0 -15
  141. data/examples/xx-spin.rb +0 -32
  142. data/ext/polyphony/agent.h +0 -39
@@ -7,8 +7,8 @@ ID ID_caller;
7
7
  ID ID_clear;
8
8
  ID ID_each;
9
9
  ID ID_inspect;
10
+ ID ID_invoke;
10
11
  ID ID_new;
11
- ID ID_raise;
12
12
  ID ID_ivar_running;
13
13
  ID ID_ivar_thread;
14
14
  ID ID_runnable;
@@ -21,7 +21,7 @@ ID ID_R;
21
21
  ID ID_W;
22
22
  ID ID_RW;
23
23
 
24
- agent_interface_t agent_interface;
24
+ backend_interface_t backend_interface;
25
25
 
26
26
  VALUE Polyphony_snooze(VALUE self) {
27
27
  VALUE ret;
@@ -60,10 +60,10 @@ void Init_Polyphony() {
60
60
  ID_clear = rb_intern("clear");
61
61
  ID_each = rb_intern("each");
62
62
  ID_inspect = rb_intern("inspect");
63
+ ID_invoke = rb_intern("invoke");
63
64
  ID_ivar_running = rb_intern("@running");
64
65
  ID_ivar_thread = rb_intern("@thread");
65
66
  ID_new = rb_intern("new");
66
- ID_raise = rb_intern("raise");
67
67
  ID_runnable = rb_intern("runnable");
68
68
  ID_runnable_value = rb_intern("runnable_value");
69
69
  ID_signal = rb_intern("signal");
@@ -4,26 +4,28 @@
4
4
  #include "ruby.h"
5
5
  #include "ruby/io.h"
6
6
  #include "libev.h"
7
- #include "agent.h"
7
+ #include "backend.h"
8
8
 
9
9
  // debugging
10
10
  #define OBJ_ID(obj) (NUM2LONG(rb_funcall(obj, rb_intern("object_id"), 0)))
11
- #define INSPECT(obj) { VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf("%s\n", StringValueCStr(s));}
12
- #define FIBER_TRACE(...) if (__tracing_enabled__) { \
13
- rb_funcall(rb_cObject, ID_fiber_trace, __VA_ARGS__); \
11
+ #define INSPECT(str, obj) { printf(str); VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf("%s\n", StringValueCStr(s)); }
12
+ #define TRACE_CALLER() { VALUE c = rb_funcall(rb_mKernel, rb_intern("caller"), 0); INSPECT("caller: ", c); }
13
+
14
+ // tracing
15
+ #define TRACE(...) rb_funcall(rb_cObject, ID_fiber_trace, __VA_ARGS__)
16
+ #define COND_TRACE(...) if (__tracing_enabled__) { \
17
+ TRACE(__VA_ARGS__); \
14
18
  }
15
19
 
16
20
  #define TEST_EXCEPTION(ret) (RTEST(rb_obj_is_kind_of(ret, rb_eException)))
17
21
 
22
+ #define RAISE_EXCEPTION(e) rb_funcall(e, ID_invoke, 0);
18
23
  #define TEST_RESUME_EXCEPTION(ret) if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) { \
19
- return rb_funcall(rb_mKernel, ID_raise, 1, ret); \
24
+ return RAISE_EXCEPTION(ret); \
20
25
  }
21
26
 
22
- extern agent_interface_t agent_interface;
23
- // #define __AGENT_PASTER__(call) (agent_interface ## . ## call)
24
- // #define __AGENT__(call) __AGENT_PASTER__(call)
25
- #define __AGENT__ (agent_interface)
26
-
27
+ extern backend_interface_t backend_interface;
28
+ #define __BACKEND__ (backend_interface)
27
29
 
28
30
  extern VALUE mPolyphony;
29
31
  extern VALUE cQueue;
@@ -35,7 +37,8 @@ extern ID ID_clear;
35
37
  extern ID ID_each;
36
38
  extern ID ID_fiber_trace;
37
39
  extern ID ID_inspect;
38
- extern ID ID_ivar_agent;
40
+ extern ID ID_invoke;
41
+ extern ID ID_ivar_backend;
39
42
  extern ID ID_ivar_running;
40
43
  extern ID ID_ivar_thread;
41
44
  extern ID ID_new;
@@ -63,31 +66,20 @@ enum {
63
66
  FIBER_STATE_SCHEDULED = 2
64
67
  };
65
68
 
66
- // watcher flags
67
- enum {
68
- // a watcher's active field will be set to this after fork
69
- GYRO_WATCHER_POST_FORK = 0xFF
70
- };
71
-
72
69
  VALUE Fiber_auto_watcher(VALUE self);
73
70
  void Fiber_make_runnable(VALUE fiber, VALUE value);
74
71
 
75
72
  VALUE Queue_push(VALUE self, VALUE value);
76
73
  VALUE Queue_unshift(VALUE self, VALUE value);
77
74
  VALUE Queue_shift(VALUE self);
75
+ VALUE Queue_shift_all(VALUE self);
78
76
  VALUE Queue_shift_no_wait(VALUE self);
79
77
  VALUE Queue_clear(VALUE self);
80
78
  VALUE Queue_delete(VALUE self, VALUE value);
81
79
  long Queue_len(VALUE self);
82
80
  void Queue_trace(VALUE self);
83
81
 
84
- VALUE Polyphony_snooze(VALUE self);
85
-
86
82
  VALUE Thread_schedule_fiber(VALUE thread, VALUE fiber, VALUE value);
87
83
  VALUE Thread_switch_fiber(VALUE thread);
88
84
 
89
- int io_setstrbuf(VALUE *str, long len);
90
- void io_set_read_length(VALUE str, long n, int shrinkable);
91
- VALUE io_enc_str(VALUE str, rb_io_t *fptr);
92
-
93
85
  #endif /* POLYPHONY_H */
@@ -2,7 +2,7 @@
2
2
 
3
3
  void Init_Fiber();
4
4
  void Init_Polyphony();
5
- void Init_LibevAgent();
5
+ void Init_LibevBackend();
6
6
  void Init_Queue();
7
7
  void Init_Event();
8
8
  void Init_Thread();
@@ -12,12 +12,11 @@ void Init_polyphony_ext() {
12
12
  ev_set_allocator(xrealloc);
13
13
 
14
14
  Init_Polyphony();
15
- Init_LibevAgent();
15
+
16
+ Init_LibevBackend();
16
17
  Init_Queue();
17
18
  Init_Event();
18
-
19
19
  Init_Fiber();
20
20
  Init_Thread();
21
-
22
21
  Init_Tracing();
23
22
  }
@@ -54,6 +54,7 @@ static VALUE Queue_initialize(VALUE self) {
54
54
  VALUE Queue_push(VALUE self, VALUE value) {
55
55
  Queue_t *queue;
56
56
  GetQueue(self, queue);
57
+
57
58
  if (queue->shift_queue.count > 0) {
58
59
  VALUE fiber = ring_buffer_shift(&queue->shift_queue);
59
60
  if (fiber != Qnil) Fiber_make_runnable(fiber, Qnil);
@@ -77,21 +78,25 @@ VALUE Queue_shift(VALUE self) {
77
78
  Queue_t *queue;
78
79
  GetQueue(self, queue);
79
80
 
80
- if (queue->values.count == 0) {
81
- VALUE agent = rb_ivar_get(rb_thread_current(), ID_ivar_agent);
82
- VALUE fiber = rb_fiber_current();
83
- VALUE switchpoint_result = Qnil;
81
+ VALUE fiber = rb_fiber_current();
82
+ VALUE thread = rb_thread_current();
83
+ VALUE backend = rb_ivar_get(thread, ID_ivar_backend);
84
+
85
+ while (1) {
84
86
  ring_buffer_push(&queue->shift_queue, fiber);
85
- switchpoint_result = __AGENT__.wait_event(agent, Qnil);
86
- if (RTEST(rb_obj_is_kind_of(switchpoint_result, rb_eException))) {
87
- ring_buffer_delete(&queue->shift_queue, fiber);
88
- return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
89
- }
90
- RB_GC_GUARD(agent);
87
+ if (queue->values.count > 0) Fiber_make_runnable(fiber, Qnil);
88
+
89
+ VALUE switchpoint_result = __BACKEND__.wait_event(backend, Qnil);
90
+ ring_buffer_delete(&queue->shift_queue, fiber);
91
+
92
+ TEST_RESUME_EXCEPTION(switchpoint_result);
91
93
  RB_GC_GUARD(switchpoint_result);
94
+
95
+ if (queue->values.count > 0)
96
+ return ring_buffer_shift(&queue->values);
92
97
  }
93
98
 
94
- return ring_buffer_shift(&queue->values);
99
+ return Qnil;
95
100
  }
96
101
 
97
102
  VALUE Queue_shift_no_wait(VALUE self) {
@@ -146,7 +151,7 @@ VALUE Queue_flush_waiters(VALUE self, VALUE value) {
146
151
  while(1) {
147
152
  VALUE fiber = ring_buffer_shift(&queue->shift_queue);
148
153
  if (fiber == Qnil) return self;
149
-
154
+
150
155
  Fiber_make_runnable(fiber, value);
151
156
  }
152
157
  }
@@ -158,6 +163,13 @@ VALUE Queue_empty_p(VALUE self) {
158
163
  return (queue->values.count == 0) ? Qtrue : Qfalse;
159
164
  }
160
165
 
166
+ VALUE Queue_pending_p(VALUE self) {
167
+ Queue_t *queue;
168
+ GetQueue(self, queue);
169
+
170
+ return (queue->shift_queue.count > 0) ? Qtrue : Qfalse;
171
+ }
172
+
161
173
  VALUE Queue_size_m(VALUE self) {
162
174
  Queue_t *queue;
163
175
  GetQueue(self, queue);
@@ -190,5 +202,6 @@ void Init_Queue() {
190
202
  rb_define_method(cQueue, "shift_all", Queue_shift_all, 0);
191
203
  rb_define_method(cQueue, "flush_waiters", Queue_flush_waiters, 1);
192
204
  rb_define_method(cQueue, "empty?", Queue_empty_p, 0);
205
+ rb_define_method(cQueue, "pending?", Queue_pending_p, 0);
193
206
  rb_define_method(cQueue, "size", Queue_size_m, 0);
194
207
  }
@@ -24,7 +24,6 @@ VALUE ring_buffer_shift(ring_buffer *buffer) {
24
24
  value = buffer->entries[buffer->head];
25
25
  buffer->head = (buffer->head + 1) % buffer->size;
26
26
  buffer->count--;
27
- // INSPECT(value);
28
27
  return value;
29
28
  }
30
29
 
@@ -1,7 +1,7 @@
1
1
  #include "polyphony.h"
2
2
 
3
3
  ID ID_deactivate_all_watchers_post_fork;
4
- ID ID_ivar_agent;
4
+ ID ID_ivar_backend;
5
5
  ID ID_ivar_join_wait_queue;
6
6
  ID ID_ivar_main_fiber;
7
7
  ID ID_ivar_result;
@@ -12,7 +12,7 @@ ID ID_stop;
12
12
 
13
13
  static VALUE Thread_setup_fiber_scheduling(VALUE self) {
14
14
  VALUE queue = rb_funcall(cQueue, ID_new, 0);
15
-
15
+
16
16
  rb_ivar_set(self, ID_ivar_main_fiber, rb_fiber_current());
17
17
  rb_ivar_set(self, ID_run_queue, queue);
18
18
 
@@ -20,20 +20,20 @@ static VALUE Thread_setup_fiber_scheduling(VALUE self) {
20
20
  }
21
21
 
22
22
  int Thread_fiber_ref_count(VALUE self) {
23
- VALUE agent = rb_ivar_get(self, ID_ivar_agent);
24
- return NUM2INT(__AGENT__.ref_count(agent));
23
+ VALUE backend = rb_ivar_get(self, ID_ivar_backend);
24
+ return NUM2INT(__BACKEND__.ref_count(backend));
25
25
  }
26
26
 
27
27
  inline void Thread_fiber_reset_ref_count(VALUE self) {
28
- VALUE agent = rb_ivar_get(self, ID_ivar_agent);
29
- __AGENT__.reset_ref_count(agent);
28
+ VALUE backend = rb_ivar_get(self, ID_ivar_backend);
29
+ __BACKEND__.reset_ref_count(backend);
30
30
  }
31
31
 
32
32
  static VALUE SYM_scheduled_fibers;
33
33
  static VALUE SYM_pending_watchers;
34
34
 
35
35
  static VALUE Thread_fiber_scheduling_stats(VALUE self) {
36
- VALUE agent = rb_ivar_get(self,ID_ivar_agent);
36
+ VALUE backend = rb_ivar_get(self,ID_ivar_backend);
37
37
  VALUE stats = rb_hash_new();
38
38
  VALUE queue = rb_ivar_get(self, ID_run_queue);
39
39
  long pending_count;
@@ -41,7 +41,7 @@ static VALUE Thread_fiber_scheduling_stats(VALUE self) {
41
41
  long scheduled_count = RARRAY_LEN(queue);
42
42
  rb_hash_aset(stats, SYM_scheduled_fibers, INT2NUM(scheduled_count));
43
43
 
44
- pending_count = __AGENT__.pending_count(agent);
44
+ pending_count = __BACKEND__.pending_count(backend);
45
45
  rb_hash_aset(stats, SYM_pending_watchers, INT2NUM(pending_count));
46
46
 
47
47
  return stats;
@@ -64,7 +64,7 @@ VALUE Thread_schedule_fiber(VALUE self, VALUE fiber, VALUE value) {
64
64
  }
65
65
 
66
66
  rb_ivar_set(fiber, ID_runnable_value, value);
67
- FIBER_TRACE(3, SYM_fiber_schedule, fiber, value);
67
+ COND_TRACE(3, SYM_fiber_schedule, fiber, value);
68
68
 
69
69
  if (!already_runnable) {
70
70
  queue = rb_ivar_get(self, ID_run_queue);
@@ -77,8 +77,8 @@ VALUE Thread_schedule_fiber(VALUE self, VALUE fiber, VALUE value) {
77
77
  // event selector. Otherwise it's gonna be stuck waiting for an event to
78
78
  // happen, not knowing that it there's already a fiber ready to run in its
79
79
  // run queue.
80
- VALUE agent = rb_ivar_get(self,ID_ivar_agent);
81
- __AGENT__.wakeup(agent);
80
+ VALUE backend = rb_ivar_get(self,ID_ivar_backend);
81
+ __BACKEND__.wakeup(backend);
82
82
  }
83
83
  }
84
84
  return self;
@@ -89,7 +89,7 @@ VALUE Thread_schedule_fiber_with_priority(VALUE self, VALUE fiber, VALUE value)
89
89
 
90
90
  if (rb_fiber_alive_p(fiber) != Qtrue) return self;
91
91
 
92
- FIBER_TRACE(3, SYM_fiber_schedule, fiber, value);
92
+ COND_TRACE(3, SYM_fiber_schedule, fiber, value);
93
93
  rb_ivar_set(fiber, ID_runnable_value, value);
94
94
 
95
95
  queue = rb_ivar_get(self, ID_run_queue);
@@ -110,8 +110,8 @@ VALUE Thread_schedule_fiber_with_priority(VALUE self, VALUE fiber, VALUE value)
110
110
  // event loop. Otherwise it's gonna be stuck waiting for an event to
111
111
  // happen, not knowing that it there's already a fiber ready to run in its
112
112
  // run queue.
113
- VALUE agent = rb_ivar_get(self, ID_ivar_agent);
114
- __AGENT__.wakeup(agent);
113
+ VALUE backend = rb_ivar_get(self, ID_ivar_backend);
114
+ __BACKEND__.wakeup(backend);
115
115
  }
116
116
  return self;
117
117
  }
@@ -121,43 +121,39 @@ VALUE Thread_switch_fiber(VALUE self) {
121
121
  VALUE queue = rb_ivar_get(self, ID_run_queue);
122
122
  VALUE next_fiber;
123
123
  VALUE value;
124
- VALUE agent = rb_ivar_get(self, ID_ivar_agent);
124
+ VALUE backend = rb_ivar_get(self, ID_ivar_backend);
125
125
  int ref_count;
126
- int agent_was_polled = 0;1;
126
+ int backend_was_polled = 0;
127
127
 
128
- if (__tracing_enabled__) {
129
- if (rb_ivar_get(current_fiber, ID_ivar_running) != Qfalse) {
130
- rb_funcall(rb_cObject, ID_fiber_trace, 2, SYM_fiber_switchpoint, current_fiber);
131
- }
132
- }
128
+ if (__tracing_enabled__ && (rb_ivar_get(current_fiber, ID_ivar_running) != Qfalse))
129
+ TRACE(2, SYM_fiber_switchpoint, current_fiber);
133
130
 
134
- ref_count = __AGENT__.ref_count(agent);
131
+ ref_count = __BACKEND__.ref_count(backend);
135
132
  while (1) {
136
133
  next_fiber = Queue_shift_no_wait(queue);
137
134
  if (next_fiber != Qnil) {
138
- if (agent_was_polled == 0 && ref_count > 0) {
139
- // this mechanism prevents event starvation in case the run queue never
140
- // empties
141
- __AGENT__.poll(agent, Qtrue, current_fiber, queue);
135
+ if (backend_was_polled == 0 && ref_count > 0) {
136
+ // this prevents event starvation in case the run queue never empties
137
+ __BACKEND__.poll(backend, Qtrue, current_fiber, queue);
142
138
  }
143
139
  break;
144
140
  }
145
141
  if (ref_count == 0) break;
146
142
 
147
- __AGENT__.poll(agent, Qnil, current_fiber, queue);
148
- agent_was_polled = 1;
143
+ __BACKEND__.poll(backend, Qnil, current_fiber, queue);
144
+ backend_was_polled = 1;
149
145
  }
150
146
 
151
147
  if (next_fiber == Qnil) return Qnil;
152
148
 
153
149
  // run next fiber
154
150
  value = rb_ivar_get(next_fiber, ID_runnable_value);
155
- FIBER_TRACE(3, SYM_fiber_run, next_fiber, value);
151
+ COND_TRACE(3, SYM_fiber_run, next_fiber, value);
156
152
 
157
153
  rb_ivar_set(next_fiber, ID_runnable, Qnil);
158
154
  RB_GC_GUARD(next_fiber);
159
155
  RB_GC_GUARD(value);
160
- return (next_fiber == current_fiber) ?
156
+ return (next_fiber == current_fiber) ?
161
157
  value : rb_funcall(next_fiber, ID_transfer, 1, value);
162
158
  }
163
159
 
@@ -175,12 +171,12 @@ VALUE Thread_reset_fiber_scheduling(VALUE self) {
175
171
  }
176
172
 
177
173
  VALUE Thread_fiber_break_out_of_ev_loop(VALUE self, VALUE fiber, VALUE resume_obj) {
178
- VALUE agent = rb_ivar_get(self, ID_ivar_agent);
174
+ VALUE backend = rb_ivar_get(self, ID_ivar_backend);
179
175
  if (fiber != Qnil) {
180
176
  Thread_schedule_fiber_with_priority(self, fiber, resume_obj);
181
177
  }
182
178
 
183
- if (__AGENT__.wakeup(agent) == Qnil) {
179
+ if (__BACKEND__.wakeup(backend) == Qnil) {
184
180
  // we're not inside the ev_loop, so we just do a switchpoint
185
181
  Thread_switch_fiber(self);
186
182
  }
@@ -188,6 +184,11 @@ VALUE Thread_fiber_break_out_of_ev_loop(VALUE self, VALUE fiber, VALUE resume_ob
188
184
  return self;
189
185
  }
190
186
 
187
+ VALUE Thread_debug(VALUE self) {
188
+ rb_ivar_set(self, rb_intern("@__debug__"), Qtrue);
189
+ return self;
190
+ }
191
+
191
192
  void Init_Thread() {
192
193
  rb_define_method(rb_cThread, "setup_fiber_scheduling", Thread_setup_fiber_scheduling, 0);
193
194
  rb_define_method(rb_cThread, "reset_fiber_scheduling", Thread_reset_fiber_scheduling, 0);
@@ -200,8 +201,10 @@ void Init_Thread() {
200
201
  rb_define_method(rb_cThread, "switch_fiber", Thread_switch_fiber, 0);
201
202
  rb_define_method(rb_cThread, "run_queue_trace", Thread_run_queue_trace, 0);
202
203
 
204
+ rb_define_method(rb_cThread, "debug!", Thread_debug, 0);
205
+
203
206
  ID_deactivate_all_watchers_post_fork = rb_intern("deactivate_all_watchers_post_fork");
204
- ID_ivar_agent = rb_intern("@agent");
207
+ ID_ivar_backend = rb_intern("@backend");
205
208
  ID_ivar_join_wait_queue = rb_intern("@join_wait_queue");
206
209
  ID_ivar_main_fiber = rb_intern("@main_fiber");
207
210
  ID_ivar_result = rb_intern("@result");
@@ -3,50 +3,36 @@
3
3
  require 'fiber'
4
4
  require_relative './polyphony_ext'
5
5
 
6
- module Polyphony
7
- # replace core Queue class with our own
8
- verbose = $VERBOSE
9
- $VERBOSE = nil
10
- Object.const_set(:Queue, Polyphony::Queue)
11
- $VERBOSE = verbose
12
- end
13
-
14
6
  require_relative './polyphony/extensions/core'
15
7
  require_relative './polyphony/extensions/thread'
16
8
  require_relative './polyphony/extensions/fiber'
17
9
  require_relative './polyphony/extensions/io'
18
10
 
19
11
  Thread.current.setup_fiber_scheduling
20
- Thread.current.agent = Polyphony::Agent.new
12
+ Thread.current.backend = Polyphony::Backend.new
21
13
 
22
14
  require_relative './polyphony/core/global_api'
23
15
  require_relative './polyphony/core/resource_pool'
16
+ require_relative './polyphony/core/sync'
24
17
  require_relative './polyphony/net'
25
18
  require_relative './polyphony/adapters/process'
26
19
 
27
- # Main Polyphony API
20
+ # Polyphony API
28
21
  module Polyphony
29
22
  class << self
30
- def wait_for_signal(sig)
31
- raise "should be reimplemented"
32
-
33
- fiber = Fiber.current
34
- # Polyphony.ref
35
- old_trap = trap(sig) do
36
- # Polyphony.unref
37
- fiber.schedule(sig)
38
- trap(sig, old_trap)
39
- end
40
- suspend
41
-
42
- end
43
-
44
23
  def fork(&block)
45
24
  Kernel.fork do
46
- # # Since the fiber doing the fork will become the main fiber of the
47
- # # forked process, we leave it behind by transferring to a new fiber
48
- # # created in the context of the forked process, which rescues *all*
49
- # # exceptions, including Interrupt and SystemExit.
25
+ # A race condition can arise if a TERM or INT signal is received before
26
+ # the forked process has finished initializing. To prevent this we restore
27
+ # the default signal handlers, and then reinstall the custom Polyphony
28
+ # handlers just before running the given block.
29
+ trap('SIGTERM', 'DEFAULT')
30
+ trap('SIGINT', 'DEFAULT')
31
+
32
+ # Since the fiber doing the fork will become the main fiber of the
33
+ # forked process, we leave it behind by transferring to a new fiber
34
+ # created in the context of the forked process, which rescues *all*
35
+ # exceptions, including Interrupt and SystemExit.
50
36
  spin_forked_block(&block).transfer
51
37
  end
52
38
  end
@@ -57,7 +43,7 @@ module Polyphony
57
43
  rescue SystemExit
58
44
  # fall through to ensure
59
45
  rescue Exception => e
60
- e.full_message
46
+ warn e.full_message
61
47
  exit!
62
48
  ensure
63
49
  exit_forked_process
@@ -65,16 +51,9 @@ module Polyphony
65
51
  end
66
52
 
67
53
  def run_forked_block(&block)
68
- # A race condition can arise if a TERM or INT signal is received before
69
- # the forked process has finished initializing. To prevent this we restore
70
- # the default signal handlers, and then reinstall the custom Polyphony
71
- # handlers just before running the given block.
72
- trap('SIGTERM', 'DEFAULT')
73
- trap('SIGINT', 'DEFAULT')
74
-
75
54
  Thread.current.setup
76
55
  Fiber.current.setup_main_fiber
77
- Thread.current.agent.post_fork
56
+ Thread.current.backend.post_fork
78
57
 
79
58
  install_terminating_signal_handlers
80
59
 
@@ -123,12 +102,20 @@ module Polyphony
123
102
  # processes (see Polyphony.fork).
124
103
  at_exit do
125
104
  next unless @original_pid == ::Process.pid
126
-
105
+
127
106
  Polyphony.terminate_threads
128
107
  Fiber.current.shutdown_all_children
129
108
  end
130
109
  end
131
110
  end
111
+
112
+ # replace core Queue class with our own
113
+ verbose = $VERBOSE
114
+ $VERBOSE = nil
115
+ Object.const_set(:Queue, Polyphony::Queue)
116
+ Object.const_set(:Mutex, Polyphony::Mutex)
117
+ Object.const_set(:ConditionVariable, Polyphony::ConditionVariable)
118
+ $VERBOSE = verbose
132
119
  end
133
120
 
134
121
  Polyphony.install_terminating_signal_handlers