polyphony 0.19 → 0.20
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/.gitignore +1 -1
 - data/.rubocop.yml +87 -1
 - data/CHANGELOG.md +35 -0
 - data/Gemfile.lock +17 -6
 - data/README.md +200 -139
 - data/Rakefile +4 -4
 - data/TODO.md +35 -7
 - data/bin/poly +11 -0
 - data/docs/getting-started/getting-started.md +1 -1
 - data/docs/summary.md +3 -0
 - data/docs/technical-overview/exception-handling.md +94 -0
 - data/docs/technical-overview/fiber-scheduling.md +99 -0
 - data/examples/core/cancel.rb +8 -4
 - data/examples/core/channel_echo.rb +18 -17
 - data/examples/core/defer.rb +12 -0
 - data/examples/core/enumerator.rb +4 -4
 - data/examples/core/fiber_error.rb +9 -0
 - data/examples/core/fiber_error_with_backtrace.rb +73 -0
 - data/examples/core/fork.rb +6 -6
 - data/examples/core/genserver.rb +16 -8
 - data/examples/core/lock.rb +3 -3
 - data/examples/core/move_on.rb +4 -3
 - data/examples/core/move_on_twice.rb +5 -5
 - data/examples/core/move_on_with_ensure.rb +8 -11
 - data/examples/core/move_on_with_value.rb +14 -0
 - data/examples/core/{multiple_spawn.rb → multiple_spin.rb} +5 -5
 - data/examples/core/nested_cancel.rb +5 -5
 - data/examples/core/{nested_multiple_spawn.rb → nested_multiple_spin.rb} +6 -6
 - data/examples/core/nested_spin.rb +17 -0
 - data/examples/core/pingpong.rb +21 -0
 - data/examples/core/pulse.rb +4 -5
 - data/examples/core/resource.rb +6 -4
 - data/examples/core/resource_cancel.rb +6 -9
 - data/examples/core/resource_delegate.rb +3 -3
 - data/examples/core/sleep.rb +3 -3
 - data/examples/core/sleep_spin.rb +19 -0
 - data/examples/core/snooze.rb +32 -0
 - data/examples/core/spin.rb +14 -0
 - data/examples/core/{spawn_cancel.rb → spin_cancel.rb} +6 -7
 - data/examples/core/spin_error.rb +17 -0
 - data/examples/core/spin_error_backtrace.rb +30 -0
 - data/examples/core/spin_uncaught_error.rb +15 -0
 - data/examples/core/supervisor.rb +8 -8
 - data/examples/core/supervisor_with_cancel_scope.rb +7 -7
 - data/examples/core/supervisor_with_error.rb +8 -8
 - data/examples/core/supervisor_with_manual_move_on.rb +6 -7
 - data/examples/core/suspend.rb +13 -0
 - data/examples/core/thread.rb +1 -1
 - data/examples/core/thread_cancel.rb +9 -11
 - data/examples/core/thread_pool.rb +18 -14
 - data/examples/core/throttle.rb +7 -7
 - data/examples/core/timeout.rb +3 -3
 - data/examples/fs/read.rb +7 -9
 - data/examples/http/config.ru +7 -3
 - data/examples/http/cuba.ru +22 -0
 - data/examples/http/happy_eyeballs.rb +6 -4
 - data/examples/http/http_client.rb +1 -1
 - data/examples/http/http_get.rb +1 -1
 - data/examples/http/http_parse_experiment.rb +21 -16
 - data/examples/http/http_proxy.rb +28 -26
 - data/examples/http/http_server.rb +10 -10
 - data/examples/http/http_server_forked.rb +6 -5
 - data/examples/http/http_server_throttled.rb +3 -3
 - data/examples/http/http_ws_server.rb +11 -11
 - data/examples/http/https_raw_client.rb +1 -1
 - data/examples/http/https_server.rb +8 -8
 - data/examples/http/https_wss_server.rb +13 -11
 - data/examples/http/rack_server.rb +2 -2
 - data/examples/http/rack_server_https.rb +4 -4
 - data/examples/http/rack_server_https_forked.rb +5 -5
 - data/examples/http/websocket_secure_server.rb +6 -6
 - data/examples/http/websocket_server.rb +5 -5
 - data/examples/interfaces/pg_client.rb +4 -4
 - data/examples/interfaces/pg_pool.rb +13 -6
 - data/examples/interfaces/pg_transaction.rb +5 -4
 - data/examples/interfaces/redis_channels.rb +15 -11
 - data/examples/interfaces/redis_client.rb +2 -2
 - data/examples/interfaces/redis_pubsub.rb +2 -1
 - data/examples/interfaces/redis_pubsub_perf.rb +13 -9
 - data/examples/io/backticks.rb +11 -0
 - data/examples/io/cat.rb +4 -5
 - data/examples/io/echo_client.rb +9 -4
 - data/examples/io/echo_client_from_stdin.rb +20 -0
 - data/examples/io/echo_pipe.rb +7 -8
 - data/examples/io/echo_server.rb +8 -6
 - data/examples/io/echo_server_with_timeout.rb +13 -10
 - data/examples/io/echo_stdin.rb +3 -3
 - data/examples/io/httparty.rb +2 -2
 - data/examples/io/httparty_multi.rb +8 -4
 - data/examples/io/httparty_threaded.rb +6 -2
 - data/examples/io/io_read.rb +2 -2
 - data/examples/io/irb.rb +16 -4
 - data/examples/io/net-http.rb +3 -3
 - data/examples/io/open.rb +17 -0
 - data/examples/io/system.rb +3 -3
 - data/examples/io/tcpserver.rb +15 -0
 - data/examples/io/tcpsocket.rb +6 -5
 - data/examples/performance/multi_snooze.rb +29 -0
 - data/examples/performance/{perf_snooze.rb → snooze.rb} +7 -5
 - data/examples/performance/snooze_raw.rb +39 -0
 - data/ext/gyro/async.c +165 -0
 - data/ext/gyro/child.c +167 -0
 - data/ext/{ev → gyro}/extconf.rb +4 -3
 - data/ext/gyro/gyro.c +316 -0
 - data/ext/{ev/ev.h → gyro/gyro.h} +12 -7
 - data/ext/gyro/gyro_ext.c +23 -0
 - data/ext/{ev → gyro}/io.c +65 -57
 - data/ext/{ev → gyro}/libev.h +0 -0
 - data/ext/gyro/signal.c +117 -0
 - data/ext/{ev → gyro}/socket.c +61 -6
 - data/ext/gyro/timer.c +199 -0
 - data/ext/libev/Changes +35 -0
 - data/ext/libev/README +2 -1
 - data/ext/libev/ev.c +213 -151
 - data/ext/libev/ev.h +95 -88
 - data/ext/libev/ev_epoll.c +26 -15
 - data/ext/libev/ev_kqueue.c +11 -5
 - data/ext/libev/ev_linuxaio.c +642 -0
 - data/ext/libev/ev_poll.c +13 -8
 - data/ext/libev/ev_port.c +5 -2
 - data/ext/libev/ev_vars.h +14 -3
 - data/ext/libev/ev_wrap.h +16 -0
 - data/lib/ev_ext.bundle +0 -0
 - data/lib/polyphony.rb +46 -50
 - data/lib/polyphony/auto_run.rb +12 -0
 - data/lib/polyphony/core/cancel_scope.rb +11 -7
 - data/lib/polyphony/core/channel.rb +16 -9
 - data/lib/polyphony/core/coprocess.rb +101 -51
 - data/lib/polyphony/core/exceptions.rb +14 -12
 - data/lib/polyphony/core/resource_pool.rb +21 -8
 - data/lib/polyphony/core/supervisor.rb +10 -5
 - data/lib/polyphony/core/sync.rb +7 -6
 - data/lib/polyphony/core/thread.rb +4 -4
 - data/lib/polyphony/core/thread_pool.rb +4 -4
 - data/lib/polyphony/core/throttler.rb +6 -4
 - data/lib/polyphony/extensions/core.rb +253 -0
 - data/lib/polyphony/extensions/io.rb +28 -16
 - data/lib/polyphony/extensions/openssl.rb +2 -1
 - data/lib/polyphony/extensions/socket.rb +47 -52
 - data/lib/polyphony/http.rb +4 -3
 - data/lib/polyphony/http/agent.rb +68 -57
 - data/lib/polyphony/http/server.rb +5 -5
 - data/lib/polyphony/http/server/http1.rb +268 -0
 - data/lib/polyphony/http/server/http2.rb +62 -0
 - data/lib/polyphony/http/server/http2_stream.rb +104 -0
 - data/lib/polyphony/http/server/rack.rb +64 -0
 - data/lib/polyphony/http/server/request.rb +119 -0
 - data/lib/polyphony/net.rb +26 -15
 - data/lib/polyphony/postgres.rb +17 -13
 - data/lib/polyphony/redis.rb +16 -15
 - data/lib/polyphony/version.rb +1 -1
 - data/lib/polyphony/websocket.rb +11 -4
 - data/polyphony.gemspec +13 -9
 - data/test/eg.rb +27 -0
 - data/test/helper.rb +25 -0
 - data/test/run.rb +5 -0
 - data/test/test_async.rb +33 -0
 - data/test/test_coprocess.rb +239 -77
 - data/test/test_core.rb +95 -61
 - data/test/test_gyro.rb +148 -0
 - data/test/test_http_server.rb +313 -0
 - data/test/test_io.rb +79 -27
 - data/test/test_kernel.rb +22 -12
 - data/test/test_signal.rb +36 -0
 - data/test/test_timer.rb +24 -0
 - metadata +89 -33
 - data/examples/core/nested_async.rb +0 -17
 - data/examples/core/next_tick.rb +0 -12
 - data/examples/core/sleep_spawn.rb +0 -19
 - data/examples/core/spawn.rb +0 -14
 - data/examples/core/spawn_error.rb +0 -28
 - data/examples/performance/perf_multi_snooze.rb +0 -21
 - data/ext/ev/async.c +0 -168
 - data/ext/ev/child.c +0 -169
 - data/ext/ev/ev_ext.c +0 -23
 - data/ext/ev/ev_module.c +0 -242
 - data/ext/ev/signal.c +0 -119
 - data/ext/ev/timer.c +0 -197
 - data/lib/polyphony/core/fiber_pool.rb +0 -98
 - data/lib/polyphony/extensions/kernel.rb +0 -169
 - data/lib/polyphony/http/http1_adapter.rb +0 -254
 - data/lib/polyphony/http/http2_adapter.rb +0 -157
 - data/lib/polyphony/http/rack.rb +0 -25
 - data/lib/polyphony/http/request.rb +0 -66
 - data/test/test_ev.rb +0 -110
 
    
        data/ext/libev/ev_poll.c
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            /*
         
     | 
| 
       2 
2 
     | 
    
         
             
             * libev poll fd activity backend
         
     | 
| 
       3 
3 
     | 
    
         
             
             *
         
     | 
| 
       4 
     | 
    
         
            -
             * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
         
     | 
| 
      
 4 
     | 
    
         
            +
             * Copyright (c) 2007,2008,2009,2010,2011,2016,2019 Marc Alexander Lehmann <libev@schmorp.de>
         
     | 
| 
       5 
5 
     | 
    
         
             
             * All rights reserved.
         
     | 
| 
       6 
6 
     | 
    
         
             
             *
         
     | 
| 
       7 
7 
     | 
    
         
             
             * Redistribution and use in source and binary forms, with or without modifica-
         
     | 
| 
         @@ -41,10 +41,12 @@ 
     | 
|
| 
       41 
41 
     | 
    
         | 
| 
       42 
42 
     | 
    
         
             
            inline_size
         
     | 
| 
       43 
43 
     | 
    
         
             
            void
         
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
      
 44 
     | 
    
         
            +
            array_needsize_pollidx (int *base, int offset, int count)
         
     | 
| 
       45 
45 
     | 
    
         
             
            {
         
     | 
| 
       46 
     | 
    
         
            -
              /*  
     | 
| 
       47 
     | 
    
         
            -
               * to  
     | 
| 
      
 46 
     | 
    
         
            +
              /* using memset (.., -1, ...) is tempting, we we try
         
     | 
| 
      
 47 
     | 
    
         
            +
               * to be ultraportable
         
     | 
| 
      
 48 
     | 
    
         
            +
               */
         
     | 
