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 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