polyphony 0.28 → 0.29
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/.rubocop.yml +0 -4
 - data/CHANGELOG.md +12 -0
 - data/Gemfile.lock +1 -1
 - data/LICENSE +1 -1
 - data/README.md +23 -21
 - data/Rakefile +2 -0
 - data/TODO.md +0 -3
 - data/docs/_includes/prevnext.html +17 -0
 - data/docs/_layouts/default.html +106 -0
 - data/docs/_sass/custom/custom.scss +21 -0
 - data/docs/faq.md +13 -10
 - data/docs/getting-started/installing.md +2 -0
 - data/docs/getting-started/tutorial.md +5 -3
 - data/docs/index.md +4 -5
 - data/docs/technical-overview/concurrency.md +21 -19
 - data/docs/technical-overview/design-principles.md +12 -20
 - data/docs/technical-overview/exception-handling.md +70 -1
 - data/docs/technical-overview/extending.md +1 -0
 - data/docs/technical-overview/fiber-scheduling.md +109 -88
 - data/docs/user-guide/all-about-timers.md +126 -0
 - data/docs/user-guide/web-server.md +2 -2
 - data/docs/user-guide.md +1 -1
 - data/examples/core/xx-deferring-an-operation.rb +2 -2
 - data/examples/core/xx-sleep-forever.rb +9 -0
 - data/examples/core/xx-snooze-starve.rb +16 -0
 - data/examples/core/xx-spin_error_backtrace.rb +1 -1
 - data/examples/core/xx-trace.rb +1 -2
 - data/examples/core/xx-worker-thread.rb +30 -0
 - data/examples/io/xx-happy-eyeballs.rb +37 -0
 - data/ext/gyro/gyro.c +8 -3
 - data/ext/gyro/gyro.h +7 -1
 - data/ext/gyro/queue.c +35 -3
 - data/ext/gyro/selector.c +31 -2
 - data/ext/gyro/thread.c +18 -16
 - data/lib/polyphony/core/global_api.rb +0 -1
 - data/lib/polyphony/core/thread_pool.rb +5 -0
 - data/lib/polyphony/core/throttler.rb +0 -1
 - data/lib/polyphony/extensions/fiber.rb +14 -3
 - data/lib/polyphony/extensions/thread.rb +16 -4
 - data/lib/polyphony/irb.rb +7 -1
 - data/lib/polyphony/trace.rb +44 -11
 - data/lib/polyphony/version.rb +1 -1
 - data/lib/polyphony.rb +1 -0
 - data/test/helper.rb +1 -3
 - data/test/test_async.rb +1 -1
 - data/test/test_cancel_scope.rb +3 -3
 - data/test/test_fiber.rb +157 -54
 - data/test/test_global_api.rb +51 -1
 - data/test/test_gyro.rb +4 -156
 - data/test/test_io.rb +1 -1
 - data/test/test_supervisor.rb +2 -2
 - data/test/test_thread.rb +72 -1
 - data/test/test_thread_pool.rb +6 -2
 - data/test/test_throttler.rb +7 -5
 - data/test/test_trace.rb +6 -6
 - metadata +10 -5
 - data/examples/core/xx-extended_fibers.rb +0 -150
 - data/examples/core/xx-mt-scheduler.rb +0 -349
 
    
        data/ext/gyro/selector.c
    CHANGED
    
    | 
         @@ -2,6 +2,7 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            struct Gyro_Selector {
         
     | 
| 
       4 
4 
     | 
    
         
             
              struct  ev_loop *ev_loop;
         
     | 
| 
      
 5 
     | 
    
         
            +
              long run_no_wait_count;
         
     | 
| 
       5 
6 
     | 
    
         
             
            };
         
     | 
| 
       6 
7 
     | 
    
         | 
| 
       7 
8 
     | 
    
         
             
            VALUE cGyro_Selector = Qnil;
         
     | 
| 
         @@ -52,6 +53,13 @@ inline struct ev_loop *Gyro_Selector_current_thread_ev_loop() { 
     | 
|
| 
       52 
53 
     | 
    
         
             
              return selector->ev_loop;
         
     | 
| 
       53 
54 
     | 
    
         
             
            }
         
     | 
| 
       54 
55 
     | 
    
         | 
| 
      
 56 
     | 
    
         
            +
            inline ev_tstamp Gyro_Selector_now(VALUE self) {
         
     | 
| 
      
 57 
     | 
    
         
            +
              struct Gyro_Selector *selector;
         
     | 
| 
      
 58 
     | 
    
         
            +
              GetGyro_Selector(self, selector);
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
              return ev_now(selector->ev_loop);
         
     | 
| 
      
 61 
     | 
    
         
            +
            }
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
       55 
