polyphony 0.47.3 → 0.47.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +1 -1
- data/TODO.md +34 -29
- data/examples/io/unix_socket.rb +26 -0
- data/ext/polyphony/backend_common.h +20 -0
- data/ext/polyphony/backend_io_uring.c +7 -8
- data/ext/polyphony/backend_libev.c +15 -15
- data/lib/polyphony/extensions/socket.rb +60 -11
- data/lib/polyphony/version.rb +1 -1
- 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: f32962c9f1004bc9c63afcaddaad91dc8878da5e8290b8e9d42d591433311c0b
|
4
|
+
data.tar.gz: 3b43ad185ccb0778d88d9c8ac1043bbff291ac0a55d5bee80da8b6e08a1f6493
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b4ba80ea441862f22398e624996144e9ed7f8297b56e2f14035c537671282f4338b3843ff192959a7031134e761d273c5050043b08b5051c1653ecc3f986cddb
|
7
|
+
data.tar.gz: '04850a036f5278d221b6610259e70fbb7e44e8afd04237d9a6906fa826a836c786734123894a0b7197c5c98502a9b5304896b09a1e7b6d16433e363dbd1803e6'
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/TODO.md
CHANGED
@@ -1,37 +1,42 @@
|
|
1
|
-
Graceful shutdown again:
|
2
|
-
|
3
|
-
- Add `Polyphony::GracefulShutdown` exception
|
4
|
-
- Two exceptions for stopping fibers:
|
5
|
-
|
6
|
-
|
7
|
-
- Fiber API:
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
- Add `Fiber#graceful_shutdown?` method
|
12
|
-
|
13
|
-
- Override `Polyphony::Terminate#invoke` to reset the `@graceful_shutdown` fiber
|
14
|
-
|
15
|
-
|
16
|
-
And then we have:
|
17
|
-
|
18
|
-
```ruby
|
19
|
-
spin do
|
20
|
-
|
21
|
-
ensure
|
22
|
-
|
23
|
-
|
24
|
-
shutdown_gracefully
|
25
|
-
end
|
26
|
-
```
|
1
|
+
- Graceful shutdown again:
|
2
|
+
|
3
|
+
- Add `Polyphony::GracefulShutdown` exception
|
4
|
+
- Two exceptions for stopping fibers:
|
5
|
+
- `Polyphony::GracefulShutdown` - graceful shutdown
|
6
|
+
- `Polyphony::Terminate` - ungraceful shutdown
|
7
|
+
- Fiber API:
|
8
|
+
- `Fiber#shutdown_children` - graceful shutdown of all children
|
9
|
+
- `Fiber#terminate_children` - ungraceful shutdown of all children
|
10
|
+
|
11
|
+
- Add `Fiber#graceful_shutdown?` method
|
12
|
+
- Returns false unless a `Polyphony::GracefulShutdown` was raised
|
13
|
+
- Override `Polyphony::Terminate#invoke` to reset the `@graceful_shutdown` fiber
|
14
|
+
flag
|
15
|
+
|
16
|
+
And then we have:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
spin do
|
20
|
+
loop { do_some_stuff }
|
21
|
+
ensure
|
22
|
+
return unless Fiber.current.graceful_shutdown?
|
23
|
+
|
24
|
+
shutdown_gracefully
|
25
|
+
end
|
26
|
+
```
|
27
27
|
|
28
|
-
- When a fiber is stopped it should use `Polyphony::Terminate` to stop child
|
29
|
-
|
30
|
-
|
28
|
+
- When a fiber is stopped it should use `Polyphony::Terminate` to stop child
|
29
|
+
fibers, *unless* it was stopped with a `Polyphony::GracefulShutdown` (which it
|
30
|
+
can check with `@graceful_shutdown`).
|
31
31
|
|
32
|
+
- More tight loops
|
33
|
+
- IO#gets_loop, Socket#gets_loop, OpenSSL::Socket#gets_loop (medium effort)
|
34
|
+
- Fiber#receive_loop (very little effort, should be implemented in C)
|
32
35
|
|
33
36
|
## Roadmap for Polyphony 1.0
|
34
37
|
|
38
|
+
- check integration with rb-inotify
|
39
|
+
|
35
40
|
- Check why worker-thread example doesn't work.
|
36
41
|
- Add test that mimics the original design for Monocrono:
|
37
42
|
- 256 fibers each waiting for a message
|
@@ -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
|
@@ -3,6 +3,26 @@
|
|
3
3
|
#include "ruby.h"
|
4
4
|
#include "ruby/io.h"
|
5
5
|
|
6
|
+
VALUE cTCPSocket;
|
7
|
+
VALUE cTCPServer;
|
8
|
+
VALUE cUNIXSocket;
|
9
|
+
VALUE cUNIXServer;
|
10
|
+
|
11
|
+
void Init_SocketClasses() {
|
12
|
+
rb_require("socket");
|
13
|
+
cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
|
14
|
+
cTCPServer = rb_const_get(rb_cObject, rb_intern("TCPServer"));
|
15
|
+
cUNIXSocket = rb_const_get(rb_cObject, rb_intern("UNIXSocket"));
|
16
|
+
cUNIXServer = rb_const_get(rb_cObject, rb_intern("UNIXServer"));
|
17
|
+
}
|
18
|
+
|
19
|
+
VALUE ConnectionSocketClass(VALUE server) {
|
20
|
+
if (RTEST(rb_obj_is_kind_of(server, cTCPServer))) return cTCPSocket;
|
21
|
+
if (RTEST(rb_obj_is_kind_of(server, cUNIXServer))) return cUNIXSocket;
|
22
|
+
|
23
|
+
rb_raise(rb_eRuntimeError, "Invalid server class");
|
24
|
+
}
|
25
|
+
|
6
26
|
//////////////////////////////////////////////////////////////////////
|
7
27
|
//////////////////////////////////////////////////////////////////////
|
8
28
|
// the following is copied verbatim from the Ruby source code (io.c)
|
@@ -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,16 @@ 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, 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 socket_class = ConnectionSocketClass(server_socket);
|
677
|
+
VALUE underlying_sock = rb_ivar_get(server_socket, ID_ivar_io);
|
678
|
+
if (underlying_sock != Qnil) server_socket = underlying_sock;
|
679
679
|
|
680
|
-
GetOpenFile(
|
680
|
+
GetOpenFile(server_socket, fptr);
|
681
681
|
while (1) {
|
682
682
|
VALUE resume_value = Qnil;
|
683
683
|
op_context_t *ctx = OP_CONTEXT_ACQUIRE(&backend->store, OP_ACCEPT);
|
@@ -695,7 +695,7 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE sock, int loop) {
|
|
695
695
|
else {
|
696
696
|
rb_io_t *fp;
|
697
697
|
|
698
|
-
socket = rb_obj_alloc(
|
698
|
+
socket = rb_obj_alloc(socket_class);
|
699
699
|
MakeOpenFile(socket, fp);
|
700
700
|
rb_update_max_fd(fd);
|
701
701
|
fp->fd = fd;
|
@@ -945,8 +945,7 @@ VALUE Backend_kind(VALUE self) {
|
|
945
945
|
}
|
946
946
|
|
947
947
|
void Init_Backend() {
|
948
|
-
|
949
|
-
cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
|
948
|
+
Init_SocketClasses();
|
950
949
|
|
951
950
|
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cData);
|
952
951
|
rb_define_alloc_func(cBackend, Backend_allocate);
|
@@ -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) {
|
498
497
|
Backend_t *backend;
|
499
498
|
struct libev_io watcher;
|
500
499
|
rb_io_t *fptr;
|
@@ -502,12 +501,13 @@ 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
|
506
|
-
|
504
|
+
VALUE socket_class = ConnectionSocketClass(server_socket);
|
505
|
+
VALUE underlying_sock = rb_ivar_get(server_socket, ID_ivar_io);
|
506
|
+
if (underlying_sock != Qnil) server_socket = underlying_sock;
|
507
507
|
|
508
508
|
GetBackend(self, backend);
|
509
|
-
GetOpenFile(
|
510
|
-
io_set_nonblock(fptr,
|
509
|
+
GetOpenFile(server_socket, fptr);
|
510
|
+
io_set_nonblock(fptr, server_socket);
|
511
511
|
watcher.fiber = Qnil;
|
512
512
|
while (1) {
|
513
513
|
fd = accept(fptr->fd, &addr, &len);
|
@@ -529,7 +529,7 @@ VALUE Backend_accept(VALUE self, VALUE sock) {
|
|
529
529
|
goto error;
|
530
530
|
}
|
531
531
|
|
532
|
-
socket = rb_obj_alloc(
|
532
|
+
socket = rb_obj_alloc(socket_class);
|
533
533
|
MakeOpenFile(socket, fp);
|
534
534
|
rb_update_max_fd(fd);
|
535
535
|
fp->fd = fd;
|
@@ -550,7 +550,7 @@ error:
|
|
550
550
|
return RAISE_EXCEPTION(switchpoint_result);
|
551
551
|
}
|
552
552
|
|
553
|
-
VALUE Backend_accept_loop(VALUE self, VALUE
|
553
|
+
VALUE Backend_accept_loop(VALUE self, VALUE server_socket) {
|
554
554
|
Backend_t *backend;
|
555
555
|
struct libev_io watcher;
|
556
556
|
rb_io_t *fptr;
|
@@ -559,12 +559,13 @@ VALUE Backend_accept_loop(VALUE self, VALUE sock) {
|
|
559
559
|
socklen_t len = (socklen_t)sizeof addr;
|
560
560
|
VALUE switchpoint_result = Qnil;
|
561
561
|
VALUE socket = Qnil;
|
562
|
-
VALUE
|
563
|
-
|
562
|
+
VALUE socket_class = ConnectionSocketClass(server_socket);
|
563
|
+
VALUE underlying_sock = rb_ivar_get(server_socket, ID_ivar_io);
|
564
|
+
if (underlying_sock != Qnil) server_socket = underlying_sock;
|
564
565
|
|
565
566
|
GetBackend(self, backend);
|
566
|
-
GetOpenFile(
|
567
|
-
io_set_nonblock(fptr,
|
567
|
+
GetOpenFile(server_socket, fptr);
|
568
|
+
io_set_nonblock(fptr, server_socket);
|
568
569
|
watcher.fiber = Qnil;
|
569
570
|
|
570
571
|
while (1) {
|
@@ -586,7 +587,7 @@ VALUE Backend_accept_loop(VALUE self, VALUE sock) {
|
|
586
587
|
goto error;
|
587
588
|
}
|
588
589
|
|
589
|
-
socket = rb_obj_alloc(
|
590
|
+
socket = rb_obj_alloc(socket_class);
|
590
591
|
MakeOpenFile(socket, fp);
|
591
592
|
rb_update_max_fd(fd);
|
592
593
|
fp->fd = fd;
|
@@ -849,8 +850,7 @@ VALUE Backend_kind(VALUE self) {
|
|
849
850
|
void Init_Backend() {
|
850
851
|
ev_set_allocator(xrealloc);
|
851
852
|
|
852
|
-
|
853
|
-
cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
|
853
|
+
Init_SocketClasses();
|
854
854
|
|
855
855
|
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cData);
|
856
856
|
rb_define_alloc_func(cBackend, Backend_allocate);
|
@@ -19,17 +19,7 @@ class ::Socket
|
|
19
19
|
end
|
20
20
|
|
21
21
|
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
|
22
|
+
Thread.current.backend.recv(self, outbuf || +'', maxlen)
|
33
23
|
end
|
34
24
|
|
35
25
|
def recv_loop(&block)
|
@@ -210,3 +200,62 @@ class ::TCPServer
|
|
210
200
|
@io.close
|
211
201
|
end
|
212
202
|
end
|
203
|
+
|
204
|
+
class ::UNIXServer
|
205
|
+
alias_method :orig_accept, :accept
|
206
|
+
def accept
|
207
|
+
Thread.current.backend.accept(self)
|
208
|
+
end
|
209
|
+
|
210
|
+
def accept_loop(&block)
|
211
|
+
Thread.current.backend.accept_loop(self, &block)
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
class ::UNIXSocket
|
218
|
+
def recv(maxlen, flags = 0, outbuf = nil)
|
219
|
+
Thread.current.backend.recv(self, buf || +'', maxlen)
|
220
|
+
end
|
221
|
+
|
222
|
+
def recv_loop(&block)
|
223
|
+
Thread.current.backend.recv_loop(self, &block)
|
224
|
+
end
|
225
|
+
alias_method :read_loop, :recv_loop
|
226
|
+
|
227
|
+
def send(mesg, flags = 0)
|
228
|
+
Thread.current.backend.send(self, mesg)
|
229
|
+
end
|
230
|
+
|
231
|
+
def write(str, *args)
|
232
|
+
if args.empty?
|
233
|
+
Thread.current.backend.send(self, str)
|
234
|
+
else
|
235
|
+
Thread.current.backend.send(self, str + args.join)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
alias_method :<<, :write
|
239
|
+
|
240
|
+
def readpartial(maxlen, str = nil)
|
241
|
+
@read_buffer ||= +''
|
242
|
+
result = Thread.current.backend.recv(self, @read_buffer, maxlen)
|
243
|
+
raise EOFError unless result
|
244
|
+
|
245
|
+
if str
|
246
|
+
str << @read_buffer
|
247
|
+
else
|
248
|
+
str = @read_buffer
|
249
|
+
end
|
250
|
+
@read_buffer = +''
|
251
|
+
str
|
252
|
+
end
|
253
|
+
|
254
|
+
def read_nonblock(len, str = nil, exception: true)
|
255
|
+
@io.read_nonblock(len, str, exception: exception)
|
256
|
+
end
|
257
|
+
|
258
|
+
def write_nonblock(buf, exception: true)
|
259
|
+
@io.write_nonblock(buf, exception: exception)
|
260
|
+
end
|
261
|
+
end
|
data/lib/polyphony/version.rb
CHANGED
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.47.
|
4
|
+
version: 0.47.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-11-
|
11
|
+
date: 2020-11-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -386,6 +386,7 @@ files:
|
|
386
386
|
- examples/io/tcpserver.rb
|
387
387
|
- examples/io/tcpsocket.rb
|
388
388
|
- examples/io/tunnel.rb
|
389
|
+
- examples/io/unix_socket.rb
|
389
390
|
- examples/io/zip.rb
|
390
391
|
- examples/performance/fiber_resume.rb
|
391
392
|
- examples/performance/fiber_transfer.rb
|