polyphony 0.45.1 → 0.46.1

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