polyphony 0.47.3 → 0.47.4
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 +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
|