polyphony 1.3 → 1.5
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/.yardopts +1 -0
- data/CHANGELOG.md +14 -0
- data/README.md +11 -45
- data/TODO.md +5 -10
- data/docs/installation.md +30 -0
- data/docs/readme.md +11 -45
- data/examples/core/stages.rb +99 -0
- data/examples/pipes/http_server.rb +42 -12
- data/examples/pipes/http_server2.rb +45 -0
- data/ext/polyphony/backend_common.c +1 -1
- data/ext/polyphony/backend_common.h +5 -0
- data/ext/polyphony/backend_io_uring.c +163 -144
- data/ext/polyphony/backend_libev.c +68 -15
- data/ext/polyphony/extconf.rb +6 -2
- data/ext/polyphony/pipe.c +1 -1
- data/ext/polyphony/polyphony.c +22 -25
- data/ext/polyphony/polyphony.h +1 -6
- data/ext/polyphony/win_uio.h +18 -0
- data/lib/polyphony/core/debug.rb +8 -8
- data/lib/polyphony/extensions/io.rb +17 -4
- data/lib/polyphony/extensions/kernel.rb +16 -0
- data/lib/polyphony/extensions/openssl.rb +11 -11
- data/lib/polyphony/extensions/pipe.rb +5 -5
- data/lib/polyphony/extensions/socket.rb +18 -32
- data/lib/polyphony/extensions/timeout.rb +5 -1
- data/lib/polyphony/version.rb +1 -1
- data/test/stress.rb +6 -1
- data/test/test_backend.rb +11 -2
- data/test/test_ext.rb +14 -0
- data/test/test_global_api.rb +5 -5
- data/test/test_io.rb +1 -1
- data/test/test_signal.rb +15 -6
- data/test/test_socket.rb +3 -102
- data/test/test_timer.rb +1 -1
- metadata +10 -6
| @@ -42,21 +42,24 @@ thread. | |
| 42 42 | 
             
            #define _GNU_SOURCE 1
         | 
| 43 43 | 
             
            #endif
         | 
| 44 44 |  | 
| 45 | 
            -
            #include <netdb.h>
         | 
| 46 | 
            -
            #include <sys/socket.h>
         | 
| 47 | 
            -
            #include <sys/uio.h>
         | 
| 48 45 | 
             
            #include <unistd.h>
         | 
| 49 | 
            -
            #include <netinet/in.h>
         | 
| 50 | 
            -
            #include <arpa/inet.h>
         | 
| 51 46 | 
             
            #include <stdnoreturn.h>
         | 
| 52 47 | 
             
            #include <sys/types.h>
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            #ifdef POLYPHONY_USE_PIDFD_OPEN
         | 
| 53 50 | 
             
            #include <sys/wait.h>
         | 
| 51 | 
            +
            #endif
         | 
| 52 | 
            +
             | 
| 54 53 | 
             
            #include <fcntl.h>
         | 
| 55 54 |  | 
| 56 55 | 
             
            #include "polyphony.h"
         | 
| 57 56 | 
             
            #include "../libev/ev.h"
         | 
| 58 57 | 
             
            #include "ruby/io.h"
         | 
| 59 58 |  | 
| 59 | 
            +
            #ifndef POLYPHONY_WINDOWS
         | 
| 60 | 
            +
            #include <sys/uio.h>
         | 
| 61 | 
            +
            #endif
         | 
| 62 | 
            +
             | 
| 60 63 | 
             
            #include "../libev/ev.h"
         | 
| 61 64 | 
             
            #include "backend_common.h"
         | 
| 62 65 |  | 
| @@ -267,21 +270,25 @@ VALUE libev_wait_fd(Backend_t *backend, int fd, int events, int raise_exception) | |
| 267 270 | 
             
            }
         | 
| 268 271 |  | 
| 269 272 | 
             
            static inline int fd_from_io(VALUE io, rb_io_t **fptr, int write_mode, int rectify_file_pos) {
         | 
| 273 | 
            +
              if (TYPE(io) == T_FIXNUM) {
         | 
| 274 | 
            +
                *fptr = NULL;
         | 
| 275 | 
            +
                return FIX2INT(io);
         | 
| 276 | 
            +
              }
         | 
| 277 | 
            +
              
         | 
| 270 278 | 
             
              if (rb_obj_class(io) == cPipe) {
         | 
| 271 279 | 
             
                *fptr = NULL;
         | 
| 272 280 | 
             
                Pipe_verify_blocking_mode(io, Qfalse);
         | 
| 273 281 | 
             
                return Pipe_get_fd(io, write_mode);
         | 
| 274 282 | 
             
              }
         | 
| 275 | 
            -
             | 
| 276 | 
            -
             | 
| 277 | 
            -
             | 
| 278 | 
            -
             | 
| 279 | 
            -
             | 
| 280 | 
            -
             | 
| 281 | 
            -
             | 
| 282 | 
            -
             | 
| 283 | 
            -
             | 
| 284 | 
            -
              }
         | 
| 283 | 
            +
             | 
| 284 | 
            +
              VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
         | 
| 285 | 
            +
              if (underlying_io != Qnil) io = underlying_io;
         | 
| 286 | 
            +
             | 
| 287 | 
            +
              GetOpenFile(io, *fptr);
         | 
| 288 | 
            +
              int fd = rb_io_descriptor(io);
         | 
| 289 | 
            +
              io_verify_blocking_mode(io, fd, Qfalse);
         | 
| 290 | 
            +
              if (rectify_file_pos) rectify_io_file_pos(*fptr);
         | 
| 291 | 
            +
              return fd;
         | 
| 285 292 | 
             
            }
         | 
