polyphony 0.24 → 0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/CHANGELOG.md +6 -0
 - data/Gemfile.lock +1 -1
 - data/TODO.md +12 -8
 - data/docs/README.md +2 -2
 - data/docs/summary.md +3 -3
 - data/docs/technical-overview/concurrency.md +4 -6
 - data/docs/technical-overview/design-principles.md +8 -8
 - data/docs/technical-overview/exception-handling.md +1 -1
 - data/examples/core/{01-spinning-up-coprocesses.rb → 01-spinning-up-fibers.rb} +1 -1
 - data/examples/core/{02-awaiting-coprocesses.rb → 02-awaiting-fibers.rb} +3 -3
 - data/examples/core/xx-erlang-style-genserver.rb +10 -10
 - data/examples/core/xx-extended_fibers.rb +150 -0
 - data/examples/core/xx-sleeping.rb +9 -0
 - data/examples/core/xx-supervisors.rb +1 -1
 - data/examples/interfaces/pg_pool.rb +3 -3
 - data/examples/performance/mem-usage.rb +19 -4
 - data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -5
 - data/ext/gyro/gyro.c +9 -15
 - data/lib/polyphony/core/cancel_scope.rb +0 -2
 - data/lib/polyphony/core/exceptions.rb +2 -2
 - data/lib/polyphony/core/global_api.rb +7 -8
 - data/lib/polyphony/core/supervisor.rb +25 -31
 - data/lib/polyphony/extensions/core.rb +4 -78
 - data/lib/polyphony/extensions/fiber.rb +166 -0
 - data/lib/polyphony/extensions/io.rb +2 -1
 - data/lib/polyphony/version.rb +1 -1
 - data/lib/polyphony.rb +6 -8
 - data/test/test_async.rb +2 -2
 - data/test/test_cancel_scope.rb +6 -6
 - data/test/test_fiber.rb +382 -0
 - data/test/test_global_api.rb +49 -50
 - data/test/test_gyro.rb +1 -1
 - data/test/test_io.rb +30 -29
 - data/test/test_kernel.rb +2 -2
 - data/test/test_signal.rb +1 -1
 - data/test/test_supervisor.rb +27 -27
 - data/test/test_timer.rb +2 -2
 - metadata +7 -7
 - data/examples/core/04-no-auto-run.rb +0 -16
 - data/lib/polyphony/core/coprocess.rb +0 -168
 - data/test/test_coprocess.rb +0 -440
 
    
        data/test/test_io.rb
    CHANGED
    
    | 
         @@ -49,33 +49,33 @@ class IOTest < MiniTest::Test 
     | 
|
| 
       49 
49 
     | 
    
         | 
| 
       50 
50 
     | 
    
         
             
                  spin { msg = @i.read }
         
     | 
| 
       51 
51 
     | 
    
         
             
                ].each(&:await)
         
     | 
| 
       52 
     | 
    
         
            -
                assert_equal 
     | 
| 
       53 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 52 
     | 
    
         
            +
                assert_equal 5, count
         
     | 
| 
      
 53 
     | 
    
         
            +
                assert_equal 'hello', msg
         
     | 
| 
       54 
54 
     | 
    
         
             
              end
         
     | 
| 
       55 
55 
     | 
    
         | 
| 
       56 
56 
     | 
    
         
             
              def test_that_double_chevron_method_returns_io
         
     | 
| 
       57 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 57 
     | 
    
         
            +
                assert_equal @o, @o << 'foo'
         
     | 
| 
       58 
58 
     | 
    
         | 
| 
       59 
59 
     | 
    
         
             
                @o << 'bar' << 'baz'
         
     | 
| 
       60 
60 
     | 
    
         
             
                @o.close
         
     | 
| 
       61 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 61 
     | 
    
         
            +
                assert_equal 'foobarbaz', @i.read
         
     | 
| 
       62 
62 
     | 
    
         
             
              end
         
     | 
| 
       63 
63 
     | 
    
         
             
            end
         
     | 
| 
       64 
64 
     | 
    
         | 
| 
       65 
65 
     | 
    
         
             
            class IOClassMethodsTest < MiniTest::Test
         
     | 
| 
       66 
66 
     | 
    
         
             
              def test_binread
         
     | 
| 
       67 
67 
     | 
    
         
             
                s = IO.binread(__FILE__)
         
     | 
| 
       68 
     | 
    
         
            -
                assert_kind_of 
     | 
| 
       69 
     | 
    
         
            -
                assert 
     | 
| 
       70 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 68 
     | 
    
         
            +
                assert_kind_of String, s
         
     | 
| 
      
 69 
     | 
    
         
            +
                assert !s.empty?
         
     | 
| 
      
 70 
     | 
    
         
            +
                assert_equal IO.orig_binread(__FILE__), s
         
     | 
| 
       71 
71 
     | 
    
         | 
| 
       72 
72 
     | 
    
         
             
                s = IO.binread(__FILE__, 100)
         
     | 
