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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 89890bc8a81fd4f0a80f6d84c7f5138cfda12bc99848e74ef8140abf681640e2
4
- data.tar.gz: d18e210b24f3d0eb2f83c1dcb188e7c1c691f949231ef0b3d07bd926c988f4d6
3
+ metadata.gz: f32962c9f1004bc9c63afcaddaad91dc8878da5e8290b8e9d42d591433311c0b
4
+ data.tar.gz: 3b43ad185ccb0778d88d9c8ac1043bbff291ac0a55d5bee80da8b6e08a1f6493
5
5
  SHA512:
6
- metadata.gz: c95bef00de396f601f91937c780202a26d0e9c5a3eb48f564d1dcb70d89b30c12ebbbc89c9ddb10b81b013f9a89398468b8b3b4c1d3158d00110e3e6ea5355a6
7
- data.tar.gz: 3c31dac6a239e73b6dbf028edfeced82ac6b2d17ba2f5f2960a41aa9d74e57336082bbe038a8ed6701a2ceefaf68cacb74764f9f71c81ce1e36d5868702e5346
6
+ metadata.gz: b4ba80ea441862f22398e624996144e9ed7f8297b56e2f14035c537671282f4338b3843ff192959a7031134e761d273c5050043b08b5051c1653ecc3f986cddb
7
+ data.tar.gz: '04850a036f5278d221b6610259e70fbb7e44e8afd04237d9a6906fa826a836c786734123894a0b7197c5c98502a9b5304896b09a1e7b6d16433e363dbd1803e6'
@@ -1,3 +1,7 @@
1
+ ## 0.47.4
2
+
3
+ * Add support for Unix sockets
4
+
1
5
  ## 0.47.3
2
6
 
3
7
  * Enable I/O in signal handlers (#45)
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.47.3)
4
+ polyphony (0.47.4)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
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
- - `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
- ```
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
- fibers, *unless* it was stopped with a `Polyphony::GracefulShutdown` (which it
30
- can check with `@graceful_shutdown`).
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 sock, int loop) {
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
- if (underlying_sock != Qnil) sock = underlying_sock;
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(sock, fptr);
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(cTCPSocket);
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
- rb_require("socket");
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 sock) {
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 underlying_sock = rb_ivar_get(sock, ID_ivar_io);
506
- if (underlying_sock != Qnil) sock = underlying_sock;
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(sock, fptr);
510
- io_set_nonblock(fptr, sock);
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(cTCPSocket);
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 sock) {
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 underlying_sock = rb_ivar_get(sock, ID_ivar_io);
563
- if (underlying_sock != Qnil) sock = underlying_sock;
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(sock, fptr);
567
- io_set_nonblock(fptr, sock);
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(cTCPSocket);
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
- rb_require("socket");
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, buf || +'', maxlen)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.47.3'
4
+ VERSION = '0.47.4'
5
5
  end
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.3
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-12 00:00:00.000000000 Z
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