| 
      
 49 
     | 
    
         
            +
              base += offset;
         
     | 
| 
       48 
50 
     | 
    
         
             
              while (count--)
         
     | 
| 
       49 
51 
     | 
    
         
             
                *base++ = -1;
         
     | 
| 
       50 
52 
     | 
    
         
             
            }
         
     | 
| 
         @@ -57,14 +59,14 @@ poll_modify (EV_P_ int fd, int oev, int nev) 
     | 
|
| 
       57 
59 
     | 
    
         
             
              if (oev == nev)
         
     | 
| 
       58 
60 
     | 
    
         
             
                return;
         
     | 
| 
       59 
61 
     | 
    
         | 
| 
       60 
     | 
    
         
            -
              array_needsize (int, pollidxs, pollidxmax, fd + 1,  
     | 
| 
      
 62 
     | 
    
         
            +
              array_needsize (int, pollidxs, pollidxmax, fd + 1, array_needsize_pollidx);
         
     | 
| 
       61 
63 
     | 
    
         | 
| 
       62 
64 
     | 
    
         
             
              idx = pollidxs [fd];
         
     | 
| 
       63 
65 
     | 
    
         | 
| 
       64 
66 
     | 
    
         
             
              if (idx < 0) /* need to allocate a new pollfd */
         
     | 
| 
       65 
67 
     | 
    
         
             
                {
         
     | 
| 
       66 
68 
     | 
    
         
             
                  pollidxs [fd] = idx = pollcnt++;
         
     | 
| 
       67 
     | 
    
         
            -
                  array_needsize (struct pollfd, polls, pollmax, pollcnt,  
     | 
| 
      
 69 
     | 
    
         
            +
                  array_needsize (struct pollfd, polls, pollmax, pollcnt, array_needsize_noinit);
         
     | 
| 
       68 
70 
     | 
    
         
             
                  polls [idx].fd = fd;
         
     | 
| 
       69 
71 
     | 
    
         
             
                }
         
     | 
| 
       70 
72 
     | 
    
         | 
| 
         @@ -108,14 +110,17 @@ poll_poll (EV_P_ ev_tstamp timeout) 
     | 
|
| 
       108 
110 
     | 
    
         
             
              else
         
     | 
| 
       109 
111 
     | 
    
         
             
                for (p = polls; res; ++p)
         
     | 
| 
       110 
112 
     | 
    
         
             
                  {
         
     | 
| 
       111 
     | 
    
         
            -
                    assert (("libev: poll 
     | 
| 
      
 113 
     | 
    
         
            +
                    assert (("libev: poll returned illegal result, broken BSD kernel?", p < polls + pollcnt));
         
     | 
| 
       112 
114 
     | 
    
         | 
| 
       113 
115 
     | 
    
         
             
                    if (expect_false (p->revents)) /* this expect is debatable */
         
     | 
| 
       114 
116 
     | 
    
         
             
                      {
         
     | 
| 
       115 
117 
     | 
    
         
             
                        --res;
         
     | 
| 
       116 
118 
     | 
    
         | 
| 
       117 
119 
     | 
    
         
             
                        if (expect_false (p->revents & POLLNVAL))
         
     | 
| 
       118 
     | 
    
         
            -
                           
     | 
| 
      
 120 
     | 
    
         
            +
                          {
         
     | 
| 
      
 121 
     | 
    
         
            +
                            assert (("libev: poll found invalid fd in poll set", 0));
         
     | 
| 
      
 122 
     | 
    
         
            +
                            fd_kill (EV_A_ p->fd);
         
     | 
| 
      
 123 
     | 
    
         
            +
                          }
         
     | 
| 
       119 
124 
     | 
    
         
             
                        else
         
     | 
| 
       120 
125 
     | 
    
         
             
                          fd_event (
         
     | 
| 
       121 
126 
     | 
    
         
             
                            EV_A_
         
     | 
    
        data/ext/libev/ev_port.c
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            /*
         
     | 
| 
       2 
2 
     | 
    
         
             
             * libev solaris event port backend
         
     | 
| 
       3 
3 
     | 
    
         
             
             *
         
     | 
| 
       4 
     | 
    
         
            -
             * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
         
     | 
| 
      
 4 
     | 
    
         
            +
             * Copyright (c) 2007,2008,2009,2010,2011,2019 Marc Alexander Lehmann <libev@schmorp.de>
         
     | 
| 
       5 
5 
     | 
    
         
             
             * All rights reserved.
         
     | 
| 
       6 
6 
     | 
    
         
             
             *
         
     | 
| 
       7 
7 
     | 
    
         
             
             * Redistribution and use in source and binary forms, with or without modifica-
         
     | 
| 
         @@ -69,7 +69,10 @@ port_associate_and_check (EV_P_ int fd, int ev) 
     | 
|
| 
       69 
69 
     | 
    
         
             
              )
         
     | 
| 
       70 
70 
     | 
    
         
             
                {
         
     | 
| 
       71 
71 
     | 
    
         
             
                  if (errno == EBADFD)
         
     | 
| 
       72 
     | 
    
         
            -
                     
     | 
| 
      
 72 
     | 
    
         
            +
                    {
         
     | 
| 
      
 73 
     | 
    
         
            +
                      assert (("libev: port_associate found invalid fd", errno != EBADFD));
         
     | 
| 
      
 74 
     | 
    
         
            +
                      fd_kill (EV_A_ fd);
         
     | 
| 
      
 75 
     | 
    
         
            +
                    }
         
     | 
| 
       73 
76 
     | 
    
         
             
                  else
         
     | 
| 
       74 
77 
     | 
    
         
             
                    ev_syserr ("(libev) port_associate");
         
     | 
| 
       75 
78 
     | 
    
         
             
                }
         
     | 
    
        data/ext/libev/ev_vars.h
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            /*
         
     | 
| 
       2 
2 
     | 
    
         
             
             * loop member variable declarations
         
     | 
| 
       3 
3 
     | 
    
         
             
             *
         
     | 
| 
       4 
     | 
    
         
            -
             * Copyright (c) 2007,2008,2009,2010,2011,2012,2013 Marc Alexander Lehmann <libev@schmorp.de>
         
     | 
| 
      
 4 
     | 
    
         
            +
             * Copyright (c) 2007,2008,2009,2010,2011,2012,2013,2019 Marc Alexander Lehmann <libev@schmorp.de>
         
     | 
| 
       5 
5 
     | 
    
         
             
             * All rights reserved.
         
     | 
| 
       6 
6 
     | 
    
         
             
             *
         
     | 
| 
       7 
7 
     | 
    
         
             
             * Redistribution and use in source and binary forms, with or without modifica-
         
     | 
| 
         @@ -107,6 +107,17 @@ VARx(int, epoll_epermcnt) 
     | 
|
| 
       107 
107 
     | 
    
         
             
            VARx(int, epoll_epermmax)
         
     | 
| 
       108 
108 
     | 
    
         
             
            #endif
         
     | 
| 
       109 
109 
     | 
    
         | 
| 
      
 110 
     | 
    
         
            +
            #if EV_USE_LINUXAIO || EV_GENWRAP
         
     | 
| 
      
 111 
     | 
    
         
            +
            VARx(aio_context_t, linuxaio_ctx)
         
     | 
| 
      
 112 
     | 
    
         
            +
            VARx(int, linuxaio_iteration)
         
     | 
| 
      
 113 
     | 
    
         
            +
            VARx(struct aniocb **, linuxaio_iocbps)
         
     | 
| 
      
 114 
     | 
    
         
            +
            VARx(int, linuxaio_iocbpmax)
         
     | 
| 
      
 115 
     | 
    
         
            +
            VARx(struct iocb **, linuxaio_submits)
         
     | 
| 
      
 116 
     | 
    
         
            +
            VARx(int, linuxaio_submitcnt)
         
     | 
| 
      
 117 
     | 
    
         
            +
            VARx(int, linuxaio_submitmax)
         
     | 
| 
      
 118 
     | 
    
         
            +
            VARx(ev_io, linuxaio_epoll_w)
         
     | 
| 
      
 119 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
       110 
121 
     | 
    
         
             
            #if EV_USE_KQUEUE || EV_GENWRAP
         
     | 
| 
       111 
122 
     | 
    
         
             
            VARx(pid_t, kqueue_fd_pid)
         
     | 
| 
       112 
123 
     | 
    
         
             
            VARx(struct kevent *, kqueue_changes)
         
     | 
| 
         @@ -195,8 +206,8 @@ VARx(unsigned int, loop_depth) /* #ev_run enters - #ev_run leaves */ 
     | 
|
| 
       195 
206 
     | 
    
         | 
| 
       196 
207 
     | 
    
         
             
            VARx(void *, userdata)
         
     | 
| 
       197 
208 
     | 
    
         
             
            /* C++ doesn't support the ev_loop_callback typedef here. stinks. */
         
     | 
| 
       198 
     | 
    
         
            -
            VAR (release_cb, void (*release_cb)(EV_P)  
     | 
| 
       199 
     | 
    
         
            -
            VAR (acquire_cb, void (*acquire_cb)(EV_P)  
     | 
| 
      
 209 
     | 
    
         
            +
            VAR (release_cb, void (*release_cb)(EV_P) EV_NOEXCEPT)
         
     | 
| 
      
 210 
     | 
    
         
            +
            VAR (acquire_cb, void (*acquire_cb)(EV_P) EV_NOEXCEPT)
         
     | 
| 
       200 
211 
     | 
    
         
             
            VAR (invoke_cb , ev_loop_callback invoke_cb)
         
     | 
| 
       201 
212 
     | 
    
         
             
            #endif
         
     | 
| 
       202 
213 
     | 
    
         | 
    
        data/ext/libev/ev_wrap.h
    CHANGED
    
    | 
         @@ -50,6 +50,14 @@ 
     | 
|
| 
       50 
50 
     | 
    
         
             
            #define kqueue_eventmax ((loop)->kqueue_eventmax)
         
     | 
| 
       51 
51 
     | 
    
         
             
            #define kqueue_events ((loop)->kqueue_events)
         
     | 
| 
       52 
52 
     | 
    
         
             
            #define kqueue_fd_pid ((loop)->kqueue_fd_pid)
         
     | 
| 
      
 53 
     | 
    
         
            +
            #define linuxaio_ctx ((loop)->linuxaio_ctx)
         
     | 
| 
      
 54 
     | 
    
         
            +
            #define linuxaio_epoll_w ((loop)->linuxaio_epoll_w)
         
     | 
| 
      
 55 
     | 
    
         
            +
            #define linuxaio_iocbpmax ((loop)->linuxaio_iocbpmax)
         
     | 
| 
      
 56 
     | 
    
         
            +
            #define linuxaio_iocbps ((loop)->linuxaio_iocbps)
         
     | 
| 
      
 57 
     | 
    
         
            +
            #define linuxaio_iteration ((loop)->linuxaio_iteration)
         
     | 
| 
      
 58 
     | 
    
         
            +
            #define linuxaio_submitcnt ((loop)->linuxaio_submitcnt)
         
     | 
| 
      
 59 
     | 
    
         
            +
            #define linuxaio_submitmax ((loop)->linuxaio_submitmax)
         
     | 
| 
      
 60 
     | 
    
         
            +
            #define linuxaio_submits ((loop)->linuxaio_submits)
         
     | 
| 
       53 
61 
     | 
    
         
             
            #define loop_count ((loop)->loop_count)
         
     | 
| 
       54 
62 
     | 
    
         
             
            #define loop_depth ((loop)->loop_depth)
         
     | 
| 
       55 
63 
     | 
    
         
             
            #define loop_done ((loop)->loop_done)
         
     | 
| 
         @@ -149,6 +157,14 @@ 
     | 
|
| 
       149 
157 
     | 
    
         
             
            #undef kqueue_eventmax
         
     | 
| 
       150 
158 
     | 
    
         
             
            #undef kqueue_events
         
     | 
| 
       151 
159 
     | 
    
         
             
            #undef kqueue_fd_pid
         
     | 
| 
      
 160 
     | 
    
         
            +
            #undef linuxaio_ctx
         
     | 
| 
      
 161 
     | 
    
         
            +
            #undef linuxaio_epoll_w
         
     | 
| 
      
 162 
     | 
    
         
            +
            #undef linuxaio_iocbpmax
         
     | 
| 
      
 163 
     | 
    
         
            +
            #undef linuxaio_iocbps
         
     | 
| 
      
 164 
     | 
    
         
            +
            #undef linuxaio_iteration
         
     | 
| 
      
 165 
     | 
    
         
            +
            #undef linuxaio_submitcnt
         
     | 
| 
      
 166 
     | 
    
         
            +
            #undef linuxaio_submitmax
         
     | 
| 
      
 167 
     | 
    
         
            +
            #undef linuxaio_submits
         
     | 
| 
       152 
168 
     | 
    
         
             
            #undef loop_count
         
     | 
| 
       153 
169 
     | 
    
         
             
            #undef loop_depth
         
     | 
| 
       154 
170 
     | 
    
         
             
            #undef loop_done
         
     | 
    
        data/lib/ev_ext.bundle
    ADDED
    
    | 
         Binary file 
     | 
    
        data/lib/polyphony.rb
    CHANGED
    
    | 
         @@ -5,60 +5,24 @@ require 'modulation/gem' 
     | 
|
| 
       5 
5 
     | 
    
         
             
            export_default :Polyphony
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            require 'fiber'
         
     | 
| 
       8 
     | 
    
         
            -
            require_relative './ 
     | 
| 
       9 
     | 
    
         
            -
            import('./polyphony/extensions/kernel')
         
     | 
| 
       10 
     | 
    
         
            -
            import('./polyphony/extensions/io')
         
     | 
| 
      
 8 
     | 
    
         
            +
            require_relative './gyro_ext'
         
     | 
| 
       11 
9 
     | 
    
         | 
| 
      
 10 
     | 
    
         
            +
            import './polyphony/extensions/core'
         
     | 
| 
      
 11 
     | 
    
         
            +
            import './polyphony/extensions/io'
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            # Main Polyphony API
         
     | 
| 
       12 
14 
     | 
    
         
             
            module Polyphony
         
     | 
| 
       13 
     | 
    
         
            -
              exceptions = import 
     | 
| 
      
 15 
     | 
    
         
            +
              exceptions = import './polyphony/core/exceptions'
         
     | 
| 
       14 
16 
     | 
    
         
             
              Cancel        = exceptions::Cancel
         
     | 
| 
       15 
17 
     | 
    
         
             
              MoveOn        = exceptions::MoveOn
         
     | 
| 
       16 
18 
     | 
    
         | 
| 
       17 
     | 
    
         
            -
              Coprocess = import 
     | 
| 
       18 
     | 
    
         
            -
               
     | 
| 
       19 
     | 
    
         
            -
              Net       = import('./polyphony/net')
         
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
      
 19 
     | 
    
         
            +
              Coprocess = import './polyphony/core/coprocess'
         
     | 
| 
      
 20 
     | 
    
         
            +
              Net       = import './polyphony/net'
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
     | 
    
         
            -
              def self.trap(sig, ref = false, &callback)
         
     | 
| 
       23 
     | 
    
         
            -
                sig = Signal.list[sig.to_s.upcase] if sig.is_a?(Symbol)
         
     | 
| 
       24 
     | 
    
         
            -
                watcher = EV::Signal.new(sig, &callback)
         
     | 
| 
       25 
     | 
    
         
            -
                EV.unref unless ref
         
     | 
| 
       26 
     | 
    
         
            -
                watcher
         
     | 
| 
       27 
     | 
    
         
            -
              end
         
     | 
| 
       28 
     | 
    
         
            -
              
         
     | 
| 
       29 
     | 
    
         
            -
              def self.fork(&block)
         
     | 
| 
       30 
     | 
    
         
            -
                EV.break
         
     | 
| 
       31 
     | 
    
         
            -
                pid = Kernel.fork do
         
     | 
| 
       32 
     | 
    
         
            -
                  FiberPool.reset!
         
     | 
| 
       33 
     | 
    
         
            -
                  EV.post_fork
         
     | 
| 
       34 
     | 
    
         
            -
                  Fiber.current.coprocess = Coprocess.new(Fiber.current)
         
     | 
| 
       35 
     | 
    
         
            -
              
         
     | 
| 
       36 
     | 
    
         
            -
                  block.()
         
     | 
| 
       37 
     | 
    
         
            -
              
         
     | 
| 
       38 
     | 
    
         
            -
                  # We cannot simply depend on the at_exit block (see below) to yield to the
         
     | 
| 
       39 
     | 
    
         
            -
                  # reactor fiber. Doing that will raise a FiberError complaining: "fiber
         
     | 
| 
       40 
     | 
    
         
            -
                  # called across stack rewinding barrier". Apparently this is a bug in
         
     | 
| 
       41 
     | 
    
         
            -
                  # Ruby, so the workaround is to yield just before exiting.
         
     | 
| 
       42 
     | 
    
         
            -
                  suspend
         
     | 
| 
       43 
     | 
    
         
            -
                end
         
     | 
| 
       44 
     | 
    
         
            -
                EV.restart
         
     | 
| 
       45 
     | 
    
         
            -
                pid
         
     | 
| 
       46 
     | 
    
         
            -
              end
         
     | 
| 
       47 
     | 
    
         
            -
              
         
     | 
| 
       48 
     | 
    
         
            -
              def self.debug
         
     | 
| 
       49 
     | 
    
         
            -
                @debug
         
     | 
| 
       50 
     | 
    
         
            -
              end
         
     | 
| 
       51 
     | 
    
         
            -
              
         
     | 
| 
       52 
     | 
    
         
            -
              def self.debug=(value)
         
     | 
| 
       53 
     | 
    
         
            -
                @debug = value
         
     | 
| 
       54 
     | 
    
         
            -
              end
         
     | 
| 
       55 
     | 
    
         
            -
              
         
     | 
| 
       56 
22 
     | 
    
         
             
              auto_import(
         
     | 
| 
       57 
23 
     | 
    
         
             
                CancelScope:  './polyphony/core/cancel_scope',
         
     | 
| 
       58 
24 
     | 
    
         
             
                Channel:      './polyphony/core/channel',
         
     | 
| 
       59 
     | 
    
         
            -
                # Coprocess:    './polyphony/core/coprocess',
         
     | 
| 
       60 
25 
     | 
    
         
             
                FS:           './polyphony/fs',
         
     | 
| 
       61 
     | 
    
         
            -
                # Net:          './polyphony/net',
         
     | 
| 
       62 
26 
     | 
    
         
             
                ResourcePool: './polyphony/core/resource_pool',
         
     | 
| 
       63 
27 
     | 
    
         
             
                Supervisor:   './polyphony/core/supervisor',
         
     | 
| 
       64 
28 
     | 
    
         
             
                Sync:         './polyphony/core/sync',
         
     | 
| 
         @@ -66,11 +30,43 @@ module Polyphony 
     | 
|
| 
       66 
30 
     | 
    
         
             
                ThreadPool:   './polyphony/core/thread_pool',
         
     | 
| 
       67 
31 
     | 
    
         
             
                Websocket:    './polyphony/websocket'
         
     | 
| 
       68 
32 
     | 
    
         
             
              )
         
     | 
| 
       69 
     | 
    
         
            -
            end
         
     | 
| 
       70 
33 
     | 
    
         | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
      
 34 
     | 
    
         
            +
              class << self
         
     | 
| 
      
 35 
     | 
    
         
            +
                def trap(sig, ref = false, &callback)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  sig = Signal.list[sig.to_s.upcase] if sig.is_a?(Symbol)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  watcher = Gyro::Signal.new(sig, &callback)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  Gyro.unref unless ref
         
     | 
| 
      
 39 
     | 
    
         
            +
                  watcher
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                def fork(&block)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  Gyro.break
         
     | 
| 
      
 44 
     | 
    
         
            +
                  pid = Kernel.fork do
         
     | 
| 
      
 45 
     | 
    
         
            +
                    setup_forked_process
         
     | 
| 
      
 46 
     | 
    
         
            +
                    block.()
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                    # We cannot simply depend on the at_exit block (see polyphony/auto_run)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    # to yield to the reactor fiber. Doing that will raise a FiberError
         
     | 
| 
      
 50 
     | 
    
         
            +
                    # complaining: "fiber called across stack rewinding barrier". Apparently
         
     | 
| 
      
 51 
     | 
    
         
            +
                    # this is a bug in Ruby, so the workaround is to yield just before
         
     | 
| 
      
 52 
     | 
    
         
            +
                    # exiting.
         
     | 
| 
      
 53 
     | 
    
         
            +
                    suspend
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  Gyro.restart
         
     | 
| 
      
 56 
     | 
    
         
            +
                  pid
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                def reset!
         
     | 
| 
      
 60 
     | 
    
         
            +
                  Fiber.root.scheduled_value = nil
         
     | 
| 
      
 61 
     | 
    
         
            +
                  Gyro.restart
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                private
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                def setup_forked_process
         
     | 
| 
      
 67 
     | 
    
         
            +
                  Gyro.post_fork
         
     | 
| 
      
 68 
     | 
    
         
            +
                  Fiber.set_root_fiber
         
     | 
| 
      
 69 
     | 
    
         
            +
                  Fiber.current.coprocess = Coprocess.new(Fiber.current)
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
      
 71 
     | 
    
         
            +
              end
         
     | 
| 
       76 
72 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative '../polyphony'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            at_exit do
         
     | 
| 
      
 6 
     | 
    
         
            +
              repl = (Pry.current rescue nil) || (IRB.CurrentContext rescue nil)
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              # in most cases, once the root fiber is done there are still pending
         
     | 
| 
      
 9 
     | 
    
         
            +
              # operations going on. If the reactor loop is not done, we suspend the root
         
     | 
| 
      
 10 
     | 
    
         
            +
              # fiber until it is done
         
     | 
| 
      
 11 
     | 
    
         
            +
              suspend if $__reactor_fiber__&.alive? && !repl
         
     | 
| 
      
 12 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -8,19 +8,23 @@ Exceptions = import('./exceptions') 
     | 
|
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
            # A cancellation scope that can be used to cancel an asynchronous task
         
     | 
| 
       10 
10 
     | 
    
         
             
            class CancelScope
         
     | 
| 
       11 
     | 
    
         
            -
              def initialize(opts = {})
         
     | 
| 
      
 11 
     | 
    
         
            +
              def initialize(opts = {}, &block)
         
     | 
| 
       12 
12 
     | 
    
         
             
                @opts = opts
         
     | 
| 
       13 
     | 
    
         
            -
                 
     | 
| 
      
 13 
     | 
    
         
            +
                call(&block) if block
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              def error_class
         
     | 
| 
      
 17 
     | 
    
         
            +
                @opts[:mode] == :cancel ? Exceptions::Cancel : Exceptions::MoveOn
         
     | 
| 
       14 
18 
     | 
    
         
             
              end
         
     | 
| 
       15 
19 
     | 
    
         | 
| 
       16 
20 
     | 
    
         
             
              def cancel!
         
     | 
| 
       17 
21 
     | 
    
         
             
                @cancelled = true
         
     | 
| 
       18 
22 
     | 
    
         
             
                @fiber.cancelled = true
         
     | 
| 
       19 
     | 
    
         
            -
                @fiber.transfer  
     | 
| 
      
 23 
     | 
    
         
            +
                @fiber.transfer error_class.new(self, @opts[:value])
         
     | 
| 
       20 
24 
     | 
    
         
             
              end
         
     | 
| 
       21 
25 
     | 
    
         | 
| 
       22 
26 
     | 
    
         
             
              def start_timeout
         
     | 
| 
       23 
     | 
    
         
            -
                @timeout =  
     | 
| 
      
 27 
     | 
    
         
            +
                @timeout = Gyro::Timer.new(@opts[:timeout], 0)
         
     | 
| 
       24 
28 
     | 
    
         
             
                @timeout.start { cancel! }
         
     | 
| 
       25 
29 
     | 
    
         
             
              end
         
     | 
| 
       26 
30 
     | 
    
         | 
| 
         @@ -41,11 +45,11 @@ class CancelScope 
     | 
|
| 
       41 
45 
     | 
    
         
             
                e.scope == self ? e.value : raise(e)
         
     | 
| 
       42 
46 
     | 
    
         
             
              ensure
         
     | 
| 
       43 
47 
     | 
    
         
             
                @timeout&.stop
         
     | 
| 
       44 
     | 
    
         
            -
                protect(&@ 
     | 
| 
      
 48 
     | 
    
         
            +
                protect(&@on_cancel) if @cancelled && @on_cancel
         
     | 
| 
       45 
49 
     | 
    
         
             
              end
         
     | 
| 
       46 
50 
     | 
    
         | 
| 
       47 
     | 
    
         
            -
              def  
     | 
| 
       48 
     | 
    
         
            -
                @ 
     | 
| 
      
 51 
     | 
    
         
            +
              def on_cancel(&block)
         
     | 
| 
      
 52 
     | 
    
         
            +
                @on_cancel = block
         
     | 
| 
       49 
53 
     | 
    
         
             
              end
         
     | 
| 
       50 
54 
     | 
    
         | 
| 
       51 
55 
     | 
    
         
             
              def cancelled?
         
     | 
| 
         @@ -4,6 +4,8 @@ export_default :Channel 
     | 
|
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            Exceptions = import('./exceptions')
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
      
 7 
     | 
    
         
            +
            # Implements a unidirectional communication channel along the lines of Go
         
     | 
| 
      
 8 
     | 
    
         
            +
            # (buffered) channels.
         
     | 
| 
       7 
9 
     | 
    
         
             
            class Channel
         
     | 
| 
       8 
10 
     | 
    
         
             
              def initialize
         
     | 
| 
       9 
11 
     | 
    
         
             
                @payload_queue = []
         
     | 
| 
         @@ -15,25 +17,30 @@ class Channel 
     | 
|
| 
       15 
17 
     | 
    
         
             
                @waiting_queue.slice(0..-1).each { |f| f.schedule(stop) }
         
     | 
| 
       16 
18 
     | 
    
         
             
              end
         
     | 
| 
       17 
19 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
              def <<( 
     | 
| 
      
 20 
     | 
    
         
            +
              def <<(value)
         
     | 
| 
       19 
21 
     | 
    
         
             
                if @waiting_queue.empty?
         
     | 
| 
       20 
     | 
    
         
            -
                  @payload_queue <<  
     | 
| 
      
 22 
     | 
    
         
            +
                  @payload_queue << value
         
     | 
| 
       21 
23 
     | 
    
         
             
                else
         
     | 
| 
       22 
     | 
    
         
            -
                  @waiting_queue.shift&.schedule( 
     | 
| 
      
 24 
     | 
    
         
            +
                  @waiting_queue.shift&.schedule(value)
         
     | 
| 
       23 
25 
     | 
    
         
             
                end
         
     | 
| 
       24 
26 
     | 
    
         
             
                snooze
         
     | 
| 
       25 
27 
     | 
    
         
             
              end
         
     | 
| 
       26 
28 
     | 
    
         | 
| 
       27 
29 
     | 
    
         
             
              def receive
         
     | 
| 
       28 
     | 
    
         
            -
                 
     | 
| 
      
 30 
     | 
    
         
            +
                Gyro.ref
         
     | 
| 
       29 
31 
     | 
    
         
             
                if @payload_queue.empty?
         
     | 
| 
       30 
32 
     | 
    
         
             
                  @waiting_queue << Fiber.current
         
     | 
| 
      
 33 
     | 
    
         
            +
                  suspend
         
     | 
| 
       31 
34 
     | 
    
         
             
                else
         
     | 
| 
       32 
     | 
    
         
            -
                   
     | 
| 
       33 
     | 
    
         
            -
                  Fiber.current.schedule(payload)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  receive_from_queue
         
     | 
| 
       34 
36 
     | 
    
         
             
                end
         
     | 
| 
       35 
     | 
    
         
            -
                suspend
         
     | 
| 
       36 
37 
     | 
    
         
             
              ensure
         
     | 
| 
       37 
     | 
    
         
            -
                 
     | 
| 
      
 38 
     | 
    
         
            +
                Gyro.unref
         
     | 
| 
       38 
39 
     | 
    
         
             
              end
         
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              def receive_from_queue
         
     | 
| 
      
 42 
     | 
    
         
            +
                payload = @payload_queue.shift
         
     | 
| 
      
 43 
     | 
    
         
            +
                snooze
         
     | 
| 
      
 44 
     | 
    
         
            +
                payload
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -2,72 +2,116 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            export_default :Coprocess
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
            import 
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
            FiberPool   = import('./fiber_pool')
         
     | 
| 
       8 
     | 
    
         
            -
            Exceptions  = import('./exceptions')
         
     | 
| 
      
 5 
     | 
    
         
            +
            import '../extensions/core'
         
     | 
| 
      
 6 
     | 
    
         
            +
            Exceptions = import './exceptions'
         
     | 
| 
       9 
7 
     | 
    
         | 
| 
       10 
8 
     | 
    
         
             
            # Encapsulates an asynchronous task
         
     | 
| 
       11 
9 
     | 
    
         
             
            class Coprocess
         
     | 
| 
       12 
     | 
    
         
            -
               
     | 
| 
      
 10 
     | 
    
         
            +
              # inter-coprocess message passing
         
     | 
| 
      
 11 
     | 
    
         
            +
              module Messaging
         
     | 
| 
      
 12 
     | 
    
         
            +
                def <<(value)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  if @receive_waiting && @fiber
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @fiber&.schedule value
         
     | 
| 
      
 15 
     | 
    
         
            +
                  else
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @queued_messages ||= []
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @queued_messages << value
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                  snooze
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def receive
         
     | 
| 
      
 23 
     | 
    
         
            +
                  if !@queued_messages || @queued_messages&.empty?
         
     | 
| 
      
 24 
     | 
    
         
            +
                    wait_for_message
         
     | 
| 
      
 25 
     | 
    
         
            +
                  else
         
     | 
| 
      
 26 
     | 
    
         
            +
                    value = @queued_messages.shift
         
     | 
| 
      
 27 
     | 
    
         
            +
                    snooze
         
     | 
| 
      
 28 
     | 
    
         
            +
                    value
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                def wait_for_message
         
     | 
| 
      
 33 
     | 
    
         
            +
                  Gyro.ref
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @receive_waiting = true
         
     | 
| 
      
 35 
     | 
    
         
            +
                  suspend
         
     | 
| 
      
 36 
     | 
    
         
            +
                ensure
         
     | 
| 
      
 37 
     | 
    
         
            +
                  Gyro.unref
         
     | 
| 
      
 38 
     | 
    
         
            +
                  @receive_waiting = nil
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
              include Messaging
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
              @@list = {}
         
     | 
| 
       13 
45 
     | 
    
         | 
| 
      
 46 
     | 
    
         
            +
              def self.list
         
     | 
| 
      
 47 
     | 
    
         
            +
                @@list
         
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
              def self.count
         
     | 
| 
      
 51 
     | 
    
         
            +
                @@list.size
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
              attr_reader :result, :fiber
         
     | 
| 
       14 
55 
     | 
    
         | 
| 
       15 
56 
     | 
    
         
             
              def initialize(fiber = nil, &block)
         
     | 
| 
       16 
57 
     | 
    
         
             
                @fiber = fiber
         
     | 
| 
       17 
58 
     | 
    
         
             
                @block = block
         
     | 
| 
       18 
59 
     | 
    
         
             
              end
         
     | 
| 
       19 
60 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
              def run 
     | 
| 
       21 
     | 
    
         
            -
                @ 
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
                @fiber = FiberPool.run do
         
     | 
| 
       24 
     | 
    
         
            -
                  @fiber.coprocess = self
         
     | 
| 
       25 
     | 
    
         
            -
                  @result = (@block || block2).call(self)
         
     | 
| 
       26 
     | 
    
         
            -
                rescue Exceptions::MoveOn, Exceptions::Stop => e
         
     | 
| 
       27 
     | 
    
         
            -
                  @result = e.value
         
     | 
| 
       28 
     | 
    
         
            -
                rescue Exception => e
         
     | 
| 
       29 
     | 
    
         
            -
                  e.cleanup_backtrace(@caller) if Exceptions.debug
         
     | 
| 
       30 
     | 
    
         
            -
                  @result = e
         
     | 
| 
       31 
     | 
    
         
            -
                ensure
         
     | 
| 
       32 
     | 
    
         
            -
                  @fiber.coprocess = nil
         
     | 
| 
       33 
     | 
    
         
            -
                  @fiber = nil
         
     | 
| 
       34 
     | 
    
         
            -
                  @awaiting_fiber&.schedule @result
         
     | 
| 
       35 
     | 
    
         
            -
                  @when_done&.()
         
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
                  # if result is an error and nobody's waiting on us, we need to raise it
         
     | 
| 
       38 
     | 
    
         
            -
                  raise @result if @result.is_a?(Exception) && !@awaiting_fiber
         
     | 
| 
       39 
     | 
    
         
            -
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
              def run
         
     | 
| 
      
 62 
     | 
    
         
            +
                @calling_fiber = Fiber.current
         
     | 
| 
       40 
63 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
                @ 
     | 
| 
      
 64 
     | 
    
         
            +
                @fiber = Fiber.new { execute }
         
     | 
| 
       42 
65 
     | 
    
         
             
                @fiber.schedule
         
     | 
| 
      
 66 
     | 
    
         
            +
                @ran = true
         
     | 
| 
       43 
67 
     | 
    
         
             
                self
         
     | 
| 
       44 
68 
     | 
    
         
             
              end
         
     | 
| 
       45 
69 
     | 
    
         | 
| 
       46 
     | 
    
         
            -
              def  
     | 
| 
       47 
     | 
    
         
            -
                 
     | 
| 
       48 
     | 
    
         
            -
                @ 
     | 
| 
       49 
     | 
    
         
            -
                @fiber 
     | 
| 
       50 
     | 
    
         
            -
                 
     | 
| 
      
 70 
     | 
    
         
            +
              def execute
         
     | 
| 
      
 71 
     | 
    
         
            +
                # uncaught_exception = nil
         
     | 
| 
      
 72 
     | 
    
         
            +
                @@list[@fiber] = self
         
     | 
| 
      
 73 
     | 
    
         
            +
                @fiber.coprocess = self
         
     | 
| 
      
 74 
     | 
    
         
            +
                @result = @block.call(self)
         
     | 
| 
      
 75 
     | 
    
         
            +
              rescue Exceptions::MoveOn => e
         
     | 
| 
      
 76 
     | 
    
         
            +
                @result = e.value
         
     | 
| 
      
 77 
     | 
    
         
            +
              rescue Exception => e
         
     | 
| 
      
 78 
     | 
    
         
            +
                uncaught_exception = true
         
     | 
| 
      
 79 
     | 
    
         
            +
                @result = e
         
     | 
| 
      
 80 
     | 
    
         
            +
              ensure
         
     | 
| 
      
 81 
     | 
    
         
            +
                finish_execution(uncaught_exception)
         
     | 
| 
       51 
82 
     | 
    
         
             
              end
         
     | 
| 
       52 
83 
     | 
    
         | 
| 
       53 
     | 
    
         
            -
              def  
     | 
| 
       54 
     | 
    
         
            -
                 
     | 
| 
       55 
     | 
    
         
            -
                @ 
     | 
| 
       56 
     | 
    
         
            -
                @fiber 
     | 
| 
       57 
     | 
    
         
            -
                 
     | 
| 
       58 
     | 
    
         
            -
                @ 
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
                 
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
      
 84 
     | 
    
         
            +
              def finish_execution(uncaught_exception)
         
     | 
| 
      
 85 
     | 
    
         
            +
                @@list.delete(@fiber)
         
     | 
| 
      
 86 
     | 
    
         
            +
                @fiber.coprocess = nil
         
     | 
| 
      
 87 
     | 
    
         
            +
                @fiber = nil
         
     | 
| 
      
 88 
     | 
    
         
            +
                @awaiting_fiber&.schedule @result
         
     | 
| 
      
 89 
     | 
    
         
            +
                @when_done&.()
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                return unless uncaught_exception && !@awaiting_fiber
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                # if no awaiting fiber, raise any uncaught error by passing it to the
         
     | 
| 
      
 94 
     | 
    
         
            +
                # calling fiber, or to the root fiber if the calling fiber
         
     | 
| 
      
 95 
     | 
    
         
            +
                calling_fiber = @calling_fiber || Fiber.root
         
     | 
| 
      
 96 
     | 
    
         
            +
                calling_fiber.transfer @result
         
     | 
| 
       62 
97 
     | 
    
         
             
              end
         
     | 
| 
       63 
98 
     | 
    
         | 
| 
       64 
     | 
    
         
            -
              def  
     | 
| 
      
 99 
     | 
    
         
            +
              def alive?
         
     | 
| 
       65 
100 
     | 
    
         
             
                @fiber
         
     | 
| 
       66 
101 
     | 
    
         
             
              end
         
     | 
| 
       67 
102 
     | 
    
         | 
| 
       68 
103 
     | 
    
         
             
              # Kernel.await expects the given argument / block to be a callable, so #call
         
     | 
| 
       69 
104 
     | 
    
         
             
              # in fact waits for the coprocess to finish
         
     | 
| 
       70 
105 
     | 
    
         
             
              def await
         
     | 
| 
      
 106 
     | 
    
         
            +
                await_coprocess_result
         
     | 
| 
      
 107 
     | 
    
         
            +
              ensure
         
     | 
| 
      
 108 
     | 
    
         
            +
                # If the awaiting fiber has been transferred an exception, the awaited fiber
         
     | 
| 
      
 109 
     | 
    
         
            +
                # might still be running, so we need to stop it
         
     | 
| 
      
 110 
     | 
    
         
            +
                @fiber&.schedule(Exceptions::MoveOn.new)
         
     | 
| 
      
 111 
     | 
    
         
            +
              end
         
     | 
| 
      
 112 
     | 
    
         
            +
              alias_method :join, :await
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
              def await_coprocess_result
         
     | 
| 
       71 
115 
     | 
    
         
             
                run unless @ran
         
     | 
| 
       72 
116 
     | 
    
         
             
                if @fiber
         
     | 
| 
       73 
117 
     | 
    
         
             
                  @awaiting_fiber = Fiber.current
         
     | 
| 
         @@ -75,30 +119,36 @@ class Coprocess 
     | 
|
| 
       75 
119 
     | 
    
         
             
                else
         
     | 
| 
       76 
120 
     | 
    
         
             
                  @result
         
     | 
| 
       77 
121 
     | 
    
         
             
                end
         
     | 
| 
       78 
     | 
    
         
            -
              ensure
         
     | 
| 
       79 
     | 
    
         
            -
                # if awaiting was interrupted and the coprocess is still running, we need to stop it
         
     | 
| 
       80 
     | 
    
         
            -
                if @fiber
         
     | 
| 
       81 
     | 
    
         
            -
                  @fiber&.schedule(Exceptions::MoveOn.new)
         
     | 
| 
       82 
     | 
    
         
            -
                  suspend
         
     | 
| 
       83 
     | 
    
         
            -
                end
         
     | 
| 
       84 
122 
     | 
    
         
             
              end
         
     | 
| 
       85 
     | 
    
         
            -
              alias_method :join, :await
         
     | 
| 
       86 
123 
     | 
    
         | 
| 
       87 
124 
     | 
    
         
             
              def when_done(&block)
         
     | 
| 
       88 
125 
     | 
    
         
             
                @when_done = block
         
     | 
| 
       89 
126 
     | 
    
         
             
              end
         
     | 
| 
       90 
127 
     | 
    
         | 
| 
       91 
128 
     | 
    
         
             
              def resume(value = nil)
         
     | 
| 
       92 
     | 
    
         
            -
                @fiber 
     | 
| 
      
 129 
     | 
    
         
            +
                return unless @fiber
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                @fiber.schedule(value)
         
     | 
| 
      
 132 
     | 
    
         
            +
                snooze
         
     | 
| 
       93 
133 
     | 
    
         
             
              end
         
     | 
| 
       94 
134 
     | 
    
         | 
| 
       95 
135 
     | 
    
         
             
              def interrupt(value = nil)
         
     | 
| 
       96 
     | 
    
         
            -
                @fiber 
     | 
| 
      
 136 
     | 
    
         
            +
                return unless @fiber
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                @fiber.schedule(Exceptions::MoveOn.new(nil, value))
         
     | 
| 
      
 139 
     | 
    
         
            +
                snooze
         
     | 
| 
       97 
140 
     | 
    
         
             
              end
         
     | 
| 
       98 
141 
     | 
    
         
             
              alias_method :stop, :interrupt
         
     | 
| 
       99 
142 
     | 
    
         | 
| 
      
 143 
     | 
    
         
            +
              def transfer(value = nil)
         
     | 
| 
      
 144 
     | 
    
         
            +
                @fiber&.schedule(value)
         
     | 
| 
      
 145 
     | 
    
         
            +
              end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
       100 
147 
     | 
    
         
             
              def cancel!
         
     | 
| 
       101 
     | 
    
         
            -
                @fiber 
     | 
| 
      
 148 
     | 
    
         
            +
                return unless @fiber
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                @fiber.schedule(Exceptions::Cancel.new)
         
     | 
| 
      
 151 
     | 
    
         
            +
                snooze
         
     | 
| 
       102 
152 
     | 
    
         
             
              end
         
     | 
| 
       103 
153 
     | 
    
         | 
| 
       104 
154 
     | 
    
         
             
              def self.current
         
     |