| 
       73 
     | 
    
         
            -
                assert_equal 
     | 
| 
       74 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 73 
     | 
    
         
            +
                assert_equal 100, s.bytesize
         
     | 
| 
      
 74 
     | 
    
         
            +
                assert_equal IO.orig_binread(__FILE__, 100), s
         
     | 
| 
       75 
75 
     | 
    
         | 
| 
       76 
76 
     | 
    
         
             
                s = IO.binread(__FILE__, 100, 2)
         
     | 
| 
       77 
     | 
    
         
            -
                assert_equal 
     | 
| 
       78 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 77 
     | 
    
         
            +
                assert_equal 100, s.bytesize
         
     | 
| 
      
 78 
     | 
    
         
            +
                assert_equal 'frozen', s[0..5]
         
     | 
| 
       79 
79 
     | 
    
         
             
              end
         
     | 
| 
       80 
80 
     | 
    
         | 
| 
       81 
81 
     | 
    
         
             
              BIN_DATA = "\x00\x01\x02\x03"
         
     | 
| 
         @@ -85,37 +85,38 @@ class IOClassMethodsTest < MiniTest::Test 
     | 
|
| 
       85 
85 
     | 
    
         
             
                FileUtils.rm(fn) rescue nil
         
     | 
| 
       86 
86 
     | 
    
         | 
| 
       87 
87 
     | 
    
         
             
                len = IO.binwrite(fn, BIN_DATA)
         
     | 
| 
       88 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 88 
     | 
    
         
            +
                assert_equal 4, len
         
     | 
| 
       89 
89 
     | 
    
         
             
                s = IO.binread(fn)
         
     | 
| 
       90 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 90 
     | 
    
         
            +
                assert_equal BIN_DATA, s
         
     | 
| 
       91 
91 
     | 
    
         
             
              end
         
     | 
| 
       92 
92 
     | 
    
         | 
| 
       93 
93 
     | 
    
         
             
              def test_foreach
         
     | 
| 
      
 94 
     | 
    
         
            +
                skip "IO.foreach is not yet implemented"
         
     | 
| 
       94 
95 
     | 
    
         
             
                lines = []
         
     | 
| 
       95 
96 
     | 
    
         
             
                IO.foreach(__FILE__) { |l| lines << l }
         
     | 
| 
       96 
     | 
    
         
            -
                assert_equal 
     | 
| 
       97 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 97 
     | 
    
         
            +
                assert_equal "# frozen_string_literal: true\n", lines[0]
         
     | 
| 
      
 98 
     | 
    
         
            +
                assert_equal "end\n", lines[-1]
         
     | 
| 
       98 
99 
     | 
    
         
             
              end
         
     | 
| 
       99 
100 
     | 
    
         | 
| 
       100 
101 
     | 
    
         
             
              def test_read
         
     | 
| 
       101 
102 
     | 
    
         
             
                s = IO.read(__FILE__)
         
     | 
| 
       102 
     | 
    
         
            -
                assert_kind_of 
     | 
| 
      
 103 
     | 
    
         
            +
                assert_kind_of String, s
         
     | 
| 
       103 
104 
     | 
    
         
             
                assert(!s.empty?)
         
     | 
| 
       104 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 105 
     | 
    
         
            +
                assert_equal IO.orig_read(__FILE__), s
         
     | 
| 
       105 
106 
     | 
    
         | 
| 
       106 
107 
     | 
    
         
             
                s = IO.read(__FILE__, 100)
         
     | 
| 
       107 
     | 
    
         
            -
                assert_equal 
     | 
| 
       108 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 108 
     | 
    
         
            +
                assert_equal 100, s.bytesize
         
     | 
| 
      
 109 
     | 
    
         
            +
                assert_equal IO.orig_read(__FILE__, 100), s
         
     | 
| 
       109 
110 
     | 
    
         | 
| 
       110 
111 
     | 
    
         
             
                s = IO.read(__FILE__, 100, 2)
         
     | 
| 
       111 
     | 
    
         
            -
                assert_equal 
     | 
| 
       112 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 112 
     | 
    
         
            +
                assert_equal 100, s.bytesize
         
     | 
| 
      
 113 
     | 
    
         
            +
                assert_equal 'frozen', s[0..5]
         
     | 
| 
       113 
114 
     | 
    
         
             
              end
         
     | 
| 
       114 
115 
     | 
    
         | 
| 
       115 
116 
     | 
    
         
             
              def test_readlines
         
     | 
| 
       116 
117 
     | 
    
         
             
                lines = IO.readlines(__FILE__)
         
     | 
| 
       117 
     | 
    
         
            -
                assert_equal 
     | 
| 
       118 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 118 
     | 
    
         
            +
                assert_equal "# frozen_string_literal: true\n", lines[0]
         
     | 
| 
      
 119 
     | 
    
         
            +
                assert_equal "end\n", lines[-1]
         
     | 
| 
       119 
120 
     | 
    
         
             
              end
         
     | 
| 
       120 
121 
     | 
    
         | 
| 
       121 
