polyphony 0.50.0 → 0.53.1
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/.github/workflows/test.yml +1 -1
- data/CHANGELOG.md +30 -0
- data/Gemfile.lock +7 -68
- data/TODO.md +37 -6
- data/examples/core/forking.rb +2 -2
- data/examples/io/echo_server.rb +1 -0
- data/examples/io/tcp_proxy.rb +2 -2
- data/ext/polyphony/backend_common.h +57 -7
- data/ext/polyphony/backend_io_uring.c +232 -49
- 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 +355 -34
- data/ext/polyphony/event.c +1 -1
- data/ext/polyphony/extconf.rb +9 -2
- data/ext/polyphony/polyphony.c +102 -0
- data/ext/polyphony/polyphony.h +32 -2
- data/ext/polyphony/polyphony_ext.c +3 -0
- data/ext/polyphony/queue.c +1 -1
- data/ext/polyphony/runqueue.c +1 -1
- data/ext/polyphony/socket_extensions.c +33 -0
- data/ext/polyphony/thread.c +8 -2
- 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 +4 -4
- 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 +21 -22
- data/lib/polyphony/extensions/openssl.rb +6 -6
- data/lib/polyphony/extensions/socket.rb +56 -47
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +6 -5
- data/test/helper.rb +1 -1
- data/test/stress.rb +2 -0
- data/test/test_backend.rb +152 -5
- data/test/test_global_api.rb +2 -2
- data/test/test_io.rb +84 -1
- data/test/test_kernel.rb +1 -1
- data/test/test_signal.rb +1 -1
- data/test/test_socket.rb +61 -0
- data/test/test_thread.rb +4 -0
- data/test/test_timer.rb +1 -1
- metadata +19 -60
@@ -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";
|
@@ -1,19 +1,66 @@
|
|
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
|
|
41
|
+
#ifdef POLYPHONY_LINUX
|
42
|
+
#define _GNU_SOURCE 1
|
43
|
+
#endif
|
44
|
+
|
45
|
+
#include <fcntl.h>
|
3
46
|
#include <netdb.h>
|
4
47
|
#include <sys/socket.h>
|
5
48
|
#include <sys/uio.h>
|
6
49
|
#include <unistd.h>
|
7
|
-
#include <fcntl.h>
|
8
50
|
#include <netinet/in.h>
|
9
51
|
#include <arpa/inet.h>
|
10
52
|
#include <stdnoreturn.h>
|
53
|
+
#include <sys/types.h>
|
54
|
+
#include <sys/wait.h>
|
11
55
|
|
12
56
|
#include "polyphony.h"
|
13
57
|
#include "../libev/ev.h"
|
14
58
|
#include "ruby/io.h"
|
15
59
|
|
16
60
|
VALUE SYM_libev;
|
61
|
+
VALUE SYM_send;
|
62
|
+
VALUE SYM_splice;
|
63
|
+
VALUE SYM_write;
|
17
64
|
|
18
65
|
ID ID_ivar_is_nonblocking;
|
19
66
|
|
@@ -74,17 +121,27 @@ void break_async_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, in
|
|
74
121
|
// of a *blocking* event loop (waking it up) in a thread-safe, signal-safe manner
|
75
122
|
}
|
76
123
|
|
124
|
+
inline struct ev_loop *libev_new_loop() {
|
125
|
+
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
126
|
+
return ev_loop_new(EVFLAG_NOSIGMASK);
|
127
|
+
#else
|
128
|
+
int is_main_thread = (rb_thread_current() == rb_thread_main());
|
129
|
+
return is_main_thread ? EV_DEFAULT : ev_loop_new(EVFLAG_NOSIGMASK);
|
130
|
+
#endif
|
131
|
+
}
|
132
|
+
|
77
133
|
static VALUE Backend_initialize(VALUE self) {
|
78
134
|
Backend_t *backend;
|
79
|
-
|
80
|
-
int is_main_thread = (thread == rb_thread_main());
|
81
|
-
|
135
|
+
|
82
136
|
GetBackend(self, backend);
|
83
|
-
backend->ev_loop =
|
137
|
+
backend->ev_loop = libev_new_loop();
|
84
138
|
|
139
|
+
// start async watcher used for breaking a poll op (from another thread)
|
85
140
|
ev_async_init(&backend->break_async, break_async_callback);
|
86
141
|
ev_async_start(backend->ev_loop, &backend->break_async);
|
87
|
-
|
142
|
+
// the break_async watcher is unreferenced, in order for Backend_poll to not
|
143
|
+
// block when no other watcher is active
|
144
|
+
ev_unref(backend->ev_loop);
|
88
145
|
|
89
146
|
backend->currently_polling = 0;
|
90
147
|
backend->pending_count = 0;
|
@@ -332,6 +389,58 @@ error:
|
|
332
389
|
return RAISE_EXCEPTION(switchpoint_result);
|
333
390
|
}
|
334
391
|
|
392
|
+
VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
393
|
+
Backend_t *backend;
|
394
|
+
struct libev_io watcher;
|
395
|
+
rb_io_t *fptr;
|
396
|
+
VALUE str;
|
397
|
+
long total;
|
398
|
+
long len = 8192;
|
399
|
+
int shrinkable;
|
400
|
+
char *buf;
|
401
|
+
VALUE switchpoint_result = Qnil;
|
402
|
+
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
403
|
+
ID method_id = SYM2ID(method);
|
404
|
+
|
405
|
+
READ_LOOP_PREPARE_STR();
|
406
|
+
|
407
|
+
GetBackend(self, backend);
|
408
|
+
if (underlying_io != Qnil) io = underlying_io;
|
409
|
+
GetOpenFile(io, fptr);
|
410
|
+
rb_io_check_byte_readable(fptr);
|
411
|
+
io_set_nonblock(fptr, io);
|
412
|
+
rectify_io_file_pos(fptr);
|
413
|
+
watcher.fiber = Qnil;
|
414
|
+
|
415
|
+
while (1) {
|
416
|
+
ssize_t n = read(fptr->fd, buf, len);
|
417
|
+
if (n < 0) {
|
418
|
+
int e = errno;
|
419
|
+
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
420
|
+
|
421
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_READ);
|
422
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
423
|
+
}
|
424
|
+
else {
|
425
|
+
switchpoint_result = backend_snooze();
|
426
|
+
|
427
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
428
|
+
|
429
|
+
if (n == 0) break; // EOF
|
430
|
+
total = n;
|
431
|
+
READ_LOOP_PASS_STR_TO_RECEIVER(receiver, method_id);
|
432
|
+
}
|
433
|
+
}
|
434
|
+
|
435
|
+
RB_GC_GUARD(str);
|
436
|
+
RB_GC_GUARD(watcher.fiber);
|
437
|
+
RB_GC_GUARD(switchpoint_result);
|
438
|
+
|
439
|
+
return io;
|
440
|
+
error:
|
441
|
+
return RAISE_EXCEPTION(switchpoint_result);
|
442
|
+
}
|
443
|
+
|
335
444
|
VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
336
445
|
Backend_t *backend;
|
337
446
|
struct libev_io watcher;
|
@@ -618,6 +727,167 @@ error:
|
|
618
727
|
return RAISE_EXCEPTION(switchpoint_result);
|
619
728
|
}
|
620
729
|
|
730
|
+
VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
731
|
+
Backend_t *backend;
|
732
|
+
struct libev_io watcher;
|
733
|
+
rb_io_t *fptr;
|
734
|
+
VALUE switchpoint_result = Qnil;
|
735
|
+
VALUE underlying_io;
|
736
|
+
char *buf = StringValuePtr(str);
|
737
|
+
long len = RSTRING_LEN(str);
|
738
|
+
long left = len;
|
739
|
+
int flags_int = NUM2INT(flags);
|
740
|
+
|
741
|
+
underlying_io = rb_ivar_get(io, ID_ivar_io);
|
742
|
+
if (underlying_io != Qnil) io = underlying_io;
|
743
|
+
GetBackend(self, backend);
|
744
|
+
io = rb_io_get_write_io(io);
|
745
|
+
GetOpenFile(io, fptr);
|
746
|
+
io_set_nonblock(fptr, io);
|
747
|
+
watcher.fiber = Qnil;
|
748
|
+
|
749
|
+
while (left > 0) {
|
750
|
+
ssize_t n = send(fptr->fd, buf, left, flags_int);
|
751
|
+
if (n < 0) {
|
752
|
+
int e = errno;
|
753
|
+
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
754
|
+
|
755
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_WRITE);
|
756
|
+
|
757
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
758
|
+
}
|
759
|
+
else {
|
760
|
+
buf += n;
|
761
|
+
left -= n;
|
762
|
+
}
|
763
|
+
}
|
764
|
+
|
765
|
+
if (watcher.fiber == Qnil) {
|
766
|
+
switchpoint_result = backend_snooze();
|
767
|
+
|
768
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
769
|
+
}
|
770
|
+
|
771
|
+
RB_GC_GUARD(watcher.fiber);
|
772
|
+
RB_GC_GUARD(switchpoint_result);
|
773
|
+
|
774
|
+
return INT2NUM(len);
|
775
|
+
error:
|
776
|
+
return RAISE_EXCEPTION(switchpoint_result);
|
777
|
+
}
|
778
|
+
|
779
|
+
#ifndef POLYPHONY_LINUX
|
780
|
+
VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
781
|
+
Backend_t *backend;
|
782
|
+
struct libev_io watcher;
|
783
|
+
VALUE switchpoint_result = Qnil;
|
784
|
+
VALUE underlying_io;
|
785
|
+
rb_io_t *src_fptr;
|
786
|
+
rb_io_t *dest_fptr;
|
787
|
+
int len;
|
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
|
+
GetBackend(self, backend);
|
844
|
+
|
845
|
+
underlying_io = rb_ivar_get(src, ID_ivar_io);
|
846
|
+
if (underlying_io != Qnil) src = underlying_io;
|
847
|
+
GetOpenFile(src, src_fptr);
|
848
|
+
io_set_nonblock(src_fptr, src);
|
849
|
+
|
850
|
+
underlying_io = rb_ivar_get(dest, ID_ivar_io);
|
851
|
+
if (underlying_io != Qnil) dest = underlying_io;
|
852
|
+
dest = rb_io_get_write_io(dest);
|
853
|
+
GetOpenFile(dest, dest_fptr);
|
854
|
+
io_set_nonblock(dest_fptr, dest);
|
855
|
+
|
856
|
+
watcher.fiber = Qnil;
|
857
|
+
while (1) {
|
858
|
+
len = splice(src_fptr->fd, 0, dest_fptr->fd, 0, NUM2INT(maxlen), 0);
|
859
|
+
if (len < 0) {
|
860
|
+
int e = errno;
|
861
|
+
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
862
|
+
|
863
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, src_fptr->fd, &watcher, EV_READ);
|
864
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
865
|
+
|
866
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, dest_fptr->fd, &watcher, EV_WRITE);
|
867
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
868
|
+
}
|
869
|
+
else if (len == 0) {
|
870
|
+
break;
|
871
|
+
}
|
872
|
+
else {
|
873
|
+
total += len;
|
874
|
+
}
|
875
|
+
}
|
876
|
+
|
877
|
+
if (watcher.fiber == Qnil) {
|
878
|
+
switchpoint_result = backend_snooze();
|
879
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
880
|
+
}
|
881
|
+
|
882
|
+
RB_GC_GUARD(watcher.fiber);
|
883
|
+
RB_GC_GUARD(switchpoint_result);
|
884
|
+
|
885
|
+
return INT2NUM(total);
|
886
|
+
error:
|
887
|
+
return RAISE_EXCEPTION(switchpoint_result);
|
888
|
+
}
|
889
|
+
#endif
|
890
|
+
|
621
891
|
VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
|
622
892
|
Backend_t *backend;
|
623
893
|
rb_io_t *fptr;
|
@@ -685,26 +955,12 @@ noreturn VALUE Backend_timer_loop(VALUE self, VALUE interval) {
|
|
685
955
|
RB_GC_GUARD(switchpoint_result);
|
686
956
|
|
687
957
|
rb_yield(Qnil);
|
688
|
-
|
689
|
-
while (1) {
|
958
|
+
do {
|
690
959
|
next_time += interval_d;
|
691
|
-
|
692
|
-
}
|
960
|
+
} while (next_time <= now);
|
693
961
|
}
|
694
962
|
}
|
695
963
|
|
696
|
-
VALUE Backend_timeout_safe(VALUE arg) {
|
697
|
-
return rb_yield(arg);
|
698
|
-
}
|
699
|
-
|
700
|
-
VALUE Backend_timeout_rescue(VALUE arg, VALUE exception) {
|
701
|
-
return exception;
|
702
|
-
}
|
703
|
-
|
704
|
-
VALUE Backend_timeout_ensure_safe(VALUE arg) {
|
705
|
-
return rb_rescue2(Backend_timeout_safe, Qnil, Backend_timeout_rescue, Qnil, rb_eException, (VALUE)0);
|
706
|
-
}
|
707
|
-
|
708
964
|
struct libev_timeout {
|
709
965
|
struct ev_timer timer;
|
710
966
|
VALUE fiber;
|
@@ -759,13 +1015,39 @@ VALUE Backend_timeout(int argc,VALUE *argv, VALUE self) {
|
|
759
1015
|
return result;
|
760
1016
|
}
|
761
1017
|
|
1018
|
+
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
1019
|
+
VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
1020
|
+
int pid_int = NUM2INT(pid);
|
1021
|
+
int fd = pidfd_open(pid_int, 0);
|
1022
|
+
if (fd >= 0) {
|
1023
|
+
Backend_t *backend;
|
1024
|
+
GetBackend(self, backend);
|
1025
|
+
|
1026
|
+
VALUE resume_value = libev_wait_fd(backend, fd, EV_READ, 0);
|
1027
|
+
close(fd);
|
1028
|
+
RAISE_IF_EXCEPTION(resume_value);
|
1029
|
+
RB_GC_GUARD(resume_value);
|
1030
|
+
}
|
1031
|
+
else {
|
1032
|
+
int e = errno;
|
1033
|
+
rb_syserr_fail(e, strerror(e));
|
1034
|
+
}
|
1035
|
+
|
1036
|
+
int status = 0;
|
1037
|
+
pid_t ret = waitpid(pid_int, &status, WNOHANG);
|
1038
|
+
if (ret < 0) {
|
1039
|
+
int e = errno;
|
1040
|
+
rb_syserr_fail(e, strerror(e));
|
1041
|
+
}
|
1042
|
+
return rb_ary_new_from_args(2, INT2NUM(ret), INT2NUM(WEXITSTATUS(status)));
|
1043
|
+
}
|
1044
|
+
#else
|
762
1045
|
struct libev_child {
|
763
1046
|
struct ev_child child;
|
764
1047
|
VALUE fiber;
|
765
1048
|
};
|
766
1049
|
|
767
|
-
void Backend_child_callback(EV_P_ ev_child *w, int revents)
|
768
|
-
{
|
1050
|
+
void Backend_child_callback(EV_P_ ev_child *w, int revents) {
|
769
1051
|
struct libev_child *watcher = (struct libev_child *)w;
|
770
1052
|
int exit_status = WEXITSTATUS(w->rstatus);
|
771
1053
|
VALUE status;
|
@@ -792,6 +1074,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
|
792
1074
|
RB_GC_GUARD(switchpoint_result);
|
793
1075
|
return switchpoint_result;
|
794
1076
|
}
|
1077
|
+
#endif
|
795
1078
|
|
796
1079
|
void Backend_async_callback(EV_P_ ev_async *w, int revents) { }
|
797
1080
|
|
@@ -817,10 +1100,35 @@ VALUE Backend_kind(VALUE self) {
|
|
817
1100
|
return SYM_libev;
|
818
1101
|
}
|
819
1102
|
|
1103
|
+
VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
1104
|
+
VALUE result = Qnil;
|
1105
|
+
if (argc == 0) return result;
|
1106
|
+
|
1107
|
+
for (int i = 0; i < argc; i++) {
|
1108
|
+
VALUE op = argv[i];
|
1109
|
+
VALUE op_type = RARRAY_AREF(op, 0);
|
1110
|
+
VALUE op_len = RARRAY_LEN(op);
|
1111
|
+
|
1112
|
+
if (op_type == SYM_write && op_len == 3)
|
1113
|
+
result = Backend_write(self, RARRAY_AREF(op, 1), RARRAY_AREF(op, 2));
|
1114
|
+
else if (op_type == SYM_send && op_len == 4)
|
1115
|
+
result = Backend_send(self, RARRAY_AREF(op, 1), RARRAY_AREF(op, 2), RARRAY_AREF(op, 3));
|
1116
|
+
#ifndef POLYPHONY_LINUX
|
1117
|
+
else if (op_type == SYM_splice && op_len == 4)
|
1118
|
+
result = Backend_splice(self, RARRAY_AREF(op, 1), RARRAY_AREF(op, 2), RARRAY_AREF(op, 3));
|
1119
|
+
#endif
|
1120
|
+
else
|
1121
|
+
rb_raise(rb_eRuntimeError, "Invalid op specified or bad op arity");
|
1122
|
+
}
|
1123
|
+
|
1124
|
+
RB_GC_GUARD(result);
|
1125
|
+
return result;
|
1126
|
+
}
|
1127
|
+
|
820
1128
|
void Init_Backend() {
|
821
1129
|
ev_set_allocator(xrealloc);
|
822
1130
|
|
823
|
-
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend",
|
1131
|
+
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cObject);
|
824
1132
|
rb_define_alloc_func(cBackend, Backend_allocate);
|
825
1133
|
|
826
1134
|
rb_define_method(cBackend, "initialize", Backend_initialize, 0);
|
@@ -829,27 +1137,40 @@ void Init_Backend() {
|
|
829
1137
|
|
830
1138
|
rb_define_method(cBackend, "poll", Backend_poll, 3);
|
831
1139
|
rb_define_method(cBackend, "break", Backend_wakeup, 0);
|
1140
|
+
rb_define_method(cBackend, "kind", Backend_kind, 0);
|
1141
|
+
rb_define_method(cBackend, "chain", Backend_chain, -1);
|
832
1142
|
|
833
|
-
rb_define_method(cBackend, "read", Backend_read, 4);
|
834
|
-
rb_define_method(cBackend, "read_loop", Backend_read_loop, 1);
|
835
|
-
rb_define_method(cBackend, "write", Backend_write_m, -1);
|
836
1143
|
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
837
1144
|
rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
|
838
1145
|
rb_define_method(cBackend, "connect", Backend_connect, 3);
|
1146
|
+
rb_define_method(cBackend, "feed_loop", Backend_feed_loop, 3);
|
1147
|
+
rb_define_method(cBackend, "read", Backend_read, 4);
|
1148
|
+
rb_define_method(cBackend, "read_loop", Backend_read_loop, 1);
|
839
1149
|
rb_define_method(cBackend, "recv", Backend_recv, 3);
|
840
1150
|
rb_define_method(cBackend, "recv_loop", Backend_read_loop, 1);
|
841
|
-
rb_define_method(cBackend, "
|
842
|
-
rb_define_method(cBackend, "
|
1151
|
+
rb_define_method(cBackend, "recv_feed_loop", Backend_feed_loop, 3);
|
1152
|
+
rb_define_method(cBackend, "send", Backend_send, 3);
|
1153
|
+
rb_define_method(cBackend, "sendv", Backend_sendv, 3);
|
843
1154
|
rb_define_method(cBackend, "sleep", Backend_sleep, 1);
|
844
|
-
|
1155
|
+
|
1156
|
+
#ifndef POLYPHONY_LINUX
|
1157
|
+
rb_define_method(cBackend, "splice", Backend_splice, 3);
|
1158
|
+
rb_define_method(cBackend, "splice_to_eof", Backend_splice_to_eof, 3);
|
1159
|
+
#endif
|
1160
|
+
|
845
1161
|
rb_define_method(cBackend, "timeout", Backend_timeout, -1);
|
846
|
-
rb_define_method(cBackend, "
|
1162
|
+
rb_define_method(cBackend, "timer_loop", Backend_timer_loop, 1);
|
847
1163
|
rb_define_method(cBackend, "wait_event", Backend_wait_event, 1);
|
848
|
-
|
849
|
-
rb_define_method(cBackend, "
|
1164
|
+
rb_define_method(cBackend, "wait_io", Backend_wait_io, 2);
|
1165
|
+
rb_define_method(cBackend, "waitpid", Backend_waitpid, 1);
|
1166
|
+
rb_define_method(cBackend, "write", Backend_write_m, -1);
|
850
1167
|
|
851
1168
|
ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
|
852
1169
|
SYM_libev = ID2SYM(rb_intern("libev"));
|
1170
|
+
|
1171
|
+
SYM_send = ID2SYM(rb_intern("send"));
|
1172
|
+
SYM_splice = ID2SYM(rb_intern("splice"));
|
1173
|
+
SYM_write = ID2SYM(rb_intern("write"));
|
853
1174
|
}
|
854
1175
|
|
855
1176
|
#endif // POLYPHONY_BACKEND_LIBEV
|