polyphony 0.51.0 → 0.52.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 +1 -1
- data/CHANGELOG.md +10 -0
- data/Gemfile.lock +5 -68
- data/TODO.md +6 -3
- data/examples/core/forking.rb +2 -2
- data/ext/polyphony/backend_common.h +29 -6
- data/ext/polyphony/backend_io_uring.c +49 -5
- data/ext/polyphony/backend_libev.c +145 -11
- data/ext/polyphony/event.c +1 -1
- data/ext/polyphony/extconf.rb +7 -2
- data/ext/polyphony/polyphony.c +94 -0
- data/ext/polyphony/polyphony.h +28 -2
- data/ext/polyphony/queue.c +1 -1
- data/ext/polyphony/runqueue.c +1 -1
- data/lib/polyphony/adapters/irb.rb +1 -1
- data/lib/polyphony/adapters/mysql2.rb +1 -1
- data/lib/polyphony/adapters/postgres.rb +5 -5
- data/lib/polyphony/adapters/process.rb +2 -2
- data/lib/polyphony/core/global_api.rb +5 -5
- data/lib/polyphony/core/sync.rb +1 -1
- data/lib/polyphony/core/throttler.rb +1 -1
- data/lib/polyphony/core/timer.rb +2 -2
- data/lib/polyphony/extensions/core.rb +1 -1
- data/lib/polyphony/extensions/io.rb +12 -25
- data/lib/polyphony/extensions/openssl.rb +6 -6
- data/lib/polyphony/extensions/socket.rb +35 -47
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +5 -5
- data/test/helper.rb +1 -1
- data/test/stress.rb +2 -0
- data/test/test_backend.rb +33 -5
- data/test/test_global_api.rb +2 -2
- data/test/test_io.rb +33 -2
- data/test/test_kernel.rb +1 -1
- data/test/test_signal.rb +1 -1
- data/test/test_socket.rb +27 -0
- data/test/test_timer.rb +1 -1
- metadata +4 -60
@@ -1,3 +1,41 @@
|
|
1
|
+
/*
|
2
|
+
# Libev-based blocking ops backend for Polyphony
|
3
|
+
|
4
|
+
## Backend initialization
|
5
|
+
|
6
|
+
The backend is initialized by creating an event loop. For the main thread the
|
7
|
+
default event loop is used, but we since we don't need to handle any signals
|
8
|
+
(see the waitpid implementation below) we might as well use a non-default event
|
9
|
+
loop for the main thread at some time in the future.
|
10
|
+
|
11
|
+
In addition, we create an async watcher that is used for interrupting the #poll
|
12
|
+
method from another thread.
|
13
|
+
|
14
|
+
## Blocking operations
|
15
|
+
|
16
|
+
I/O operations start by making sure the io has been set to non-blocking
|
17
|
+
operation (O_NONBLOCK). That way, if the syscall would block, we'd get an
|
18
|
+
EWOULDBLOCK or EAGAIN instead of blocking.
|
19
|
+
|
20
|
+
Once the OS has indicated that the operation would block, we start a watcher
|
21
|
+
(its type corresponding to the desired operation), and call ev_xxxx_start. in We
|
22
|
+
then call Thread_switch_fiber and switch to another fiber while waiting for the
|
23
|
+
watcher to be triggered.
|
24
|
+
|
25
|
+
## Polling for events
|
26
|
+
|
27
|
+
Backend_poll is called either once the corresponding thread has no more work to
|
28
|
+
do (no runnable fibers) or periodically while the thread is scheduling fibers in
|
29
|
+
order to prevent event starvation.
|
30
|
+
|
31
|
+
## Behaviour of waitpid
|
32
|
+
|
33
|
+
On Linux 5.3+, pidfd_open will be used, otherwise a libev child watcher will be
|
34
|
+
used. Note that if a child watcher is used, waitpid will only work from the main
|
35
|
+
thread.
|
36
|
+
|
37
|
+
*/
|
38
|
+
|
1
39
|
#ifdef POLYPHONY_BACKEND_LIBEV
|
2
40
|
|
3
41
|
#include <netdb.h>
|
@@ -76,17 +114,27 @@ void break_async_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, in
|
|
76
114
|
// of a *blocking* event loop (waking it up) in a thread-safe, signal-safe manner
|
77
115
|
}
|
78
116
|
|
117
|
+
inline struct ev_loop *libev_new_loop() {
|
118
|
+
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
119
|
+
return ev_loop_new(EVFLAG_NOSIGMASK);
|
120
|
+
#else
|
121
|
+
int is_main_thread = (rb_thread_current() == rb_thread_main());
|
122
|
+
return is_main_thread ? EV_DEFAULT : ev_loop_new(EVFLAG_NOSIGMASK);
|
123
|
+
#endif
|
124
|
+
}
|
125
|
+
|
79
126
|
static VALUE Backend_initialize(VALUE self) {
|
80
127
|
Backend_t *backend;
|
81
|
-
|
82
|
-
int is_main_thread = (thread == rb_thread_main());
|
83
|
-
|
128
|
+
|
84
129
|
GetBackend(self, backend);
|
85
|
-
backend->ev_loop =
|
130
|
+
backend->ev_loop = libev_new_loop();
|
86
131
|
|
132
|
+
// start async watcher used for breaking a poll op (from another thread)
|
87
133
|
ev_async_init(&backend->break_async, break_async_callback);
|
88
134
|
ev_async_start(backend->ev_loop, &backend->break_async);
|
89
|
-
|
135
|
+
// the break_async watcher is unreferenced, in order for Backend_poll to not
|
136
|
+
// block when no other watcher is active
|
137
|
+
ev_unref(backend->ev_loop);
|
90
138
|
|
91
139
|
backend->currently_polling = 0;
|
92
140
|
backend->pending_count = 0;
|
@@ -672,6 +720,55 @@ error:
|
|
672
720
|
return RAISE_EXCEPTION(switchpoint_result);
|
673
721
|
}
|
674
722
|
|
723
|
+
VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
724
|
+
Backend_t *backend;
|
725
|
+
struct libev_io watcher;
|
726
|
+
rb_io_t *fptr;
|
727
|
+
VALUE switchpoint_result = Qnil;
|
728
|
+
VALUE underlying_io;
|
729
|
+
char *buf = StringValuePtr(str);
|
730
|
+
long len = RSTRING_LEN(str);
|
731
|
+
long left = len;
|
732
|
+
int flags_int = NUM2INT(flags);
|
733
|
+
|
734
|
+
underlying_io = rb_ivar_get(io, ID_ivar_io);
|
735
|
+
if (underlying_io != Qnil) io = underlying_io;
|
736
|
+
GetBackend(self, backend);
|
737
|
+
io = rb_io_get_write_io(io);
|
738
|
+
GetOpenFile(io, fptr);
|
739
|
+
io_set_nonblock(fptr, io);
|
740
|
+
watcher.fiber = Qnil;
|
741
|
+
|
742
|
+
while (left > 0) {
|
743
|
+
ssize_t n = send(fptr->fd, buf, left, flags_int);
|
744
|
+
if (n < 0) {
|
745
|
+
int e = errno;
|
746
|
+
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
747
|
+
|
748
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_WRITE);
|
749
|
+
|
750
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
751
|
+
}
|
752
|
+
else {
|
753
|
+
buf += n;
|
754
|
+
left -= n;
|
755
|
+
}
|
756
|
+
}
|
757
|
+
|
758
|
+
if (watcher.fiber == Qnil) {
|
759
|
+
switchpoint_result = backend_snooze();
|
760
|
+
|
761
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
762
|
+
}
|
763
|
+
|
764
|
+
RB_GC_GUARD(watcher.fiber);
|
765
|
+
RB_GC_GUARD(switchpoint_result);
|
766
|
+
|
767
|
+
return INT2NUM(len);
|
768
|
+
error:
|
769
|
+
return RAISE_EXCEPTION(switchpoint_result);
|
770
|
+
}
|
771
|
+
|
675
772
|
VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
|
676
773
|
Backend_t *backend;
|
677
774
|
rb_io_t *fptr;
|
@@ -799,6 +896,7 @@ VALUE Backend_timeout(int argc,VALUE *argv, VALUE self) {
|
|
799
896
|
return result;
|
800
897
|
}
|
801
898
|
|
899
|
+
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
802
900
|
VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
803
901
|
int pid_int = NUM2INT(pid);
|
804
902
|
int fd = pidfd_open(pid_int, 0);
|
@@ -811,18 +909,53 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
|
811
909
|
RAISE_IF_EXCEPTION(resume_value);
|
812
910
|
RB_GC_GUARD(resume_value);
|
813
911
|
}
|
912
|
+
else {
|
913
|
+
int e = errno;
|
914
|
+
rb_syserr_fail(e, strerror(e));
|
915
|
+
}
|
814
916
|
|
815
917
|
int status = 0;
|
816
918
|
pid_t ret = waitpid(pid_int, &status, WNOHANG);
|
817
919
|
if (ret < 0) {
|
818
920
|
int e = errno;
|
819
|
-
|
820
|
-
ret = pid_int;
|
821
|
-
else
|
822
|
-
rb_syserr_fail(e, strerror(e));
|
921
|
+
rb_syserr_fail(e, strerror(e));
|
823
922
|
}
|
824
923
|
return rb_ary_new_from_args(2, INT2NUM(ret), INT2NUM(WEXITSTATUS(status)));
|
825
924
|
}
|
925
|
+
#else
|
926
|
+
struct libev_child {
|
927
|
+
struct ev_child child;
|
928
|
+
VALUE fiber;
|
929
|
+
};
|
930
|
+
|
931
|
+
void Backend_child_callback(EV_P_ ev_child *w, int revents) {
|
932
|
+
struct libev_child *watcher = (struct libev_child *)w;
|
933
|
+
int exit_status = WEXITSTATUS(w->rstatus);
|
934
|
+
VALUE status;
|
935
|
+
|
936
|
+
status = rb_ary_new_from_args(2, INT2NUM(w->rpid), INT2NUM(exit_status));
|
937
|
+
Fiber_make_runnable(watcher->fiber, status);
|
938
|
+
}
|
939
|
+
|
940
|
+
VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
941
|
+
Backend_t *backend;
|
942
|
+
struct libev_child watcher;
|
943
|
+
VALUE switchpoint_result = Qnil;
|
944
|
+
GetBackend(self, backend);
|
945
|
+
|
946
|
+
watcher.fiber = rb_fiber_current();
|
947
|
+
ev_child_init(&watcher.child, Backend_child_callback, NUM2INT(pid), 0);
|
948
|
+
ev_child_start(backend->ev_loop, &watcher.child);
|
949
|
+
|
950
|
+
switchpoint_result = backend_await(backend);
|
951
|
+
|
952
|
+
ev_child_stop(backend->ev_loop, &watcher.child);
|
953
|
+
RAISE_IF_EXCEPTION(switchpoint_result);
|
954
|
+
RB_GC_GUARD(watcher.fiber);
|
955
|
+
RB_GC_GUARD(switchpoint_result);
|
956
|
+
return switchpoint_result;
|
957
|
+
}
|
958
|
+
#endif
|
826
959
|
|
827
960
|
void Backend_async_callback(EV_P_ ev_async *w, int revents) { }
|
828
961
|
|
@@ -851,7 +984,7 @@ VALUE Backend_kind(VALUE self) {
|
|
851
984
|
void Init_Backend() {
|
852
985
|
ev_set_allocator(xrealloc);
|
853
986
|
|
854
|
-
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend",
|
987
|
+
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cObject);
|
855
988
|
rb_define_alloc_func(cBackend, Backend_allocate);
|
856
989
|
|
857
990
|
rb_define_method(cBackend, "initialize", Backend_initialize, 0);
|
@@ -871,7 +1004,8 @@ void Init_Backend() {
|
|
871
1004
|
rb_define_method(cBackend, "recv", Backend_recv, 3);
|
872
1005
|
rb_define_method(cBackend, "recv_loop", Backend_read_loop, 1);
|
873
1006
|
rb_define_method(cBackend, "recv_feed_loop", Backend_feed_loop, 3);
|
874
|
-
rb_define_method(cBackend, "send",
|
1007
|
+
rb_define_method(cBackend, "send", Backend_send, 3);
|
1008
|
+
rb_define_method(cBackend, "sendv", Backend_sendv, 3);
|
875
1009
|
rb_define_method(cBackend, "wait_io", Backend_wait_io, 2);
|
876
1010
|
rb_define_method(cBackend, "sleep", Backend_sleep, 1);
|
877
1011
|
rb_define_method(cBackend, "timer_loop", Backend_timer_loop, 1);
|
data/ext/polyphony/event.c
CHANGED
@@ -77,7 +77,7 @@ VALUE Event_await(VALUE self) {
|
|
77
77
|
}
|
78
78
|
|
79
79
|
void Init_Event() {
|
80
|
-
cEvent = rb_define_class_under(mPolyphony, "Event",
|
80
|
+
cEvent = rb_define_class_under(mPolyphony, "Event", rb_cObject);
|
81
81
|
rb_define_alloc_func(cEvent, Event_allocate);
|
82
82
|
|
83
83
|
rb_define_method(cEvent, "initialize", Event_initialize, 0);
|
data/ext/polyphony/extconf.rb
CHANGED
@@ -4,15 +4,19 @@ require 'rubygems'
|
|
4
4
|
require 'mkmf'
|
5
5
|
|
6
6
|
use_liburing = false
|
7
|
+
use_pidfd_open = false
|
7
8
|
force_use_libev = ENV['POLYPHONY_USE_LIBEV'] != nil
|
8
9
|
|
9
|
-
if
|
10
|
+
if RUBY_PLATFORM =~ /linux/ && `uname -sr` =~ /Linux 5\.([\d+])/
|
10
11
|
kernel_minor_version = $1.gsub('.', '').to_i
|
11
|
-
use_liburing = kernel_minor_version >= 6
|
12
|
+
use_liburing = !force_use_libev && kernel_minor_version >= 6
|
13
|
+
use_pidfd_open = kernel_minor_version >= 3
|
12
14
|
end
|
13
15
|
|
16
|
+
$defs << '-DPOLYPHONY_USE_PIDFD_OPEN' if use_pidfd_open
|
14
17
|
if use_liburing
|
15
18
|
$defs << "-DPOLYPHONY_BACKEND_LIBURING"
|
19
|
+
$defs << "-DPOLYPHONY_UNSET_NONBLOCK" if RUBY_VERSION =~ /^3/
|
16
20
|
$CFLAGS << " -Wno-pointer-arith"
|
17
21
|
else
|
18
22
|
$defs << "-DPOLYPHONY_BACKEND_LIBEV"
|
@@ -23,6 +27,7 @@ else
|
|
23
27
|
$defs << '-DEV_USE_KQUEUE' if have_header('sys/event.h') && have_header('sys/queue.h')
|
24
28
|
$defs << '-DEV_USE_PORT' if have_type('port_event_t', 'port.h')
|
25
29
|
$defs << '-DHAVE_SYS_RESOURCE_H' if have_header('sys/resource.h')
|
30
|
+
|
26
31
|
$CFLAGS << " -Wno-comment"
|
27
32
|
$CFLAGS << " -Wno-unused-result"
|
28
33
|
$CFLAGS << " -Wno-dangling-else"
|
data/ext/polyphony/polyphony.c
CHANGED
@@ -46,11 +46,105 @@ VALUE Polyphony_trace(VALUE self, VALUE enabled) {
|
|
46
46
|
return Qnil;
|
47
47
|
}
|
48
48
|
|
49
|
+
#define BACKEND() (rb_ivar_get(rb_thread_current(), ID_ivar_backend))
|
50
|
+
|
51
|
+
VALUE Polyphony_backend_accept(VALUE self, VALUE server_socket, VALUE socket_class) {
|
52
|
+
return Backend_accept(BACKEND(), server_socket, socket_class);
|
53
|
+
}
|
54
|
+
|
55
|
+
VALUE Polyphony_backend_accept_loop(VALUE self, VALUE server_socket, VALUE socket_class) {
|
56
|
+
return Backend_accept_loop(BACKEND(), server_socket, socket_class);
|
57
|
+
}
|
58
|
+
|
59
|
+
VALUE Polyphony_backend_connect(VALUE self, VALUE io, VALUE addr, VALUE port) {
|
60
|
+
return Backend_connect(BACKEND(), io, addr, port);
|
61
|
+
}
|
62
|
+
|
63
|
+
VALUE Polyphony_backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
64
|
+
return Backend_feed_loop(BACKEND(), io, receiver, method);
|
65
|
+
}
|
66
|
+
|
67
|
+
VALUE Polyphony_backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof) {
|
68
|
+
return Backend_read(BACKEND(), io, str, length, to_eof);
|
69
|
+
}
|
70
|
+
|
71
|
+
VALUE Polyphony_backend_read_loop(VALUE self, VALUE io) {
|
72
|
+
return Backend_read_loop(BACKEND(), io);
|
73
|
+
}
|
74
|
+
|
75
|
+
VALUE Polyphony_backend_recv(VALUE self, VALUE io, VALUE str, VALUE length) {
|
76
|
+
return Backend_recv(BACKEND(), io, str, length);
|
77
|
+
}
|
78
|
+
|
79
|
+
VALUE Polyphony_backend_recv_loop(VALUE self, VALUE io) {
|
80
|
+
return Backend_recv_loop(BACKEND(), io);
|
81
|
+
}
|
82
|
+
|
83
|
+
VALUE Polyphony_backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
84
|
+
return Backend_recv_feed_loop(BACKEND(), io, receiver, method);
|
85
|
+
}
|
86
|
+
|
87
|
+
VALUE Polyphony_backend_send(VALUE self, VALUE io, VALUE msg, VALUE flags) {
|
88
|
+
return Backend_send(BACKEND(), io, msg, flags);
|
89
|
+
}
|
90
|
+
|
91
|
+
VALUE Polyphony_backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags) {
|
92
|
+
return Backend_sendv(BACKEND(), io, ary, flags);
|
93
|
+
}
|
94
|
+
|
95
|
+
VALUE Polyphony_backend_sleep(VALUE self, VALUE duration) {
|
96
|
+
return Backend_sleep(BACKEND(), duration);
|
97
|
+
}
|
98
|
+
|
99
|
+
VALUE Polyphony_backend_timeout(int argc,VALUE *argv, VALUE self) {
|
100
|
+
return Backend_timeout(argc, argv, BACKEND());
|
101
|
+
}
|
102
|
+
|
103
|
+
VALUE Polyphony_backend_timer_loop(VALUE self, VALUE interval) {
|
104
|
+
return Backend_timer_loop(BACKEND(), interval);
|
105
|
+
}
|
106
|
+
|
107
|
+
VALUE Polyphony_backend_wait_event(VALUE self, VALUE raise) {
|
108
|
+
return Backend_wait_event(BACKEND(), raise);
|
109
|
+
}
|
110
|
+
|
111
|
+
VALUE Polyphony_backend_wait_io(VALUE self, VALUE io, VALUE write) {
|
112
|
+
return Backend_wait_io(BACKEND(), io, write);
|
113
|
+
}
|
114
|
+
|
115
|
+
VALUE Polyphony_backend_waitpid(VALUE self, VALUE pid) {
|
116
|
+
return Backend_waitpid(BACKEND(), pid);
|
117
|
+
}
|
118
|
+
|
119
|
+
VALUE Polyphony_backend_write(int argc, VALUE *argv, VALUE self) {
|
120
|
+
return Backend_write_m(argc, argv, BACKEND());
|
121
|
+
}
|
122
|
+
|
49
123
|
void Init_Polyphony() {
|
50
124
|
mPolyphony = rb_define_module("Polyphony");
|
51
125
|
|
52
126
|
rb_define_singleton_method(mPolyphony, "trace", Polyphony_trace, 1);
|
53
127
|
|
128
|
+
// backend methods
|
129
|
+
rb_define_singleton_method(mPolyphony, "backend_accept", Polyphony_backend_accept, 2);
|
130
|
+
rb_define_singleton_method(mPolyphony, "backend_accept_loop", Polyphony_backend_accept_loop, 2);
|
131
|
+
rb_define_singleton_method(mPolyphony, "backend_connect", Polyphony_backend_connect, 3);
|
132
|
+
rb_define_singleton_method(mPolyphony, "backend_feed_loop", Polyphony_backend_feed_loop, 3);
|
133
|
+
rb_define_singleton_method(mPolyphony, "backend_read", Polyphony_backend_read, 4);
|
134
|
+
rb_define_singleton_method(mPolyphony, "backend_read_loop", Polyphony_backend_read_loop, 1);
|
135
|
+
rb_define_singleton_method(mPolyphony, "backend_recv", Polyphony_backend_recv, 3);
|
136
|
+
rb_define_singleton_method(mPolyphony, "backend_recv_loop", Polyphony_backend_recv_loop, 1);
|
137
|
+
rb_define_singleton_method(mPolyphony, "backend_recv_feed_loop", Polyphony_backend_recv_feed_loop, 3);
|
138
|
+
rb_define_singleton_method(mPolyphony, "backend_send", Polyphony_backend_send, 3);
|
139
|
+
rb_define_singleton_method(mPolyphony, "backend_sendv", Polyphony_backend_sendv, 3);
|
140
|
+
rb_define_singleton_method(mPolyphony, "backend_sleep", Polyphony_backend_sleep, 1);
|
141
|
+
rb_define_singleton_method(mPolyphony, "backend_timeout", Polyphony_backend_timeout, -1);
|
142
|
+
rb_define_singleton_method(mPolyphony, "backend_timer_loop", Polyphony_backend_timer_loop, 1);
|
143
|
+
rb_define_singleton_method(mPolyphony, "backend_wait_event", Polyphony_backend_wait_event, 1);
|
144
|
+
rb_define_singleton_method(mPolyphony, "backend_wait_io", Polyphony_backend_wait_io, 2);
|
145
|
+
rb_define_singleton_method(mPolyphony, "backend_waitpid", Polyphony_backend_waitpid, 1);
|
146
|
+
rb_define_singleton_method(mPolyphony, "backend_write", Polyphony_backend_write, -1);
|
147
|
+
|
54
148
|
rb_define_global_function("snooze", Polyphony_snooze, 0);
|
55
149
|
rb_define_global_function("suspend", Polyphony_suspend, 0);
|
56
150
|
|
data/ext/polyphony/polyphony.h
CHANGED
@@ -23,9 +23,9 @@
|
|
23
23
|
#define COND_TRACE(...) if (__tracing_enabled__) { TRACE(__VA_ARGS__); }
|
24
24
|
|
25
25
|
// exceptions
|
26
|
-
#define TEST_EXCEPTION(ret) (
|
26
|
+
#define TEST_EXCEPTION(ret) (rb_obj_is_kind_of(ret, rb_eException) == Qtrue)
|
27
27
|
#define RAISE_EXCEPTION(e) rb_funcall(e, ID_invoke, 0);
|
28
|
-
#define RAISE_IF_EXCEPTION(ret) if (
|
28
|
+
#define RAISE_IF_EXCEPTION(ret) if (rb_obj_is_kind_of(ret, rb_eException) == Qtrue) { RAISE_EXCEPTION(ret); }
|
29
29
|
#define RAISE_IF_NOT_NIL(ret) if (ret != Qnil) { RAISE_EXCEPTION(ret); }
|
30
30
|
|
31
31
|
// Fiber#transfer
|
@@ -89,6 +89,32 @@ void Runqueue_clear(VALUE self);
|
|
89
89
|
long Runqueue_len(VALUE self);
|
90
90
|
int Runqueue_empty_p(VALUE self);
|
91
91
|
|
92
|
+
#ifdef POLYPHONY_BACKEND_LIBEV
|
93
|
+
#define Backend_recv_loop Backend_read_loop
|
94
|
+
#define Backend_recv_feed_loop Backend_feed_loop
|
95
|
+
#endif
|
96
|
+
|
97
|
+
// Backend public interface
|
98
|
+
|
99
|
+
VALUE Backend_accept(VALUE self, VALUE server_socket, VALUE socket_class);
|
100
|
+
VALUE Backend_accept_loop(VALUE self, VALUE server_socket, VALUE socket_class);
|
101
|
+
VALUE Backend_connect(VALUE self, VALUE io, VALUE addr, VALUE port);
|
102
|
+
VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method);
|
103
|
+
VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof);
|
104
|
+
VALUE Backend_read_loop(VALUE self, VALUE io);
|
105
|
+
VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length);
|
106
|
+
VALUE Backend_recv_loop(VALUE self, VALUE io);
|
107
|
+
VALUE Backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method);
|
108
|
+
VALUE Backend_send(VALUE self, VALUE io, VALUE msg, VALUE flags);
|
109
|
+
VALUE Backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags);
|
110
|
+
VALUE Backend_sleep(VALUE self, VALUE duration);
|
111
|
+
VALUE Backend_timeout(int argc,VALUE *argv, VALUE self);
|
112
|
+
VALUE Backend_timer_loop(VALUE self, VALUE interval);
|
113
|
+
VALUE Backend_wait_event(VALUE self, VALUE raise);
|
114
|
+
VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write);
|
115
|
+
VALUE Backend_waitpid(VALUE self, VALUE pid);
|
116
|
+
VALUE Backend_write_m(int argc, VALUE *argv, VALUE self);
|
117
|
+
|
92
118
|
unsigned int Backend_pending_count(VALUE self);
|
93
119
|
VALUE Backend_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE runqueue);
|
94
120
|
VALUE Backend_wait_event(VALUE self, VALUE raise_on_exception);
|
data/ext/polyphony/queue.c
CHANGED
@@ -247,7 +247,7 @@ VALUE Queue_size_m(VALUE self) {
|
|
247
247
|
}
|
248
248
|
|
249
249
|
void Init_Queue() {
|
250
|
-
cQueue = rb_define_class_under(mPolyphony, "Queue",
|
250
|
+
cQueue = rb_define_class_under(mPolyphony, "Queue", rb_cObject);
|
251
251
|
rb_define_alloc_func(cQueue, Queue_allocate);
|
252
252
|
|
253
253
|
rb_define_method(cQueue, "initialize", Queue_initialize, -1);
|
data/ext/polyphony/runqueue.c
CHANGED
@@ -101,7 +101,7 @@ int Runqueue_empty_p(VALUE self) {
|
|
101
101
|
}
|
102
102
|
|
103
103
|
void Init_Runqueue() {
|
104
|
-
cRunqueue = rb_define_class_under(mPolyphony, "Runqueue",
|
104
|
+
cRunqueue = rb_define_class_under(mPolyphony, "Runqueue", rb_cObject);
|
105
105
|
rb_define_alloc_func(cRunqueue, Runqueue_allocate);
|
106
106
|
|
107
107
|
rb_define_method(cRunqueue, "initialize", Runqueue_initialize, 0);
|
@@ -15,8 +15,8 @@ module ::PG
|
|
15
15
|
res = conn.connect_poll
|
16
16
|
case res
|
17
17
|
when PGRES_POLLING_FAILED then raise Error, conn.error_message
|
18
|
-
when PGRES_POLLING_READING then
|
19
|
-
when PGRES_POLLING_WRITING then
|
18
|
+
when PGRES_POLLING_READING then Polyphony.backend_wait_io(socket_io, false)
|
19
|
+
when PGRES_POLLING_WRITING then Polyphony.backend_wait_io(socket_io, true)
|
20
20
|
when PGRES_POLLING_OK then return conn.setnonblocking(true)
|
21
21
|
end
|
22
22
|
end
|
@@ -42,7 +42,7 @@ class ::PG::Connection
|
|
42
42
|
|
43
43
|
def get_result(&block)
|
44
44
|
while is_busy
|
45
|
-
|
45
|
+
Polyphony.backend_wait_io(socket_io, false)
|
46
46
|
consume_input
|
47
47
|
end
|
48
48
|
orig_get_result(&block)
|
@@ -59,7 +59,7 @@ class ::PG::Connection
|
|
59
59
|
|
60
60
|
def block(_timeout = 0)
|
61
61
|
while is_busy
|
62
|
-
|
62
|
+
Polyphony.backend_wait_io(socket_io, false)
|
63
63
|
consume_input
|
64
64
|
end
|
65
65
|
end
|
@@ -97,7 +97,7 @@ class ::PG::Connection
|
|
97
97
|
return move_on_after(timeout) { wait_for_notify(&block) } if timeout
|
98
98
|
|
99
99
|
while true
|
100
|
-
|
100
|
+
Polyphony.backend_wait_io(socket_io, false)
|
101
101
|
consume_input
|
102
102
|
notice = notifies
|
103
103
|
next unless notice
|