122 
     | 
    
         
             
              WRITE_DATA = "foo\nbar קוקו"
         
     | 
| 
         @@ -125,9 +126,9 @@ class IOClassMethodsTest < MiniTest::Test 
     | 
|
| 
       125 
126 
     | 
    
         
             
                FileUtils.rm(fn) rescue nil
         
     | 
| 
       126 
127 
     | 
    
         | 
| 
       127 
128 
     | 
    
         
             
                len = IO.write(fn, WRITE_DATA)
         
     | 
| 
       128 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 129 
     | 
    
         
            +
                assert_equal WRITE_DATA.bytesize, len
         
     | 
| 
       129 
130 
     | 
    
         
             
                s = IO.read(fn)
         
     | 
| 
       130 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 131 
     | 
    
         
            +
                assert_equal WRITE_DATA, s
         
     | 
| 
       131 
132 
     | 
    
         
             
              end
         
     | 
| 
       132 
133 
     | 
    
         | 
| 
       133 
134 
     | 
    
         
             
              def test_popen
         
     | 
| 
         @@ -139,7 +140,7 @@ class IOClassMethodsTest < MiniTest::Test 
     | 
|
| 
       139 
140 
     | 
    
         | 
| 
       140 
141 
     | 
    
         
             
                result = nil
         
     | 
| 
       141 
142 
     | 
    
         
             
                IO.popen('echo "foo"') { |io| result = io.read(8192) }
         
     | 
| 
       142 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 143 
     | 
    
         
            +
                assert_equal "foo\n", result
         
     | 
| 
       143 
144 
     | 
    
         
             
              ensure
         
     | 
| 
       144 
145 
     | 
    
         
             
                timer&.stop
         
     | 
| 
       145 
146 
     | 
    
         
             
              end
         
     | 
| 
         @@ -158,7 +159,7 @@ class IOClassMethodsTest < MiniTest::Test 
     | 
|
| 
       158 
159 
     | 
    
         
             
                end
         
     | 
| 
       159 
160 
     | 
    
         | 
| 
       160 
161 
     | 
    
         
             
                assert(counter >= 0)
         
     | 
| 
       161 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 162 
     | 
    
         
            +
                assert_equal "foo\n", gets
         
     | 
| 
       162 
163 
     | 
    
         
             
              ensure
         
     | 
| 
       163 
164 
     | 
    
         
             
                $stdin = orig_stdin
         
     | 
| 
       164 
165 
     | 
    
         
             
                timer&.stop
         
     | 
| 
         @@ -170,7 +171,7 @@ class IOClassMethodsTest < MiniTest::Test 
     | 
|
| 
       170 
171 
     | 
    
         
             
                s = StringIO.new(IO.orig_read(__FILE__))
         
     | 
| 
       171 
172 
     | 
    
         | 
| 
       172 
173 
     | 
    
         
             
                while (l = s.gets)
         
     | 
| 
       173 
     | 
    
         
            -
                  assert_equal 
     | 
| 
      
 174 
     | 
    
         
            +
                  assert_equal l, gets
         
     | 
| 
       174 
175 
     | 
    
         
             
                end
         
     | 
| 
       175 
176 
     | 
    
         
             
              ensure
         
     | 
| 
       176 
177 
     | 
    
         
             
                ARGV.delete __FILE__
         
     | 
| 
         @@ -188,7 +189,7 @@ class IOClassMethodsTest < MiniTest::Test 
     | 
|
| 
       188 
189 
     | 
    
         
             
                $stdout = o
         
     | 
| 
       189 
190 
     | 
    
         | 
| 
       190 
191 
     | 
    
         
             
                puts 'foobar'
         
     | 
| 
       191 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 192 
     | 
    
         
            +
                assert_equal "foobar\n", o.buf
         
     | 
| 
       192 
193 
     | 
    
         
             
              ensure
         
     | 
| 
       193 
194 
     | 
    
         
             
                $stdout = orig_stdout
         
     | 
| 
       194 
195 
     | 
    
         
             
              end
         
     | 
    
        data/test/test_kernel.rb
    CHANGED
    
    | 
         @@ -15,7 +15,7 @@ class KernelTest < MiniTest::Test 
     | 
|
| 
       15 
15 
     | 
    
         
             
                $stdout = o
         
     | 
| 
       16 
16 
     | 
    
         
             
                system('echo "hello"')
         
     | 
| 
       17 
17 
     | 
    
         
             
                o.close
         
     | 
| 
       18 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 18 
     | 
    
         
            +
                assert_equal "hello\n", i.read
         
     | 
| 
       19 
19 
     | 
    
         
             
              ensure
         
     | 
| 
       20 
20 
     | 
    
         
             
                $stdout = orig_stdout
         
     | 
| 
       21 
21 
     | 
    
         
             
                timer&.stop
         
     | 
| 
         @@ -29,7 +29,7 @@ class KernelTest < MiniTest::Test 
     | 
|
| 
       29 
