polyphony 0.47.1 → 0.47.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +312 -294
- data/Gemfile.lock +1 -1
- data/TODO.md +32 -3
- data/examples/core/supervisor.rb +3 -3
- data/examples/core/worker-thread.rb +3 -4
- data/examples/io/unix_socket.rb +26 -0
- data/ext/polyphony/backend_io_uring.c +11 -15
- data/ext/polyphony/backend_libev.c +14 -18
- data/lib/polyphony/core/global_api.rb +5 -14
- data/lib/polyphony/core/resource_pool.rb +1 -12
- data/lib/polyphony/extensions/fiber.rb +14 -2
- data/lib/polyphony/extensions/socket.rb +74 -17
- data/lib/polyphony/version.rb +1 -1
- data/test/test_global_api.rb +11 -1
- data/test/test_resource_pool.rb +0 -21
- data/test/test_signal.rb +18 -0
- data/test/test_socket.rb +27 -1
- data/test/test_supervise.rb +2 -1
- metadata +3 -2
data/Gemfile.lock
CHANGED
data/TODO.md
CHANGED
@@ -1,12 +1,41 @@
|
|
1
|
+
- Graceful shutdown again:
|
2
|
+
|
3
|
+
- Fiber API:
|
4
|
+
- `Fiber#terminate(graceul)` - with a graceful flag
|
5
|
+
- `Fiber#terminate_all_children(graceful)` - with a graceful flag
|
6
|
+
- `Fiber#shutdown_all_children(graceful)` - with a graceful flag
|
7
|
+
|
8
|
+
- Set graceful termination in `@graceful_shutdown`
|
9
|
+
- Add `Fiber#graceful_shutdown?` method
|
10
|
+
- Returns `@graceful_shutdown`
|
11
|
+
|
12
|
+
And then we have:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
spin do
|
16
|
+
loop { do_some_stuff }
|
17
|
+
ensure
|
18
|
+
shutdown_gracefully if Fiber.current.graceful_shutdown?
|
19
|
+
end
|
20
|
+
```
|
21
|
+
|
22
|
+
- `Fiber#finalize_children` should pass graceful shutdown flag to children
|
23
|
+
|
24
|
+
- More tight loops
|
25
|
+
- IO#gets_loop, Socket#gets_loop, OpenSSL::Socket#gets_loop (medium effort)
|
26
|
+
- Fiber#receive_loop (very little effort, should be implemented in C)
|
27
|
+
|
1
28
|
## Roadmap for Polyphony 1.0
|
2
29
|
|
3
|
-
-
|
30
|
+
- check integration with rb-inotify
|
31
|
+
|
32
|
+
- Improve `#supervise`. It does not work as advertised, and seems to exhibit an
|
33
|
+
inconsistent behaviour (see supervisor example).
|
34
|
+
|
4
35
|
- Add test that mimics the original design for Monocrono:
|
5
36
|
- 256 fibers each waiting for a message
|
6
37
|
- When message received do some blocking work using a `ThreadPool`
|
7
38
|
- Send messages, collect responses, check for correctness
|
8
|
-
- Improve `#supervise`. It does not work as advertised, and seems to exhibit an
|
9
|
-
inconsistent behaviour (see supervisor example).
|
10
39
|
|
11
40
|
- io_uring
|
12
41
|
- Use playground.c to find out why we when submitting and waiting for
|
data/examples/core/supervisor.rb
CHANGED
@@ -9,9 +9,9 @@ def my_sleep(t)
|
|
9
9
|
puts "#{t} done"
|
10
10
|
end
|
11
11
|
|
12
|
-
spin { my_sleep(1) }
|
13
|
-
spin { my_sleep(2) }
|
14
|
-
spin { my_sleep(3) }
|
12
|
+
spin { my_sleep(0.1) }
|
13
|
+
spin { my_sleep(0.2) }
|
14
|
+
spin { my_sleep(0.3) }
|
15
15
|
spin { puts "fiber count: #{Fiber.current.children.count}" }
|
16
16
|
snooze
|
17
17
|
|
@@ -13,11 +13,9 @@ end
|
|
13
13
|
$worker = Thread.new do
|
14
14
|
Fiber.current.tag = :worker
|
15
15
|
loop do
|
16
|
-
client, block = receive
|
16
|
+
(client, block) = receive
|
17
17
|
do_work(client, &block)
|
18
18
|
end
|
19
|
-
rescue Exception => e
|
20
|
-
p e
|
21
19
|
end
|
22
20
|
|
23
21
|
def process(&block)
|
@@ -27,4 +25,5 @@ end
|
|
27
25
|
|
28
26
|
sleep 0.1
|
29
27
|
|
30
|
-
p process { 1 + 1 }
|
28
|
+
p process { 1 + 1 }
|
29
|
+
p process { 42 ** 2 }
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
unix_path = '/tmp/polyphony-unix-socket'
|
8
|
+
|
9
|
+
FileUtils.rm unix_path rescue nil
|
10
|
+
server = UNIXServer.new(unix_path)
|
11
|
+
spin do
|
12
|
+
server.accept_loop do |socket|
|
13
|
+
p [:accept, socket]
|
14
|
+
spin do
|
15
|
+
while (line = socket.gets)
|
16
|
+
socket.puts line
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
snooze
|
23
|
+
client = UNIXSocket.new('/tmp/polyphony-unix-socket')
|
24
|
+
p [:connected, client]
|
25
|
+
client.puts 'hello!'
|
26
|
+
p client.gets
|
@@ -27,7 +27,6 @@ static int pidfd_open(pid_t pid, unsigned int flags) {
|
|
27
27
|
return syscall(__NR_pidfd_open, pid, flags);
|
28
28
|
}
|
29
29
|
|
30
|
-
VALUE cTCPSocket;
|
31
30
|
VALUE SYM_io_uring;
|
32
31
|
|
33
32
|
typedef struct Backend_t {
|
@@ -669,15 +668,15 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str) {
|
|
669
668
|
return INT2NUM(len);
|
670
669
|
}
|
671
670
|
|
672
|
-
VALUE io_uring_backend_accept(Backend_t *backend, VALUE
|
671
|
+
VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE socket_class, int loop) {
|
673
672
|
rb_io_t *fptr;
|
674
673
|
struct sockaddr addr;
|
675
674
|
socklen_t len = (socklen_t)sizeof addr;
|
676
|
-
VALUE underlying_sock = rb_ivar_get(sock, ID_ivar_io);
|
677
675
|
VALUE socket = Qnil;
|
678
|
-
|
676
|
+
VALUE underlying_sock = rb_ivar_get(server_socket, ID_ivar_io);
|
677
|
+
if (underlying_sock != Qnil) server_socket = underlying_sock;
|
679
678
|
|
680
|
-
GetOpenFile(
|
679
|
+
GetOpenFile(server_socket, fptr);
|
681
680
|
while (1) {
|
682
681
|
VALUE resume_value = Qnil;
|
683
682
|
op_context_t *ctx = OP_CONTEXT_ACQUIRE(&backend->store, OP_ACCEPT);
|
@@ -695,7 +694,7 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE sock, int loop) {
|
|
695
694
|
else {
|
696
695
|
rb_io_t *fp;
|
697
696
|
|
698
|
-
socket = rb_obj_alloc(
|
697
|
+
socket = rb_obj_alloc(socket_class);
|
699
698
|
MakeOpenFile(socket, fp);
|
700
699
|
rb_update_max_fd(fd);
|
701
700
|
fp->fd = fd;
|
@@ -718,16 +717,16 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE sock, int loop) {
|
|
718
717
|
return Qnil;
|
719
718
|
}
|
720
719
|
|
721
|
-
VALUE Backend_accept(VALUE self, VALUE
|
720
|
+
VALUE Backend_accept(VALUE self, VALUE server_socket, VALUE socket_class) {
|
722
721
|
Backend_t *backend;
|
723
722
|
GetBackend(self, backend);
|
724
|
-
return io_uring_backend_accept(backend,
|
723
|
+
return io_uring_backend_accept(backend, server_socket, socket_class, 0);
|
725
724
|
}
|
726
725
|
|
727
|
-
VALUE Backend_accept_loop(VALUE self, VALUE
|
726
|
+
VALUE Backend_accept_loop(VALUE self, VALUE server_socket, VALUE socket_class) {
|
728
727
|
Backend_t *backend;
|
729
728
|
GetBackend(self, backend);
|
730
|
-
io_uring_backend_accept(backend,
|
729
|
+
io_uring_backend_accept(backend, server_socket, socket_class, 1);
|
731
730
|
return self;
|
732
731
|
}
|
733
732
|
|
@@ -945,9 +944,6 @@ VALUE Backend_kind(VALUE self) {
|
|
945
944
|
}
|
946
945
|
|
947
946
|
void Init_Backend() {
|
948
|
-
rb_require("socket");
|
949
|
-
cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
|
950
|
-
|
951
947
|
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cData);
|
952
948
|
rb_define_alloc_func(cBackend, Backend_allocate);
|
953
949
|
|
@@ -968,8 +964,8 @@ void Init_Backend() {
|
|
968
964
|
rb_define_method(cBackend, "recv", Backend_recv, 3);
|
969
965
|
rb_define_method(cBackend, "recv_loop", Backend_recv_loop, 1);
|
970
966
|
rb_define_method(cBackend, "send", Backend_send, 2);
|
971
|
-
rb_define_method(cBackend, "accept", Backend_accept,
|
972
|
-
rb_define_method(cBackend, "accept_loop", Backend_accept_loop,
|
967
|
+
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
968
|
+
rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
|
973
969
|
rb_define_method(cBackend, "connect", Backend_connect, 3);
|
974
970
|
rb_define_method(cBackend, "wait_io", Backend_wait_io, 2);
|
975
971
|
rb_define_method(cBackend, "sleep", Backend_sleep, 1);
|
@@ -13,7 +13,6 @@
|
|
13
13
|
#include "../libev/ev.h"
|
14
14
|
#include "ruby/io.h"
|
15
15
|
|
16
|
-
VALUE cTCPSocket;
|
17
16
|
VALUE SYM_libev;
|
18
17
|
|
19
18
|
ID ID_ivar_is_nonblocking;
|
@@ -494,7 +493,7 @@ VALUE Backend_write_m(int argc, VALUE *argv, VALUE self) {
|
|
494
493
|
Backend_writev(self, argv[0], argc - 1, argv + 1);
|
495
494
|
}
|
496
495
|
|
497
|
-
VALUE Backend_accept(VALUE self, VALUE
|
496
|
+
VALUE Backend_accept(VALUE self, VALUE server_socket, VALUE socket_class) {
|
498
497
|
Backend_t *backend;
|
499
498
|
struct libev_io watcher;
|
500
499
|
rb_io_t *fptr;
|
@@ -502,12 +501,12 @@ VALUE Backend_accept(VALUE self, VALUE sock) {
|
|
502
501
|
struct sockaddr addr;
|
503
502
|
socklen_t len = (socklen_t)sizeof addr;
|
504
503
|
VALUE switchpoint_result = Qnil;
|
505
|
-
VALUE underlying_sock = rb_ivar_get(
|
506
|
-
if (underlying_sock != Qnil)
|
504
|
+
VALUE underlying_sock = rb_ivar_get(server_socket, ID_ivar_io);
|
505
|
+
if (underlying_sock != Qnil) server_socket = underlying_sock;
|
507
506
|
|
508
507
|
GetBackend(self, backend);
|
509
|
-
GetOpenFile(
|
510
|
-
io_set_nonblock(fptr,
|
508
|
+
GetOpenFile(server_socket, fptr);
|
509
|
+
io_set_nonblock(fptr, server_socket);
|
511
510
|
watcher.fiber = Qnil;
|
512
511
|
while (1) {
|
513
512
|
fd = accept(fptr->fd, &addr, &len);
|
@@ -529,7 +528,7 @@ VALUE Backend_accept(VALUE self, VALUE sock) {
|
|
529
528
|
goto error;
|
530
529
|
}
|
531
530
|
|
532
|
-
socket = rb_obj_alloc(
|
531
|
+
socket = rb_obj_alloc(socket_class);
|
533
532
|
MakeOpenFile(socket, fp);
|
534
533
|
rb_update_max_fd(fd);
|
535
534
|
fp->fd = fd;
|
@@ -550,7 +549,7 @@ error:
|
|
550
549
|
return RAISE_EXCEPTION(switchpoint_result);
|
551
550
|
}
|
552
551
|
|
553
|
-
VALUE Backend_accept_loop(VALUE self, VALUE
|
552
|
+
VALUE Backend_accept_loop(VALUE self, VALUE server_socket, VALUE socket_class) {
|
554
553
|
Backend_t *backend;
|
555
554
|
struct libev_io watcher;
|
556
555
|
rb_io_t *fptr;
|
@@ -559,12 +558,12 @@ VALUE Backend_accept_loop(VALUE self, VALUE sock) {
|
|
559
558
|
socklen_t len = (socklen_t)sizeof addr;
|
560
559
|
VALUE switchpoint_result = Qnil;
|
561
560
|
VALUE socket = Qnil;
|
562
|
-
VALUE underlying_sock = rb_ivar_get(
|
563
|
-
if (underlying_sock != Qnil)
|
561
|
+
VALUE underlying_sock = rb_ivar_get(server_socket, ID_ivar_io);
|
562
|
+
if (underlying_sock != Qnil) server_socket = underlying_sock;
|
564
563
|
|
565
564
|
GetBackend(self, backend);
|
566
|
-
GetOpenFile(
|
567
|
-
io_set_nonblock(fptr,
|
565
|
+
GetOpenFile(server_socket, fptr);
|
566
|
+
io_set_nonblock(fptr, server_socket);
|
568
567
|
watcher.fiber = Qnil;
|
569
568
|
|
570
569
|
while (1) {
|
@@ -586,7 +585,7 @@ VALUE Backend_accept_loop(VALUE self, VALUE sock) {
|
|
586
585
|
goto error;
|
587
586
|
}
|
588
587
|
|
589
|
-
socket = rb_obj_alloc(
|
588
|
+
socket = rb_obj_alloc(socket_class);
|
590
589
|
MakeOpenFile(socket, fp);
|
591
590
|
rb_update_max_fd(fd);
|
592
591
|
fp->fd = fd;
|
@@ -849,9 +848,6 @@ VALUE Backend_kind(VALUE self) {
|
|
849
848
|
void Init_Backend() {
|
850
849
|
ev_set_allocator(xrealloc);
|
851
850
|
|
852
|
-
rb_require("socket");
|
853
|
-
cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
|
854
|
-
|
855
851
|
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cData);
|
856
852
|
rb_define_alloc_func(cBackend, Backend_allocate);
|
857
853
|
|
@@ -869,8 +865,8 @@ void Init_Backend() {
|
|
869
865
|
rb_define_method(cBackend, "read", Backend_read, 4);
|
870
866
|
rb_define_method(cBackend, "read_loop", Backend_read_loop, 1);
|
871
867
|
rb_define_method(cBackend, "write", Backend_write_m, -1);
|
872
|
-
rb_define_method(cBackend, "accept", Backend_accept,
|
873
|
-
rb_define_method(cBackend, "accept_loop", Backend_accept_loop,
|
868
|
+
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
869
|
+
rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
|
874
870
|
rb_define_method(cBackend, "connect", Backend_connect, 3);
|
875
871
|
rb_define_method(cBackend, "recv", Backend_recv, 3);
|
876
872
|
rb_define_method(cBackend, "recv_loop", Backend_read_loop, 1);
|
@@ -53,10 +53,10 @@ module Polyphony
|
|
53
53
|
Fiber.current.spin(tag, caller, &block)
|
54
54
|
end
|
55
55
|
|
56
|
-
def spin_loop(tag = nil, rate: nil, &block)
|
57
|
-
if rate
|
56
|
+
def spin_loop(tag = nil, rate: nil, interval: nil, &block)
|
57
|
+
if rate || interval
|
58
58
|
Fiber.current.spin(tag, caller) do
|
59
|
-
throttled_loop(rate, &block)
|
59
|
+
throttled_loop(rate: rate, interval: interval, &block)
|
60
60
|
end
|
61
61
|
else
|
62
62
|
Fiber.current.spin(tag, caller) { loop(&block) }
|
@@ -73,17 +73,8 @@ module Polyphony
|
|
73
73
|
end.await
|
74
74
|
end
|
75
75
|
|
76
|
-
def every(interval)
|
77
|
-
|
78
|
-
loop do
|
79
|
-
now = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
80
|
-
Thread.current.backend.sleep(next_time - now)
|
81
|
-
yield
|
82
|
-
loop do
|
83
|
-
next_time += interval
|
84
|
-
break if next_time > now
|
85
|
-
end
|
86
|
-
end
|
76
|
+
def every(interval, &block)
|
77
|
+
Thread.current.backend.timer_loop(interval, &block)
|
87
78
|
end
|
88
79
|
|
89
80
|
def move_on_after(interval, with_value: nil, &block)
|
@@ -58,18 +58,7 @@ module Polyphony
|
|
58
58
|
# Discards the currently-acquired resource
|
59
59
|
# instead of returning it to the pool when done.
|
60
60
|
def discard!
|
61
|
-
if
|
62
|
-
@size.times do
|
63
|
-
acquire do |r|
|
64
|
-
next if yield(r)
|
65
|
-
|
66
|
-
@size -= 1
|
67
|
-
@acquired_resources.delete(Fiber.current)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
else
|
71
|
-
@size -= 1 if @acquired_resources.delete(Fiber.current)
|
72
|
-
end
|
61
|
+
@size -= 1 if @acquired_resources.delete(Fiber.current)
|
73
62
|
end
|
74
63
|
|
75
64
|
def preheat!
|
@@ -67,19 +67,29 @@ module Polyphony
|
|
67
67
|
self << fiber unless result.is_a?(Exception)
|
68
68
|
end
|
69
69
|
loop { supervise_perform(opts) }
|
70
|
+
rescue Polyphony::MoveOn
|
71
|
+
# generated in #supervise_perform to stop supervisor
|
70
72
|
ensure
|
71
73
|
@on_child_done = nil
|
72
74
|
end
|
73
75
|
|
74
76
|
def supervise_perform(opts)
|
75
77
|
fiber = receive
|
76
|
-
|
78
|
+
if fiber && opts[:restart]
|
79
|
+
restart_fiber(fiber, opts)
|
80
|
+
elsif Fiber.current.children.empty?
|
81
|
+
Fiber.current.stop
|
82
|
+
end
|
77
83
|
rescue Polyphony::Restart
|
78
84
|
restart_all_children
|
79
85
|
rescue Exception => e
|
80
86
|
Kernel.raise e if e.source_fiber.nil? || e.source_fiber == self
|
81
87
|
|
82
|
-
|
88
|
+
if opts[:restart]
|
89
|
+
restart_fiber(e.source_fiber, opts)
|
90
|
+
elsif Fiber.current.children.empty?
|
91
|
+
Fiber.current.stop
|
92
|
+
end
|
83
93
|
end
|
84
94
|
|
85
95
|
def restart_fiber(fiber, opts)
|
@@ -173,6 +183,7 @@ module Polyphony
|
|
173
183
|
# signals (see also the patched `Kernel#trap`)
|
174
184
|
def schedule_priority_oob_fiber(&block)
|
175
185
|
f = Fiber.new do
|
186
|
+
Fiber.current.setup_raw
|
176
187
|
block.call
|
177
188
|
rescue Exception => e
|
178
189
|
Thread.current.schedule_and_wakeup(Thread.main.main_fiber, e)
|
@@ -262,6 +273,7 @@ module Polyphony
|
|
262
273
|
# allows the fiber to be scheduled and to receive messages.
|
263
274
|
def setup_raw
|
264
275
|
@thread = Thread.current
|
276
|
+
@running = true
|
265
277
|
end
|
266
278
|
|
267
279
|
def setup_main_fiber
|
@@ -8,7 +8,11 @@ require_relative '../core/thread_pool'
|
|
8
8
|
# Socket overrides (eventually rewritten in C)
|
9
9
|
class ::Socket
|
10
10
|
def accept
|
11
|
-
Thread.current.backend.accept(self)
|
11
|
+
Thread.current.backend.accept(self, TCPSocket)
|
12
|
+
end
|
13
|
+
|
14
|
+
def accept_loop(&block)
|
15
|
+
Thread.current.backend.accept_loop(self, TCPSocket, &block)
|
12
16
|
end
|
13
17
|
|
14
18
|
NO_EXCEPTION = { exception: false }.freeze
|
@@ -19,17 +23,7 @@ class ::Socket
|
|
19
23
|
end
|
20
24
|
|
21
25
|
def recv(maxlen, flags = 0, outbuf = nil)
|
22
|
-
Thread.current.backend.recv(self,
|
23
|
-
# outbuf ||= +''
|
24
|
-
# loop do
|
25
|
-
# result = recv_nonblock(maxlen, flags, outbuf, **NO_EXCEPTION)
|
26
|
-
# case result
|
27
|
-
# when nil then raise IOError
|
28
|
-
# when :wait_readable then Thread.current.backend.wait_io(self, false)
|
29
|
-
# else
|
30
|
-
# return result
|
31
|
-
# end
|
32
|
-
# end
|
26
|
+
Thread.current.backend.recv(self, outbuf || +'', maxlen)
|
33
27
|
end
|
34
28
|
|
35
29
|
def recv_loop(&block)
|
@@ -144,19 +138,24 @@ class ::TCPSocket
|
|
144
138
|
end
|
145
139
|
|
146
140
|
def recv(maxlen, flags = 0, outbuf = nil)
|
147
|
-
Thread.current.backend.recv(self,
|
141
|
+
Thread.current.backend.recv(self, outbuf || +'', maxlen)
|
148
142
|
end
|
149
143
|
|
150
144
|
def recv_loop(&block)
|
151
145
|
Thread.current.backend.recv_loop(self, &block)
|
152
146
|
end
|
147
|
+
alias_method :read_loop, :recv_loop
|
153
148
|
|
154
149
|
def send(mesg, flags = 0)
|
155
150
|
Thread.current.backend.send(self, mesg)
|
156
151
|
end
|
157
152
|
|
158
|
-
def write(str)
|
159
|
-
|
153
|
+
def write(str, *args)
|
154
|
+
if args.empty?
|
155
|
+
Thread.current.backend.send(self, str)
|
156
|
+
else
|
157
|
+
Thread.current.backend.send(self, str + args.join)
|
158
|
+
end
|
160
159
|
end
|
161
160
|
alias_method :<<, :write
|
162
161
|
|
@@ -193,11 +192,12 @@ class ::TCPServer
|
|
193
192
|
|
194
193
|
alias_method :orig_accept, :accept
|
195
194
|
def accept
|
196
|
-
@io
|
195
|
+
Thread.current.backend.accept(@io, TCPSocket)
|
196
|
+
# @io.accept
|
197
197
|
end
|
198
198
|
|
199
199
|
def accept_loop(&block)
|
200
|
-
Thread.current.backend.accept_loop(@io, &block)
|
200
|
+
Thread.current.backend.accept_loop(@io, TCPSocket, &block)
|
201
201
|
end
|
202
202
|
|
203
203
|
alias_method :orig_close, :close
|
@@ -205,3 +205,60 @@ class ::TCPServer
|
|
205
205
|
@io.close
|
206
206
|
end
|
207
207
|
end
|
208
|
+
|
209
|
+
class ::UNIXServer
|
210
|
+
alias_method :orig_accept, :accept
|
211
|
+
def accept
|
212
|
+
Thread.current.backend.accept(self, UNIXSocket)
|
213
|
+
end
|
214
|
+
|
215
|
+
def accept_loop(&block)
|
216
|
+
Thread.current.backend.accept_loop(self, UNIXSocket, &block)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
class ::UNIXSocket
|
221
|
+
def recv(maxlen, flags = 0, outbuf = nil)
|
222
|
+
Thread.current.backend.recv(self, outbuf || +'', maxlen)
|
223
|
+
end
|
224
|
+
|
225
|
+
def recv_loop(&block)
|
226
|
+
Thread.current.backend.recv_loop(self, &block)
|
227
|
+
end
|
228
|
+
alias_method :read_loop, :recv_loop
|
229
|
+
|
230
|
+
def send(mesg, flags = 0)
|
231
|
+
Thread.current.backend.send(self, mesg)
|
232
|
+
end
|
233
|
+
|
234
|
+
def write(str, *args)
|
235
|
+
if args.empty?
|
236
|
+
Thread.current.backend.send(self, str)
|
237
|
+
else
|
238
|
+
Thread.current.backend.send(self, str + args.join)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
alias_method :<<, :write
|
242
|
+
|
243
|
+
def readpartial(maxlen, str = nil)
|
244
|
+
@read_buffer ||= +''
|
245
|
+
result = Thread.current.backend.recv(self, @read_buffer, maxlen)
|
246
|
+
raise EOFError unless result
|
247
|
+
|
248
|
+
if str
|
249
|
+
str << @read_buffer
|
250
|
+
else
|
251
|
+
str = @read_buffer
|
252
|
+
end
|
253
|
+
@read_buffer = +''
|
254
|
+
str
|
255
|
+
end
|
256
|
+
|
257
|
+
def read_nonblock(len, str = nil, exception: true)
|
258
|
+
@io.read_nonblock(len, str, exception: exception)
|
259
|
+
end
|
260
|
+
|
261
|
+
def write_nonblock(buf, exception: true)
|
262
|
+
@io.write_nonblock(buf, exception: exception)
|
263
|
+
end
|
264
|
+
end
|