polyphony 0.47.1 → 0.47.5.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/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
|