29 
     | 
    
         
             
                assert(counter >= 2)
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
31 
     | 
    
         
             
                result = `echo "hello"`
         
     | 
| 
       32 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 32 
     | 
    
         
            +
                assert_equal "hello\n", result
         
     | 
| 
       33 
33 
     | 
    
         
             
              ensure
         
     | 
| 
       34 
34 
     | 
    
         
             
                timer&.stop
         
     | 
| 
       35 
35 
     | 
    
         
             
              end
         
     | 
    
        data/test/test_signal.rb
    CHANGED
    
    
    
        data/test/test_supervisor.rb
    CHANGED
    
    | 
         @@ -13,7 +13,7 @@ class SupervisorTest < MiniTest::Test 
     | 
|
| 
       13 
13 
     | 
    
         
             
                assert_equal [:foo], result
         
     | 
| 
       14 
14 
     | 
    
         
             
              end
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
              def  
     | 
| 
      
 16 
     | 
    
         
            +
              def test_await_multiple_fibers
         
     | 
| 
       17 
17 
     | 
    
         
             
                result = Polyphony::Supervisor.new.await { |s|
         
     | 
| 
       18 
18 
     | 
    
         
             
                  (1..3).each { |i|
         
     | 
| 
       19 
19 
     | 
    
         
             
                    s.spin {
         
     | 
| 
         @@ -25,7 +25,7 @@ class SupervisorTest < MiniTest::Test 
     | 
|
| 
       25 
25 
     | 
    
         
             
                assert_equal [10, 20, 30], result
         
     | 
| 
       26 
26 
     | 
    
         
             
              end
         
     | 
| 
       27 
27 
     | 
    
         | 
| 
       28 
     | 
    
         
            -
              def  
     | 
| 
      
 28 
     | 
    
         
            +
              def test_join_multiple_fibers
         
     | 
| 
       29 
29 
     | 
    
         
             
                result = Polyphony::Supervisor.new.join { |s|
         
     | 
| 
       30 
30 
     | 
    
         
             
                  (1..3).each { |i|
         
     | 
| 
       31 
31 
     | 
    
         
             
                    s.spin {
         
     | 
| 
         @@ -48,24 +48,24 @@ class SupervisorTest < MiniTest::Test 
     | 
|
| 
       48 
48 
     | 
    
         
             
                  }
         
     | 
| 
       49 
49 
     | 
    
         
             
                }
         
     | 
| 
       50 
50 
     | 
    
         | 
| 
       51 
     | 
    
         
            -
                assert_equal [ 
     | 
| 
      
 51 
     | 
    
         
            +
                assert_equal [Fiber], buffer.map { |v| v.class }.uniq
         
     | 
| 
       52 
52 
     | 
    
         
             
              end
         
     | 
| 
       53 
53 
     | 
    
         | 
| 
       54 
54 
     | 
    
         
             
              def test_supervisor_select
         
     | 
| 
       55 
55 
     | 
    
         
             
                buffer = []
         
     | 
| 
       56 
     | 
    
         
            -
                 
     | 
| 
       57 
     | 
    
         
            -
                result,  
     | 
| 
       58 
     | 
    
         
            -
                   
     | 
| 
       59 
     | 
    
         
            -
                   
     | 
| 
       60 
     | 
    
         
            -
                   
     | 
| 
      
 56 
     | 
    
         
            +
                foo_f = bar_f = baz_f = nil
         
     | 
| 
      
 57 
     | 
    
         
            +
                result, f = Polyphony::Supervisor.new.select { |s|
         
     | 
| 
      
 58 
     | 
    
         
            +
                  foo_f = s.spin { sleep 0.01; buffer << :foo; :foo }
         
     | 
| 
      
 59 
     | 
    
         
            +
                  bar_f = s.spin { sleep 0.02; buffer << :bar; :bar }
         
     | 
| 
      
 60 
     | 
    
         
            +
                  baz_f = s.spin { sleep 0.03; buffer << :baz; :baz }
         
     | 
| 
       61 
61 
     | 
    
         
             
                }
         
     | 
| 
       62 
62 
     | 
    
         | 
| 
       63 
63 
     | 
    
         
             
                assert_equal :foo, result
         
     | 
| 
       64 
     | 
    
         
            -
                assert_equal  
     | 
| 
      
 64 
     | 
    
         
            +
                assert_equal foo_f, f
         
     | 
| 
       65 
65 
     | 
    
         | 
| 
       66 
66 
     | 
    
         
             
                sleep 0.03
         
     | 
| 
       67 
     | 
    
         
            -
                 
     | 
| 
       68 
     | 
    
         
            -
                 
     | 
| 
      
 67 
     | 
    
         
            +
                assert !bar_f.running?
         
     | 
| 
      
 68 
     | 
    
         
            +
                assert !baz_f.running?
         
     | 
| 
       69 
69 
     | 
    
         
             
                assert_equal [:foo], buffer
         
     | 
| 
       70 
70 
     | 
    
         
             
              end
         
     | 
| 
       71 
71 
     | 
    
         | 
| 
         @@ -137,31 +137,31 @@ class SupervisorTest < MiniTest::Test 
     | 
|
| 
       137 
137 
     | 
    
         
             
              end
         
     | 
| 
       138 
138 
     | 
    
         
             
            end
         
     | 
| 
       139 
139 
     | 
    
         | 
| 
       140 
     | 
    
         
            -
            class  
     | 
| 
      
 140 
     | 
    
         
            +
            class FiberExtensionsTest < MiniTest::Test
         
     | 
| 
       141 
141 
     | 
    
         
             
              def test_join
         
     | 
| 
       142 
     | 
    
         
            -
                 
     | 
| 
       143 
     | 
    
         
            -
                 
     | 
| 
       144 
     | 
    
         
            -
                assert_equal [:foo, :bar],  
     | 
| 
      
 142 
     | 
    
         
            +
                f1 = spin { :foo }
         
     | 
| 
      
 143 
     | 
    
         
            +
                f2 = spin { :bar }
         
     | 
| 
      
 144 
     | 
    
         
            +
                assert_equal [:foo, :bar], Fiber.join(f1, f2)
         
     | 
| 
       145 
145 
     | 
    
         | 
| 
       146 
     | 
    
         
            -
                 
     | 
| 
       147 
     | 
    
         
            -
                 
     | 
| 
       148 
     | 
    
         
            -
                result = capture_exception {  
     | 
| 
      
 146 
     | 
    
         
            +
                f1 = spin { :foo }
         
     | 
| 
      
 147 
     | 
    
         
            +
                f2 = spin { raise 'bar' }
         
     | 
| 
      
 148 
     | 
    
         
            +
                result = capture_exception { Fiber.join(f1, f2) }
         
     | 
| 
       149 
149 
     | 
    
         
             
                assert_kind_of RuntimeError, result
         
     | 
| 
       150 
150 
     | 
    
         
             
                assert_equal 'bar', result.message
         
     | 
| 
       151 
151 
     | 
    
         
             
              end
         
     | 
| 
       152 
152 
     | 
    
         | 
| 
       153 
153 
     | 
    
         
             
              def test_select
         
     | 
| 
       154 
     | 
    
         
            -
                 
     | 
| 
       155 
     | 
    
         
            -
                 
     | 
| 
       156 
     | 
    
         
            -
                assert_equal [:bar,  
     | 
| 
      
 154 
     | 
    
         
            +
                f1 = spin { sleep 1; :foo }
         
     | 
| 
      
 155 
     | 
    
         
            +
                f2 = spin { :bar }
         
     | 
| 
      
 156 
     | 
    
         
            +
                assert_equal [:bar, f2], Fiber.select(f1, f2)
         
     | 
| 
       157 
157 
     | 
    
         | 
| 
       158 
     | 
    
         
            -
                 
     | 
| 
       159 
     | 
    
         
            -
                 
     | 
| 
       160 
     | 
    
         
            -
                assert_equal [:foo,  
     | 
| 
      
 158 
     | 
    
         
            +
                f1 = spin { :foo }
         
     | 
| 
      
 159 
     | 
    
         
            +
                f2 = spin { sleep 0.01; raise 'bar' }
         
     | 
| 
      
 160 
     | 
    
         
            +
                assert_equal [:foo, f1], Fiber.select(f1, f2)
         
     | 
| 
       161 
161 
     | 
    
         | 
| 
       162 
     | 
    
         
            -
                 
     | 
| 
       163 
     | 
    
         
            -
                 
     | 
| 
       164 
     | 
    
         
            -
                result = capture_exception {  
     | 
| 
      
 162 
     | 
    
         
            +
                f1 = spin { sleep 1; :foo }
         
     | 
| 
      
 163 
     | 
    
         
            +
                f2 = spin { raise 'bar' }
         
     | 
| 
      
 164 
     | 
    
         
            +
                result = capture_exception { Fiber.select(f1, f2) }
         
     | 
| 
       165 
165 
     | 
    
         
             
                assert_kind_of RuntimeError, result
         
     | 
| 
       166 
166 
     | 
    
         
             
                assert_equal 'bar', result.message
         
     | 
| 
       167 
167 
     | 
    
         
             
              end
         
     | 
    
        data/test/test_timer.rb
    CHANGED
    
    | 
         @@ -11,7 +11,7 @@ class TimerTest < MiniTest::Test 
     | 
|
| 
       11 
11 
     | 
    
         
             
                  count += 1
         
     | 
| 
       12 
12 
     | 
    
         
             
                }
         
     | 
| 
       13 
13 
     | 
    
         
             
                suspend
         
     | 
| 
       14 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 14 
     | 
    
         
            +
                assert_equal 1, count
         
     | 
| 
       15 
15 
     | 
    
         
             
              end
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
17 
     | 
    
         
             
              def test_that_repeating_timer_works
         
     | 
| 
         @@ -25,7 +25,7 @@ class TimerTest < MiniTest::Test 
     | 
|
| 
       25 
25 
     | 
    
         
             
                  }
         
     | 
| 
       26 
26 
     | 
    
         
             
                }
         
     | 
| 
       27 
27 
     | 
    
         
             
                suspend
         
     | 
| 
       28 
     | 
    
         
            -
                assert_equal 
     | 
| 
      
 28 
     | 
    
         
            +
                assert_equal 3, count
         
     | 
| 
       29 
29 
     | 
    
         
             
              end
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
31 
     | 
    
         
             
              def test_that_repeating_timer_compensates_for_drift
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: polyphony
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: '0. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: '0.25'
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Sharon Rosner
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2020-01- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2020-01-10 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: modulation
         
     | 
| 
         @@ -194,13 +194,13 @@ files: 
     | 
|
| 
       194 
194 
     | 
    
         
             
            - docs/technical-overview/faq.md
         
     | 
| 
       195 
195 
     | 
    
         
             
            - docs/technical-overview/fiber-scheduling.md
         
     | 
| 
       196 
196 
     | 
    
         
             
            - docs/user-guide/web-server.md
         
     | 
| 
       197 
     | 
    
         
            -
            - examples/core/01-spinning-up- 
     | 
| 
       198 
     | 
    
         
            -
            - examples/core/02-awaiting- 
     | 
| 
      
 197 
     | 
    
         
            +
            - examples/core/01-spinning-up-fibers.rb
         
     | 
| 
      
 198 
     | 
    
         
            +
            - examples/core/02-awaiting-fibers.rb
         
     | 
| 
       199 
199 
     | 
    
         
             
            - examples/core/03-interrupting.rb
         
     | 
| 
       200 
     | 
    
         
            -
            - examples/core/04-no-auto-run.rb
         
     | 
| 
       201 
200 
     | 
    
         
             
            - examples/core/xx-channels.rb
         
     | 
| 
       202 
201 
     | 
    
         
             
            - examples/core/xx-deferring-an-operation.rb
         
     | 
| 
       203 
202 
     | 
    
         
             
            - examples/core/xx-erlang-style-genserver.rb
         
     | 
| 
      
 203 
     | 
    
         
            +
            - examples/core/xx-extended_fibers.rb
         
     | 
| 
       204 
204 
     | 
    
         
             
            - examples/core/xx-forking.rb
         
     | 
| 
       205 
205 
     | 
    
         
             
            - examples/core/xx-move_on.rb
         
     | 
| 
       206 
206 
     | 
    
         
             
            - examples/core/xx-recurrent-timer.rb
         
     | 
| 
         @@ -277,7 +277,6 @@ files: 
     | 
|
| 
       277 
277 
     | 
    
         
             
            - lib/polyphony.rb
         
     | 
| 
       278 
278 
     | 
    
         
             
            - lib/polyphony/core/cancel_scope.rb
         
     | 
| 
       279 
279 
     | 
    
         
             
            - lib/polyphony/core/channel.rb
         
     | 
| 
       280 
     | 
    
         
            -
            - lib/polyphony/core/coprocess.rb
         
     | 
| 
       281 
280 
     | 
    
         
             
            - lib/polyphony/core/exceptions.rb
         
     | 
| 
       282 
281 
     | 
    
         
             
            - lib/polyphony/core/global_api.rb
         
     | 
| 
       283 
282 
     | 
    
         
             
            - lib/polyphony/core/resource_pool.rb
         
     | 
| 
         @@ -287,6 +286,7 @@ files: 
     | 
|
| 
       287 
286 
     | 
    
         
             
            - lib/polyphony/core/thread_pool.rb
         
     | 
| 
       288 
287 
     | 
    
         
             
            - lib/polyphony/core/throttler.rb
         
     | 
| 
       289 
288 
     | 
    
         
             
            - lib/polyphony/extensions/core.rb
         
     | 
| 
      
 289 
     | 
    
         
            +
            - lib/polyphony/extensions/fiber.rb
         
     | 
| 
       290 
290 
     | 
    
         
             
            - lib/polyphony/extensions/io.rb
         
     | 
| 
       291 
291 
     | 
    
         
             
            - lib/polyphony/extensions/openssl.rb
         
     | 
| 
       292 
292 
     | 
    
         
             
            - lib/polyphony/extensions/socket.rb
         
     | 
| 
         @@ -303,7 +303,7 @@ files: 
     | 
|
| 
       303 
303 
     | 
    
         
             
            - test/run.rb
         
     | 
| 
       304 
304 
     | 
    
         
             
            - test/test_async.rb
         
     | 
| 
       305 
305 
     | 
    
         
             
            - test/test_cancel_scope.rb
         
     | 
| 
       306 
     | 
    
         
            -
            - test/ 
     | 
| 
      
 306 
     | 
    
         
            +
            - test/test_fiber.rb
         
     | 
| 
       307 
307 
     | 
    
         
             
            - test/test_global_api.rb
         
     | 
| 
       308 
308 
     | 
    
         
             
            - test/test_gyro.rb
         
     | 
| 
       309 
309 
     | 
    
         
             
            - test/test_io.rb
         
     | 
| 
         @@ -1,16 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frozen_string_literal: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            require 'bundler/setup'
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            require 'polyphony'
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
            def nap(tag, t)
         
     | 
| 
       8 
     | 
    
         
            -
              puts "#{Time.now} #{tag} napping for #{t} seconds..."
         
     | 
| 
       9 
     | 
    
         
            -
              sleep t
         
     | 
| 
       10 
     | 
    
         
            -
              puts "#{Time.now} #{tag} done napping"
         
     | 
| 
       11 
     | 
    
         
            -
            end
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
            spin { nap(:a, 1) }
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
            # Wait for any coprocess still alive
         
     | 
| 
       16 
     | 
    
         
            -
            suspend
         
     | 
| 
         @@ -1,168 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frozen_string_literal: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            export_default :Coprocess
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            import '../extensions/core'
         
     | 
| 
       6 
     | 
    
         
            -
            Exceptions = import './exceptions'
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
            # Encapsulates an asynchronous task
         
     | 
| 
       9 
     | 
    
         
            -
            class Coprocess
         
     | 
| 
       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 
     | 
    
         
            -
              @@map = {}
         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
              def self.map
         
     | 
| 
       47 
     | 
    
         
            -
                @@map
         
     | 
| 
       48 
     | 
    
         
            -
              end
         
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
              def self.count
         
     | 
| 
       51 
     | 
    
         
            -
                @@map.size
         
     | 
| 
       52 
     | 
    
         
            -
              end
         
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
              attr_reader :result, :fiber
         
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
              def initialize(fiber = nil, &block)
         
     | 
| 
       57 
     | 
    
         
            -
                @fiber = fiber
         
     | 
| 
       58 
     | 
    
         
            -
                @block = block
         
     | 
| 
       59 
     | 
    
         
            -
              end
         
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
              def location
         
     | 
| 
       62 
     | 
    
         
            -
                @block ? @block.source_location.join(':') : nil
         
     | 
| 
       63 
     | 
    
         
            -
              end
         
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
       65 
     | 
    
         
            -
              def caller
         
     | 
| 
       66 
     | 
    
         
            -
                @fiber ? @fiber.caller[2..-1] : nil
         
     | 
| 
       67 
     | 
    
         
            -
              end
         
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
              def run
         
     | 
| 
       70 
     | 
    
         
            -
                @calling_fiber = Fiber.current
         
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
     | 
    
         
            -
                @fiber = Fiber.new(location) { |v| execute(v) }
         
     | 
| 
       73 
     | 
    
         
            -
                @fiber.schedule
         
     | 
| 
       74 
     | 
    
         
            -
                @ran = true
         
     | 
| 
       75 
     | 
    
         
            -
                self
         
     | 
| 
       76 
     | 
    
         
            -
              end
         
     | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
       78 
     | 
    
         
            -
              def execute(first_value)
         
     | 
| 
       79 
     | 
    
         
            -
                # The first value passed to the coprocess can be used to stop it before it
         
     | 
| 
       80 
     | 
    
         
            -
                # is scheduled for the first time
         
     | 
| 
       81 
     | 
    
         
            -
                raise first_value if first_value.is_a?(Exception)
         
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
                @@map[@fiber] = @fiber.coprocess = self
         
     | 
| 
       84 
     | 
    
         
            -
                @result = @block.call(self)
         
     | 
| 
       85 
     | 
    
         
            -
              rescue Exceptions::MoveOn => e
         
     | 
| 
       86 
     | 
    
         
            -
                @result = e.value
         
     | 
| 
       87 
     | 
    
         
            -
              rescue Exception => e
         
     | 
| 
       88 
     | 
    
         
            -
                uncaught_exception = true
         
     | 
| 
       89 
     | 
    
         
            -
                @result = e
         
     | 
| 
       90 
     | 
    
         
            -
              ensure
         
     | 
| 
       91 
     | 
    
         
            -
                finish_execution(uncaught_exception)
         
     | 
| 
       92 
     | 
    
         
            -
              end
         
     | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
       94 
     | 
    
         
            -
              def finish_execution(uncaught_exception)
         
     | 
| 
       95 
     | 
    
         
            -
                @@map.delete(@fiber)
         
     | 
| 
       96 
     | 
    
         
            -
                @fiber.coprocess = nil
         
     | 
| 
       97 
     | 
    
         
            -
                @fiber = nil
         
     | 
| 
       98 
     | 
    
         
            -
                @awaiting_fiber&.schedule @result
         
     | 
| 
       99 
     | 
    
         
            -
                @when_done&.()
         
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
                return unless uncaught_exception && !@awaiting_fiber
         
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
                # if no awaiting fiber, raise any uncaught error by passing it to the
         
     | 
| 
       104 
     | 
    
         
            -
                # calling fiber, or to the root fiber if the calling fiber
         
     | 
| 
       105 
     | 
    
         
            -
                calling_fiber_alive = @calling_fiber && @calling_fiber.state != :dead
         
     | 
| 
       106 
     | 
    
         
            -
                calling_fiber = calling_fiber_alive ? @calling_fiber : Fiber.root
         
     | 
| 
       107 
     | 
    
         
            -
                calling_fiber.transfer @result
         
     | 
| 
       108 
     | 
    
         
            -
              end
         
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
     | 
    
         
            -
              def alive?
         
     | 
| 
       111 
     | 
    
         
            -
                @fiber
         
     | 
| 
       112 
     | 
    
         
            -
              end
         
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
              # Kernel.await expects the given argument / block to be a callable, so #call
         
     | 
| 
       115 
     | 
    
         
            -
              # in fact waits for the coprocess to finish
         
     | 
| 
       116 
     | 
    
         
            -
              def await
         
     | 
| 
       117 
     | 
    
         
            -
                await_coprocess_result
         
     | 
| 
       118 
     | 
    
         
            -
              ensure
         
     | 
| 
       119 
     | 
    
         
            -
                # If the awaiting fiber has been transferred an exception, the awaited fiber
         
     | 
| 
       120 
     | 
    
         
            -
                # might still be running, so we need to stop it
         
     | 
| 
       121 
     | 
    
         
            -
                @fiber&.schedule(Exceptions::MoveOn.new)
         
     | 
| 
       122 
     | 
    
         
            -
              end
         
     | 
| 
       123 
     | 
    
         
            -
              alias_method :join, :await
         
     | 
| 
       124 
     | 
    
         
            -
             
     | 
| 
       125 
     | 
    
         
            -
              def await_coprocess_result
         
     | 
| 
       126 
     | 
    
         
            -
                run unless @ran
         
     | 
| 
       127 
     | 
    
         
            -
                if @fiber
         
     | 
| 
       128 
     | 
    
         
            -
                  @awaiting_fiber = Fiber.current
         
     | 
| 
       129 
     | 
    
         
            -
                  suspend
         
     | 
| 
       130 
     | 
    
         
            -
                else
         
     | 
| 
       131 
     | 
    
         
            -
                  @result
         
     | 
| 
       132 
     | 
    
         
            -
                end
         
     | 
| 
       133 
     | 
    
         
            -
              end
         
     | 
| 
       134 
     | 
    
         
            -
             
     | 
| 
       135 
     | 
    
         
            -
              def when_done(&block)
         
     | 
| 
       136 
     | 
    
         
            -
                @when_done = block
         
     | 
| 
       137 
     | 
    
         
            -
              end
         
     | 
| 
       138 
     | 
    
         
            -
             
     | 
| 
       139 
     | 
    
         
            -
              def schedule(value = nil)
         
     | 
| 
       140 
     | 
    
         
            -
                @fiber&.schedule(value)
         
     | 
| 
       141 
     | 
    
         
            -
              end
         
     | 
| 
       142 
     | 
    
         
            -
             
     | 
| 
       143 
     | 
    
         
            -
              def resume(value = nil)
         
     | 
| 
       144 
     | 
    
         
            -
                return unless @fiber
         
     | 
| 
       145 
     | 
    
         
            -
             
     | 
| 
       146 
     | 
    
         
            -
                @fiber.schedule(value)
         
     | 
| 
       147 
     | 
    
         
            -
                snooze
         
     | 
| 
       148 
     | 
    
         
            -
              end
         
     | 
| 
       149 
     | 
    
         
            -
             
     | 
| 
       150 
     | 
    
         
            -
              def interrupt(value = nil)
         
     | 
| 
       151 
     | 
    
         
            -
                return unless @fiber
         
     | 
| 
       152 
     | 
    
         
            -
             
     | 
| 
       153 
     | 
    
         
            -
                @fiber.schedule(Exceptions::MoveOn.new(nil, value))
         
     | 
| 
       154 
     | 
    
         
            -
                snooze
         
     | 
| 
       155 
     | 
    
         
            -
              end
         
     | 
| 
       156 
     | 
    
         
            -
              alias_method :stop, :interrupt
         
     | 
| 
       157 
     | 
    
         
            -
             
     | 
| 
       158 
     | 
    
         
            -
              def cancel!
         
     | 
| 
       159 
     | 
    
         
            -
                return unless @fiber
         
     | 
| 
       160 
     | 
    
         
            -
             
     | 
| 
       161 
     | 
    
         
            -
                @fiber.schedule(Exceptions::Cancel.new)
         
     | 
| 
       162 
     | 
    
         
            -
                snooze
         
     | 
| 
       163 
     | 
    
         
            -
              end
         
     | 
| 
       164 
     | 
    
         
            -
             
     | 
| 
       165 
     | 
    
         
            -
              def self.current
         
     | 
| 
       166 
     | 
    
         
            -
                Fiber.current.coprocess
         
     | 
| 
       167 
     | 
    
         
            -
              end
         
     | 
| 
       168 
     | 
    
         
            -
            end
         
     |