polyphony 0.45.2 → 0.47.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +2 -0
  3. data/.gitmodules +0 -0
  4. data/CHANGELOG.md +39 -0
  5. data/Gemfile.lock +3 -3
  6. data/README.md +3 -3
  7. data/Rakefile +1 -1
  8. data/TODO.md +20 -28
  9. data/bin/test +4 -0
  10. data/examples/core/enumerable.rb +64 -0
  11. data/examples/io/raw.rb +14 -0
  12. data/examples/io/reline.rb +18 -0
  13. data/examples/performance/fiber_resume.rb +43 -0
  14. data/examples/performance/fiber_transfer.rb +13 -4
  15. data/examples/performance/multi_snooze.rb +0 -1
  16. data/examples/performance/thread-vs-fiber/compare.rb +59 -0
  17. data/examples/performance/thread-vs-fiber/em_server.rb +33 -0
  18. data/examples/performance/thread-vs-fiber/polyphony_server.rb +10 -21
  19. data/examples/performance/thread-vs-fiber/threaded_server.rb +22 -15
  20. data/examples/performance/thread_switch.rb +44 -0
  21. data/ext/liburing/liburing.h +585 -0
  22. data/ext/liburing/liburing/README.md +4 -0
  23. data/ext/liburing/liburing/barrier.h +73 -0
  24. data/ext/liburing/liburing/compat.h +15 -0
  25. data/ext/liburing/liburing/io_uring.h +343 -0
  26. data/ext/liburing/queue.c +333 -0
  27. data/ext/liburing/register.c +187 -0
  28. data/ext/liburing/setup.c +210 -0
  29. data/ext/liburing/syscall.c +54 -0
  30. data/ext/liburing/syscall.h +18 -0
  31. data/ext/polyphony/backend.h +1 -15
  32. data/ext/polyphony/backend_common.h +129 -0
  33. data/ext/polyphony/backend_io_uring.c +995 -0
  34. data/ext/polyphony/backend_io_uring_context.c +74 -0
  35. data/ext/polyphony/backend_io_uring_context.h +53 -0
  36. data/ext/polyphony/{libev_backend.c → backend_libev.c} +308 -297
  37. data/ext/polyphony/event.c +1 -1
  38. data/ext/polyphony/extconf.rb +31 -13
  39. data/ext/polyphony/fiber.c +60 -32
  40. data/ext/polyphony/libev.c +4 -0
  41. data/ext/polyphony/libev.h +8 -2
  42. data/ext/polyphony/liburing.c +8 -0
  43. data/ext/polyphony/playground.c +51 -0
  44. data/ext/polyphony/polyphony.c +9 -6
  45. data/ext/polyphony/polyphony.h +35 -19
  46. data/ext/polyphony/polyphony_ext.c +12 -4
  47. data/ext/polyphony/queue.c +100 -35
  48. data/ext/polyphony/runqueue.c +102 -0
  49. data/ext/polyphony/runqueue_ring_buffer.c +85 -0
  50. data/ext/polyphony/runqueue_ring_buffer.h +31 -0
  51. data/ext/polyphony/thread.c +42 -90
  52. data/lib/polyphony.rb +2 -2
  53. data/lib/polyphony/adapters/process.rb +0 -3
  54. data/lib/polyphony/adapters/trace.rb +2 -2
  55. data/lib/polyphony/core/exceptions.rb +0 -4
  56. data/lib/polyphony/core/global_api.rb +47 -23
  57. data/lib/polyphony/core/sync.rb +7 -5
  58. data/lib/polyphony/extensions/core.rb +14 -33
  59. data/lib/polyphony/extensions/debug.rb +13 -0
  60. data/lib/polyphony/extensions/fiber.rb +21 -3
  61. data/lib/polyphony/extensions/io.rb +15 -4
  62. data/lib/polyphony/extensions/openssl.rb +6 -0
  63. data/lib/polyphony/extensions/socket.rb +63 -10
  64. data/lib/polyphony/version.rb +1 -1
  65. data/polyphony.gemspec +1 -1
  66. data/test/helper.rb +36 -4
  67. data/test/io_uring_test.rb +55 -0
  68. data/test/stress.rb +4 -1
  69. data/test/test_backend.rb +63 -6
  70. data/test/test_ext.rb +1 -2
  71. data/test/test_fiber.rb +55 -20
  72. data/test/test_global_api.rb +132 -31
  73. data/test/test_io.rb +42 -0
  74. data/test/test_queue.rb +117 -0
  75. data/test/test_signal.rb +11 -8
  76. data/test/test_socket.rb +2 -2
  77. data/test/test_sync.rb +21 -0
  78. data/test/test_throttler.rb +3 -6
  79. data/test/test_trace.rb +7 -5
  80. metadata +36 -6