| 286 293 |  | 
| 287 294 | 
             
            VALUE Backend_read(VALUE self, VALUE io, VALUE buffer, VALUE length, VALUE to_eof, VALUE pos) {
         | 
| @@ -558,6 +565,7 @@ error: | |
| 558 565 | 
             
              return RAISE_EXCEPTION(switchpoint_result);
         | 
| 559 566 | 
             
            }
         | 
| 560 567 |  | 
| 568 | 
            +
            #ifndef POLYPHONY_WINDOWS
         | 
| 561 569 | 
             
            VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
         | 
| 562 570 | 
             
              Backend_t *backend;
         | 
| 563 571 | 
             
              struct libev_io watcher;
         | 
| @@ -629,15 +637,23 @@ error: | |
| 629 637 | 
             
              free(iov);
         | 
| 630 638 | 
             
              return RAISE_EXCEPTION(switchpoint_result);
         | 
| 631 639 | 
             
            }
         | 
| 640 | 
            +
            #endif
         | 
| 632 641 |  | 
| 633 642 | 
             
            VALUE Backend_write_m(int argc, VALUE *argv, VALUE self) {
         | 
| 634 643 | 
             
              if (argc < 2)
         | 
| 635 644 | 
             
                // TODO: raise ArgumentError
         | 
| 636 645 | 
             
                rb_raise(rb_eRuntimeError, "(wrong number of arguments (expected 2 or more))");
         | 
| 637 646 |  | 
| 647 | 
            +
            #ifdef POLYPHONY_WINDOWS
         | 
| 648 | 
            +
              int total = 0;
         | 
| 649 | 
            +
              for (int i = 1; i < argc; i++)
         | 
| 650 | 
            +
                total += FIX2INT(Backend_write(self, argv[0], argv[i]));
         | 
| 651 | 
            +
              return INT2FIX(total);
         | 
| 652 | 
            +
            #else
         | 
| 638 653 | 
             
              return (argc == 2) ?
         | 
| 639 654 | 
             
                Backend_write(self, argv[0], argv[1]) :
         | 
| 640 655 | 
             
                Backend_writev(self, argv[0], argc - 1, argv + 1);
         | 
| 656 | 
            +
            #endif
         | 
| 641 657 | 
             
            }
         | 
| 642 658 |  | 
| 643 659 | 
             
            VALUE Backend_accept(VALUE self, VALUE server_socket, VALUE socket_class) {
         | 
| @@ -1135,6 +1151,31 @@ VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) { | |
| 1135 1151 | 
             
              return libev_wait_fd(backend, fd, events, 1);
         | 
| 1136 1152 | 
             
            }
         | 
| 1137 1153 |  | 
| 1154 | 
            +
            VALUE Backend_close(VALUE self, VALUE io) {
         | 
| 1155 | 
            +
              Backend_t *backend;
         | 
| 1156 | 
            +
              rb_io_t *fptr;
         | 
| 1157 | 
            +
              VALUE resume_value = Qnil;
         | 
| 1158 | 
            +
              int result;
         | 
| 1159 | 
            +
              int fd = fd_from_io(io, &fptr, 0, 0);
         | 
| 1160 | 
            +
              if (fd < 0) return Qnil;
         | 
| 1161 | 
            +
             | 
| 1162 | 
            +
              GetBackend(self, backend);
         | 
| 1163 | 
            +
             | 
| 1164 | 
            +
              result = close(fd);
         | 
| 1165 | 
            +
              if (result == -1) {
         | 
| 1166 | 
            +
                int err = errno;
         | 
| 1167 | 
            +
                rb_syserr_fail(err, strerror(err));
         | 
| 1168 | 
            +
              }
         | 
| 1169 | 
            +
             | 
| 1170 | 
            +
              resume_value = backend_snooze(&backend->base);
         | 
| 1171 | 
            +
              RAISE_IF_EXCEPTION(resume_value);
         | 
| 1172 | 
            +
              RB_GC_GUARD(resume_value);
         | 
| 1173 | 
            +
             | 
| 1174 | 
            +
              if (fptr) fptr_finalize(fptr);
         | 
| 1175 | 
            +
              // fd = -1;
         | 
| 1176 | 
            +
              return io;
         | 
| 1177 | 
            +
            }
         | 
| 1178 | 
            +
             | 
