polyphony 0.45.0 → 0.46.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 (156) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +2 -0
  3. data/.gitmodules +0 -0
  4. data/.rubocop.yml +1 -0
  5. data/CHANGELOG.md +38 -0
  6. data/Gemfile.lock +11 -3
  7. data/README.md +3 -3
  8. data/Rakefile +1 -1
  9. data/TODO.md +10 -18
  10. data/examples/adapters/redis_client.rb +3 -1
  11. data/examples/adapters/redis_pubsub_perf.rb +11 -8
  12. data/examples/adapters/sequel_mysql.rb +1 -1
  13. data/examples/adapters/sequel_pg.rb +24 -0
  14. data/examples/core/{02-awaiting-fibers.rb → await.rb} +0 -0
  15. data/examples/core/{xx-channels.rb → channels.rb} +0 -0
  16. data/examples/core/deferring-an-operation.rb +16 -0
  17. data/examples/core/{xx-erlang-style-genserver.rb → erlang-style-genserver.rb} +16 -9
  18. data/examples/core/{xx-forking.rb → forking.rb} +1 -1
  19. data/examples/core/handling-signals.rb +11 -0
  20. data/examples/core/{03-interrupting.rb → interrupt.rb} +0 -0
  21. data/examples/core/{xx-pingpong.rb → pingpong.rb} +7 -5
  22. data/examples/core/{xx-recurrent-timer.rb → recurrent-timer.rb} +1 -1
  23. data/examples/core/{xx-resource_delegate.rb → resource_delegate.rb} +3 -4
  24. data/examples/core/{01-spinning-up-fibers.rb → spin.rb} +1 -1
  25. data/examples/core/{xx-spin_error_backtrace.rb → spin_error_backtrace.rb} +1 -1
  26. data/examples/core/{xx-supervise-process.rb → supervise-process.rb} +8 -5
  27. data/examples/core/supervisor.rb +20 -0
  28. data/examples/core/{xx-thread-sleep.rb → thread-sleep.rb} +0 -0
  29. data/examples/core/{xx-thread_pool.rb → thread_pool.rb} +0 -0
  30. data/examples/core/{xx-throttling.rb → throttling.rb} +0 -0
  31. data/examples/core/{xx-timeout.rb → timeout.rb} +0 -0
  32. data/examples/core/{xx-using-a-mutex.rb → using-a-mutex.rb} +0 -0
  33. data/examples/core/{xx-worker-thread.rb → worker-thread.rb} +2 -2
  34. data/examples/io/{xx-backticks.rb → backticks.rb} +0 -0
  35. data/examples/io/{xx-echo_client.rb → echo_client.rb} +1 -1
  36. data/examples/io/{xx-echo_client_from_stdin.rb → echo_client_from_stdin.rb} +2 -2
  37. data/examples/io/{xx-echo_pipe.rb → echo_pipe.rb} +1 -1
  38. data/examples/io/{xx-echo_server.rb → echo_server.rb} +0 -0
  39. data/examples/io/{xx-echo_server_with_timeout.rb → echo_server_with_timeout.rb} +1 -1
  40. data/examples/io/{xx-echo_stdin.rb → echo_stdin.rb} +0 -0
  41. data/examples/io/{xx-happy-eyeballs.rb → happy-eyeballs.rb} +0 -0
  42. data/examples/io/{xx-httparty.rb → httparty.rb} +4 -13
  43. data/examples/io/{xx-irb.rb → irb.rb} +0 -0
  44. data/examples/io/{xx-net-http.rb → net-http.rb} +0 -0
  45. data/examples/io/{xx-open.rb → open.rb} +0 -0
  46. data/examples/io/{xx-pry.rb → pry.rb} +0 -0
  47. data/examples/io/{xx-rack_server.rb → rack_server.rb} +0 -0
  48. data/examples/io/raw.rb +14 -0
  49. data/examples/io/reline.rb +18 -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/performance/multi_snooze.rb +0 -1
  58. data/examples/{io/xx-switch.rb → performance/switch.rb} +2 -1
  59. data/examples/performance/thread-vs-fiber/{xx-httparty_multi.rb → httparty_multi.rb} +3 -4
  60. data/examples/performance/thread-vs-fiber/{xx-httparty_threaded.rb → httparty_threaded.rb} +0 -0
  61. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +1 -1
  62. data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -2
  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/liburing/liburing.h +585 -0
  66. data/ext/liburing/liburing/README.md +4 -0
  67. data/ext/liburing/liburing/barrier.h +73 -0
  68. data/ext/liburing/liburing/compat.h +15 -0
  69. data/ext/liburing/liburing/io_uring.h +343 -0
  70. data/ext/liburing/queue.c +333 -0
  71. data/ext/liburing/register.c +187 -0
  72. data/ext/liburing/setup.c +210 -0
  73. data/ext/liburing/syscall.c +54 -0
  74. data/ext/liburing/syscall.h +18 -0
  75. data/ext/polyphony/backend.h +1 -16
  76. data/ext/polyphony/backend_common.h +109 -0
  77. data/ext/polyphony/backend_io_uring.c +884 -0
  78. data/ext/polyphony/backend_io_uring_context.c +73 -0
  79. data/ext/polyphony/backend_io_uring_context.h +52 -0
  80. data/ext/polyphony/{libev_backend.c → backend_libev.c} +255 -345
  81. data/ext/polyphony/event.c +1 -1
  82. data/ext/polyphony/extconf.rb +31 -13
  83. data/ext/polyphony/fiber.c +111 -27
  84. data/ext/polyphony/libev.c +4 -0
  85. data/ext/polyphony/libev.h +8 -2
  86. data/ext/polyphony/liburing.c +8 -0
  87. data/ext/polyphony/playground.c +51 -0
  88. data/ext/polyphony/polyphony.c +6 -8
  89. data/ext/polyphony/polyphony.h +29 -25
  90. data/ext/polyphony/polyphony_ext.c +13 -6
  91. data/ext/polyphony/queue.c +3 -4
  92. data/ext/polyphony/ring_buffer.c +0 -1
  93. data/ext/polyphony/runqueue.c +102 -0
  94. data/ext/polyphony/runqueue_ring_buffer.c +85 -0
  95. data/ext/polyphony/runqueue_ring_buffer.h +31 -0
  96. data/ext/polyphony/thread.c +45 -92
  97. data/lib/polyphony.rb +2 -2
  98. data/lib/polyphony/adapters/fs.rb +1 -1
  99. data/lib/polyphony/adapters/process.rb +0 -3
  100. data/lib/polyphony/adapters/redis.rb +1 -1
  101. data/lib/polyphony/adapters/trace.rb +2 -2
  102. data/lib/polyphony/core/global_api.rb +9 -12
  103. data/lib/polyphony/core/sync.rb +6 -2
  104. data/lib/polyphony/extensions/core.rb +6 -24
  105. data/lib/polyphony/extensions/debug.rb +13 -0
  106. data/lib/polyphony/extensions/fiber.rb +21 -44
  107. data/lib/polyphony/extensions/io.rb +55 -10
  108. data/lib/polyphony/extensions/socket.rb +70 -12
  109. data/lib/polyphony/version.rb +1 -1
  110. data/polyphony.gemspec +3 -2
  111. data/test/helper.rb +36 -4
  112. data/test/io_uring_test.rb +55 -0
  113. data/test/stress.rb +5 -2
  114. data/test/test_backend.rb +4 -6
  115. data/test/test_ext.rb +1 -2
  116. data/test/test_fiber.rb +31 -24
  117. data/test/test_global_api.rb +58 -31
  118. data/test/test_io.rb +58 -0
  119. data/test/test_signal.rb +11 -8
  120. data/test/test_socket.rb +17 -0
  121. data/test/test_sync.rb +21 -0
  122. data/test/test_throttler.rb +3 -6
  123. data/test/test_trace.rb +7 -5
  124. metadata +86 -76
  125. data/examples/adapters/concurrent-ruby.rb +0 -9
  126. data/examples/core/04-handling-signals.rb +0 -19
  127. data/examples/core/xx-at_exit.rb +0 -29
  128. data/examples/core/xx-backend.rb +0 -102
  129. data/examples/core/xx-caller.rb +0 -12
  130. data/examples/core/xx-daemon.rb +0 -14
  131. data/examples/core/xx-deadlock.rb +0 -8
  132. data/examples/core/xx-deferring-an-operation.rb +0 -14
  133. data/examples/core/xx-exception-backtrace.rb +0 -40
  134. data/examples/core/xx-fork-cleanup.rb +0 -22
  135. data/examples/core/xx-fork-spin.rb +0 -42
  136. data/examples/core/xx-fork-terminate.rb +0 -27
  137. data/examples/core/xx-move_on.rb +0 -23
  138. data/examples/core/xx-queue-async.rb +0 -120
  139. data/examples/core/xx-readpartial.rb +0 -18
  140. data/examples/core/xx-signals.rb +0 -16
  141. data/examples/core/xx-sleep-forever.rb +0 -9
  142. data/examples/core/xx-sleeping.rb +0 -25
  143. data/examples/core/xx-snooze-starve.rb +0 -16
  144. data/examples/core/xx-spin-fork.rb +0 -49
  145. data/examples/core/xx-state-machine.rb +0 -51
  146. data/examples/core/xx-stop.rb +0 -20
  147. data/examples/core/xx-supervisors.rb +0 -21
  148. data/examples/core/xx-thread-selector-sleep.rb +0 -51
  149. data/examples/core/xx-thread-selector-snooze.rb +0 -46
  150. data/examples/core/xx-thread-snooze.rb +0 -34
  151. data/examples/core/xx-timer-gc.rb +0 -17
  152. data/examples/core/xx-trace.rb +0 -79
  153. data/examples/performance/xx-array.rb +0 -11
  154. data/examples/performance/xx-fiber-switch.rb +0 -9
  155. data/examples/performance/xx-snooze.rb +0 -15
  156. data/examples/xx-spin.rb +0 -32
