polyphony 0.49.1 → 0.52.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/.github/workflows/test.yml +1 -1
- data/CHANGELOG.md +35 -0
- data/Gemfile.lock +7 -68
- data/TODO.md +6 -0
- data/examples/core/forking.rb +2 -2
- data/examples/core/nested.rb +21 -0
- data/examples/core/suspend.rb +13 -0
- data/examples/core/terminate_main_fiber.rb +12 -0
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +2 -4
- data/ext/polyphony/backend_common.h +58 -8
- data/ext/polyphony/backend_io_uring.c +158 -35
- data/ext/polyphony/backend_libev.c +192 -25
- data/ext/polyphony/event.c +1 -1
- data/ext/polyphony/extconf.rb +7 -2
- data/ext/polyphony/fiber.c +2 -1
- data/ext/polyphony/polyphony.c +94 -0
- data/ext/polyphony/polyphony.h +29 -2
- data/ext/polyphony/queue.c +1 -1
- data/ext/polyphony/runqueue.c +7 -1
- data/ext/polyphony/runqueue_ring_buffer.c +9 -0
- data/ext/polyphony/runqueue_ring_buffer.h +1 -0
- data/ext/polyphony/thread.c +14 -0
- 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/exceptions.rb +1 -0
- data/lib/polyphony/core/global_api.rb +6 -6
- data/lib/polyphony/core/sync.rb +1 -1
- data/lib/polyphony/core/throttler.rb +1 -1
- data/lib/polyphony/core/timer.rb +63 -20
- data/lib/polyphony/extensions/core.rb +5 -5
- data/lib/polyphony/extensions/fiber.rb +11 -8
- data/lib/polyphony/extensions/io.rb +13 -22
- data/lib/polyphony/extensions/openssl.rb +6 -6
- data/lib/polyphony/extensions/socket.rb +41 -41
- data/lib/polyphony/extensions/thread.rb +1 -2
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +6 -5
- data/test/helper.rb +2 -3
- data/test/stress.rb +2 -0
- data/test/test_backend.rb +58 -5
- data/test/test_fiber.rb +31 -0
- 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 +2 -3
- data/test/test_socket.rb +61 -0
- data/test/test_timer.rb +41 -8
- metadata +21 -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>
|
@@ -8,6 +46,8 @@
|
|
8
46
|
#include <netinet/in.h>
|
9
47
|
#include <arpa/inet.h>
|
10
48
|
#include <stdnoreturn.h>
|
49
|
+
#include <sys/types.h>
|
50
|
+
#include <sys/wait.h>
|
11
51
|
|
12
52
|
#include "polyphony.h"
|
13
53
|
#include "../libev/ev.h"
|
@@ -74,17 +114,27 @@ void break_async_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, in
|
|
74
114
|
// of a *blocking* event loop (waking it up) in a thread-safe, signal-safe manner
|
75
115
|
}
|
76
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
|
+
|
77
126
|
static VALUE Backend_initialize(VALUE self) {
|
78
127
|
Backend_t *backend;
|
79
|
-
|
80
|
-
int is_main_thread = (thread == rb_thread_main());
|
81
|
-
|
128
|
+
|
82
129
|
GetBackend(self, backend);
|
83
|
-
backend->ev_loop =
|
130
|
+
backend->ev_loop = libev_new_loop();
|
84
131
|
|
132
|
+
// start async watcher used for breaking a poll op (from another thread)
|
85
133
|
ev_async_init(&backend->break_async, break_async_callback);
|
86
134
|
ev_async_start(backend->ev_loop, &backend->break_async);
|
87
|
-
|
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);
|
88
138
|
|
89
139
|
backend->currently_polling = 0;
|
90
140
|
backend->pending_count = 0;
|
@@ -332,6 +382,58 @@ error:
|
|
332
382
|
return RAISE_EXCEPTION(switchpoint_result);
|
333
383
|
}
|
334
384
|
|
385
|
+
VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
386
|
+
Backend_t *backend;
|
387
|
+
struct libev_io watcher;
|
388
|
+
rb_io_t *fptr;
|
389
|
+
VALUE str;
|
390
|
+
long total;
|
391
|
+
long len = 8192;
|
392
|
+
int shrinkable;
|
393
|
+
char *buf;
|
394
|
+
VALUE switchpoint_result = Qnil;
|
395
|
+
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
396
|
+
ID method_id = SYM2ID(method);
|
397
|
+
|
398
|
+
READ_LOOP_PREPARE_STR();
|
399
|
+
|
400
|
+
GetBackend(self, backend);
|
401
|
+
if (underlying_io != Qnil) io = underlying_io;
|
402
|
+
GetOpenFile(io, fptr);
|
403
|
+
rb_io_check_byte_readable(fptr);
|
404
|
+
io_set_nonblock(fptr, io);
|
405
|
+
rectify_io_file_pos(fptr);
|
406
|
+
watcher.fiber = Qnil;
|
407
|
+
|
408
|
+
while (1) {
|
409
|
+
ssize_t n = read(fptr->fd, buf, len);
|
410
|
+
if (n < 0) {
|
411
|
+
int e = errno;
|
412
|
+
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
413
|
+
|
414
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_READ);
|
415
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
416
|
+
}
|
417
|
+
else {
|
418
|
+
switchpoint_result = backend_snooze();
|
419
|
+
|
420
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
421
|
+
|
422
|
+
if (n == 0) break; // EOF
|
423
|
+
total = n;
|
424
|
+
READ_LOOP_PASS_STR_TO_RECEIVER(receiver, method_id);
|
425
|
+
}
|
426
|
+
}
|
427
|
+
|
428
|
+
RB_GC_GUARD(str);
|
429
|
+
RB_GC_GUARD(watcher.fiber);
|
430
|
+
RB_GC_GUARD(switchpoint_result);
|
431
|
+
|
432
|
+
return io;
|
433
|
+
error:
|
434
|
+
return RAISE_EXCEPTION(switchpoint_result);
|
435
|
+
}
|
436
|
+
|
335
437
|
VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
336
438
|
Backend_t *backend;
|
337
439
|
struct libev_io watcher;
|
@@ -618,6 +720,55 @@ error:
|
|
618
720
|
return RAISE_EXCEPTION(switchpoint_result);
|
619
721
|
}
|
620
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
|
+
|
621
772
|
VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
|
622
773
|
Backend_t *backend;
|
623
774
|
rb_io_t *fptr;
|
@@ -685,26 +836,12 @@ noreturn VALUE Backend_timer_loop(VALUE self, VALUE interval) {
|
|
685
836
|
RB_GC_GUARD(switchpoint_result);
|
686
837
|
|
687
838
|
rb_yield(Qnil);
|
688
|
-
|
689
|
-
while (1) {
|
839
|
+
do {
|
690
840
|
next_time += interval_d;
|
691
|
-
|
692
|
-
}
|
841
|
+
} while (next_time <= now);
|
693
842
|
}
|
694
843
|
}
|
695
844
|
|
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
845
|
struct libev_timeout {
|
709
846
|
struct ev_timer timer;
|
710
847
|
VALUE fiber;
|
@@ -759,13 +896,39 @@ VALUE Backend_timeout(int argc,VALUE *argv, VALUE self) {
|
|
759
896
|
return result;
|
760
897
|
}
|
761
898
|
|
899
|
+
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
900
|
+
VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
901
|
+
int pid_int = NUM2INT(pid);
|
902
|
+
int fd = pidfd_open(pid_int, 0);
|
903
|
+
if (fd >= 0) {
|
904
|
+
Backend_t *backend;
|
905
|
+
GetBackend(self, backend);
|
906
|
+
|
907
|
+
VALUE resume_value = libev_wait_fd(backend, fd, EV_READ, 0);
|
908
|
+
close(fd);
|
909
|
+
RAISE_IF_EXCEPTION(resume_value);
|
910
|
+
RB_GC_GUARD(resume_value);
|
911
|
+
}
|
912
|
+
else {
|
913
|
+
int e = errno;
|
914
|
+
rb_syserr_fail(e, strerror(e));
|
915
|
+
}
|
916
|
+
|
917
|
+
int status = 0;
|
918
|
+
pid_t ret = waitpid(pid_int, &status, WNOHANG);
|
919
|
+
if (ret < 0) {
|
920
|
+
int e = errno;
|
921
|
+
rb_syserr_fail(e, strerror(e));
|
922
|
+
}
|
923
|
+
return rb_ary_new_from_args(2, INT2NUM(ret), INT2NUM(WEXITSTATUS(status)));
|
924
|
+
}
|
925
|
+
#else
|
762
926
|
struct libev_child {
|
763
927
|
struct ev_child child;
|
764
928
|
VALUE fiber;
|
765
929
|
};
|
766
930
|
|
767
|
-
void Backend_child_callback(EV_P_ ev_child *w, int revents)
|
768
|
-
{
|
931
|
+
void Backend_child_callback(EV_P_ ev_child *w, int revents) {
|
769
932
|
struct libev_child *watcher = (struct libev_child *)w;
|
770
933
|
int exit_status = WEXITSTATUS(w->rstatus);
|
771
934
|
VALUE status;
|
@@ -792,6 +955,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
|
792
955
|
RB_GC_GUARD(switchpoint_result);
|
793
956
|
return switchpoint_result;
|
794
957
|
}
|
958
|
+
#endif
|
795
959
|
|
796
960
|
void Backend_async_callback(EV_P_ ev_async *w, int revents) { }
|
797
961
|
|
@@ -820,7 +984,7 @@ VALUE Backend_kind(VALUE self) {
|
|
820
984
|
void Init_Backend() {
|
821
985
|
ev_set_allocator(xrealloc);
|
822
986
|
|
823
|
-
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend",
|
987
|
+
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cObject);
|
824
988
|
rb_define_alloc_func(cBackend, Backend_allocate);
|
825
989
|
|
826
990
|
rb_define_method(cBackend, "initialize", Backend_initialize, 0);
|
@@ -832,13 +996,16 @@ void Init_Backend() {
|
|
832
996
|
|
833
997
|
rb_define_method(cBackend, "read", Backend_read, 4);
|
834
998
|
rb_define_method(cBackend, "read_loop", Backend_read_loop, 1);
|
999
|
+
rb_define_method(cBackend, "feed_loop", Backend_feed_loop, 3);
|
835
1000
|
rb_define_method(cBackend, "write", Backend_write_m, -1);
|
836
1001
|
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
837
1002
|
rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
|
838
1003
|
rb_define_method(cBackend, "connect", Backend_connect, 3);
|
839
1004
|
rb_define_method(cBackend, "recv", Backend_recv, 3);
|
840
1005
|
rb_define_method(cBackend, "recv_loop", Backend_read_loop, 1);
|
841
|
-
rb_define_method(cBackend, "
|
1006
|
+
rb_define_method(cBackend, "recv_feed_loop", Backend_feed_loop, 3);
|
1007
|
+
rb_define_method(cBackend, "send", Backend_send, 3);
|
1008
|
+
rb_define_method(cBackend, "sendv", Backend_sendv, 3);
|
842
1009
|
rb_define_method(cBackend, "wait_io", Backend_wait_io, 2);
|
843
1010
|
rb_define_method(cBackend, "sleep", Backend_sleep, 1);
|
844
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/fiber.c
CHANGED
@@ -101,7 +101,8 @@ VALUE Fiber_await(VALUE self) {
|
|
101
101
|
}
|
102
102
|
rb_hash_aset(waiting_fibers, fiber, Qtrue);
|
103
103
|
|
104
|
-
|
104
|
+
VALUE backend = rb_ivar_get(rb_thread_current(), ID_ivar_backend);
|
105
|
+
result = Backend_wait_event(backend, Qnil);
|
105
106
|
|
106
107
|
rb_hash_delete(waiting_fibers, fiber);
|
107
108
|
RAISE_IF_EXCEPTION(result);
|
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
|
|