| 1138 1179 | 
             
            struct libev_timer {
         | 
| 1139 1180 | 
             
              struct ev_timer timer;
         | 
| 1140 1181 | 
             
              VALUE fiber;
         | 
| @@ -1292,6 +1333,7 @@ struct libev_child { | |
| 1292 1333 | 
             
              VALUE fiber;
         | 
| 1293 1334 | 
             
            };
         | 
| 1294 1335 |  | 
| 1336 | 
            +
            #ifndef POLYPHONY_WINDOWS
         | 
| 1295 1337 | 
             
            void Backend_child_callback(EV_P_ ev_child *w, int revents) {
         | 
| 1296 1338 | 
             
              struct libev_child *watcher = (struct libev_child *)w;
         | 
| 1297 1339 | 
             
              int exit_status = WEXITSTATUS(w->rstatus);
         | 
| @@ -1300,8 +1342,12 @@ void Backend_child_callback(EV_P_ ev_child *w, int revents) { | |
| 1300 1342 | 
             
              status = rb_ary_new_from_args(2, INT2FIX(w->rpid), INT2FIX(exit_status));
         | 
| 1301 1343 | 
             
              Fiber_make_runnable(watcher->fiber, status);
         | 
| 1302 1344 | 
             
            }
         | 
| 1345 | 
            +
            #endif
         | 
| 1303 1346 |  | 
| 1304 1347 | 
             
            VALUE Backend_waitpid(VALUE self, VALUE pid) {
         | 
| 1348 | 
            +
            #ifdef POLYPHONY_WINDOWS
         | 
| 1349 | 
            +
              rb_raise(rb_eStandardError, "Not implemented");
         | 
| 1350 | 
            +
            #else
         | 
| 1305 1351 | 
             
              Backend_t *backend;
         | 
| 1306 1352 | 
             
              struct libev_child watcher;
         | 
| 1307 1353 | 
             
              VALUE switchpoint_result = Qnil;
         | 
| @@ -1319,6 +1365,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) { | |
| 1319 1365 | 
             
              RB_GC_GUARD(watcher.fiber);
         | 
| 1320 1366 | 
             
              RB_GC_GUARD(switchpoint_result);
         | 
| 1321 1367 | 
             
              return switchpoint_result;
         | 
| 1368 | 
            +
            #endif
         | 
| 1322 1369 | 
             
            }
         | 
| 1323 1370 | 
             
            #endif
         | 
| 1324 1371 |  | 
| @@ -1472,6 +1519,7 @@ done: | |
| 1472 1519 | 
             
            #endif
         | 
| 1473 1520 | 
             
            }
         | 
| 1474 1521 |  | 
| 1522 | 
            +
            #ifdef POLYPHONY_LINUX
         | 
| 1475 1523 | 
             
            VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VALUE postfix, VALUE chunk_prefix, VALUE chunk_postfix, VALUE chunk_size) {
         | 
| 1476 1524 | 
             
              Backend_t *backend;
         | 
| 1477 1525 | 
             
              GetBackend(self, backend);
         | 
| @@ -1561,6 +1609,7 @@ error: | |
| 1561 1609 | 
             
              if (pipefd[1] != -1) close(pipefd[1]);
         | 
| 1562 1610 | 
             
              return RAISE_EXCEPTION(result);
         | 
| 1563 1611 | 
             
            }
         | 
| 1612 | 
            +
            #endif
         | 