@@ -69,7 +69,7 @@ VALUE Event_await(VALUE self) {
69
69
  VALUE switchpoint_result = __BACKEND__.wait_event(backend, Qnil);
70
70
  event->waiting_fiber = Qnil;
71
71
 
72
- TEST_RESUME_EXCEPTION(switchpoint_result);
72
+ RAISE_IF_EXCEPTION(switchpoint_result);
73
73
  RB_GC_GUARD(backend);
74
74
  RB_GC_GUARD(switchpoint_result);
75
75
 
@@ -1,20 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rubygems"
3
+ require 'rubygems'
4
+ require 'mkmf'
4
5
 
5
- require "mkmf"
6
+ use_liburing = false
7
+ force_use_libev = ENV['POLYPHONY_USE_LIBEV'] != nil
6
8
 
7
- have_header("unistd.h")
9
+ if !force_use_libev && RUBY_PLATFORM =~ /linux/ && `uname -sr` =~ /Linux 5\.([\d+])/
10
+ kernel_minor_version = $1.gsub('.', '').to_i
11
+ use_liburing = kernel_minor_version >= 6
12
+ end
8
13
 
9
- $defs << "-DEV_USE_LINUXAIO" if have_header("linux/aio_abi.h")
10
- $defs << "-DEV_USE_SELECT" if have_header("sys/select.h")
11
- $defs << "-DEV_USE_POLL" if have_type("port_event_t", "poll.h")
12
- $defs << "-DEV_USE_EPOLL" if have_header("sys/epoll.h")
13
- $defs << "-DEV_USE_KQUEUE" if have_header("sys/event.h") && have_header("sys/queue.h")
14
- $defs << "-DEV_USE_PORT" if have_type("port_event_t", "port.h")
15
- $defs << "-DHAVE_SYS_RESOURCE_H" if have_header("sys/resource.h")
14
+ if use_liburing
15
+ $defs << "-DPOLYPHONY_BACKEND_LIBURING"
16
+ $CFLAGS << " -Wno-pointer-arith"
17
+ else
18
+ $defs << "-DPOLYPHONY_BACKEND_LIBEV"
19
+ $defs << '-DEV_USE_LINUXAIO' if have_header('linux/aio_abi.h')
20
+ $defs << '-DEV_USE_SELECT' if have_header('sys/select.h')
21
+ $defs << '-DEV_USE_POLL' if have_type('port_event_t', 'poll.h')
22
+ $defs << '-DEV_USE_EPOLL' if have_header('sys/epoll.h')
23
+ $defs << '-DEV_USE_KQUEUE' if have_header('sys/event.h') && have_header('sys/queue.h')
24
+ $defs << '-DEV_USE_PORT' if have_type('port_event_t', 'port.h')
25
+ $defs << '-DHAVE_SYS_RESOURCE_H' if have_header('sys/resource.h')
26
+ $CFLAGS << " -Wno-comment"
27
+ $CFLAGS << " -Wno-unused-result"
28
+ $CFLAGS << " -Wno-dangling-else"
29
+ $CFLAGS << " -Wno-parentheses"
30
+ end
16
31
 
17
- CONFIG["optflags"] << " -fno-strict-aliasing" unless RUBY_PLATFORM =~ /mswin/
32
+ $defs << '-DPOLYPHONY_PLAYGROUND' if ENV['POLYPHONY_PLAYGROUND']
18
33
 
19
- dir_config "polyphony_ext"
20
- create_makefile "polyphony_ext"
34
+ CONFIG['optflags'] << ' -fno-strict-aliasing' unless RUBY_PLATFORM =~ /mswin/
35
+
36
+
37
+ dir_config 'polyphony_ext'
38
+ create_makefile 'polyphony_ext'
@@ -2,12 +2,9 @@
2
2
 
3
3
  ID ID_fiber_trace;
4
4
  ID ID_ivar_auto_watcher;
5
- ID ID_trace_ev_loop_enter;
6
- ID ID_trace_ev_loop_leave;
7
- ID ID_trace_run;
8
- ID ID_trace_runnable;
9
- ID ID_trace_terminate;
10
- ID ID_trace_wait;
5
+ ID ID_ivar_mailbox;
6
+ ID ID_ivar_result;
7
+ ID ID_ivar_waiting_fibers;
11
8
 
12
9
  VALUE SYM_dead;
13
10
  VALUE SYM_running;
@@ -15,8 +12,8 @@ VALUE SYM_runnable;
15
12
  VALUE SYM_waiting;
16
13
 
17
14
  VALUE SYM_fiber_create;
18
- VALUE SYM_fiber_ev_loop_enter;
19
- VALUE SYM_fiber_ev_loop_leave;
15
+ VALUE SYM_fiber_event_poll_enter;
16
+ VALUE SYM_fiber_event_poll_leave;
20
17
  VALUE SYM_fiber_run;
21
18
  VALUE SYM_fiber_schedule;
22
19
  VALUE SYM_fiber_switchpoint;
@@ -26,7 +23,7 @@ static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self) {
26
23
  VALUE arg = (argc == 0) ? Qnil : argv[0];
27
24
  VALUE ret = rb_funcall(self, ID_transfer, 1, arg);
28
25
 
29
- TEST_RESUME_EXCEPTION(ret);
26
+ RAISE_IF_EXCEPTION(ret);
30
27
  RB_GC_GUARD(ret);
31
28
  return ret;
32
29
  }