@@ -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'
@@ -12,8 +12,8 @@ VALUE SYM_runnable;
12
12
  VALUE SYM_waiting;
13
13
 
14
14
  VALUE SYM_fiber_create;
15
- VALUE SYM_fiber_ev_loop_enter;
16
- VALUE SYM_fiber_ev_loop_leave;
15
+ VALUE SYM_fiber_event_poll_enter;
16
+ VALUE SYM_fiber_event_poll_leave;
17
17
  VALUE SYM_fiber_run;
18
18
  VALUE SYM_fiber_schedule;
19
19
  VALUE SYM_fiber_switchpoint;
@@ -21,9 +21,9 @@ VALUE SYM_fiber_terminate;
21
21
 
22
22
  static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self) {
23
23
  VALUE arg = (argc == 0) ? Qnil : argv[0];
24
- VALUE ret = rb_funcall(self, ID_transfer, 1, arg);
24
+ VALUE ret = FIBER_TRANSFER(self, arg);
25
25
 
26
- TEST_RESUME_EXCEPTION(ret);
26
+ RAISE_IF_EXCEPTION(ret);
27
27
  RB_GC_GUARD(ret);
28
28
  return ret;
29
29
  }
@@ -39,31 +39,49 @@ inline VALUE Fiber_auto_watcher(VALUE self) {
39
39
  return watcher;
40
40
  }
41
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
+ rb_raise(rb_eRuntimeError, "No thread set for fiber");
46
+ // rb_warn("No thread set for fiber");
47
+ return;
48
+ }
49
+
50
+ Thread_schedule_fiber(thread, fiber, value);
51
+ }
52
+
53
+ void Fiber_make_runnable_with_priority(VALUE fiber, VALUE value) {
54
+ VALUE thread = rb_ivar_get(fiber, ID_ivar_thread);
55
+ if (thread == Qnil) {
56
+ rb_raise(rb_eRuntimeError, "No thread set for fiber");
57
+ // rb_warn("No thread set for fiber");
58
+ return;
59
+ }
60
+
61
+ Thread_schedule_fiber_with_priority(thread, fiber, value);
62
+ }
63
+
42
64
  static VALUE Fiber_schedule(int argc, VALUE *argv, VALUE self) {
43
65
  VALUE value = (argc == 0) ? Qnil : argv[0];
44
66
  Fiber_make_runnable(self, value);
45
67
  return self;
46
68
  }
47
69
 
70
+ static VALUE Fiber_schedule_with_priority(int argc, VALUE *argv, VALUE self) {
71
+ VALUE value = (argc == 0) ? Qnil : argv[0];
72
+ Fiber_make_runnable_with_priority(self, value);
73
+ return self;
74
+ }
75
+
48
76
  static VALUE Fiber_state(VALUE self) {
49
77
  if (!rb_fiber_alive_p(self) || (rb_ivar_get(self, ID_ivar_running) == Qfalse))
50
78
  return SYM_dead;
51
79
  if (rb_fiber_current() == self) return SYM_running;
52
- if (rb_ivar_get(self, ID_runnable) != Qnil) return SYM_runnable;
80
+ if (rb_ivar_get(self, ID_ivar_runnable) != Qnil) return SYM_runnable;
53
81
 
54
82
  return SYM_waiting;
55
83
  }
56
84
 