63 
     | 
    
         
             
            long Gyro_Selector_pending_count(VALUE self) {
         
     | 
| 
       56 
64 
     | 
    
         
             
              struct Gyro_Selector *selector;
         
     | 
| 
       57 
65 
     | 
    
         
             
              GetGyro_Selector(self, selector);
         
     | 
| 
         @@ -65,19 +73,40 @@ static VALUE Gyro_Selector_initialize(VALUE self, VALUE thread) { 
     | 
|
| 
       65 
73 
     | 
    
         | 
| 
       66 
74 
     | 
    
         
             
              int use_default_loop = (rb_thread_current() == rb_thread_main());
         
     | 
| 
       67 
75 
     | 
    
         
             
              selector->ev_loop = use_default_loop ? EV_DEFAULT : ev_loop_new(EVFLAG_NOSIGMASK);
         
     | 
| 
      
 76 
     | 
    
         
            +
              selector->run_no_wait_count = 0;
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
              ev_run(selector->ev_loop, EVRUN_NOWAIT);
         
     | 
| 
       68 
79 
     | 
    
         | 
| 
       69 
80 
     | 
    
         
             
              return Qnil;
         
     | 
| 
       70 
81 
     | 
    
         
             
            }
         
     | 
| 
       71 
82 
     | 
    
         | 
| 
       72 
     | 
    
         
            -
            inline VALUE Gyro_Selector_run(VALUE self) {
         
     | 
| 
      
 83 
     | 
    
         
            +
            inline VALUE Gyro_Selector_run(VALUE self, VALUE current_fiber) {
         
     | 
| 
       73 
84 
     | 
    
         
             
              struct Gyro_Selector *selector;
         
     | 
| 
       74 
85 
     | 
    
         
             
              GetGyro_Selector(self, selector);
         
     | 
| 
       75 
86 
     | 
    
         
             
              if (selector->ev_loop) {
         
     | 
| 
      
 87 
     | 
    
         
            +
                selector->run_no_wait_count = 0;
         
     | 
| 
      
 88 
     | 
    
         
            +
                FIBER_TRACE(2, SYM_fiber_ev_loop_enter, current_fiber);
         
     | 
| 
       76 
89 
     | 
    
         
             
                ev_run(selector->ev_loop, EVRUN_ONCE);
         
     | 
| 
      
 90 
     | 
    
         
            +
                FIBER_TRACE(2, SYM_fiber_ev_loop_leave, current_fiber);
         
     | 
| 
       77 
91 
     | 
    
         
             
              }
         
     | 
| 
       78 
92 
     | 
    
         
             
              return Qnil;
         
     | 
| 
       79 
93 
     | 
    
         
             
            }
         
     | 
| 
       80 
94 
     | 
    
         | 
| 
      
 95 
     | 
    
         
            +
            inline void Gyro_Selector_run_no_wait(VALUE self, VALUE current_fiber, long runnable_count) {
         
     | 
| 
      
 96 
     | 
    
         
            +
              struct Gyro_Selector *selector;
         
     | 
| 
      
 97 
     | 
    
         
            +
              GetGyro_Selector(self, selector);
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
              selector->run_no_wait_count++;
         
     | 
| 
      
 100 
     | 
    
         
            +
              if (selector->run_no_wait_count < runnable_count || selector->run_no_wait_count < 10) {
         
     | 
| 
      
 101 
     | 
    
         
            +
                return;
         
     | 
| 
      
 102 
     | 
    
         
            +
              }
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
              selector->run_no_wait_count = 0;
         
     | 
| 
      
 105 
     | 
    
         
            +
              FIBER_TRACE(2, SYM_fiber_ev_loop_enter, current_fiber);
         
     | 
| 
      
 106 
     | 
    
         
            +
              ev_run(selector->ev_loop, EVRUN_NOWAIT);
         
     | 
| 
      
 107 
     | 
    
         
            +
              FIBER_TRACE(2, SYM_fiber_ev_loop_leave, current_fiber);
         
     | 
| 
      
 108 
     | 
    
         
            +
            }
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
       81 
110 
     | 
    
         
             
            VALUE Gyro_Selector_stop(VALUE self) {
         
     | 
| 
       82 
111 
     | 
    
         
             
              struct Gyro_Selector *selector;
         
     | 
| 
       83 
112 
     | 
    
         
             
              GetGyro_Selector(self, selector);
         
     | 
| 
         @@ -109,7 +138,7 @@ void Init_Gyro_Selector() { 
     | 
|
| 
       109 
138 
     | 
    
         
             
              rb_define_alloc_func(cGyro_Selector, Gyro_Selector_allocate);
         
     | 
| 
       110 
139 
     | 
    
         | 
| 
       111 
140 
     | 
    
         
             
              rb_define_method(cGyro_Selector, "initialize", Gyro_Selector_initialize, 1);
         
     | 
| 
       112 
     | 
    
         
            -
              rb_define_method(cGyro_Selector, "run", Gyro_Selector_run,  
     | 
| 
      
 141 
     | 
    
         
            +
              rb_define_method(cGyro_Selector, "run", Gyro_Selector_run, 1);
         
     | 
| 
       113 
142 
     | 
    
         
             
              rb_define_method(cGyro_Selector, "stop", Gyro_Selector_stop, 0);
         
     | 
| 
       114 
143 
     | 
    
         
             
              rb_define_method(cGyro_Selector, "wait_readable", Gyro_Selector_wait_readable, 1);
         
     | 
| 
       115 
144 
     | 
    
         
             
              rb_define_method(cGyro_Selector, "wait_writable", Gyro_Selector_wait_writable, 1);
         
     | 
    
        data/ext/gyro/thread.c
    CHANGED
    
    | 
         @@ -98,13 +98,16 @@ static VALUE Thread_fiber_scheduling_stats(VALUE self) { 
     | 
|
| 
       98 
98 
     | 
    
         
             
            }
         
     | 
| 
       99 
99 
     | 
    
         | 
| 
       100 
100 
     | 
    
         
             
            inline VALUE Thread_schedule_fiber(VALUE self, VALUE fiber, VALUE value) {
         
     | 
| 
      
 101 
     | 
    
         
            +
              FIBER_TRACE(3, SYM_fiber_schedule, fiber, value);
         
     | 
| 
       101 
102 
     | 
    
         
             
              // if fiber is already scheduled, just set the scheduled value, then return
         
     | 
| 
       102 
103 
     | 
    
         
             
              rb_ivar_set(fiber, ID_runnable_value, value);
         
     | 
| 
       103 
     | 
    
         
            -
              if (rb_ivar_get(fiber, ID_runnable)  
     | 
| 
       104 
     | 
    
         
            -
                 
     | 
| 
       105 
     | 
    
         
            -
                rb_ary_push(queue, fiber);
         
     | 
| 
       106 
     | 
    
         
            -
                rb_ivar_set(fiber, ID_runnable, Qtrue);
         
     | 
| 
      
 104 
     | 
    
         
            +
              if (rb_ivar_get(fiber, ID_runnable) != Qnil) {
         
     | 
| 
      
 105 
     | 
    
         
            +
                return self;
         
     | 
| 
       107 
106 
     | 
    
         
             
              }
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
              VALUE queue = rb_ivar_get(self, ID_run_queue);
         
     | 
| 
      
 109 
     | 
    
         
            +
              rb_ary_push(queue, fiber);
         
     | 
| 
      
 110 
     | 
    
         
            +
              rb_ivar_set(fiber, ID_runnable, Qtrue);
         
     | 
| 
       108 
111 
     | 
    
         
             
              return self;
         
     | 
| 
       109 
112 
     | 
    
         
             
            }
         
     | 
| 
       110 
113 
     | 
    
         | 
| 
         @@ -118,6 +121,7 @@ VALUE Thread_switch_fiber(VALUE self) { 
     | 
|
| 
       118 
121 
     | 
    
         
             
              }
         
     | 
| 
       119 
122 
     | 
    
         
             
              VALUE queue = rb_ivar_get(self, ID_run_queue);
         
     | 
| 
       120 
123 
     | 
    
         
             
              VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
       121 
125 
     | 
    
         
             
              VALUE next_fiber;
         
     | 
| 
       122 
126 
     | 
    
         | 
| 
       123 
127 
     | 
    
         
             
              while (1) {
         
     | 
| 
         @@ -125,17 +129,18 @@ VALUE Thread_switch_fiber(VALUE self) { 
     | 
|
| 
       125 
129 
     | 
    
         
             
                // if (break_flag != 0) {
         
     | 
| 
       126 
130 
     | 
    
         
             
                //   return Qnil;
         
     | 
| 
       127 
131 
     | 
    
         
             
                // }
         
     | 
| 
       128 
     | 
    
         
            -
                 
     | 
| 
      
 132 
     | 
    
         
            +
                int ref_count = Thread_fiber_ref_count(self);
         
     | 
| 
      
 133 
     | 
    
         
            +
                if (next_fiber != Qnil) {
         
     | 
| 
      
 134 
     | 
    
         
            +
                  if (ref_count > 0) {
         
     | 
| 
      
 135 
     | 
    
         
            +
                    Gyro_Selector_run_no_wait(selector, current_fiber, RARRAY_LEN(queue));
         
     | 
| 
      
 136 
     | 
    
         
            +
                  }
         
     | 
| 
       129 
137 
     | 
    
         
             
                  break;
         
     | 
| 
       130 
138 
     | 
    
         
             
                }
         
     | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
       132 
     | 
    
         
            -
             
     | 
| 
       133 
     | 
    
         
            -
                  rb_funcall(rb_cObject, ID_fiber_trace, 2, SYM_fiber_ev_loop_enter, current_fiber);
         
     | 
| 
       134 
     | 
    
         
            -
                }
         
     | 
| 
       135 
     | 
    
         
            -
                Gyro_Selector_run(selector);
         
     | 
| 
       136 
     | 
    
         
            -
                if (__tracing_enabled__) {
         
     | 
| 
       137 
     | 
    
         
            -
                  rb_funcall(rb_cObject, ID_fiber_trace, 2, SYM_fiber_ev_loop_leave, current_fiber);
         
     | 
| 
      
 139 
     | 
    
         
            +
                if (ref_count == 0) {
         
     | 
| 
      
 140 
     | 
    
         
            +
                  break;
         
     | 
| 
       138 
141 
     | 
    
         
             
                }
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                Gyro_Selector_run(selector, current_fiber);
         
     | 
| 
       139 
144 
     | 
    
         
             
              }
         
     | 
| 
       140 
145 
     | 
    
         | 
| 
       141 
146 
     | 
    
         
             
              if (next_fiber == Qnil) {
         
     | 
| 
         @@ -144,10 +149,7 @@ VALUE Thread_switch_fiber(VALUE self) { 
     | 
|
| 
       144 
149 
     | 
    
         | 
| 
       145 
150 
     | 
    
         
             
              // run next fiber
         
     | 
| 
       146 
151 
     | 
    
         
             
              VALUE value = rb_ivar_get(next_fiber, ID_runnable_value);
         
     | 
| 
       147 
     | 
    
         
            -
             
     | 
| 
       148 
     | 
    
         
            -
              if (__tracing_enabled__) {
         
     | 
| 
       149 
     | 
    
         
            -
                rb_funcall(rb_cObject, ID_fiber_trace, 3, SYM_fiber_run, next_fiber, value);
         
     | 
| 
       150 
     | 
    
         
            -
              }
         
     | 
| 
      
 152 
     | 
    
         
            +
              FIBER_TRACE(3, SYM_fiber_run, next_fiber, value);
         
     | 
| 
       151 
153 
     | 
    
         | 
| 
       152 
154 
     | 
    
         
             
              rb_ivar_set(next_fiber, ID_runnable, Qnil);
         
     | 
| 
       153 
155 
     | 
    
         
             
              RB_GC_GUARD(next_fiber);
         
     | 
| 
         @@ -55,11 +55,12 @@ module FiberMessaging 
     | 
|
| 
       55 
55 
     | 
    
         
             
                if @receive_waiting && @running
         
     | 
| 
       56 
56 
     | 
    
         
             
                  schedule value
         
     | 
| 
       57 
57 
     | 
    
         
             
                else
         
     | 
| 
       58 
     | 
    
         
            -
                  @queued_messages ||=  
     | 
| 
      
 58 
     | 
    
         
            +
                  @queued_messages ||= Gyro::Queue.new
         
     | 
| 
       59 
59 
     | 
    
         
             
                  @queued_messages << value
         
     | 
| 
       60 
60 
     | 
    
         
             
                end
         
     | 
| 
       61 
61 
     | 
    
         
             
                snooze
         
     | 
| 
       62 
62 
     | 
    
         
             
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
              alias_method :send, :<<
         
     | 
| 
       63 
64 
     | 
    
         | 
| 
       64 
65 
     | 
    
         
             
              def receive
         
     | 
| 
       65 
66 
     | 
    
         
             
                if !@queued_messages || @queued_messages&.empty?
         
     | 
| 
         @@ -110,11 +111,11 @@ class ::Fiber 
     | 
|
| 
       110 
111 
     | 
    
         
             
                f
         
     | 
| 
       111 
112 
     | 
    
         
             
              end
         
     | 
| 
       112 
113 
     | 
    
         | 
| 
       113 
     | 
    
         
            -
              attr_accessor :tag
         
     | 
| 
       114 
     | 
    
         
            -
              Fiber.current.tag = :main
         
     | 
| 
      
 114 
     | 
    
         
            +
              attr_accessor :tag, :thread
         
     | 
| 
       115 
115 
     | 
    
         | 
| 
       116 
116 
     | 
    
         
             
              def setup(tag, block, caller)
         
     | 
| 
       117 
117 
     | 
    
         
             
                __fiber_trace__(:fiber_create, self)
         
     | 
| 
      
 118 
     | 
    
         
            +
                @thread = Thread.current
         
     | 
| 
       118 
119 
     | 
    
         
             
                @tag = tag
         
     | 
| 
       119 
120 
     | 
    
         
             
                @calling_fiber = Fiber.current
         
     | 
| 
       120 
121 
     | 
    
         
             
                @caller = caller
         
     | 
| 
         @@ -122,12 +123,20 @@ class ::Fiber 
     | 
|
| 
       122 
123 
     | 
    
         
             
                schedule
         
     | 
| 
       123 
124 
     | 
    
         
             
              end
         
     | 
| 
       124 
125 
     | 
    
         | 
| 
      
 126 
     | 
    
         
            +
              def setup_main_fiber
         
     | 
| 
      
 127 
     | 
    
         
            +
                @tag = :main
         
     | 
| 
      
 128 
     | 
    
         
            +
                @thread = Thread.current
         
     | 
| 
      
 129 
     | 
    
         
            +
                @running = true
         
     | 
| 
      
 130 
     | 
    
         
            +
              end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
       125 
132 
     | 
    
         
             
              def run(first_value)
         
     | 
| 
       126 
133 
     | 
    
         
             
                Kernel.raise first_value if first_value.is_a?(Exception)
         
     | 
| 
       127 
134 
     | 
    
         | 
| 
       128 
135 
     | 
    
         
             
                start_execution(first_value)
         
     | 
| 
       129 
136 
     | 
    
         
             
              rescue ::Interrupt, ::SystemExit => e
         
     | 
| 
       130 
137 
     | 
    
         
             
                Thread.current.main_fiber.transfer e.class.new
         
     | 
| 
      
 138 
     | 
    
         
            +
              rescue ::SignalException => e
         
     | 
| 
      
 139 
     | 
    
         
            +
                Thread.current.main_fiber.transfer e
         
     | 
| 
       131 
140 
     | 
    
         
             
              rescue Exceptions::MoveOn => e
         
     | 
| 
       132 
141 
     | 
    
         
             
                finish_execution(e.value)
         
     | 
| 
       133 
142 
     | 
    
         
             
              rescue Exception => e
         
     | 
| 
         @@ -187,3 +196,5 @@ class ::Fiber 
     | 
|
| 
       187 
196 
     | 
    
         
             
                end
         
     | 
| 
       188 
197 
     | 
    
         
             
              end
         
     | 
| 
       189 
198 
     | 
    
         
             
            end
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
            Fiber.current.setup_main_fiber
         
     | 
| 
         @@ -4,6 +4,10 @@ Exceptions = import '../core/exceptions' 
     | 
|
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            # Thread extensions
         
     | 
| 
       6 
6 
     | 
    
         
             
            class ::Thread
         
     | 
| 
      
 7 
     | 
    
         
            +
              def self.join_queue_mutex
         
     | 
| 
      
 8 
     | 
    
         
            +
                @join_queue_mutex ||= Mutex.new
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
       7 
11 
     | 
    
         
             
              attr_reader :main_fiber
         
     | 
| 
       8 
12 
     | 
    
         | 
| 
       9 
13 
     | 
    
         
             
              alias_method :orig_initialize, :initialize
         
     | 
| 
         @@ -11,10 +15,11 @@ class ::Thread 
     | 
|
| 
       11 
15 
     | 
    
         
             
                @join_wait_queue = Gyro::Queue.new
         
     | 
| 
       12 
16 
     | 
    
         
             
                @block = block
         
     | 
| 
       13 
17 
     | 
    
         
             
                orig_initialize do
         
     | 
| 
      
 18 
     | 
    
         
            +
                  Fiber.current.setup_main_fiber
         
     | 
| 
       14 
19 
     | 
    
         
             
                  setup_fiber_scheduling
         
     | 
| 
       15 
20 
     | 
    
         
             
                  block.(*args)
         
     | 
| 
       16 
     | 
    
         
            -
                  signal_waiters
         
     | 
| 
       17 
21 
     | 
    
         
             
                ensure
         
     | 
| 
      
 22 
     | 
    
         
            +
                  signal_waiters
         
     | 
| 
       18 
23 
     | 
    
         
             
                  stop_event_selector
         
     | 
| 
       19 
24 
     | 
    
         
             
                end
         
     | 
| 
       20 
25 
     | 
    
         
             
              end
         
     | 
| 
         @@ -25,10 +30,12 @@ class ::Thread 
     | 
|
| 
       25 
30 
     | 
    
         | 
| 
       26 
31 
     | 
    
         
             
              alias_method :orig_join, :join
         
     | 
| 
       27 
32 
     | 
    
         
             
              def join(timeout = nil)
         
     | 
| 
       28 
     | 
    
         
            -
                return unless alive?
         
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
33 
     | 
    
         
             
                async = Gyro::Async.new
         
     | 
| 
       31 
     | 
    
         
            -
                 
     | 
| 
      
 34 
     | 
    
         
            +
                Thread.join_queue_mutex.synchronize do
         
     | 
| 
      
 35 
     | 
    
         
            +
                  return unless alive?
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  @join_wait_queue << async
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
       32 
39 
     | 
    
         | 
| 
       33 
40 
     | 
    
         
             
                if timeout
         
     | 
| 
       34 
41 
     | 
    
         
             
                  move_on_after(timeout) { async.await }
         
     | 
| 
         @@ -49,4 +56,9 @@ class ::Thread 
     | 
|
| 
       49 
56 
     | 
    
         
             
              def location
         
     | 
| 
       50 
57 
     | 
    
         
             
                @block.source_location.join(':')
         
     | 
| 
       51 
58 
     | 
    
         
             
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
              def <<(value)
         
     | 
| 
      
 61 
     | 
    
         
            +
                main_fiber << value
         
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
              alias_method :send, :<<
         
     | 
| 
       52 
64 
     | 
    
         
             
            end
         
     | 
    
        data/lib/polyphony/irb.rb
    CHANGED
    
    | 
         @@ -7,7 +7,13 @@ require 'polyphony' 
     | 
|
| 
       7 
7 
     | 
    
         
             
            # readline to return
         
     | 
| 
       8 
8 
     | 
    
         
             
            module ::Readline
         
     | 
| 
       9 
9 
     | 
    
         
             
              alias_method :orig_readline, :readline
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
       10 
11 
     | 
    
         
             
              def readline(*args)
         
     | 
| 
       11 
     | 
    
         
            -
                 
     | 
| 
      
 12 
     | 
    
         
            +
                async = Gyro::Async.new
         
     | 
| 
      
 13 
     | 
    
         
            +
                Thread.new do
         
     | 
| 
      
 14 
     | 
    
         
            +
                  result = orig_readline(*args)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  async.signal!(result)
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
                async.await
         
     | 
| 
       12 
18 
     | 
    
         
             
              end
         
     | 
| 
       13 
19 
     | 
    
         
             
            end
         
     | 
    
        data/lib/polyphony/trace.rb
    CHANGED
    
    | 
         @@ -6,9 +6,10 @@ require 'polyphony' 
     | 
|
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            STOCK_EVENTS = %i[line call return c_call c_return b_call b_return].freeze
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
            def new
         
     | 
| 
      
 9 
     | 
    
         
            +
            def new(*events)
         
     | 
| 
       10 
10 
     | 
    
         
             
              start_stamp = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
         
     | 
| 
       11 
     | 
    
         
            -
               
     | 
| 
      
 11 
     | 
    
         
            +
              events = STOCK_EVENTS if events.empty?
         
     | 
| 
      
 12 
     | 
    
         
            +
              ::TracePoint.new(*events) { |tp| yield trace_record(tp, start_stamp) }
         
     | 
| 
       12 
13 
     | 
    
         
             
            end
         
     | 
| 
       13 
14 
     | 
    
         | 
| 
       14 
15 
     | 
    
         
             
            def trace_record(trp, start_stamp)
         
     | 
| 
         @@ -16,7 +17,7 @@ def trace_record(trp, start_stamp) 
     | 
|
| 
       16 
17 
     | 
    
         
             
              { stamp: stamp, self: trp.self, binding: trp.binding, event: trp.event,
         
     | 
| 
       17 
18 
     | 
    
         
             
                fiber: tp_fiber(trp), lineno: trp.lineno, method_id: trp.method_id,
         
     | 
| 
       18 
19 
     | 
    
         
             
                file: trp.path, parameters: tp_params(trp),
         
     | 
| 
       19 
     | 
    
         
            -
                return_value: tp_return_value(trp),
         
     | 
| 
      
 20 
     | 
    
         
            +
                return_value: tp_return_value(trp), schedule_value: tp_schedule_value(trp),
         
     | 
| 
       20 
21 
     | 
    
         
             
                exception: tp_raised_exception(trp) }
         
     | 
| 
       21 
22 
     | 
    
         
             
            end
         
     | 
| 
       22 
23 
     | 
    
         | 
| 
         @@ -36,6 +37,12 @@ def tp_return_value(trp) 
     | 
|
| 
       36 
37 
     | 
    
         
             
              RETURN_VALUE_EVENTS.include?(trp.event) ? trp.return_value : nil
         
     | 
| 
       37 
38 
     | 
    
         
             
            end
         
     | 
| 
       38 
39 
     | 
    
         | 
| 
      
 40 
     | 
    
         
            +
            SCHEDULE_VALUE_EVENTS = %i[fiber_schedule fiber_run].freeze
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            def tp_schedule_value(trp)
         
     | 
| 
      
 43 
     | 
    
         
            +
              SCHEDULE_VALUE_EVENTS.include?(trp.event) ? trp.value : nil
         
     | 
| 
      
 44 
     | 
    
         
            +
            end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
       39 
46 
     | 
    
         
             
            def tp_raised_exception(trp)
         
     | 
| 
       40 
47 
     | 
    
         
             
              trp.event == :raise && trp.raised_exception
         
     | 
| 
       41 
48 
     | 
    
         
             
            end
         
     | 
| 
         @@ -79,19 +86,45 @@ class FiberTracePoint 
     | 
|
| 
       79 
86 
     | 
    
         
             
            end
         
     | 
| 
       80 
87 
     | 
    
         | 
| 
       81 
88 
     | 
    
         
             
            class << ::TracePoint
         
     | 
| 
      
 89 
     | 
    
         
            +
              POLYPHONY_FILE_REGEXP = /^#{::Exception::POLYPHONY_DIR}/.freeze
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
       82 
91 
     | 
    
         
             
              alias_method :orig_new, :new
         
     | 
| 
       83 
92 
     | 
    
         
             
              def new(*args, &block)
         
     | 
| 
       84 
     | 
    
         
            -
                 
     | 
| 
      
 93 
     | 
    
         
            +
                events_mask, fiber_events_mask = event_masks(args)
         
     | 
| 
       85 
94 
     | 
    
         | 
| 
       86 
     | 
    
         
            -
                orig_new(* 
     | 
| 
       87 
     | 
    
         
            -
                   
     | 
| 
      
 95 
     | 
    
         
            +
                orig_new(*events_mask) do |tp|
         
     | 
| 
      
 96 
     | 
    
         
            +
                  handle_tp_event(tp, fiber_events_mask, &block)
         
     | 
| 
      
 97 
     | 
    
         
            +
                end
         
     | 
| 
      
 98 
     | 
    
         
            +
              end
         
     | 
| 
       88 
99 
     | 
    
         | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
                  else
         
     | 
| 
       92 
     | 
    
         
            -
                    next if tp.path =~ polyphony_file_regexp
         
     | 
| 
      
 100 
     | 
    
         
            +
              def handle_tp_event(tpoint, fiber_events_mask)
         
     | 
| 
      
 101 
     | 
    
         
            +
                # next unless !$watched_fiber || Fiber.current == $watched_fiber
         
     | 
| 
       93 
102 
     | 
    
         | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
      
 103 
     | 
    
         
            +
                if tpoint.method_id == :__fiber_trace__
         
     | 
| 
      
 104 
     | 
    
         
            +
                  return if tpoint.event != :c_return
         
     | 
| 
      
 105 
     | 
    
         
            +
                  return unless fiber_events_mask.include?(tpoint.return_value[0])
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                  tpoint = FiberTracePoint.new(tpoint)
         
     | 
| 
      
 108 
     | 
    
         
            +
                elsif tpoint.path =~ POLYPHONY_FILE_REGEXP
         
     | 
| 
      
 109 
     | 
    
         
            +
                  return
         
     | 
| 
      
 110 
     | 
    
         
            +
                end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                yield tpoint
         
     | 
| 
      
 113 
     | 
    
         
            +
              end
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
              ALL_FIBER_EVENTS = %i[
         
     | 
| 
      
 116 
     | 
    
         
            +
                fiber_create fiber_terminate fiber_schedule fiber_switchpoint fiber_run
         
     | 
| 
      
 117 
     | 
    
         
            +
                fiber_ev_loop_enter fiber_ev_loop_leave
         
     | 
| 
      
 118 
     | 
    
         
            +
              ].freeze
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
              def event_masks(events)
         
     | 
| 
      
 121 
     | 
    
         
            +
                events.each_with_object([[], []]) do |e, masks|
         
     | 
| 
      
 122 
     | 
    
         
            +
                  case e
         
     | 
| 
      
 123 
     | 
    
         
            +
                  when /fiber_/
         
     | 
| 
      
 124 
     | 
    
         
            +
                    masks[1] += e == :fiber_all ? ALL_FIBER_EVENTS : [e]
         
     | 
| 
      
 125 
     | 
    
         
            +
                    masks[0] << :c_return unless masks[0].include?(:c_return)
         
     | 
| 
      
 126 
     | 
    
         
            +
                  else
         
     | 
| 
      
 127 
     | 
    
         
            +
                    masks[0] << e
         
     | 
| 
       95 
128 
     | 
    
         
             
                  end
         
     | 
| 
       96 
129 
     | 
    
         
             
                end
         
     | 
| 
       97 
130 
     | 
    
         
             
              end
         
     | 
    
        data/lib/polyphony/version.rb
    CHANGED
    
    
    
        data/lib/polyphony.rb
    CHANGED
    
    
    
        data/test/helper.rb
    CHANGED
    
    
    
        data/test/test_async.rb
    CHANGED
    
    
    
        data/test/test_cancel_scope.rb
    CHANGED
    
    | 
         @@ -6,7 +6,7 @@ class CancelScopeTest < MiniTest::Test 
     | 
|
| 
       6 
6 
     | 
    
         
             
              def test_that_cancel_scope_can_cancel_provided_block
         
     | 
| 
       7 
7 
     | 
    
         
             
                buffer = []
         
     | 
| 
       8 
8 
     | 
    
         
             
                Polyphony::CancelScope.new { |scope|
         
     | 
| 
       9 
     | 
    
         
            -
                   
     | 
| 
      
 9 
     | 
    
         
            +
                  spin { scope.cancel! }
         
     | 
| 
       10 
10 
     | 
    
         
             
                  buffer << 1
         
     | 
| 
       11 
11 
     | 
    
         
             
                  snooze
         
     | 
| 
       12 
12 
     | 
    
         
             
                  buffer << 2
         
     | 
| 
         @@ -77,7 +77,7 @@ class CancelScopeTest < MiniTest::Test 
     | 
|
| 
       77 
77 
     | 
    
         
             
                scope.call {
         
     | 
| 
       78 
78 
     | 
    
         
             
                  sleep 0.005
         
     | 
| 
       79 
79 
     | 
    
         
             
                  scope.reset_timeout
         
     | 
| 
       80 
     | 
    
         
            -
                  sleep 0. 
     | 
| 
      
 80 
     | 
    
         
            +
                  sleep 0.005
         
     | 
| 
       81 
81 
     | 
    
         
             
                }
         
     | 
| 
       82 
82 
     | 
    
         | 
| 
       83 
83 
     | 
    
         
             
                assert !scope.cancelled?
         
     | 
| 
         @@ -86,7 +86,7 @@ class CancelScopeTest < MiniTest::Test 
     | 
|
| 
       86 
86 
     | 
    
         
             
              def test_on_cancel
         
     | 
| 
       87 
87 
     | 
    
         
             
                buffer = []
         
     | 
| 
       88 
88 
     | 
    
         
             
                Polyphony::CancelScope.new { |scope|
         
     | 
| 
       89 
     | 
    
         
            -
                   
     | 
| 
      
 89 
     | 
    
         
            +
                  spin { scope.cancel! }
         
     | 
| 
       90 
90 
     | 
    
         
             
                  scope.on_cancel { buffer << :cancelled }
         
     | 
| 
       91 
91 
     | 
    
         
             
                  buffer << 1
         
     | 
| 
       92 
92 
     | 
    
         
             
                  snooze
         
     |