polyphony 0.45.0 → 0.46.0

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