polyphony 0.52.0 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +1 -1
- data/TODO.md +36 -8
- data/examples/io/echo_server.rb +1 -0
- data/examples/io/tcp_proxy.rb +2 -2
- data/ext/polyphony/backend_io_uring.c +67 -10
- data/ext/polyphony/backend_io_uring_context.c +1 -0
- data/ext/polyphony/backend_io_uring_context.h +1 -0
- data/ext/polyphony/backend_libev.c +131 -10
- data/ext/polyphony/extconf.rb +3 -1
- data/ext/polyphony/polyphony.c +10 -2
- data/ext/polyphony/polyphony.h +4 -0
- data/ext/polyphony/polyphony_ext.c +3 -0
- data/ext/polyphony/socket_extensions.c +33 -0
- data/lib/polyphony/extensions/io.rb +8 -0
- data/lib/polyphony/extensions/socket.rb +24 -15
- data/lib/polyphony/version.rb +1 -1
- data/test/test_backend.rb +36 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0682736e3fdca0ada986f4210f1bb25d682c75a7b9d297451c186b90c8025e13'
|
4
|
+
data.tar.gz: 5ff46620651c056983a6f73c879ca1c49acea22c0c7abcefb1a119cbe248cb77
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cfbb8141b21cc9e56cdcd9a34fd55cd3b48573dcc3011f127ece5049b13ca2c7fa8a17c8525ba5996ab97afcbfc8e46064a3d68c79d71d44d40c274ff9051d2d
|
7
|
+
data.tar.gz: f31d711c88fe354b8ffd63e37f30887b1bfb5c3709d3760412ee4ec4ea06d14c0a17e668ddd750958295dc12307b96cf64874b1be4ed46b8564d04236114ee67
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/TODO.md
CHANGED
@@ -1,8 +1,7 @@
|
|
1
|
-
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
- libvev Backend_writev (for iov)
|
1
|
+
- Add support for IPv6:
|
2
|
+
https://www.reddit.com/r/ruby/comments/lyen23/understanding_ipv6_and_why_its_important_to_you/
|
3
|
+
|
4
|
+
- Add support for UDP sockets
|
6
5
|
|
7
6
|
- Check segfault when resetting a `cancel_after` timeout lots of times at very high rate
|
8
7
|
- Check why `throttled_loop` inside of `move_on_after` fails to stop
|
@@ -19,17 +18,46 @@
|
|
19
18
|
- `Fiber#receive_loop` (very little effort, should be implemented in C)
|
20
19
|
|
21
20
|
|
22
|
-
- Add `Backend#splice`, `Backend#
|
21
|
+
- Add `Backend#splice`, `Backend#splice_to_eof` for implementing stuff like proxying:
|
23
22
|
|
24
23
|
```ruby
|
25
24
|
def two_way_proxy(socket1, socket2)
|
26
25
|
backend = Thread.current.backend
|
27
|
-
f1 = spin { backend.
|
28
|
-
f2 = spin { backend.
|
26
|
+
f1 = spin { backend.splice_to_eof(socket1, socket2) }
|
27
|
+
f2 = spin { backend.splice_to_eof(socket2, socket1) }
|
29
28
|
Fiber.await(f1, f2)
|
30
29
|
end
|
31
30
|
```
|
32
31
|
|
32
|
+
- Add support for `close` to io_uring backend
|
33
|
+
|
34
|
+
- Add support for submission of multiple requests to io_uring backend:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
Thread.current.backend.submit(
|
38
|
+
[sock, :<<, chunk_header(len)],
|
39
|
+
[sock, :splice, file, len]
|
40
|
+
)
|
41
|
+
```
|
42
|
+
|
43
|
+
Full example (for writing chunks from a file to an HTTP response):
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
def serve_io(io)
|
47
|
+
i, o = IO.pipe
|
48
|
+
backend = Thread.current.backend
|
49
|
+
while true
|
50
|
+
len = o.splice(io, 8192)
|
51
|
+
break if len == 0
|
52
|
+
|
53
|
+
backend.submit(
|
54
|
+
[sock, :<<, chunk_header(len)],
|
55
|
+
[sock, :splice, file, len]
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
33
61
|
- Graceful shutdown again:
|
34
62
|
- What happens to children when doing a graceful shutdown?
|
35
63
|
- What are the implications of passing graceful shutdown flag to children?
|
data/examples/io/echo_server.rb
CHANGED
data/examples/io/tcp_proxy.rb
CHANGED
@@ -15,7 +15,7 @@ f1 = spin {
|
|
15
15
|
client1 = server1.accept
|
16
16
|
loop do
|
17
17
|
if client2
|
18
|
-
Thread.current.backend.
|
18
|
+
Thread.current.backend.splice_to_eof(client1, client2)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
}
|
@@ -24,7 +24,7 @@ f2 = spin {
|
|
24
24
|
client2 = server2.accept
|
25
25
|
loop do
|
26
26
|
if client1
|
27
|
-
Thread.current.backend.
|
27
|
+
Thread.current.backend.splice_to_eof(client2, client1)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
}
|
@@ -43,6 +43,7 @@ inline void io_unset_nonblock(rb_io_t *fptr, VALUE io) {
|
|
43
43
|
fcntl(fptr->fd, F_SETFL, oflags);
|
44
44
|
}
|
45
45
|
#else
|
46
|
+
// NOP
|
46
47
|
#define io_unset_nonblock(fptr, io)
|
47
48
|
#endif
|
48
49
|
|
@@ -824,6 +825,60 @@ VALUE Backend_accept_loop(VALUE self, VALUE server_socket, VALUE socket_class) {
|
|
824
825
|
return self;
|
825
826
|
}
|
826
827
|
|
828
|
+
VALUE io_uring_backend_splice(Backend_t *backend, VALUE src, VALUE dest, VALUE maxlen, int loop) {
|
829
|
+
rb_io_t *src_fptr;
|
830
|
+
rb_io_t *dest_fptr;
|
831
|
+
VALUE underlying_io;
|
832
|
+
int total = 0;
|
833
|
+
|
834
|
+
underlying_io = rb_ivar_get(src, ID_ivar_io);
|
835
|
+
if (underlying_io != Qnil) src = underlying_io;
|
836
|
+
GetOpenFile(src, src_fptr);
|
837
|
+
io_unset_nonblock(src_fptr, src);
|
838
|
+
|
839
|
+
underlying_io = rb_ivar_get(dest, ID_ivar_io);
|
840
|
+
if (underlying_io != Qnil) dest = underlying_io;
|
841
|
+
dest = rb_io_get_write_io(dest);
|
842
|
+
GetOpenFile(dest, dest_fptr);
|
843
|
+
io_unset_nonblock(dest_fptr, dest);
|
844
|
+
|
845
|
+
VALUE resume_value = Qnil;
|
846
|
+
|
847
|
+
while (1) {
|
848
|
+
op_context_t *ctx = OP_CONTEXT_ACQUIRE(&backend->store, OP_SPLICE);
|
849
|
+
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
850
|
+
io_uring_prep_splice(sqe, src_fptr->fd, -1, dest_fptr->fd, -1, NUM2INT(maxlen), 0);
|
851
|
+
|
852
|
+
int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
853
|
+
OP_CONTEXT_RELEASE(&backend->store, ctx);
|
854
|
+
RAISE_IF_EXCEPTION(resume_value);
|
855
|
+
if (!ctx->completed) return resume_value;
|
856
|
+
|
857
|
+
if (result < 0)
|
858
|
+
rb_syserr_fail(-result, strerror(-result));
|
859
|
+
|
860
|
+
if (result == 0 || !loop) return INT2NUM(total);
|
861
|
+
total += result;
|
862
|
+
}
|
863
|
+
|
864
|
+
RB_GC_GUARD(resume_value);
|
865
|
+
}
|
866
|
+
|
867
|
+
VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
868
|
+
Backend_t *backend;
|
869
|
+
GetBackend(self, backend);
|
870
|
+
|
871
|
+
return io_uring_backend_splice(backend, src, dest, maxlen, 0);
|
872
|
+
}
|
873
|
+
|
874
|
+
VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE chunksize) {
|
875
|
+
Backend_t *backend;
|
876
|
+
GetBackend(self, backend);
|
877
|
+
|
878
|
+
return io_uring_backend_splice(backend, src, dest, chunksize, 1);
|
879
|
+
}
|
880
|
+
|
881
|
+
|
827
882
|
VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
828
883
|
Backend_t *backend;
|
829
884
|
rb_io_t *fptr;
|
@@ -1045,27 +1100,29 @@ void Init_Backend() {
|
|
1045
1100
|
|
1046
1101
|
rb_define_method(cBackend, "poll", Backend_poll, 3);
|
1047
1102
|
rb_define_method(cBackend, "break", Backend_wakeup, 0);
|
1103
|
+
rb_define_method(cBackend, "kind", Backend_kind, 0);
|
1048
1104
|
|
1105
|
+
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
1106
|
+
rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
|
1107
|
+
rb_define_method(cBackend, "connect", Backend_connect, 3);
|
1108
|
+
rb_define_method(cBackend, "feed_loop", Backend_feed_loop, 3);
|
1049
1109
|
rb_define_method(cBackend, "read", Backend_read, 4);
|
1050
1110
|
rb_define_method(cBackend, "read_loop", Backend_read_loop, 1);
|
1051
|
-
rb_define_method(cBackend, "feed_loop", Backend_feed_loop, 3);
|
1052
|
-
rb_define_method(cBackend, "write", Backend_write_m, -1);
|
1053
1111
|
rb_define_method(cBackend, "recv", Backend_recv, 3);
|
1054
|
-
rb_define_method(cBackend, "recv_loop", Backend_recv_loop, 1);
|
1055
1112
|
rb_define_method(cBackend, "recv_feed_loop", Backend_recv_feed_loop, 3);
|
1113
|
+
rb_define_method(cBackend, "recv_loop", Backend_recv_loop, 1);
|
1056
1114
|
rb_define_method(cBackend, "send", Backend_send, 3);
|
1057
1115
|
rb_define_method(cBackend, "sendv", Backend_sendv, 3);
|
1058
|
-
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
1059
|
-
rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
|
1060
|
-
rb_define_method(cBackend, "connect", Backend_connect, 3);
|
1061
|
-
rb_define_method(cBackend, "wait_io", Backend_wait_io, 2);
|
1062
1116
|
rb_define_method(cBackend, "sleep", Backend_sleep, 1);
|
1063
|
-
rb_define_method(cBackend, "
|
1117
|
+
rb_define_method(cBackend, "splice", Backend_splice, 3);
|
1118
|
+
rb_define_method(cBackend, "splice_to_eof", Backend_splice_to_eof, 3);
|
1064
1119
|
rb_define_method(cBackend, "timeout", Backend_timeout, -1);
|
1065
|
-
rb_define_method(cBackend, "
|
1120
|
+
rb_define_method(cBackend, "timer_loop", Backend_timer_loop, 1);
|
1066
1121
|
rb_define_method(cBackend, "wait_event", Backend_wait_event, 1);
|
1122
|
+
rb_define_method(cBackend, "wait_io", Backend_wait_io, 2);
|
1123
|
+
rb_define_method(cBackend, "waitpid", Backend_waitpid, 1);
|
1124
|
+
rb_define_method(cBackend, "write", Backend_write_m, -1);
|
1067
1125
|
|
1068
|
-
rb_define_method(cBackend, "kind", Backend_kind, 0);
|
1069
1126
|
|
1070
1127
|
#ifdef POLYPHONY_UNSET_NONBLOCK
|
1071
1128
|
ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
|
@@ -10,6 +10,7 @@ const char *op_type_to_str(enum op_type type) {
|
|
10
10
|
case OP_WRITE: return "WRITE";
|
11
11
|
case OP_RECV: return "RECV";
|
12
12
|
case OP_SEND: return "SEND";
|
13
|
+
case OP_SPLICE: return "SPLICE";
|
13
14
|
case OP_TIMEOUT: return "TIMEOUT";
|
14
15
|
case OP_POLL: return "POLL";
|
15
16
|
case OP_ACCEPT: return "ACCEPT";
|
@@ -38,11 +38,15 @@ thread.
|
|
38
38
|
|
39
39
|
#ifdef POLYPHONY_BACKEND_LIBEV
|
40
40
|
|
41
|
+
#ifdef POLYPHONY_LINUX
|
42
|
+
#define _GNU_SOURCE 1
|
43
|
+
#endif
|
44
|
+
|
45
|
+
#include <fcntl.h>
|
41
46
|
#include <netdb.h>
|
42
47
|
#include <sys/socket.h>
|
43
48
|
#include <sys/uio.h>
|
44
49
|
#include <unistd.h>
|
45
|
-
#include <fcntl.h>
|
46
50
|
#include <netinet/in.h>
|
47
51
|
#include <arpa/inet.h>
|
48
52
|
#include <stdnoreturn.h>
|
@@ -769,6 +773,124 @@ error:
|
|
769
773
|
return RAISE_EXCEPTION(switchpoint_result);
|
770
774
|
}
|
771
775
|
|
776
|
+
VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
777
|
+
Backend_t *backend;
|
778
|
+
struct libev_io watcher;
|
779
|
+
VALUE switchpoint_result = Qnil;
|
780
|
+
VALUE underlying_io;
|
781
|
+
rb_io_t *src_fptr;
|
782
|
+
rb_io_t *dest_fptr;
|
783
|
+
int len;
|
784
|
+
|
785
|
+
#ifndef POLYPHONY_LINUX
|
786
|
+
rb_raise(rb_eRuntimeError, "splice not supported");
|
787
|
+
#endif
|
788
|
+
|
789
|
+
GetBackend(self, backend);
|
790
|
+
|
791
|
+
underlying_io = rb_ivar_get(src, ID_ivar_io);
|
792
|
+
if (underlying_io != Qnil) src = underlying_io;
|
793
|
+
GetOpenFile(src, src_fptr);
|
794
|
+
io_set_nonblock(src_fptr, src);
|
795
|
+
|
796
|
+
underlying_io = rb_ivar_get(dest, ID_ivar_io);
|
797
|
+
if (underlying_io != Qnil) dest = underlying_io;
|
798
|
+
dest = rb_io_get_write_io(dest);
|
799
|
+
GetOpenFile(dest, dest_fptr);
|
800
|
+
io_set_nonblock(dest_fptr, dest);
|
801
|
+
|
802
|
+
watcher.fiber = Qnil;
|
803
|
+
while (1) {
|
804
|
+
len = splice(src_fptr->fd, 0, dest_fptr->fd, 0, NUM2INT(maxlen), 0);
|
805
|
+
if (len < 0) {
|
806
|
+
int e = errno;
|
807
|
+
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
808
|
+
|
809
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, src_fptr->fd, &watcher, EV_READ);
|
810
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
811
|
+
|
812
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, dest_fptr->fd, &watcher, EV_WRITE);
|
813
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
814
|
+
}
|
815
|
+
else {
|
816
|
+
break;
|
817
|
+
}
|
818
|
+
}
|
819
|
+
|
820
|
+
if (watcher.fiber == Qnil) {
|
821
|
+
switchpoint_result = backend_snooze();
|
822
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
823
|
+
}
|
824
|
+
|
825
|
+
RB_GC_GUARD(watcher.fiber);
|
826
|
+
RB_GC_GUARD(switchpoint_result);
|
827
|
+
|
828
|
+
return INT2NUM(len);
|
829
|
+
error:
|
830
|
+
return RAISE_EXCEPTION(switchpoint_result);
|
831
|
+
}
|
832
|
+
|
833
|
+
VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
834
|
+
Backend_t *backend;
|
835
|
+
struct libev_io watcher;
|
836
|
+
VALUE switchpoint_result = Qnil;
|
837
|
+
VALUE underlying_io;
|
838
|
+
rb_io_t *src_fptr;
|
839
|
+
rb_io_t *dest_fptr;
|
840
|
+
int len;
|
841
|
+
int total = 0;
|
842
|
+
|
843
|
+
#ifndef POLYPHONY_LINUX
|
844
|
+
rb_raise(rb_eRuntimeError, "splice not supported");
|
845
|
+
#endif
|
846
|
+
|
847
|
+
GetBackend(self, backend);
|
848
|
+
|
849
|
+
underlying_io = rb_ivar_get(src, ID_ivar_io);
|
850
|
+
if (underlying_io != Qnil) src = underlying_io;
|
851
|
+
GetOpenFile(src, src_fptr);
|
852
|
+
io_set_nonblock(src_fptr, src);
|
853
|
+
|
854
|
+
underlying_io = rb_ivar_get(dest, ID_ivar_io);
|
855
|
+
if (underlying_io != Qnil) dest = underlying_io;
|
856
|
+
dest = rb_io_get_write_io(dest);
|
857
|
+
GetOpenFile(dest, dest_fptr);
|
858
|
+
io_set_nonblock(dest_fptr, dest);
|
859
|
+
|
860
|
+
watcher.fiber = Qnil;
|
861
|
+
while (1) {
|
862
|
+
len = splice(src_fptr->fd, 0, dest_fptr->fd, 0, NUM2INT(maxlen), 0);
|
863
|
+
if (len < 0) {
|
864
|
+
int e = errno;
|
865
|
+
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
866
|
+
|
867
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, src_fptr->fd, &watcher, EV_READ);
|
868
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
869
|
+
|
870
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, dest_fptr->fd, &watcher, EV_WRITE);
|
871
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
872
|
+
}
|
873
|
+
else if (len == 0) {
|
874
|
+
break;
|
875
|
+
}
|
876
|
+
else {
|
877
|
+
total += len;
|
878
|
+
}
|
879
|
+
}
|
880
|
+
|
881
|
+
if (watcher.fiber == Qnil) {
|
882
|
+
switchpoint_result = backend_snooze();
|
883
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
884
|
+
}
|
885
|
+
|
886
|
+
RB_GC_GUARD(watcher.fiber);
|
887
|
+
RB_GC_GUARD(switchpoint_result);
|
888
|
+
|
889
|
+
return INT2NUM(total);
|
890
|
+
error:
|
891
|
+
return RAISE_EXCEPTION(switchpoint_result);
|
892
|
+
}
|
893
|
+
|
772
894
|
VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
|
773
895
|
Backend_t *backend;
|
774
896
|
rb_io_t *fptr;
|
@@ -993,27 +1115,26 @@ void Init_Backend() {
|
|
993
1115
|
|
994
1116
|
rb_define_method(cBackend, "poll", Backend_poll, 3);
|
995
1117
|
rb_define_method(cBackend, "break", Backend_wakeup, 0);
|
1118
|
+
rb_define_method(cBackend, "kind", Backend_kind, 0);
|
996
1119
|
|
997
|
-
rb_define_method(cBackend, "read", Backend_read, 4);
|
998
|
-
rb_define_method(cBackend, "read_loop", Backend_read_loop, 1);
|
999
|
-
rb_define_method(cBackend, "feed_loop", Backend_feed_loop, 3);
|
1000
|
-
rb_define_method(cBackend, "write", Backend_write_m, -1);
|
1001
1120
|
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
1002
1121
|
rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
|
1003
1122
|
rb_define_method(cBackend, "connect", Backend_connect, 3);
|
1123
|
+
rb_define_method(cBackend, "feed_loop", Backend_feed_loop, 3);
|
1124
|
+
rb_define_method(cBackend, "read", Backend_read, 4);
|
1125
|
+
rb_define_method(cBackend, "read_loop", Backend_read_loop, 1);
|
1004
1126
|
rb_define_method(cBackend, "recv", Backend_recv, 3);
|
1005
1127
|
rb_define_method(cBackend, "recv_loop", Backend_read_loop, 1);
|
1006
1128
|
rb_define_method(cBackend, "recv_feed_loop", Backend_feed_loop, 3);
|
1007
1129
|
rb_define_method(cBackend, "send", Backend_send, 3);
|
1008
1130
|
rb_define_method(cBackend, "sendv", Backend_sendv, 3);
|
1009
|
-
rb_define_method(cBackend, "wait_io", Backend_wait_io, 2);
|
1010
1131
|
rb_define_method(cBackend, "sleep", Backend_sleep, 1);
|
1011
|
-
rb_define_method(cBackend, "timer_loop", Backend_timer_loop, 1);
|
1012
1132
|
rb_define_method(cBackend, "timeout", Backend_timeout, -1);
|
1013
|
-
rb_define_method(cBackend, "
|
1133
|
+
rb_define_method(cBackend, "timer_loop", Backend_timer_loop, 1);
|
1014
1134
|
rb_define_method(cBackend, "wait_event", Backend_wait_event, 1);
|
1015
|
-
|
1016
|
-
rb_define_method(cBackend, "
|
1135
|
+
rb_define_method(cBackend, "wait_io", Backend_wait_io, 2);
|
1136
|
+
rb_define_method(cBackend, "waitpid", Backend_waitpid, 1);
|
1137
|
+
rb_define_method(cBackend, "write", Backend_write_m, -1);
|
1017
1138
|
|
1018
1139
|
ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
|
1019
1140
|
SYM_libev = ID2SYM(rb_intern("libev"));
|
data/ext/polyphony/extconf.rb
CHANGED
@@ -6,8 +6,9 @@ require 'mkmf'
|
|
6
6
|
use_liburing = false
|
7
7
|
use_pidfd_open = false
|
8
8
|
force_use_libev = ENV['POLYPHONY_USE_LIBEV'] != nil
|
9
|
+
linux = RUBY_PLATFORM =~ /linux/
|
9
10
|
|
10
|
-
if
|
11
|
+
if linux && `uname -sr` =~ /Linux 5\.([\d+])/
|
11
12
|
kernel_minor_version = $1.gsub('.', '').to_i
|
12
13
|
use_liburing = !force_use_libev && kernel_minor_version >= 6
|
13
14
|
use_pidfd_open = kernel_minor_version >= 3
|
@@ -20,6 +21,7 @@ if use_liburing
|
|
20
21
|
$CFLAGS << " -Wno-pointer-arith"
|
21
22
|
else
|
22
23
|
$defs << "-DPOLYPHONY_BACKEND_LIBEV"
|
24
|
+
$defs << "-DPOLYPHONY_LINUX" if linux
|
23
25
|
$defs << '-DEV_USE_LINUXAIO' if have_header('linux/aio_abi.h')
|
24
26
|
$defs << '-DEV_USE_SELECT' if have_header('sys/select.h')
|
25
27
|
$defs << '-DEV_USE_POLL' if have_type('port_event_t', 'poll.h')
|
data/ext/polyphony/polyphony.c
CHANGED
@@ -46,8 +46,6 @@ 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
49
|
VALUE Polyphony_backend_accept(VALUE self, VALUE server_socket, VALUE socket_class) {
|
52
50
|
return Backend_accept(BACKEND(), server_socket, socket_class);
|
53
51
|
}
|
@@ -96,6 +94,14 @@ VALUE Polyphony_backend_sleep(VALUE self, VALUE duration) {
|
|
96
94
|
return Backend_sleep(BACKEND(), duration);
|
97
95
|
}
|
98
96
|
|
97
|
+
VALUE Polyphony_backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
98
|
+
return Backend_splice(BACKEND(), src, dest, maxlen);
|
99
|
+
}
|
100
|
+
|
101
|
+
VALUE Polyphony_backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE chunksize) {
|
102
|
+
return Backend_splice_to_eof(BACKEND(), src, dest, chunksize);
|
103
|
+
}
|
104
|
+
|
99
105
|
VALUE Polyphony_backend_timeout(int argc,VALUE *argv, VALUE self) {
|
100
106
|
return Backend_timeout(argc, argv, BACKEND());
|
101
107
|
}
|
@@ -138,6 +144,8 @@ void Init_Polyphony() {
|
|
138
144
|
rb_define_singleton_method(mPolyphony, "backend_send", Polyphony_backend_send, 3);
|
139
145
|
rb_define_singleton_method(mPolyphony, "backend_sendv", Polyphony_backend_sendv, 3);
|
140
146
|
rb_define_singleton_method(mPolyphony, "backend_sleep", Polyphony_backend_sleep, 1);
|
147
|
+
rb_define_singleton_method(mPolyphony, "backend_splice", Polyphony_backend_splice, 3);
|
148
|
+
rb_define_singleton_method(mPolyphony, "backend_splice_to_eof", Polyphony_backend_splice_to_eof, 3);
|
141
149
|
rb_define_singleton_method(mPolyphony, "backend_timeout", Polyphony_backend_timeout, -1);
|
142
150
|
rb_define_singleton_method(mPolyphony, "backend_timer_loop", Polyphony_backend_timer_loop, 1);
|
143
151
|
rb_define_singleton_method(mPolyphony, "backend_wait_event", Polyphony_backend_wait_event, 1);
|
data/ext/polyphony/polyphony.h
CHANGED
@@ -31,6 +31,8 @@
|
|
31
31
|
// Fiber#transfer
|
32
32
|
#define FIBER_TRANSFER(fiber, value) rb_funcall(fiber, ID_transfer, 1, value)
|
33
33
|
|
34
|
+
#define BACKEND() (rb_ivar_get(rb_thread_current(), ID_ivar_backend))
|
35
|
+
|
34
36
|
extern VALUE mPolyphony;
|
35
37
|
extern VALUE cQueue;
|
36
38
|
extern VALUE cEvent;
|
@@ -108,6 +110,8 @@ VALUE Backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method)
|
|
108
110
|
VALUE Backend_send(VALUE self, VALUE io, VALUE msg, VALUE flags);
|
109
111
|
VALUE Backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags);
|
110
112
|
VALUE Backend_sleep(VALUE self, VALUE duration);
|
113
|
+
VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen);
|
114
|
+
VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE chunksize);
|
111
115
|
VALUE Backend_timeout(int argc,VALUE *argv, VALUE self);
|
112
116
|
VALUE Backend_timer_loop(VALUE self, VALUE interval);
|
113
117
|
VALUE Backend_wait_event(VALUE self, VALUE raise);
|
@@ -6,6 +6,7 @@ void Init_Backend();
|
|
6
6
|
void Init_Queue();
|
7
7
|
void Init_Event();
|
8
8
|
void Init_Runqueue();
|
9
|
+
void Init_SocketExtensions();
|
9
10
|
void Init_Thread();
|
10
11
|
void Init_Tracing();
|
11
12
|
|
@@ -24,6 +25,8 @@ void Init_polyphony_ext() {
|
|
24
25
|
Init_Thread();
|
25
26
|
Init_Tracing();
|
26
27
|
|
28
|
+
Init_SocketExtensions();
|
29
|
+
|
27
30
|
#ifdef POLYPHONY_PLAYGROUND
|
28
31
|
playground();
|
29
32
|
#endif
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#include "polyphony.h"
|
2
|
+
|
3
|
+
VALUE Socket_send(VALUE self, VALUE msg, VALUE flags) {
|
4
|
+
return Backend_send(BACKEND(), self, msg, flags);
|
5
|
+
}
|
6
|
+
|
7
|
+
VALUE Socket_write(int argc, VALUE *argv, VALUE self) {
|
8
|
+
VALUE ary = rb_ary_new_from_values(argc, argv);
|
9
|
+
VALUE result = Backend_sendv(BACKEND(), self, ary, INT2NUM(0));
|
10
|
+
RB_GC_GUARD(ary);
|
11
|
+
return result;
|
12
|
+
}
|
13
|
+
|
14
|
+
VALUE Socket_double_chevron(VALUE self, VALUE msg) {
|
15
|
+
Backend_send(BACKEND(), self, msg, INT2NUM(0));
|
16
|
+
return self;
|
17
|
+
}
|
18
|
+
|
19
|
+
void Init_SocketExtensions() {
|
20
|
+
rb_require("socket");
|
21
|
+
|
22
|
+
VALUE cSocket = rb_const_get(rb_cObject, rb_intern("Socket"));
|
23
|
+
VALUE cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
|
24
|
+
|
25
|
+
rb_define_method(cSocket, "send", Socket_send, 2);
|
26
|
+
rb_define_method(cTCPSocket, "send", Socket_send, 2);
|
27
|
+
|
28
|
+
rb_define_method(cSocket, "write", Socket_write, -1);
|
29
|
+
rb_define_method(cTCPSocket, "write", Socket_write, -1);
|
30
|
+
|
31
|
+
rb_define_method(cSocket, "<<", Socket_double_chevron, 1);
|
32
|
+
rb_define_method(cTCPSocket, "<<", Socket_double_chevron, 1);
|
33
|
+
}
|
@@ -48,14 +48,17 @@ class ::Socket
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
def send(mesg, flags)
|
52
|
-
|
53
|
-
end
|
51
|
+
# def send(mesg, flags)
|
52
|
+
# Polyphony.backend_send(self, mesg, flags)
|
53
|
+
# end
|
54
54
|
|
55
|
-
def write(*args)
|
56
|
-
|
57
|
-
end
|
58
|
-
|
55
|
+
# def write(*args)
|
56
|
+
# Polyphony.backend_sendv(self, args, 0)
|
57
|
+
# end
|
58
|
+
|
59
|
+
# def <<(mesg)
|
60
|
+
# Polyphony.backend_send(self, mesg, 0)
|
61
|
+
# end
|
59
62
|
|
60
63
|
def readpartial(maxlen, str = +'')
|
61
64
|
Polyphony.backend_recv(self, str, maxlen)
|
@@ -150,14 +153,17 @@ class ::TCPSocket
|
|
150
153
|
Polyphony.backend_recv_feed_loop(self, receiver, method, &block)
|
151
154
|
end
|
152
155
|
|
153
|
-
def send(mesg, flags)
|
154
|
-
|
155
|
-
end
|
156
|
+
# def send(mesg, flags)
|
157
|
+
# Polyphony.backend_send(self, mesg, flags)
|
158
|
+
# end
|
156
159
|
|
157
|
-
def write(*args)
|
158
|
-
|
159
|
-
end
|
160
|
-
|
160
|
+
# def write(*args)
|
161
|
+
# Polyphony.backend_sendv(self, args, 0)
|
162
|
+
# end
|
163
|
+
|
164
|
+
# def <<(mesg)
|
165
|
+
# Polyphony.backend_send(self, mesg, 0)
|
166
|
+
# end
|
161
167
|
|
162
168
|
def readpartial(maxlen, str = nil)
|
163
169
|
@read_buffer ||= +''
|
@@ -238,7 +244,10 @@ class ::UNIXSocket
|
|
238
244
|
def write(*args)
|
239
245
|
Polyphony.backend_sendv(self, args, 0)
|
240
246
|
end
|
241
|
-
|
247
|
+
|
248
|
+
def <<(mesg)
|
249
|
+
Polyphony.backend_send(self, mesg, 0)
|
250
|
+
end
|
242
251
|
|
243
252
|
def readpartial(maxlen, str = nil)
|
244
253
|
@read_buffer ||= +''
|
data/lib/polyphony/version.rb
CHANGED
data/test/test_backend.rb
CHANGED
@@ -237,4 +237,40 @@ class BackendTest < MiniTest::Test
|
|
237
237
|
end
|
238
238
|
assert_equal [1], buffer
|
239
239
|
end
|
240
|
+
|
241
|
+
def test_splice
|
242
|
+
i1, o1 = IO.pipe
|
243
|
+
i2, o2 = IO.pipe
|
244
|
+
|
245
|
+
spin {
|
246
|
+
o2.splice(i1, 1000)
|
247
|
+
o2.close
|
248
|
+
}
|
249
|
+
|
250
|
+
o1.write('foobar')
|
251
|
+
result = i2.read
|
252
|
+
|
253
|
+
assert_equal 'foobar', result
|
254
|
+
end
|
255
|
+
|
256
|
+
def test_splice_to_eof
|
257
|
+
i1, o1 = IO.pipe
|
258
|
+
i2, o2 = IO.pipe
|
259
|
+
|
260
|
+
f = spin {
|
261
|
+
o2.splice_to_eof(i1, 1000)
|
262
|
+
o2.close
|
263
|
+
}
|
264
|
+
|
265
|
+
o1.write('foo')
|
266
|
+
result = i2.readpartial(1000)
|
267
|
+
assert_equal 'foo', result
|
268
|
+
|
269
|
+
o1.write('bar')
|
270
|
+
result = i2.readpartial(1000)
|
271
|
+
assert_equal 'bar', result
|
272
|
+
ensure
|
273
|
+
f.interrupt
|
274
|
+
f.await
|
275
|
+
end
|
240
276
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: polyphony
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.53.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-04-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -418,6 +418,7 @@ files:
|
|
418
418
|
- ext/polyphony/runqueue.c
|
419
419
|
- ext/polyphony/runqueue_ring_buffer.c
|
420
420
|
- ext/polyphony/runqueue_ring_buffer.h
|
421
|
+
- ext/polyphony/socket_extensions.c
|
421
422
|
- ext/polyphony/thread.c
|
422
423
|
- ext/polyphony/tracing.c
|
423
424
|
- lib/polyphony.rb
|