polyphony 0.45.0 → 0.46.0
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/.rubocop.yml +1 -0
- data/CHANGELOG.md +38 -0
- data/Gemfile.lock +11 -3
- data/README.md +3 -3
- data/Rakefile +1 -1
- data/TODO.md +10 -18
- data/examples/adapters/redis_client.rb +3 -1
- data/examples/adapters/redis_pubsub_perf.rb +11 -8
- data/examples/adapters/sequel_mysql.rb +1 -1
- data/examples/adapters/sequel_pg.rb +24 -0
- data/examples/core/{02-awaiting-fibers.rb → await.rb} +0 -0
- data/examples/core/{xx-channels.rb → channels.rb} +0 -0
- data/examples/core/deferring-an-operation.rb +16 -0
- data/examples/core/{xx-erlang-style-genserver.rb → erlang-style-genserver.rb} +16 -9
- data/examples/core/{xx-forking.rb → forking.rb} +1 -1
- data/examples/core/handling-signals.rb +11 -0
- data/examples/core/{03-interrupting.rb → interrupt.rb} +0 -0
- data/examples/core/{xx-pingpong.rb → pingpong.rb} +7 -5
- data/examples/core/{xx-recurrent-timer.rb → recurrent-timer.rb} +1 -1
- data/examples/core/{xx-resource_delegate.rb → resource_delegate.rb} +3 -4
- data/examples/core/{01-spinning-up-fibers.rb → spin.rb} +1 -1
- data/examples/core/{xx-spin_error_backtrace.rb → spin_error_backtrace.rb} +1 -1
- data/examples/core/{xx-supervise-process.rb → supervise-process.rb} +8 -5
- data/examples/core/supervisor.rb +20 -0
- data/examples/core/{xx-thread-sleep.rb → thread-sleep.rb} +0 -0
- data/examples/core/{xx-thread_pool.rb → thread_pool.rb} +0 -0
- data/examples/core/{xx-throttling.rb → throttling.rb} +0 -0
- data/examples/core/{xx-timeout.rb → timeout.rb} +0 -0
- data/examples/core/{xx-using-a-mutex.rb → using-a-mutex.rb} +0 -0
- data/examples/core/{xx-worker-thread.rb → worker-thread.rb} +2 -2
- data/examples/io/{xx-backticks.rb → backticks.rb} +0 -0
- data/examples/io/{xx-echo_client.rb → echo_client.rb} +1 -1
- data/examples/io/{xx-echo_client_from_stdin.rb → echo_client_from_stdin.rb} +2 -2
- data/examples/io/{xx-echo_pipe.rb → echo_pipe.rb} +1 -1
- data/examples/io/{xx-echo_server.rb → echo_server.rb} +0 -0
- data/examples/io/{xx-echo_server_with_timeout.rb → echo_server_with_timeout.rb} +1 -1
- data/examples/io/{xx-echo_stdin.rb → echo_stdin.rb} +0 -0
- data/examples/io/{xx-happy-eyeballs.rb → happy-eyeballs.rb} +0 -0
- data/examples/io/{xx-httparty.rb → httparty.rb} +4 -13
- data/examples/io/{xx-irb.rb → irb.rb} +0 -0
- data/examples/io/{xx-net-http.rb → net-http.rb} +0 -0
- data/examples/io/{xx-open.rb → open.rb} +0 -0
- data/examples/io/{xx-pry.rb → pry.rb} +0 -0
- data/examples/io/{xx-rack_server.rb → rack_server.rb} +0 -0
- data/examples/io/raw.rb +14 -0
- data/examples/io/reline.rb +18 -0
- data/examples/io/{xx-system.rb → system.rb} +1 -1
- data/examples/io/{xx-tcpserver.rb → tcpserver.rb} +0 -0
- data/examples/io/{xx-tcpsocket.rb → tcpsocket.rb} +0 -0
- data/examples/io/tunnel.rb +6 -1
- data/examples/io/{xx-zip.rb → zip.rb} +0 -0
- data/examples/performance/fiber_transfer.rb +2 -1
- data/examples/performance/fs_read.rb +5 -6
- data/examples/performance/multi_snooze.rb +0 -1
- data/examples/{io/xx-switch.rb → performance/switch.rb} +2 -1
- data/examples/performance/thread-vs-fiber/{xx-httparty_multi.rb → httparty_multi.rb} +3 -4
- data/examples/performance/thread-vs-fiber/{xx-httparty_threaded.rb → httparty_threaded.rb} +0 -0
- data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +1 -1
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -2
- data/examples/performance/thread-vs-fiber/threaded_server.rb +1 -5
- data/examples/performance/thread_pool_perf.rb +6 -7
- 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 -16
- data/ext/polyphony/backend_common.h +109 -0
- data/ext/polyphony/backend_io_uring.c +884 -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} +255 -345
- data/ext/polyphony/event.c +1 -1
- data/ext/polyphony/extconf.rb +31 -13
- data/ext/polyphony/fiber.c +111 -27
- 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 -8
- data/ext/polyphony/polyphony.h +29 -25
- data/ext/polyphony/polyphony_ext.c +13 -6
- data/ext/polyphony/queue.c +3 -4
- data/ext/polyphony/ring_buffer.c +0 -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 +45 -92
- data/lib/polyphony.rb +2 -2
- data/lib/polyphony/adapters/fs.rb +1 -1
- data/lib/polyphony/adapters/process.rb +0 -3
- data/lib/polyphony/adapters/redis.rb +1 -1
- data/lib/polyphony/adapters/trace.rb +2 -2
- data/lib/polyphony/core/global_api.rb +9 -12
- data/lib/polyphony/core/sync.rb +6 -2
- data/lib/polyphony/extensions/core.rb +6 -24
- data/lib/polyphony/extensions/debug.rb +13 -0
- data/lib/polyphony/extensions/fiber.rb +21 -44
- data/lib/polyphony/extensions/io.rb +55 -10
- data/lib/polyphony/extensions/socket.rb +70 -12
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +3 -2
- data/test/helper.rb +36 -4
- data/test/io_uring_test.rb +55 -0
- data/test/stress.rb +5 -2
- data/test/test_backend.rb +4 -6
- data/test/test_ext.rb +1 -2
- data/test/test_fiber.rb +31 -24
- data/test/test_global_api.rb +58 -31
- data/test/test_io.rb +58 -0
- data/test/test_signal.rb +11 -8
- data/test/test_socket.rb +17 -0
- data/test/test_sync.rb +21 -0
- data/test/test_throttler.rb +3 -6
- data/test/test_trace.rb +7 -5
- metadata +86 -76
- data/examples/adapters/concurrent-ruby.rb +0 -9
- data/examples/core/04-handling-signals.rb +0 -19
- data/examples/core/xx-at_exit.rb +0 -29
- data/examples/core/xx-backend.rb +0 -102
- data/examples/core/xx-caller.rb +0 -12
- data/examples/core/xx-daemon.rb +0 -14
- data/examples/core/xx-deadlock.rb +0 -8
- data/examples/core/xx-deferring-an-operation.rb +0 -14
- data/examples/core/xx-exception-backtrace.rb +0 -40
- data/examples/core/xx-fork-cleanup.rb +0 -22
- data/examples/core/xx-fork-spin.rb +0 -42
- data/examples/core/xx-fork-terminate.rb +0 -27
- data/examples/core/xx-move_on.rb +0 -23
- data/examples/core/xx-queue-async.rb +0 -120
- data/examples/core/xx-readpartial.rb +0 -18
- data/examples/core/xx-signals.rb +0 -16
- data/examples/core/xx-sleep-forever.rb +0 -9
- data/examples/core/xx-sleeping.rb +0 -25
- data/examples/core/xx-snooze-starve.rb +0 -16
- data/examples/core/xx-spin-fork.rb +0 -49
- data/examples/core/xx-state-machine.rb +0 -51
- data/examples/core/xx-stop.rb +0 -20
- data/examples/core/xx-supervisors.rb +0 -21
- data/examples/core/xx-thread-selector-sleep.rb +0 -51
- data/examples/core/xx-thread-selector-snooze.rb +0 -46
- data/examples/core/xx-thread-snooze.rb +0 -34
- data/examples/core/xx-timer-gc.rb +0 -17
- data/examples/core/xx-trace.rb +0 -79
- data/examples/performance/xx-array.rb +0 -11
- data/examples/performance/xx-fiber-switch.rb +0 -9
- data/examples/performance/xx-snooze.rb +0 -15
- data/examples/xx-spin.rb +0 -32
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;
|
@@ -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
|
-
|
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,
|
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
|
-
|
61
|
-
VALUE
|
62
|
-
|
63
|
-
|
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
|
-
|
66
|
-
|
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
|
87
|
-
ID_ivar_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
|
90
|
-
|
91
|
-
|
92
|
-
SYM_fiber_run
|
93
|
-
SYM_fiber_schedule
|
94
|
-
SYM_fiber_switchpoint
|
95
|
-
SYM_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(&
|
99
|
-
rb_global_variable(&
|
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);
|
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,11 +9,10 @@ ID ID_each;
|
|
9
9
|
ID ID_inspect;
|
10
10
|
ID ID_invoke;
|
11
11
|
ID ID_new;
|
12
|
-
ID
|
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
|
-
|
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
|
-
|
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");
|
data/ext/polyphony/polyphony.h
CHANGED
@@ -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
|
24
|
-
|
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
|
56
|
-
extern VALUE
|
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
|
-
|
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 */
|