@@ -42,38 +39,122 @@ inline VALUE Fiber_auto_watcher(VALUE self) {
42
39
  return watcher;
43
40
  }
44
41
 
42
+ void Fiber_make_runnable(VALUE fiber, VALUE value) {
43
+ VALUE thread = rb_ivar_get(fiber, ID_ivar_thread);
44
+ if (thread == Qnil) {
45
+ INSPECT("Fiber with no thread", fiber);
46
+ TRACE_CALLER();
47
+ TRACE_C_STACK();
48
+ exit(-1);
49
+ rb_raise(rb_eRuntimeError, "No thread set for fiber");
50
+ // rb_warn("No thread set for fiber");
51
+ return;
52
+ }
53
+
54
+ Thread_schedule_fiber(thread, fiber, value);
55
+ }
56
+
57
+ void Fiber_make_runnable_with_priority(VALUE fiber, VALUE value) {
58
+ VALUE thread = rb_ivar_get(fiber, ID_ivar_thread);
59
+ if (thread == Qnil) {
60
+ INSPECT("Fiber with no thread", fiber);
61
+ rb_raise(rb_eRuntimeError, "No thread set for fiber");
62
+ // rb_warn("No thread set for fiber");
63
+ return;
64
+ }
65
+
66
+ Thread_schedule_fiber_with_priority(thread, fiber, value);
67
+ }
68
+
45
69
  static VALUE Fiber_schedule(int argc, VALUE *argv, VALUE self) {
46
70
  VALUE value = (argc == 0) ? Qnil : argv[0];
47
71
  Fiber_make_runnable(self, value);
48
72
  return self;
49
73
  }
