polyphony 0.45.1 → 0.46.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +2 -0
- data/.gitmodules +0 -0
- data/CHANGELOG.md +35 -0
- data/Gemfile.lock +3 -3
- data/README.md +3 -3
- data/Rakefile +1 -1
- data/TODO.md +20 -14
- data/bin/test +4 -0
- data/examples/io/raw.rb +14 -0
- data/examples/io/reline.rb +18 -0
- data/examples/performance/fiber_transfer.rb +13 -4
- data/examples/performance/multi_snooze.rb +0 -1
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +8 -20
- data/ext/liburing/liburing.h +585 -0
- data/ext/liburing/liburing/README.md +4 -0
- data/ext/liburing/liburing/barrier.h +73 -0
- data/ext/liburing/liburing/compat.h +15 -0
- data/ext/liburing/liburing/io_uring.h +343 -0
- data/ext/liburing/queue.c +333 -0
- data/ext/liburing/register.c +187 -0
- data/ext/liburing/setup.c +210 -0
- data/ext/liburing/syscall.c +54 -0
- data/ext/liburing/syscall.h +18 -0
- data/ext/polyphony/backend.h +1 -15
- data/ext/polyphony/backend_common.h +120 -0
- data/ext/polyphony/backend_io_uring.c +919 -0
- data/ext/polyphony/backend_io_uring_context.c +73 -0
- data/ext/polyphony/backend_io_uring_context.h +52 -0
- data/ext/polyphony/{libev_backend.c → backend_libev.c} +241 -297
- data/ext/polyphony/event.c +1 -1
- data/ext/polyphony/extconf.rb +31 -13
- data/ext/polyphony/fiber.c +107 -28
- data/ext/polyphony/libev.c +4 -0
- data/ext/polyphony/libev.h +8 -2
- data/ext/polyphony/liburing.c +8 -0
- data/ext/polyphony/playground.c +51 -0
- data/ext/polyphony/polyphony.c +6 -6
- data/ext/polyphony/polyphony.h +34 -14
- data/ext/polyphony/polyphony_ext.c +12 -4
- data/ext/polyphony/queue.c +1 -1
- data/ext/polyphony/runqueue.c +102 -0
- data/ext/polyphony/runqueue_ring_buffer.c +85 -0
- data/ext/polyphony/runqueue_ring_buffer.h +31 -0
- data/ext/polyphony/thread.c +42 -90
- data/lib/polyphony.rb +2 -2
- data/lib/polyphony/adapters/process.rb +0 -3
- data/lib/polyphony/adapters/trace.rb +2 -2
- data/lib/polyphony/core/exceptions.rb +0 -4
- data/lib/polyphony/core/global_api.rb +13 -11
- data/lib/polyphony/core/sync.rb +7 -5
- data/lib/polyphony/extensions/core.rb +14 -33
- data/lib/polyphony/extensions/debug.rb +13 -0
- data/lib/polyphony/extensions/fiber.rb +21 -44
- data/lib/polyphony/extensions/io.rb +15 -4
- data/lib/polyphony/extensions/openssl.rb +6 -0
- data/lib/polyphony/extensions/socket.rb +63 -10
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +1 -1
- data/test/helper.rb +36 -4
- data/test/io_uring_test.rb +55 -0
- data/test/stress.rb +4 -1
- data/test/test_backend.rb +15 -6
- data/test/test_ext.rb +1 -2
- data/test/test_fiber.rb +31 -24
- data/test/test_global_api.rb +71 -31
- data/test/test_io.rb +42 -0
- data/test/test_queue.rb +1 -1
- data/test/test_signal.rb +11 -8
- data/test/test_socket.rb +2 -2
- data/test/test_sync.rb +21 -0
- data/test/test_throttler.rb +3 -7
- data/test/test_trace.rb +7 -5
- metadata +31 -6
data/ext/polyphony/event.c
CHANGED
@@ -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
|
-
|
72
|
+
RAISE_IF_EXCEPTION(switchpoint_result);
|
73
73
|
RB_GC_GUARD(backend);
|
74
74
|
RB_GC_GUARD(switchpoint_result);
|
75
75
|
|
data/ext/polyphony/extconf.rb
CHANGED
@@ -1,20 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'rubygems'
|
4
|
+
require 'mkmf'
|
4
5
|
|
5
|
-
|
6
|
+
use_liburing = false
|
7
|
+
force_use_libev = ENV['POLYPHONY_USE_LIBEV'] != nil
|
6
8
|
|
7
|
-
|
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
|
-
|
10
|
-
$defs << "-
|
11
|
-
$
|
12
|
-
|
13
|
-
$defs << "-
|
14
|
-
$defs <<
|
15
|
-
$defs <<
|
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
|
-
|
32
|
+
$defs << '-DPOLYPHONY_PLAYGROUND' if ENV['POLYPHONY_PLAYGROUND']
|
18
33
|
|
19
|
-
|
20
|
-
|
34
|
+
CONFIG['optflags'] << ' -fno-strict-aliasing' unless RUBY_PLATFORM =~ /mswin/
|
35
|
+
|
36
|
+
|
37
|
+
dir_config 'polyphony_ext'
|
38
|
+
create_makefile 'polyphony_ext'
|
data/ext/polyphony/fiber.c
CHANGED
@@ -2,12 +2,9 @@
|
|
2
2
|
|
3
3
|
ID ID_fiber_trace;
|
4
4
|
ID ID_ivar_auto_watcher;
|
5
|
-
ID
|
6
|
-
ID
|
7
|
-
ID
|
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
|
19
|
-
VALUE
|
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 =
|
24
|
+
VALUE ret = FIBER_TRANSFER(self, arg);
|
28
25
|
|
29
|
-
|
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,
|
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
|
-
|
61
|
-
VALUE
|
62
|
-
|
63
|
-
|
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
|
-
|
66
|
-
|
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
|
87
|
-
ID_ivar_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
|
90
|
-
|
91
|
-
|
92
|
-
SYM_fiber_run
|
93
|
-
SYM_fiber_schedule
|
94
|
-
SYM_fiber_switchpoint
|
95
|
-
SYM_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(&
|
99
|
-
rb_global_variable(&
|
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);
|
data/ext/polyphony/libev.c
CHANGED
data/ext/polyphony/libev.h
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
-
#define EV_STANDALONE
|
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,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
|
data/ext/polyphony/polyphony.c
CHANGED
@@ -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
|
-
|
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
|
-
|
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");
|
data/ext/polyphony/polyphony.h
CHANGED
@@ -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
|
24
|
-
|
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
|
55
|
-
extern VALUE
|
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 */
|