57
- void Fiber_make_runnable(VALUE fiber, VALUE value) {
58
- VALUE thread = rb_ivar_get(fiber, ID_ivar_thread);
59
- if (thread != Qnil) {
60
- Thread_schedule_fiber(thread, fiber, value);
61
- }
62
- else {
63
- rb_warn("No thread set for fiber (fiber, value, caller):");
64
- }
65
- }
66
-
67
85
  VALUE Fiber_await(VALUE self) {
68
86
  VALUE result;
69
87
 
@@ -71,7 +89,7 @@ VALUE Fiber_await(VALUE self) {
71
89
  // @running set to nil
72
90
  if (rb_ivar_get(self, ID_ivar_running) == Qfalse) {
73
91
  result = rb_ivar_get(self, ID_ivar_result);
74
- TEST_RESUME_EXCEPTION(result);
92
+ RAISE_IF_EXCEPTION(result);
75
93
  return result;
76
94
  }
77
95
 
@@ -86,7 +104,7 @@ VALUE Fiber_await(VALUE self) {
86
104
  result = Thread_switch_fiber(rb_thread_current());
87
105
 
88
106
  rb_hash_delete(waiting_fibers, fiber);
89
- TEST_RESUME_EXCEPTION(result);
107
+ RAISE_IF_EXCEPTION(result);
90
108
  RB_GC_GUARD(result);
91
109
  return result;
92
110
  }
@@ -110,6 +128,15 @@ VALUE Fiber_receive(VALUE self) {
110
128
  return Queue_shift(mailbox);
111
129
  }
112
130
 
131
+ VALUE Fiber_mailbox(VALUE self) {
132
+ VALUE mailbox = rb_ivar_get(self, ID_ivar_mailbox);
133
+ if (mailbox == Qnil) {
134
+ mailbox = rb_funcall(cQueue, ID_new, 0);
135
+ rb_ivar_set(self, ID_ivar_mailbox, mailbox);
136
+ }
137
+ return mailbox;
138
+ }
139
+
113
140
  VALUE Fiber_receive_all_pending(VALUE self) {
114
141
  VALUE mailbox = rb_ivar_get(self, ID_ivar_mailbox);
115
142
  return (mailbox == Qnil) ? rb_ary_new() : Queue_shift_all(mailbox);
@@ -119,6 +146,7 @@ void Init_Fiber() {
119
146
  VALUE cFiber = rb_const_get(rb_cObject, rb_intern("Fiber"));
120
147
  rb_define_method(cFiber, "safe_transfer", Fiber_safe_transfer, -1);
121
148
  rb_define_method(cFiber, "schedule", Fiber_schedule, -1);
149
+ rb_define_method(cFiber, "schedule_with_priority", Fiber_schedule_with_priority, -1);
122
150
  rb_define_method(cFiber, "state", Fiber_state, 0);
123
151
  rb_define_method(cFiber, "auto_watcher", Fiber_auto_watcher, 0);
124
152
 
@@ -127,9 +155,9 @@ void Init_Fiber() {
127
155
 
128
156
  rb_define_method(cFiber, "<<", Fiber_send, 1);
129
157
  rb_define_method(cFiber, "send", Fiber_send, 1);
130
-
131
158
  rb_define_method(cFiber, "receive", Fiber_receive, 0);
132
159
  rb_define_method(cFiber, "receive_all_pending", Fiber_receive_all_pending, 0);
160
+ rb_define_method(cFiber, "mailbox", Fiber_mailbox, 0);
133
161
 
134
162
  SYM_dead = ID2SYM(rb_intern("dead"));
135
163
  SYM_running = ID2SYM(rb_intern("running"));
@@ -140,23 +168,23 @@ void Init_Fiber() {
140
168
  rb_global_variable(&SYM_runnable);
141
169
  rb_global_variable(&SYM_waiting);
142
170
 
143
- ID_fiber_trace = rb_intern("__fiber_trace__");
144
- ID_ivar_auto_watcher = rb_intern("@auto_watcher");
145
- ID_ivar_mailbox = rb_intern("@mailbox");
146
- ID_ivar_result = rb_intern("@result");
147
- ID_ivar_waiting_fibers = rb_intern("@waiting_fibers");
171
+ ID_fiber_trace = rb_intern("__fiber_trace__");
172
+ ID_ivar_auto_watcher = rb_intern("@auto_watcher");
173
+ ID_ivar_mailbox = rb_intern("@mailbox");
174
+ ID_ivar_result = rb_intern("@result");
175
+ ID_ivar_waiting_fibers = rb_intern("@waiting_fibers");
148
176
 
149
- SYM_fiber_create = ID2SYM(rb_intern("fiber_create"));
150
- SYM_fiber_ev_loop_enter = ID2SYM(rb_intern("fiber_ev_loop_enter"));
151
- SYM_fiber_ev_loop_leave = ID2SYM(rb_intern("fiber_ev_loop_leave"));
152
- SYM_fiber_run = ID2SYM(rb_intern("fiber_run"));
153
- SYM_fiber_schedule = ID2SYM(rb_intern("fiber_schedule"));
154
- SYM_fiber_switchpoint = ID2SYM(rb_intern("fiber_switchpoint"));
155
- SYM_fiber_terminate = ID2SYM(rb_intern("fiber_terminate"));
177
+ SYM_fiber_create = ID2SYM(rb_intern("fiber_create"));
178
+ SYM_fiber_event_poll_enter = ID2SYM(rb_intern("fiber_event_poll_enter"));
179
+ SYM_fiber_event_poll_leave = ID2SYM(rb_intern("fiber_event_poll_leave"));
180
+ SYM_fiber_run = ID2SYM(rb_intern("fiber_run"));
181
+ SYM_fiber_schedule = ID2SYM(rb_intern("fiber_schedule"));
182
+ SYM_fiber_switchpoint = ID2SYM(rb_intern("fiber_switchpoint"));
183
+ SYM_fiber_terminate = ID2SYM(rb_intern("fiber_terminate"));
156
184
 
157
185
  rb_global_variable(&SYM_fiber_create);
158
- rb_global_variable(&SYM_fiber_ev_loop_enter);
159
- rb_global_variable(&SYM_fiber_ev_loop_leave);
186
+ rb_global_variable(&SYM_fiber_event_poll_enter);
187
+ rb_global_variable(&SYM_fiber_event_poll_leave);
160
188
  rb_global_variable(&SYM_fiber_run);
161
189
  rb_global_variable(&SYM_fiber_schedule);
162
190
  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
@@ -1,6 +1,7 @@
1
1
  #include "polyphony.h"
2
2
 
3
3
  VALUE mPolyphony;
4
+ VALUE cTimeoutException;
4
5
 
5
6
  ID ID_call;
6
7
  ID ID_caller;
@@ -9,10 +10,10 @@ ID ID_each;
9
10
  ID ID_inspect;
10
11
  ID ID_invoke;
11
12
  ID ID_new;
13
+ ID ID_ivar_io;
14
+ ID ID_ivar_runnable;
12
15
  ID ID_ivar_running;
13
16
  ID ID_ivar_thread;
14
- ID ID_runnable;
15
- ID ID_runnable_value;
16
17
  ID ID_size;
17
18
  ID ID_signal;
18
19
  ID ID_switch_fiber;
@@ -29,7 +30,7 @@ VALUE Polyphony_snooze(VALUE self) {
29
30
 
30
31
  Fiber_make_runnable(fiber, Qnil);
31
32
  ret = Thread_switch_fiber(rb_thread_current());
32
- TEST_RESUME_EXCEPTION(ret);
33
+ RAISE_IF_EXCEPTION(ret);
33
34
  RB_GC_GUARD(ret);
34
35
  return ret;
35
36
  }
@@ -37,7 +38,7 @@ VALUE Polyphony_snooze(VALUE self) {
37
38
  static VALUE Polyphony_suspend(VALUE self) {
38
39
  VALUE ret = Thread_switch_fiber(rb_thread_current());
39
40
 
40
- TEST_RESUME_EXCEPTION(ret);
41
+ RAISE_IF_EXCEPTION(ret);
41
42
  RB_GC_GUARD(ret);
42
43
  return ret;
43
44
  }
@@ -55,17 +56,19 @@ void Init_Polyphony() {
55
56
  rb_define_global_function("snooze", Polyphony_snooze, 0);
56
57
  rb_define_global_function("suspend", Polyphony_suspend, 0);
57
58
 
59
+ cTimeoutException = rb_define_class_under(mPolyphony, "TimeoutException", rb_eException);
60
+
58
61
  ID_call = rb_intern("call");
59
62
  ID_caller = rb_intern("caller");
60
63
  ID_clear = rb_intern("clear");
61
64
  ID_each = rb_intern("each");
62
65
  ID_inspect = rb_intern("inspect");
63
66
  ID_invoke = rb_intern("invoke");
67
+ ID_ivar_io = rb_intern("@io");
68
+ ID_ivar_runnable = rb_intern("@runnable");
64
69
  ID_ivar_running = rb_intern("@running");
65
70
  ID_ivar_thread = rb_intern("@thread");
66
71
  ID_new = rb_intern("new");
67
- ID_runnable = rb_intern("runnable");
68
- ID_runnable_value = rb_intern("runnable_value");
69
72
  ID_signal = rb_intern("signal");
70
73
  ID_size = rb_intern("size");
71
74
  ID_switch_fiber = rb_intern("switch_fiber");
@@ -1,28 +1,36 @@
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
 
26
+ // exceptions
20
27
  #define TEST_EXCEPTION(ret) (RTEST(rb_obj_is_kind_of(ret, rb_eException)))
21
-
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
- }
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); }
31
+
32
+ // Fiber#transfer
33
+ #define FIBER_TRANSFER(fiber, value) rb_funcall(fiber, ID_transfer, 1, value)
26
34
 
27
35
  extern backend_interface_t backend_interface;
28
36
  #define __BACKEND__ (backend_interface)
@@ -30,6 +38,8 @@ extern backend_interface_t backend_interface;
30
38
  extern VALUE mPolyphony;
31
39
  extern VALUE cQueue;
32
40
  extern VALUE cEvent;
41
+ extern VALUE cRunqueue;
42
+ extern VALUE cTimeoutException;
33
43
 
34
44
  extern ID ID_call;
35
45
  extern ID ID_caller;
@@ -39,20 +49,20 @@ extern ID ID_fiber_trace;
39
49
  extern ID ID_inspect;
40
50
  extern ID ID_invoke;
41
51
  extern ID ID_ivar_backend;
52
+ extern ID ID_ivar_io;
53
+ extern ID ID_ivar_runnable;
42
54
  extern ID ID_ivar_running;
43
55
  extern ID ID_ivar_thread;
44
56
  extern ID ID_new;
45
57
  extern ID ID_raise;
46
- extern ID ID_runnable;
47
- extern ID ID_runnable_value;
48
58
  extern ID ID_signal;
49
59
  extern ID ID_size;
50
60
  extern ID ID_switch_fiber;
51
61
  extern ID ID_transfer;
52
62
 
53
63
  extern VALUE SYM_fiber_create;
54
- extern VALUE SYM_fiber_ev_loop_enter;
55
- extern VALUE SYM_fiber_ev_loop_leave;
64
+ extern VALUE SYM_fiber_event_poll_enter;
65
+ extern VALUE SYM_fiber_event_poll_leave;
56
66
  extern VALUE SYM_fiber_run;
57
67
  extern VALUE SYM_fiber_schedule;
58
68
  extern VALUE SYM_fiber_switchpoint;
@@ -73,13 +83,19 @@ VALUE Queue_push(VALUE self, VALUE value);
73
83
  VALUE Queue_unshift(VALUE self, VALUE value);
74
84
  VALUE Queue_shift(VALUE self);
75
85
  VALUE Queue_shift_all(VALUE self);
76
- VALUE Queue_shift_no_wait(VALUE self);
77
- VALUE Queue_clear(VALUE self);
78
- VALUE Queue_delete(VALUE self, VALUE value);
79
- long Queue_len(VALUE self);
80
- void Queue_trace(VALUE self);
86
+
87
+ void Runqueue_push(VALUE self, VALUE fiber, VALUE value, int reschedule);
88
+ void Runqueue_unshift(VALUE self, VALUE fiber, VALUE value, int reschedule);
89
+ runqueue_entry Runqueue_shift(VALUE self);
90
+ void Runqueue_delete(VALUE self, VALUE fiber);
91
+ void Runqueue_clear(VALUE self);
92
+ long Runqueue_len(VALUE self);
93
+ int Runqueue_empty_p(VALUE self);
81
94
 
82
95
  VALUE Thread_schedule_fiber(VALUE thread, VALUE fiber, VALUE value);
96
+ VALUE Thread_schedule_fiber_with_priority(VALUE thread, VALUE fiber, VALUE value);
83
97
  VALUE Thread_switch_fiber(VALUE thread);
84
98
 
99
+ VALUE Polyphony_snooze(VALUE self);
100
+
85
101
  #endif /* POLYPHONY_H */