50
74
 
75
+ static VALUE Fiber_schedule_with_priority(int argc, VALUE *argv, VALUE self) {
76
+ VALUE value = (argc == 0) ? Qnil : argv[0];
77
+ Fiber_make_runnable_with_priority(self, value);
78
+ return self;
79
+ }
80
+
51
81
  static VALUE Fiber_state(VALUE self) {
52
82
  if (!rb_fiber_alive_p(self) || (rb_ivar_get(self, ID_ivar_running) == Qfalse))
53
83
  return SYM_dead;
54
84
  if (rb_fiber_current() == self) return SYM_running;
55
- if (rb_ivar_get(self, ID_runnable) != Qnil) return SYM_runnable;
85
+ if (rb_ivar_get(self, ID_ivar_runnable) != Qnil) return SYM_runnable;
56
86
 
57
87
  return SYM_waiting;
58
88
  }
59
89
 
60
- void Fiber_make_runnable(VALUE fiber, VALUE value) {
61
- VALUE thread = rb_ivar_get(fiber, ID_ivar_thread);
62
- if (thread != Qnil) {
63
- Thread_schedule_fiber(thread, fiber, value);
90
+ VALUE Fiber_await(VALUE self) {
91
+ VALUE result;
92
+
93
+ // we compare with false, since a fiber that has not yet started will have
94
+ // @running set to nil
95
+ if (rb_ivar_get(self, ID_ivar_running) == Qfalse) {
96
+ result = rb_ivar_get(self, ID_ivar_result);
97
+ RAISE_IF_EXCEPTION(result);
98
+ return result;
99
+ }
100
+
101
+ VALUE fiber = rb_fiber_current();
102
+ VALUE waiting_fibers = rb_ivar_get(self, ID_ivar_waiting_fibers);
103
+ if (waiting_fibers == Qnil) {
104
+ waiting_fibers = rb_hash_new();
105
+ rb_ivar_set(self, ID_ivar_waiting_fibers, waiting_fibers);
106
+ }
107
+ rb_hash_aset(waiting_fibers, fiber, Qtrue);
108
+
109
+ result = Thread_switch_fiber(rb_thread_current());
110
+
111
+ rb_hash_delete(waiting_fibers, fiber);
112
+ RAISE_IF_EXCEPTION(result);
113
+ RB_GC_GUARD(result);
114
+ return result;
115
+ }
116
+
117
+ VALUE Fiber_send(VALUE self, VALUE value) {
118
+ VALUE mailbox = rb_ivar_get(self, ID_ivar_mailbox);
119
+ if (mailbox == Qnil) {
120
+ mailbox = rb_funcall(cQueue, ID_new, 0);
121
+ rb_ivar_set(self, ID_ivar_mailbox, mailbox);
64
122
  }
65
- else {
66
- rb_warn("No thread set for fiber (fiber, value, caller):");
123
+ Queue_push(mailbox, value);
124
+ return self;
125
+ }
126
+
127
+ VALUE Fiber_receive(VALUE self) {
128
+ VALUE mailbox = rb_ivar_get(self, ID_ivar_mailbox);
129
+ if (mailbox == Qnil) {
130
+ mailbox = rb_funcall(cQueue, ID_new, 0);
131
+ rb_ivar_set(self, ID_ivar_mailbox, mailbox);
67
132
  }
133
+ return Queue_shift(mailbox);
134
+ }
135
+
136
+ VALUE Fiber_receive_all_pending(VALUE self) {
137
+ VALUE mailbox = rb_ivar_get(self, ID_ivar_mailbox);
138
+ return (mailbox == Qnil) ? rb_ary_new() : Queue_shift_all(mailbox);
68
139
  }
69
140
 
70
141
  void Init_Fiber() {
71
142
  VALUE cFiber = rb_const_get(rb_cObject, rb_intern("Fiber"));
72
143
  rb_define_method(cFiber, "safe_transfer", Fiber_safe_transfer, -1);
73
144
  rb_define_method(cFiber, "schedule", Fiber_schedule, -1);
145
+ rb_define_method(cFiber, "schedule_with_priority", Fiber_schedule_with_priority, -1);
74
146
  rb_define_method(cFiber, "state", Fiber_state, 0);
75
147
  rb_define_method(cFiber, "auto_watcher", Fiber_auto_watcher, 0);
76
148
 
149
+ rb_define_method(cFiber, "await", Fiber_await, 0);
150
+ rb_define_method(cFiber, "join", Fiber_await, 0);
151
+
152
+ rb_define_method(cFiber, "<<", Fiber_send, 1);
153
+ rb_define_method(cFiber, "send", Fiber_send, 1);
154
+
155
+ rb_define_method(cFiber, "receive", Fiber_receive, 0);
156
+ rb_define_method(cFiber, "receive_all_pending", Fiber_receive_all_pending, 0);
157
+
77
158
  SYM_dead = ID2SYM(rb_intern("dead"));
78
159
  SYM_running = ID2SYM(rb_intern("running"));
79
160
  SYM_runnable = ID2SYM(rb_intern("runnable"));
@@ -83,20 +164,23 @@ void Init_Fiber() {
83
164
  rb_global_variable(&SYM_runnable);
84
165
  rb_global_variable(&SYM_waiting);
85
166
 
86
- ID_fiber_trace = rb_intern("__fiber_trace__");
87
- ID_ivar_auto_watcher = rb_intern("@auto_watcher");
167
+ ID_fiber_trace = rb_intern("__fiber_trace__");
168
+ ID_ivar_auto_watcher = rb_intern("@auto_watcher");
169
+ ID_ivar_mailbox = rb_intern("@mailbox");
170
+ ID_ivar_result = rb_intern("@result");
171
+ ID_ivar_waiting_fibers = rb_intern("@waiting_fibers");
88
172
 
89
- SYM_fiber_create = ID2SYM(rb_intern("fiber_create"));
90
- SYM_fiber_ev_loop_enter = ID2SYM(rb_intern("fiber_ev_loop_enter"));
91
- SYM_fiber_ev_loop_leave = ID2SYM(rb_intern("fiber_ev_loop_leave"));
92
- SYM_fiber_run = ID2SYM(rb_intern("fiber_run"));
93
- SYM_fiber_schedule = ID2SYM(rb_intern("fiber_schedule"));
94
- SYM_fiber_switchpoint = ID2SYM(rb_intern("fiber_switchpoint"));
95
- SYM_fiber_terminate = ID2SYM(rb_intern("fiber_terminate"));
173
+ SYM_fiber_create = ID2SYM(rb_intern("fiber_create"));
174
+ SYM_fiber_event_poll_enter = ID2SYM(rb_intern("fiber_event_poll_enter"));
175
+ SYM_fiber_event_poll_leave = ID2SYM(rb_intern("fiber_event_poll_leave"));
176
+ SYM_fiber_run = ID2SYM(rb_intern("fiber_run"));
177
+ SYM_fiber_schedule = ID2SYM(rb_intern("fiber_schedule"));
178
+ SYM_fiber_switchpoint = ID2SYM(rb_intern("fiber_switchpoint"));
179
+ SYM_fiber_terminate = ID2SYM(rb_intern("fiber_terminate"));
96
180
 
97
181
  rb_global_variable(&SYM_fiber_create);
98
- rb_global_variable(&SYM_fiber_ev_loop_enter);
99
- rb_global_variable(&SYM_fiber_ev_loop_leave);
182
+ rb_global_variable(&SYM_fiber_event_poll_enter);
183
+ rb_global_variable(&SYM_fiber_event_poll_leave);
100
184
  rb_global_variable(&SYM_fiber_run);
101
185
  rb_global_variable(&SYM_fiber_schedule);
102
186
  rb_global_variable(&SYM_fiber_switchpoint);
@@ -1,2 +1,6 @@
1
+ #ifdef POLYPHONY_BACKEND_LIBEV
2
+
1
3
  #include "libev.h"
2
4
  #include "../libev/ev.c"
5
+
6
+ #endif // POLYPHONY_BACKEND_LIBEV
@@ -1,4 +1,8 @@
1
- #define EV_STANDALONE /* keeps ev from requiring config.h */
1
+ #define EV_STANDALONE
2
+
3
+ #ifdef POLYPHONY_BACKEND_LIBEV
4
+
5
+ /* keeps ev from requiring config.h */
2
6
 
3
7
  #ifdef _WIN32
4
8
  #define EV_SELECT_IS_WINSOCKET 1
@@ -6,4 +10,6 @@
6
10
  #define EV_USE_REALTIME 0
7
11
  #endif
8
12
 
9
- #include "../libev/ev.h"
13
+ #include "../libev/ev.h"
14
+
15
+ #endif // POLYPHONY_BACKEND_LIBEV
@@ -0,0 +1,8 @@
1
+ #ifdef POLYPHONY_BACKEND_LIBURING
2
+
3
+ #include "../liburing/queue.c"
4
+ #include "../liburing/register.c"
5
+ #include "../liburing/setup.c"
6
+ #include "../liburing/syscall.c"
7
+
8
+ #endif // POLYPHONY_BACKEND_LIBURING
@@ -0,0 +1,51 @@
1
+ #ifdef POLYPHONY_PLAYGROUND
2
+
3
+ #include <netdb.h>
4
+ #include <sys/socket.h>
5
+ #include <sys/uio.h>
6
+ #include <unistd.h>
7
+ #include <fcntl.h>
8
+ #include <netinet/in.h>
9
+ #include <arpa/inet.h>
10
+
11
+ #include "polyphony.h"
12
+ #include "../liburing/liburing.h"
13
+ #include "ruby/thread.h"
14
+
15
+ #include <poll.h>
16
+ #include <sys/types.h>
17
+ #include <sys/eventfd.h>
18
+ #include <sys/wait.h>
19
+ #include <time.h>
20
+ #include <stdnoreturn.h>
21
+
22
+ void print(struct io_uring *ring, const char *str) {
23
+ struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
24
+ io_uring_prep_write(sqe, 1, str, strlen(str), -1);
25
+ io_uring_sqe_set_data(sqe, (void *)42);
26
+ // io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
27
+ io_uring_submit(ring);
28
+
29
+ struct io_uring_cqe *cqe;
30
+ int ret = __io_uring_get_cqe(ring, &cqe, 0, 1, NULL);
31
+ if (ret != 0) {
32
+ printf("ret: %d\n", ret);
33
+ exit(1);
34
+ }
35
+ printf(" cqe res: %d\n", cqe->res);
36
+ io_uring_cqe_seen(ring, cqe);
37
+ }
38
+
39
+ noreturn void playground() {
40
+ struct io_uring ring;
41
+ io_uring_queue_init(1024, &ring, 0);
42
+
43
+ for (int i = 0; i < 10; i++) {
44
+ print(&ring, "hi\n");
45
+ }
46
+
47
+ io_uring_queue_exit(&ring);
48
+ exit(0);
49
+ }
50
+
51
+ #endif //POLYPHONY_PLAYGROUND
@@ -9,11 +9,10 @@ ID ID_each;
9
9
  ID ID_inspect;
10
10
  ID ID_invoke;
11
11
  ID ID_new;
12
- ID ID_raise;
12
+ ID ID_ivar_io;
13
+ ID ID_ivar_runnable;
13
14
  ID ID_ivar_running;
14
15
  ID ID_ivar_thread;
15
- ID ID_runnable;
16
- ID ID_runnable_value;
17
16
  ID ID_size;
18
17
  ID ID_signal;
19
18
  ID ID_switch_fiber;
@@ -30,7 +29,7 @@ VALUE Polyphony_snooze(VALUE self) {
30
29
 
31
30
  Fiber_make_runnable(fiber, Qnil);
32
31
  ret = Thread_switch_fiber(rb_thread_current());
33
- TEST_RESUME_EXCEPTION(ret);
32
+ RAISE_IF_EXCEPTION(ret);
34
33
  RB_GC_GUARD(ret);
35
34
  return ret;
36
35
  }
@@ -38,7 +37,7 @@ VALUE Polyphony_snooze(VALUE self) {
38
37
  static VALUE Polyphony_suspend(VALUE self) {
39
38
  VALUE ret = Thread_switch_fiber(rb_thread_current());
40
39
 
41
- TEST_RESUME_EXCEPTION(ret);
40
+ RAISE_IF_EXCEPTION(ret);
42
41
  RB_GC_GUARD(ret);
43
42
  return ret;
44
43
  }
@@ -62,12 +61,11 @@ void Init_Polyphony() {
62
61
  ID_each = rb_intern("each");
63
62
  ID_inspect = rb_intern("inspect");
64
63
  ID_invoke = rb_intern("invoke");
64
+ ID_ivar_io = rb_intern("@io");
65
+ ID_ivar_runnable = rb_intern("@runnable");
65
66
  ID_ivar_running = rb_intern("@running");
66
67
  ID_ivar_thread = rb_intern("@thread");
67
68
  ID_new = rb_intern("new");
68
- ID_raise = rb_intern("raise");
69
- ID_runnable = rb_intern("runnable");
70
- ID_runnable_value = rb_intern("runnable_value");
71
69
  ID_signal = rb_intern("signal");
72
70
  ID_size = rb_intern("size");
73
71
  ID_switch_fiber = rb_intern("switch_fiber");
@@ -1,29 +1,33 @@
1
1
  #ifndef POLYPHONY_H
2
2
  #define POLYPHONY_H
3
3
 
4
+ #include <execinfo.h>
5
+
4
6
  #include "ruby.h"
5
- #include "ruby/io.h"
6
- #include "libev.h"
7
7
  #include "backend.h"
8
+ #include "runqueue_ring_buffer.h"
8
9
 
9
10
  // debugging
10
11
  #define OBJ_ID(obj) (NUM2LONG(rb_funcall(obj, rb_intern("object_id"), 0)))
11
- #define INSPECT(str, obj) { printf(str); VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf("%s\n", StringValueCStr(s)); }
12
+ #define INSPECT(str, obj) { printf(str); VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf(": %s\n", StringValueCStr(s)); }
12
13
  #define TRACE_CALLER() { VALUE c = rb_funcall(rb_mKernel, rb_intern("caller"), 0); INSPECT("caller: ", c); }
14
+ #define TRACE_C_STACK() { \
15
+ void *entries[10]; \
16
+ size_t size = backtrace(entries, 10); \
17
+ char **strings = backtrace_symbols(entries, size); \
18
+ for (unsigned long i = 0; i < size; i++) printf("%s\n", strings[i]); \
19
+ free(strings); \
20
+ }
13
21
 
14
22
  // tracing
15
23
  #define TRACE(...) rb_funcall(rb_cObject, ID_fiber_trace, __VA_ARGS__)
16
- #define COND_TRACE(...) if (__tracing_enabled__) { \
17
- TRACE(__VA_ARGS__); \
18
- }
24
+ #define COND_TRACE(...) if (__tracing_enabled__) { TRACE(__VA_ARGS__); }
19
25
 
20
26
  #define TEST_EXCEPTION(ret) (RTEST(rb_obj_is_kind_of(ret, rb_eException)))
21
27
 
22
28
  #define RAISE_EXCEPTION(e) rb_funcall(e, ID_invoke, 0);
23
- #define TEST_RESUME_EXCEPTION(ret) if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) { \
24
- return RAISE_EXCEPTION(ret); \
25
- }
26
-
29
+ #define RAISE_IF_EXCEPTION(ret) if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) { RAISE_EXCEPTION(ret); }
30
+ #define RAISE_IF_NOT_NIL(ret) if (ret != Qnil) { RAISE_EXCEPTION(ret); }
27
31
 
28
32
  extern backend_interface_t backend_interface;
29
33
  #define __BACKEND__ (backend_interface)
@@ -31,6 +35,7 @@ extern backend_interface_t backend_interface;
31
35
  extern VALUE mPolyphony;
32
36
  extern VALUE cQueue;
33
37
  extern VALUE cEvent;
38
+ extern VALUE cRunqueue;
34
39
 
35
40
  extern ID ID_call;
36
41
  extern ID ID_caller;
@@ -40,20 +45,20 @@ extern ID ID_fiber_trace;
40
45
  extern ID ID_inspect;
41
46
  extern ID ID_invoke;
42
47
  extern ID ID_ivar_backend;
48
+ extern ID ID_ivar_io;
49
+ extern ID ID_ivar_runnable;
43
50
  extern ID ID_ivar_running;
44
51
  extern ID ID_ivar_thread;
45
52
  extern ID ID_new;
46
53
  extern ID ID_raise;
47
- extern ID ID_runnable;
48
- extern ID ID_runnable_value;
49
54
  extern ID ID_signal;
50
55
  extern ID ID_size;
51
56
  extern ID ID_switch_fiber;
52
57
  extern ID ID_transfer;
53
58
 
54
59
  extern VALUE SYM_fiber_create;
55
- extern VALUE SYM_fiber_ev_loop_enter;
56
- extern VALUE SYM_fiber_ev_loop_leave;
60
+ extern VALUE SYM_fiber_event_poll_enter;
61
+ extern VALUE SYM_fiber_event_poll_leave;
57
62
  extern VALUE SYM_fiber_run;
58
63
  extern VALUE SYM_fiber_schedule;
59
64
  extern VALUE SYM_fiber_switchpoint;
@@ -67,31 +72,30 @@ enum {
67
72
  FIBER_STATE_SCHEDULED = 2
68
73
  };
69
74
 
70
- // watcher flags
71
- enum {
72
- // a watcher's active field will be set to this after fork
73
- GYRO_WATCHER_POST_FORK = 0xFF
74
- };
75
-
76
75
  VALUE Fiber_auto_watcher(VALUE self);
77
76
  void Fiber_make_runnable(VALUE fiber, VALUE value);
78
77
 
79
78
  VALUE Queue_push(VALUE self, VALUE value);
80
79
  VALUE Queue_unshift(VALUE self, VALUE value);
81
80
  VALUE Queue_shift(VALUE self);
81
+ VALUE Queue_shift_all(VALUE self);
82
82
  VALUE Queue_shift_no_wait(VALUE self);
83
83
  VALUE Queue_clear(VALUE self);
84
84
  VALUE Queue_delete(VALUE self, VALUE value);
85
85
  long Queue_len(VALUE self);
86
86
  void Queue_trace(VALUE self);
87
87
 
88
- VALUE Polyphony_snooze(VALUE self);
88
+
89
+ void Runqueue_push(VALUE self, VALUE fiber, VALUE value, int reschedule);
90
+ void Runqueue_unshift(VALUE self, VALUE fiber, VALUE value, int reschedule);
91
+ runqueue_entry Runqueue_shift(VALUE self);
92
+ void Runqueue_delete(VALUE self, VALUE fiber);
93
+ void Runqueue_clear(VALUE self);
94
+ long Runqueue_len(VALUE self);
95
+ int Runqueue_empty_p(VALUE self);
89
96
 
90
97
  VALUE Thread_schedule_fiber(VALUE thread, VALUE fiber, VALUE value);
98
+ VALUE Thread_schedule_fiber_with_priority(VALUE thread, VALUE fiber, VALUE value);
91
99
  VALUE Thread_switch_fiber(VALUE thread);
92
100
 
93
- int io_setstrbuf(VALUE *str, long len);
94
- void io_set_read_length(VALUE str, long n, int shrinkable);
95
- VALUE io_enc_str(VALUE str, rb_io_t *fptr);
96
-
97
101
  #endif /* POLYPHONY_H */