| 1564 1613 |  | 
| 1565 1614 | 
             
            VALUE Backend_trace(int argc, VALUE *argv, VALUE self) {
         | 
| 1566 1615 | 
             
              Backend_t *backend;
         | 
| @@ -1626,7 +1675,10 @@ void Init_Backend(void) { | |
| 1626 1675 | 
             
              rb_define_method(cBackend, "chain", Backend_chain, -1);
         | 
| 1627 1676 | 
             
              rb_define_method(cBackend, "idle_gc_period=", Backend_idle_gc_period_set, 1);
         | 
| 1628 1677 | 
             
              rb_define_method(cBackend, "idle_proc=", Backend_idle_proc_set, 1);
         | 
| 1678 | 
            +
              
         | 
| 1679 | 
            +
              #ifdef POLYPHONY_LINUX
         | 
| 1629 1680 | 
             
              rb_define_method(cBackend, "splice_chunks", Backend_splice_chunks, 7);
         | 
| 1681 | 
            +
              #endif
         | 
| 1630 1682 |  | 
| 1631 1683 | 
             
              rb_define_method(cBackend, "accept", Backend_accept, 2);
         | 
| 1632 1684 | 
             
              rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
         | 
| @@ -1654,6 +1706,7 @@ void Init_Backend(void) { | |
| 1654 1706 | 
             
              rb_define_method(cBackend, "wait_io", Backend_wait_io, 2);
         | 
| 1655 1707 | 
             
              rb_define_method(cBackend, "waitpid", Backend_waitpid, 1);
         | 
| 1656 1708 | 
             
              rb_define_method(cBackend, "write", Backend_write_m, -1);
         | 
| 1709 | 
            +
              rb_define_method(cBackend, "close", Backend_close, 1);
         | 
| 1657 1710 |  | 
| 1658 1711 | 
             
              SYM_libev = ID2SYM(rb_intern("libev"));
         | 
| 1659 1712 |  | 
    
        data/ext/polyphony/extconf.rb
    CHANGED
    
    | @@ -2,12 +2,14 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            require 'rubygems'
         | 
| 4 4 | 
             
            require 'mkmf'
         | 
| 5 | 
            +
            require 'rbconfig'
         | 
| 5 6 |  | 
| 6 7 | 
             
            dir_config 'polyphony_ext'
         | 
| 7 8 |  | 
| 8 9 | 
             
            KERNEL_INFO_RE = /Linux (\d)\.(\d+)(?:\.)?((?:\d+\.?)*)(?:\-)?([\w\-]+)?/
         | 
| 9 10 | 
             
            def get_config
         | 
| 10 11 | 
             
              config = { linux: !!(RUBY_PLATFORM =~ /linux/) }
         | 
| 12 | 
            +
              config[:windows] = !!(RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/)
         | 
| 11 13 | 
             
              return config if !config[:linux]
         | 
| 12 14 |  | 
| 13 15 | 
             
              kernel_info = `uname -sr`
         | 
| @@ -17,7 +19,8 @@ def get_config | |
| 17 19 | 
             
              version, major_revision, distribution = m[1].to_i, m[2].to_i, m[4]
         | 
| 18 20 |  | 
| 19 21 | 
             
              combined_version = version.to_i * 100 + major_revision.to_i
         | 
| 20 | 
            -
             | 
| 22 | 
            +
              
         | 
| 23 | 
            +
              config[:kernel_version]     = combined_version
         | 
| 21 24 | 
             
              config[:pidfd_open]         = combined_version > 503
         | 
| 22 25 | 
             
              config[:multishot_recv]     = combined_version >= 600
         | 
| 23 26 | 
             
              config[:multishot_recvmsg]  = combined_version >= 600
         | 
| @@ -31,7 +34,7 @@ def get_config | |
| 31 34 | 
             
            end
         | 
| 32 35 |  | 
| 33 36 | 
             
            config = get_config
         | 
| 34 | 
            -
            puts "Building Polyphony | 
| 37 | 
            +
            puts "Building Polyphony (\n#{config.map { |(k, v)| "  #{k}: #{v}\n"}.join})"
         | 
| 35 38 |  | 
| 36 39 | 
             
            require_relative 'zlib_conf'
         | 
| 37 40 |  | 
| @@ -71,6 +74,7 @@ if config[:io_uring] | |
| 71 74 | 
             
            else
         | 
| 72 75 | 
             
              $defs << "-DPOLYPHONY_BACKEND_LIBEV"
         | 
| 73 76 | 
             
              $defs << "-DPOLYPHONY_LINUX" if config[:linux]
         | 
| 77 | 
            +
              $defs << "-DPOLYPHONY_WINDOWS" if config[:windows]
         | 
| 74 78 |  | 
| 75 79 | 
             
              $defs << "-DEV_STANDALONE" # prevent libev from assuming "config.h" exists
         | 
| 76 80 |  | 
    
        data/ext/polyphony/pipe.c
    CHANGED
    
    | @@ -97,8 +97,8 @@ VALUE Pipe_close(VALUE self) { | |
| 97 97 | 
             
              if (pipe->w_closed)
         | 
| 98 98 | 
             
                rb_raise(rb_eRuntimeError, "Pipe is already closed for writing");
         | 
| 99 99 |  | 
| 100 | 
            +
              Backend_close(BACKEND(), INT2FIX(pipe->fds[1]));
         | 
| 100 101 | 
             
              pipe->w_closed = 1;
         | 
| 101 | 
            -
              close(pipe->fds[1]);
         | 
| 102 102 | 
             
              return self;
         | 
| 103 103 | 
             
            }
         | 
| 104 104 |  | 
    
        data/ext/polyphony/polyphony.c
    CHANGED
    
    | @@ -80,20 +80,6 @@ VALUE Polyphony_backend_accept_loop(VALUE self, VALUE server_socket, VALUE socke | |
| 80 80 | 
             
              return Backend_accept_loop(BACKEND(), server_socket, socket_class);
         | 
| 81 81 | 
             
            }
         | 
| 82 82 |  | 
| 83 | 
            -
            #ifdef HAVE_IO_URING_PREP_MULTISHOT_ACCEPT
         | 
| 84 | 
            -
            /* Starts a multishot accept operation on the given server socket. This API is
         | 
| 85 | 
            -
             * available only for the io_uring backend.
         | 
| 86 | 
            -
             *
         | 
| 87 | 
            -
             * @param server_socket [Socket] socket to accept on
         | 
| 88 | 
            -
             * @return [any] block return value
         | 
| 89 | 
            -
             */
         | 
| 90 | 
            -
             | 
| 91 | 
            -
            VALUE Polyphony_backend_multishot_accept(VALUE self, VALUE server_socket) {
         | 
| 92 | 
            -
              return Backend_multishot_accept(BACKEND(), server_socket);
         | 
| 93 | 
            -
            }
         | 
| 94 | 
            -
            #endif
         | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 83 | 
             
            /* Connects the given socket to the given address and port.
         | 
| 98 84 | 
             
             *
         | 
| 99 85 | 
             
             * @param io [Socket] socket to connect
         | 
| @@ -404,9 +390,26 @@ VALUE Polyphony_raw_buffer_size(VALUE self, VALUE buffer) { | |
| 404 390 | 
             
              return INT2FIX(buffer_spec->len);
         | 
| 405 391 | 
             
            }
         | 
| 406 392 |  | 
| 407 | 
            -
             | 
| 408 | 
            -
             | 
| 409 | 
            -
             | 
| 393 | 
            +
            /* Closes the given IO.
         | 
| 394 | 
            +
             *
         | 
| 395 | 
            +
             * @param io [IO, Polyphony::Pipe] IO instance
         | 
| 396 | 
            +
             * @return [IO, Polyphony::Pipe] given IO
         | 
| 397 | 
            +
             */
         | 
| 398 | 
            +
             | 
| 399 | 
            +
            VALUE Polyphony_backend_close(VALUE self, VALUE io) {
         | 
| 400 | 
            +
              return Backend_close(BACKEND(), io);
         | 
| 401 | 
            +
            }
         | 
| 402 | 
            +
             | 
| 403 | 
            +
            /* Ensures the given IO is in blocking/non-blocking mode.
         | 
| 404 | 
            +
             *
         | 
| 405 | 
            +
             * @param io [IO, Polyphony::Pipe] IO instance
         | 
| 406 | 
            +
             * @param blocking [boolean] true for blocking, false for non-blocking mode
         | 
| 407 | 
            +
             * @return [IO, Polyphony::Pipe] given IO
         | 
| 408 | 
            +
             */
         | 
| 409 | 
            +
             | 
| 410 | 
            +
            VALUE Polyphony_backend_verify_blocking_mode(VALUE self, VALUE io, VALUE blocking) {
         | 
| 411 | 
            +
              return Backend_verify_blocking_mode(BACKEND(), io, blocking);
         | 
| 412 | 
            +
            }
         | 
| 410 413 |  | 
| 411 414 | 
             
            void Init_Polyphony(void) {
         | 
| 412 415 | 
             
              mPolyphony = rb_define_module("Polyphony");
         | 
| @@ -416,12 +419,6 @@ void Init_Polyphony(void) { | |
| 416 419 | 
             
              rb_define_singleton_method(mPolyphony, "backend_accept_loop", Polyphony_backend_accept_loop, 2);
         | 
| 417 420 | 
             
              rb_define_singleton_method(mPolyphony, "backend_connect", Polyphony_backend_connect, 3);
         | 
| 418 421 | 
             
              rb_define_singleton_method(mPolyphony, "backend_feed_loop", Polyphony_backend_feed_loop, 3);
         | 
| 419 | 
            -
             | 
| 420 | 
            -
              #ifdef HAVE_IO_URING_PREP_MULTISHOT_ACCEPT
         | 
| 421 | 
            -
              rb_define_singleton_method(mPolyphony, "backend_multishot_accept", Polyphony_backend_multishot_accept, 1);
         | 
| 422 | 
            -
              #endif
         | 
| 423 | 
            -
             | 
| 424 | 
            -
             | 
| 425 422 | 
             
              rb_define_singleton_method(mPolyphony, "backend_read", Polyphony_backend_read, 5);
         | 
| 426 423 | 
             
              rb_define_singleton_method(mPolyphony, "backend_read_loop", Polyphony_backend_read_loop, 2);
         | 
| 427 424 | 
             
              rb_define_singleton_method(mPolyphony, "backend_recv", Polyphony_backend_recv, 4);
         | 
| @@ -448,8 +445,8 @@ void Init_Polyphony(void) { | |
| 448 445 | 
             
              rb_define_singleton_method(mPolyphony, "backend_wait_io", Polyphony_backend_wait_io, 2);
         | 
| 449 446 | 
             
              rb_define_singleton_method(mPolyphony, "backend_waitpid", Polyphony_backend_waitpid, 1);
         | 
| 450 447 | 
             
              rb_define_singleton_method(mPolyphony, "backend_write", Polyphony_backend_write, -1);
         | 
| 451 | 
            -
               | 
| 452 | 
            -
              rb_define_singleton_method(mPolyphony, "backend_verify_blocking_mode",  | 
| 448 | 
            +
              rb_define_singleton_method(mPolyphony, "backend_close", Polyphony_backend_close, 1);
         | 
| 449 | 
            +
              rb_define_singleton_method(mPolyphony, "backend_verify_blocking_mode", Polyphony_backend_verify_blocking_mode, 2);
         | 
| 453 450 |  | 
| 454 451 | 
             
              rb_define_singleton_method(mPolyphony, "__with_raw_buffer__", Polyphony_with_raw_buffer, 1);
         | 
| 455 452 | 
             
              rb_define_singleton_method(mPolyphony, "__raw_buffer_get__", Polyphony_raw_buffer_get, -1);
         | 
    
        data/ext/polyphony/polyphony.h
    CHANGED
    
    | @@ -101,11 +101,6 @@ VALUE Backend_accept(VALUE self, VALUE server_socket, VALUE socket_class); | |
| 101 101 | 
             
            VALUE Backend_accept_loop(VALUE self, VALUE server_socket, VALUE socket_class);
         | 
| 102 102 | 
             
            VALUE Backend_connect(VALUE self, VALUE io, VALUE addr, VALUE port);
         | 
| 103 103 | 
             
            VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method);
         | 
| 104 | 
            -
             | 
| 105 | 
            -
            #ifdef HAVE_IO_URING_PREP_MULTISHOT_ACCEPT
         | 
| 106 | 
            -
            VALUE Backend_multishot_accept(VALUE self, VALUE io);
         | 
| 107 | 
            -
            #endif
         | 
| 108 | 
            -
             | 
| 109 104 | 
             
            VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof, VALUE pos);
         | 
| 110 105 | 
             
            VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen);
         | 
| 111 106 | 
             
            VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos);
         | 
| @@ -133,7 +128,7 @@ VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write); | |
| 133 128 | 
             
            VALUE Backend_waitpid(VALUE self, VALUE pid);
         | 
| 134 129 | 
             
            VALUE Backend_write(VALUE self, VALUE io, VALUE str);
         | 
| 135 130 | 
             
            VALUE Backend_write_m(int argc, VALUE *argv, VALUE self);
         | 
| 136 | 
            -
             | 
| 131 | 
            +
            VALUE Backend_close(VALUE self, VALUE io);
         | 
| 137 132 |  | 
| 138 133 | 
             
            VALUE Backend_poll(VALUE self, VALUE blocking);
         | 
| 139 134 | 
             
            VALUE Backend_wait_event(VALUE self, VALUE raise_on_exception);
         | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            // source: https://stackoverflow.com/questions/57897314/fatal-error-when-compiling-include-sys-uio-h-on-project-windows
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            #ifndef SYS_UIO_H
         | 
| 4 | 
            +
            #define SYS_UIO_H
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            #include <inttypes.h>
         | 
| 7 | 
            +
            #include <unistd.h>
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            struct iovec
         | 
| 10 | 
            +
            {
         | 
| 11 | 
            +
                void    *iov_base;  /* Base address of a memory region for input or output */
         | 
| 12 | 
            +
                size_t   iov_len;   /* The size of the memory pointed to by iov_base */
         | 
| 13 | 
            +
            };
         | 
| 14 | 
            +
             | 
| 15 | 
            +
             ssize_t readv(int fildes, const struct iovec *iov, int iovcnt);
         | 
| 16 | 
            +
            ssize_t writev(int fildes, const struct iovec *iov, int iovcnt);
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            #endif /* SYS_UIO_H */
         | 
    
        data/lib/polyphony/core/debug.rb
    CHANGED
    
    | @@ -52,7 +52,7 @@ module Polyphony | |
| 52 52 |  | 
| 53 53 | 
             
                  # Converts an event (expressed as an array) to a hash.
         | 
| 54 54 | 
             
                  #
         | 
| 55 | 
            -
                  # @param  | 
| 55 | 
            +
                  # @param event [Array] event as emitted by the backend
         | 
| 56 56 | 
             
                  # @return [Hash] event hash
         | 
| 57 57 | 
             
                  def trace_event_info(event)
         | 
| 58 58 | 
             
                    {
         | 
| @@ -65,7 +65,7 @@ module Polyphony | |
| 65 65 |  | 
| 66 66 | 
             
                  # Returns an event hash for a `:block` event.
         | 
| 67 67 | 
             
                  #
         | 
| 68 | 
            -
                  # @param  | 
| 68 | 
            +
                  # @param event [Array] event array
         | 
| 69 69 | 
             
                  # @return [Hash] event hash
         | 
| 70 70 | 
             
                  def event_props_block(event)
         | 
| 71 71 | 
             
                    {
         | 
| @@ -76,7 +76,7 @@ module Polyphony | |
| 76 76 |  | 
| 77 77 | 
             
                  # Returns an event hash for a `:enter_poll` event.
         | 
| 78 78 | 
             
                  #
         | 
| 79 | 
            -
                  # @param  | 
| 79 | 
            +
                  # @param _event [Array] event array
         | 
| 80 80 | 
             
                  # @return [Hash] event hash
         | 
| 81 81 | 
             
                  def event_props_enter_poll(_event)
         | 
| 82 82 | 
             
                    {}
         | 
| @@ -84,7 +84,7 @@ module Polyphony | |
| 84 84 |  | 
| 85 85 | 
             
                  # Returns an event hash for a `:leave_poll` event.
         | 
| 86 86 | 
             
                  #
         | 
| 87 | 
            -
                  # @param  | 
| 87 | 
            +
                  # @param _event [Array] event array
         | 
| 88 88 | 
             
                  # @return [Hash] event hash
         | 
| 89 89 | 
             
                  def event_props_leave_poll(_event)
         | 
| 90 90 | 
             
                    {}
         | 
| @@ -92,7 +92,7 @@ module Polyphony | |
| 92 92 |  | 
| 93 93 | 
             
                  # Returns an event hash for a `:schedule` event.
         | 
| 94 94 | 
             
                  #
         | 
| 95 | 
            -
                  # @param  | 
| 95 | 
            +
                  # @param event [Array] event array
         | 
| 96 96 | 
             
                  # @return [Hash] event hash
         | 
| 97 97 | 
             
                  def event_props_schedule(event)
         | 
| 98 98 | 
             
                    {
         | 
| @@ -105,7 +105,7 @@ module Polyphony | |
| 105 105 |  | 
| 106 106 | 
             
                  # Returns an event hash for a `:spin` event.
         | 
| 107 107 | 
             
                  #
         | 
| 108 | 
            -
                  # @param  | 
| 108 | 
            +
                  # @param event [Array] event array
         | 
| 109 109 | 
             
                  # @return [Hash] event hash
         | 
| 110 110 | 
             
                  def event_props_spin(event)
         | 
| 111 111 | 
             
                    {
         | 
| @@ -117,7 +117,7 @@ module Polyphony | |
| 117 117 |  | 
| 118 118 | 
             
                  # Returns an event hash for a `:terminate` event.
         | 
| 119 119 | 
             
                  #
         | 
| 120 | 
            -
                  # @param  | 
| 120 | 
            +
                  # @param event [Array] event array
         | 
| 121 121 | 
             
                  # @return [Hash] event hash
         | 
| 122 122 | 
             
                  def event_props_terminate(event)
         | 
| 123 123 | 
             
                    {
         | 
| @@ -128,7 +128,7 @@ module Polyphony | |
| 128 128 |  | 
| 129 129 | 
             
                  # Returns an event hash for a `:unblock` event.
         | 
| 130 130 | 
             
                  #
         | 
| 131 | 
            -
                  # @param  | 
| 131 | 
            +
                  # @param event [Array] event array
         | 
| 132 132 | 
             
                  # @return [Hash] event hash
         | 
| 133 133 | 
             
                  def event_props_unblock(event)
         | 
| 134 134 | 
             
                    {
         | 
| @@ -197,7 +197,7 @@ class ::IO | |
| 197 197 | 
             
              alias_method :orig_read, :read
         | 
| 198 198 |  | 
| 199 199 | 
             
              # @!visibility private
         | 
| 200 | 
            -
              def read(len = nil, buf = nil, buffer_pos | 
| 200 | 
            +
              def read(len = nil, buf = nil, buffer_pos = 0)
         | 
| 201 201 | 
             
                return '' if len == 0
         | 
| 202 202 | 
             
                return Polyphony.backend_read(self, buf, len, true, buffer_pos) if buf
         | 
| 203 203 |  | 
| @@ -214,7 +214,7 @@ class ::IO | |
| 214 214 | 
             
              alias_method :orig_readpartial, :read
         | 
| 215 215 |  | 
| 216 216 | 
             
              # @!visibility private
         | 
| 217 | 
            -
              def readpartial(len, str = +'', buffer_pos | 
| 217 | 
            +
              def readpartial(len, str = +'', buffer_pos = 0, raise_on_eof = true)
         | 
| 218 218 | 
             
                result = Polyphony.backend_read(self, str, len, false, buffer_pos)
         | 
| 219 219 | 
             
                raise EOFError if !result && raise_on_eof
         | 
| 220 220 |  | 
| @@ -255,7 +255,7 @@ class ::IO | |
| 255 255 | 
             
                  idx = @read_buffer.index(sep)
         | 
| 256 256 | 
             
                  return @read_buffer.slice!(0, idx + sep_size) if idx
         | 
| 257 257 |  | 
| 258 | 
            -
                  result = readpartial(8192, @read_buffer,  | 
| 258 | 
            +
                  result = readpartial(8192, @read_buffer, -1)
         | 
| 259 259 | 
             
                  return nil unless result
         | 
| 260 260 | 
             
                end
         | 
| 261 261 | 
             
              rescue EOFError
         | 
| @@ -280,7 +280,7 @@ class ::IO | |
| 280 280 | 
             
                    yield line
         | 
| 281 281 | 
             
                  end
         | 
| 282 282 |  | 
| 283 | 
            -
                  result = readpartial(8192, @read_buffer,  | 
| 283 | 
            +
                  result = readpartial(8192, @read_buffer, -1)
         | 
| 284 284 | 
             
                  return self if !result
         | 
| 285 285 | 
             
                end
         | 
| 286 286 | 
             
              rescue EOFError
         | 
| @@ -427,6 +427,19 @@ class ::IO | |
| 427 427 | 
             
                Polyphony.backend_splice(src, self, maxlen)
         | 
| 428 428 | 
             
              end
         | 
| 429 429 |  | 
| 430 | 
            +
              # @!visibility private
         | 
| 431 | 
            +
              alias_method :orig_close, :close
         | 
| 432 | 
            +
             | 
| 433 | 
            +
              # Closes the IO instance
         | 
| 434 | 
            +
              #
         | 
| 435 | 
            +
              # @return [void]
         | 
| 436 | 
            +
              def close
         | 
| 437 | 
            +
                return if closed?
         | 
| 438 | 
            +
             | 
| 439 | 
            +
                Polyphony.backend_close(self)
         | 
| 440 | 
            +
                nil
         | 
| 441 | 
            +
              end
         | 
| 442 | 
            +
             | 
| 430 443 | 
             
              if RUBY_PLATFORM =~ /linux/
         | 
| 431 444 | 
             
                # Tees data from the given IO.
         | 
| 432 445 | 
             
                #
         | 
| @@ -5,6 +5,22 @@ require 'open3' | |
| 5 5 | 
             
            module Polyphony
         | 
| 6 6 | 
             
              # Intercepts calls to #trap
         | 
| 7 7 | 
             
              module TrapInterceptor
         | 
| 8 | 
            +
                # Installs a signal handler. If a block is given (or the command parameter
         | 
| 9 | 
            +
                # is a Proc or a callable), it is executed inside an out-of-band,
         | 
| 10 | 
            +
                # prioritized fiber.
         | 
| 11 | 
            +
                #
         | 
| 12 | 
            +
                # If the command is the string “IGNORE” or “SIG_IGN”, the signal will be
         | 
| 13 | 
            +
                # ignored. If the command is “DEFAULT” or “SIG_DFL”, the Ruby’s default
         | 
| 14 | 
            +
                # handler will be invoked. If the command is “EXIT”, the script will be
         | 
| 15 | 
            +
                # terminated by the signal. If the command is “SYSTEM_DEFAULT”, the
         | 
| 16 | 
            +
                # operating system’s default handler will be invoked. Otherwise, the given
         | 
| 17 | 
            +
                # command or block will be run. The special signal name “EXIT” or signal
         | 
| 18 | 
            +
                # number zero will be invoked just prior to program termination.
         | 
| 19 | 
            +
                #
         | 
| 20 | 
            +
                # trap returns the previous handler for the given signal.
         | 
| 21 | 
            +
                #
         | 
| 22 | 
            +
                # @param sig [String, Symbol, Integer] signal name or number
         | 
| 23 | 
            +
                # @param command [String, Proc] command to perform
         | 
| 8 24 | 
             
                def trap(sig, command = nil, &block)
         | 
| 9 25 | 
             
                  return super(sig, command) if command.is_a? String
         | 
| 10 26 |  | 
| @@ -90,7 +90,7 @@ class ::OpenSSL::SSL::SSLSocket | |
| 90 90 |  | 
| 91 91 | 
             
              # Reads from the socket. If `maxlen` is given, reads up to `maxlen` bytes from
         | 
| 92 92 | 
             
              # the socket, otherwise reads to `EOF`. If `buf` is given, it is used as the
         | 
| 93 | 
            -
              # buffer to read into, otherwise a new string is allocated. If ` | 
| 93 | 
            +
              # buffer to read into, otherwise a new string is allocated. If `buffer_pos` is
         | 
| 94 94 | 
             
              # given, reads into the given offset (in bytes) in the given buffer. If the
         | 
| 95 95 | 
             
              # given buffer offset is negative, it is calculated from the current end of
         | 
| 96 96 | 
             
              # the buffer (`-1` means the read data will be appended to the end of the
         | 
| @@ -101,21 +101,21 @@ class ::OpenSSL::SSL::SSLSocket | |
| 101 101 | 
             
              #
         | 
| 102 102 | 
             
              # @param maxlen [Integer, nil] maximum bytes to read from socket
         | 
| 103 103 | 
             
              # @param buf [String, nil] buffer to read into
         | 
| 104 | 
            -
              # @param  | 
| 104 | 
            +
              # @param buffer_pos [Number] buffer position to read into
         | 
| 105 105 | 
             
              # @return [String] buffer used for reading
         | 
| 106 | 
            -
              def read(maxlen = nil, buf = nil, buffer_pos | 
| 107 | 
            -
                return readpartial(maxlen, buf, buffer_pos | 
| 106 | 
            +
              def read(maxlen = nil, buf = nil, buffer_pos = 0)
         | 
| 107 | 
            +
                return readpartial(maxlen, buf, buffer_pos) if buf
         | 
| 108 108 |  | 
| 109 109 | 
             
                buf = +''
         | 
| 110 110 | 
             
                return readpartial(maxlen, buf) if maxlen
         | 
| 111 111 |  | 
| 112 | 
            -
                readpartial(4096, buf,  | 
| 112 | 
            +
                readpartial(4096, buf, -1) while true
         | 
| 113 113 | 
             
              rescue EOFError
         | 
| 114 114 | 
             
                buf
         | 
| 115 115 | 
             
              end
         | 
| 116 116 |  | 
| 117 117 | 
             
              # Reads up to `maxlen` from the socket. If `buf` is given, it is used as the
         | 
| 118 | 
            -
              # buffer to read into, otherwise a new string is allocated. If ` | 
| 118 | 
            +
              # buffer to read into, otherwise a new string is allocated. If `buffer_pos` is
         | 
| 119 119 | 
             
              # given, reads into the given offset (in bytes) in the given buffer. If the
         | 
| 120 120 | 
             
              # given buffer offset is negative, it is calculated from the current end of
         | 
| 121 121 | 
             
              # the buffer (`-1` means the read data will be appended to the end of the
         | 
| @@ -127,16 +127,16 @@ class ::OpenSSL::SSL::SSLSocket | |
| 127 127 | 
             
              #
         | 
| 128 128 | 
             
              # @param maxlen [Integer, nil] maximum bytes to read from socket
         | 
| 129 129 | 
             
              # @param buf [String, nil] buffer to read into
         | 
| 130 | 
            -
              # @param  | 
| 130 | 
            +
              # @param buffer_pos [Number] buffer position to read into
         | 
| 131 131 | 
             
              # @param raise_on_eof [bool] whether to raise an exception on `EOF`
         | 
| 132 132 | 
             
              # @return [String, nil] buffer used for reading or nil on `EOF`
         | 
| 133 | 
            -
              def readpartial(maxlen, buf = +'', buffer_pos | 
| 134 | 
            -
                if  | 
| 133 | 
            +
              def readpartial(maxlen, buf = +'', buffer_pos = 0, raise_on_eof = true)
         | 
| 134 | 
            +
                if buffer_pos != 0
         | 
| 135 135 | 
             
                  if (result = sysread(maxlen, +''))
         | 
| 136 | 
            -
                    if  | 
| 136 | 
            +
                    if buffer_pos == -1
         | 
| 137 137 | 
             
                      result = buf + result
         | 
| 138 138 | 
             
                    else
         | 
| 139 | 
            -
                      result = buf[0... | 
| 139 | 
            +
                      result = buf[0...buffer_pos] + result
         | 
| 140 140 | 
             
                    end
         | 
| 141 141 | 
             
                  end
         | 
| 142 142 | 
             
                else
         | 
| @@ -41,9 +41,9 @@ class Polyphony::Pipe | |
| 41 41 | 
             
              #
         | 
| 42 42 | 
             
              # @param len [Integer, nil] maximum bytes to read
         | 
| 43 43 | 
             
              # @param buf [String, nil] buffer to read into
         | 
| 44 | 
            -
              # @param  | 
| 44 | 
            +
              # @param buffer_pos [Integer] buffer position to read into
         | 
| 45 45 | 
             
              # @return [String] read data
         | 
| 46 | 
            -
              def read(len = nil, buf = nil, buffer_pos | 
| 46 | 
            +
              def read(len = nil, buf = nil, buffer_pos = 0)
         | 
| 47 47 | 
             
                return Polyphony.backend_read(self, buf, len, true, buffer_pos) if buf
         | 
| 48 48 |  | 
| 49 49 | 
             
                @read_buffer ||= +''
         | 
| @@ -59,10 +59,10 @@ class Polyphony::Pipe | |
| 59 59 | 
             
              #
         | 
| 60 60 | 
             
              # @param len [Integer, nil] maximum bytes to read
         | 
| 61 61 | 
             
              # @param buf [String, nil] buffer to read into
         | 
| 62 | 
            -
              # @param  | 
| 62 | 
            +
              # @param buffer_pos [Integer] buffer position to read into
         | 
| 63 63 | 
             
              # @param raise_on_eof [boolean] whether to raise an error if EOF is detected
         | 
| 64 64 | 
             
              # @return [String] read data
         | 
| 65 | 
            -
              def readpartial(len, buf = +'', buffer_pos | 
| 65 | 
            +
              def readpartial(len, buf = +'', buffer_pos = 0, raise_on_eof = true)
         | 
| 66 66 | 
             
                result = Polyphony.backend_read(self, buf, len, false, buffer_pos)
         | 
| 67 67 | 
             
                raise EOFError if !result && raise_on_eof
         | 
| 68 68 |  | 
| @@ -104,7 +104,7 @@ class Polyphony::Pipe | |
| 104 104 | 
             
                  idx = @read_buffer.index(sep)
         | 
| 105 105 | 
             
                  return @read_buffer.slice!(0, idx + sep_size) if idx
         | 
| 106 106 |  | 
| 107 | 
            -
                  result = readpartial(8192, @read_buffer,  | 
| 107 | 
            +
                  result = readpartial(8192, @read_buffer, -1)
         | 
| 108 108 | 
             
                  return nil unless result
         | 
| 109 109 | 
             
                end
         | 
| 110 110 | 
             
              rescue EOFError
         |