polyphony 0.36 → 0.42

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.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +11 -2
  3. data/.gitignore +2 -2
  4. data/.rubocop.yml +30 -0
  5. data/CHANGELOG.md +28 -2
  6. data/Gemfile +0 -11
  7. data/Gemfile.lock +15 -14
  8. data/README.md +2 -1
  9. data/Rakefile +7 -3
  10. data/TODO.md +28 -95
  11. data/docs/_config.yml +56 -7
  12. data/docs/_sass/custom/custom.scss +0 -30
  13. data/docs/_sass/overrides.scss +0 -46
  14. data/docs/{user-guide → _user-guide}/all-about-timers.md +0 -0
  15. data/docs/_user-guide/index.md +9 -0
  16. data/docs/{user-guide → _user-guide}/web-server.md +0 -0
  17. data/docs/api-reference/fiber.md +2 -2
  18. data/docs/api-reference/index.md +9 -0
  19. data/docs/api-reference/polyphony-process.md +1 -1
  20. data/docs/api-reference/thread.md +1 -1
  21. data/docs/faq.md +21 -11
  22. data/docs/getting-started/index.md +10 -0
  23. data/docs/getting-started/installing.md +2 -6
  24. data/docs/getting-started/overview.md +507 -0
  25. data/docs/getting-started/tutorial.md +27 -19
  26. data/docs/index.md +3 -2
  27. data/docs/main-concepts/concurrency.md +0 -5
  28. data/docs/main-concepts/design-principles.md +69 -21
  29. data/docs/main-concepts/extending.md +1 -1
  30. data/docs/main-concepts/index.md +9 -0
  31. data/examples/core/01-spinning-up-fibers.rb +1 -0
  32. data/examples/core/03-interrupting.rb +4 -1
  33. data/examples/core/04-handling-signals.rb +19 -0
  34. data/examples/core/xx-agent.rb +102 -0
  35. data/examples/core/xx-fork-cleanup.rb +22 -0
  36. data/examples/core/xx-sleeping.rb +14 -6
  37. data/examples/io/tunnel.rb +48 -0
  38. data/examples/io/xx-irb.rb +1 -1
  39. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +7 -6
  40. data/examples/performance/thread-vs-fiber/polyphony_server.rb +13 -36
  41. data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +58 -0
  42. data/examples/performance/xx-array.rb +11 -0
  43. data/examples/performance/xx-fiber-switch.rb +9 -0
  44. data/examples/performance/xx-snooze.rb +15 -0
  45. data/ext/{gyro → polyphony}/extconf.rb +2 -2
  46. data/ext/{gyro → polyphony}/fiber.c +18 -22
  47. data/ext/{gyro → polyphony}/libev.c +0 -0
  48. data/ext/{gyro → polyphony}/libev.h +0 -0
  49. data/ext/polyphony/libev_agent.c +718 -0
  50. data/ext/polyphony/libev_queue.c +216 -0
  51. data/ext/{gyro/gyro.c → polyphony/polyphony.c} +16 -46
  52. data/ext/{gyro/gyro.h → polyphony/polyphony.h} +25 -39
  53. data/ext/polyphony/polyphony_ext.c +23 -0
  54. data/ext/{gyro → polyphony}/socket.c +21 -18
  55. data/ext/polyphony/thread.c +206 -0
  56. data/ext/{gyro → polyphony}/tracing.c +1 -1
  57. data/lib/polyphony.rb +40 -44
  58. data/lib/polyphony/adapters/fs.rb +1 -4
  59. data/lib/polyphony/adapters/irb.rb +1 -1
  60. data/lib/polyphony/adapters/postgres.rb +6 -5
  61. data/lib/polyphony/adapters/process.rb +27 -23
  62. data/lib/polyphony/adapters/trace.rb +110 -105
  63. data/lib/polyphony/core/channel.rb +35 -35
  64. data/lib/polyphony/core/exceptions.rb +29 -29
  65. data/lib/polyphony/core/global_api.rb +94 -91
  66. data/lib/polyphony/core/resource_pool.rb +83 -83
  67. data/lib/polyphony/core/sync.rb +16 -16
  68. data/lib/polyphony/core/thread_pool.rb +49 -37
  69. data/lib/polyphony/core/throttler.rb +30 -23
  70. data/lib/polyphony/event.rb +27 -0
  71. data/lib/polyphony/extensions/core.rb +25 -17
  72. data/lib/polyphony/extensions/fiber.rb +269 -267
  73. data/lib/polyphony/extensions/io.rb +56 -26
  74. data/lib/polyphony/extensions/openssl.rb +5 -9
  75. data/lib/polyphony/extensions/socket.rb +29 -10
  76. data/lib/polyphony/extensions/thread.rb +19 -12
  77. data/lib/polyphony/net.rb +64 -60
  78. data/lib/polyphony/version.rb +1 -1
  79. data/polyphony.gemspec +4 -7
  80. data/test/helper.rb +14 -1
  81. data/test/stress.rb +17 -12
  82. data/test/test_agent.rb +124 -0
  83. data/test/{test_async.rb → test_event.rb} +15 -7
  84. data/test/test_ext.rb +25 -4
  85. data/test/test_fiber.rb +19 -10
  86. data/test/test_global_api.rb +4 -4
  87. data/test/test_io.rb +46 -24
  88. data/test/test_queue.rb +74 -0
  89. data/test/test_signal.rb +3 -40
  90. data/test/test_socket.rb +33 -0
  91. data/test/test_thread.rb +38 -16
  92. data/test/test_thread_pool.rb +2 -2
  93. data/test/test_throttler.rb +0 -1
  94. data/test/test_trace.rb +6 -5
  95. metadata +41 -57
  96. data/docs/_includes/nav.html +0 -51
  97. data/docs/_includes/prevnext.html +0 -17
  98. data/docs/_layouts/default.html +0 -106
  99. data/docs/api-reference.md +0 -11
  100. data/docs/api-reference/gyro-async.md +0 -57
  101. data/docs/api-reference/gyro-child.md +0 -29
  102. data/docs/api-reference/gyro-queue.md +0 -44
  103. data/docs/api-reference/gyro-timer.md +0 -51
  104. data/docs/api-reference/gyro.md +0 -25
  105. data/docs/getting-started.md +0 -10
  106. data/docs/main-concepts.md +0 -10
  107. data/docs/user-guide.md +0 -10
  108. data/examples/core/forever_sleep.rb +0 -19
  109. data/ext/gyro/async.c +0 -148
  110. data/ext/gyro/child.c +0 -127
  111. data/ext/gyro/gyro_ext.c +0 -33
  112. data/ext/gyro/io.c +0 -474
  113. data/ext/gyro/queue.c +0 -142
  114. data/ext/gyro/selector.c +0 -205
  115. data/ext/gyro/signal.c +0 -118
  116. data/ext/gyro/thread.c +0 -298
  117. data/ext/gyro/timer.c +0 -134
  118. data/test/test_timer.rb +0 -56
@@ -1,132 +1,137 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- export :new, :analyze, :STOCK_EVENTS
4
-
5
- require 'polyphony'
3
+ require_relative '../../polyphony'
6
4
 
7
5
  STOCK_EVENTS = %i[line call return c_call c_return b_call b_return].freeze
8
6
 
9
- def new(*events)
10
- start_stamp = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
11
- events = STOCK_EVENTS if events.empty?
12
- ::TracePoint.new(*events) { |tp| yield trace_record(tp, start_stamp) }
13
- end
14
-
15
- def trace_record(trp, start_stamp)
16
- stamp = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - start_stamp
17
-
18
- { stamp: stamp, event: trp.event, location: "#{trp.path}:#{trp.lineno}",
19
- self: trp.self, binding: trp.binding, fiber: tp_fiber(trp),
20
- lineno: trp.lineno, method_id: trp.method_id,
21
- path: trp.path, parameters: tp_params(trp),
22
- return_value: tp_return_value(trp), schedule_value: tp_schedule_value(trp),
23
- exception: tp_raised_exception(trp) }
24
- end
25
-
26
- def tp_fiber(trp)
27
- trp.is_a?(FiberTracePoint) ? trp.fiber : Fiber.current
28
- end
29
-
30
- PARAMS_EVENTS = %i[call c_call b_call].freeze
31
-
32
- def tp_params(trp)
33
- PARAMS_EVENTS.include?(trp.event) ? trp.parameters : nil
34
- end
35
-
36
- RETURN_VALUE_EVENTS = %i[return c_return b_return].freeze
37
-
38
- def tp_return_value(trp)
39
- RETURN_VALUE_EVENTS.include?(trp.event) ? trp.return_value : nil
40
- end
7
+ module Polyphony
8
+ # Tracing functionality for Polyphony
9
+ module Trace
10
+ class << self
11
+ def new(*events)
12
+ start_stamp = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
13
+ events = STOCK_EVENTS if events.empty?
14
+ ::TracePoint.new(*events) { |tp| yield trace_record(tp, start_stamp) }
15
+ end
41
16
 
42
- SCHEDULE_VALUE_EVENTS = %i[fiber_schedule fiber_run].freeze
17
+ def trace_record(trp, start_stamp)
18
+ stamp = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - start_stamp
43
19
 
44
- def tp_schedule_value(trp)
45
- SCHEDULE_VALUE_EVENTS.include?(trp.event) ? trp.value : nil
46
- end
20
+ { stamp: stamp, event: trp.event, location: "#{trp.path}:#{trp.lineno}",
21
+ self: trp.self, binding: trp.binding, fiber: tp_fiber(trp),
22
+ lineno: trp.lineno, method_id: trp.method_id,
23
+ path: trp.path, parameters: tp_params(trp),
24
+ return_value: tp_return_value(trp), schedule_value: tp_schedule_value(trp),
25
+ exception: tp_raised_exception(trp) }
26
+ end
47
27
 
48
- def tp_raised_exception(trp)
49
- trp.event == :raise && trp.raised_exception
50
- end
28
+ def tp_fiber(trp)
29
+ trp.is_a?(FiberTracePoint) ? trp.fiber : Fiber.current
30
+ end
51
31
 
52
- def analyze(records)
53
- by_fiber = Hash.new { |h, f| h[f] = [] }
54
- records.each_with_object(by_fiber) { |r, h| h[r[:fiber]] << r }
55
- { by_fiber: by_fiber }
56
- end
32
+ PARAMS_EVENTS = %i[call c_call b_call].freeze
57
33
 
58
- # Implements fake TracePoint instances for fiber-related events
59
- class FiberTracePoint
60
- attr_reader :event, :fiber, :value
34
+ def tp_params(trp)
35
+ PARAMS_EVENTS.include?(trp.event) ? trp.parameters : nil
36
+ end
61
37
 
62
- def initialize(tpoint)
63
- @tp = tpoint
64
- @event = tpoint.return_value[0]
65
- @fiber = tpoint.return_value[1]
66
- @value = tpoint.return_value[2]
67
- end
38
+ RETURN_VALUE_EVENTS = %i[return c_return b_return].freeze
68
39
 
69
- def lineno
70
- @tp.lineno
71
- end
40
+ def tp_return_value(trp)
41
+ RETURN_VALUE_EVENTS.include?(trp.event) ? trp.return_value : nil
42
+ end
72
43
 
73
- def method_id
74
- @tp.method_id
75
- end
44
+ SCHEDULE_VALUE_EVENTS = %i[fiber_schedule fiber_run].freeze
76
45
 
77
- def path
78
- @tp.path
79
- end
46
+ def tp_schedule_value(trp)
47
+ SCHEDULE_VALUE_EVENTS.include?(trp.event) ? trp.value : nil
48
+ end
80
49
 
81
- def self
82
- @tp.self
83
- end
50
+ def tp_raised_exception(trp)
51
+ trp.event == :raise && trp.raised_exception
52
+ end
84
53
 
85
- def binding
86
- @tp.binding
87
- end
88
- end
54
+ def analyze(records)
55
+ by_fiber = Hash.new { |h, f| h[f] = [] }
56
+ records.each_with_object(by_fiber) { |r, h| h[r[:fiber]] << r }
57
+ { by_fiber: by_fiber }
58
+ end
89
59
 
90
- class << ::TracePoint
91
- POLYPHONY_FILE_REGEXP = /^#{::Exception::POLYPHONY_DIR}/.freeze
60
+ # Implements fake TracePoint instances for fiber-related events
61
+ class FiberTracePoint
62
+ attr_reader :event, :fiber, :value
92
63
 
93
- alias_method :orig_new, :new
94
- def new(*args, &block)
95
- events_mask, fiber_events_mask = event_masks(args)
64
+ def initialize(tpoint)
65
+ @tp = tpoint
66
+ @event = tpoint.return_value[0]
67
+ @fiber = tpoint.return_value[1]
68
+ @value = tpoint.return_value[2]
69
+ end
96
70
 
97
- orig_new(*events_mask) do |tp|
98
- handle_tp_event(tp, fiber_events_mask, &block)
99
- end
100
- end
71
+ def lineno
72
+ @tp.lineno
73
+ end
101
74
 
102
- def handle_tp_event(tpoint, fiber_events_mask)
103
- # next unless !$watched_fiber || Fiber.current == $watched_fiber
75
+ def method_id
76
+ @tp.method_id
77
+ end
104
78
 
105
- if tpoint.method_id == :__fiber_trace__
106
- return if tpoint.event != :c_return
107
- return unless fiber_events_mask.include?(tpoint.return_value[0])
79
+ def path
80
+ @tp.path
81
+ end
108
82
 
109
- tpoint = FiberTracePoint.new(tpoint)
110
- elsif tpoint.path =~ POLYPHONY_FILE_REGEXP
111
- return
112
- end
83
+ def self
84
+ @tp.self
85
+ end
113
86
 
114
- yield tpoint
115
- end
87
+ def binding
88
+ @tp.binding
89
+ end
90
+ end
116
91
 
117
- ALL_FIBER_EVENTS = %i[
118
- fiber_create fiber_terminate fiber_schedule fiber_switchpoint fiber_run
119
- fiber_ev_loop_enter fiber_ev_loop_leave
120
- ].freeze
121
-
122
- def event_masks(events)
123
- events.each_with_object([[], []]) do |e, masks|
124
- case e
125
- when /fiber_/
126
- masks[1] += e == :fiber_all ? ALL_FIBER_EVENTS : [e]
127
- masks[0] << :c_return unless masks[0].include?(:c_return)
128
- else
129
- masks[0] << e
92
+ class << ::TracePoint
93
+ POLYPHONY_FILE_REGEXP = /^#{::Exception::POLYPHONY_DIR}/.freeze
94
+
95
+ alias_method :orig_new, :new
96
+ def new(*args, &block)
97
+ events_mask, fiber_events_mask = event_masks(args)
98
+
99
+ orig_new(*events_mask) do |tp|
100
+ handle_tp_event(tp, fiber_events_mask, &block)
101
+ end
102
+ end
103
+
104
+ def handle_tp_event(tpoint, fiber_events_mask)
105
+ # next unless !$watched_fiber || Fiber.current == $watched_fiber
106
+
107
+ if tpoint.method_id == :__fiber_trace__
108
+ return if tpoint.event != :c_return
109
+ return unless fiber_events_mask.include?(tpoint.return_value[0])
110
+
111
+ tpoint = FiberTracePoint.new(tpoint)
112
+ elsif tpoint.path =~ POLYPHONY_FILE_REGEXP
113
+ return
114
+ end
115
+
116
+ yield tpoint
117
+ end
118
+
119
+ ALL_FIBER_EVENTS = %i[
120
+ fiber_create fiber_terminate fiber_schedule fiber_switchpoint fiber_run
121
+ fiber_ev_loop_enter fiber_ev_loop_leave
122
+ ].freeze
123
+
124
+ def event_masks(events)
125
+ events.each_with_object([[], []]) do |e, masks|
126
+ case e
127
+ when /fiber_/
128
+ masks[1] += e == :fiber_all ? ALL_FIBER_EVENTS : [e]
129
+ masks[0] << :c_return unless masks[0].include?(:c_return)
130
+ else
131
+ masks[0] << e
132
+ end
133
+ end
134
+ end
130
135
  end
131
136
  end
132
137
  end
@@ -1,46 +1,46 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- export_default :Channel
3
+ require_relative './exceptions'
4
4
 
5
- Exceptions = import('./exceptions')
6
-
7
- # Implements a unidirectional communication channel along the lines of Go
8
- # (buffered) channels.
9
- class Channel
10
- def initialize
11
- @payload_queue = []
12
- @waiting_queue = []
13
- end
5
+ module Polyphony
6
+ # Implements a unidirectional communication channel along the lines of Go
7
+ # (buffered) channels.
8
+ class Channel
9
+ def initialize
10
+ @payload_queue = []
11
+ @waiting_queue = []
12
+ end
14
13
 
15
- def close
16
- stop = Exceptions::MoveOn.new
17
- @waiting_queue.slice(0..-1).each { |f| f.schedule(stop) }
18
- end
14
+ def close
15
+ stop = Polyphony::MoveOn.new
16
+ @waiting_queue.slice(0..-1).each { |f| f.schedule(stop) }
17
+ end
19
18
 
20
- def <<(value)
21
- if @waiting_queue.empty?
22
- @payload_queue << value
23
- else
24
- @waiting_queue.shift&.schedule(value)
19
+ def <<(value)
20
+ if @waiting_queue.empty?
21
+ @payload_queue << value
22
+ else
23
+ @waiting_queue.shift&.schedule(value)
24
+ end
25
+ snooze
25
26
  end
26
- snooze
27
- end
28
27
 
29
- def receive
30
- Gyro.ref
31
- if @payload_queue.empty?
32
- @waiting_queue << Fiber.current
33
- suspend
34
- else
35
- receive_from_queue
28
+ def receive
29
+ Thread.current.agent.ref
30
+ if @payload_queue.empty?
31
+ @waiting_queue << Fiber.current
32
+ suspend
33
+ else
34
+ receive_from_queue
35
+ end
36
+ ensure
37
+ Thread.current.agent.unref
36
38
  end
37
- ensure
38
- Gyro.unref
39
- end
40
39
 
41
- def receive_from_queue
42
- payload = @payload_queue.shift
43
- snooze
44
- payload
40
+ def receive_from_queue
41
+ payload = @payload_queue.shift
42
+ snooze
43
+ payload
44
+ end
45
45
  end
46
46
  end
@@ -1,36 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- export :BaseException, :MoveOn, :Cancel, :Terminate, :Restart
4
-
5
- # Common exception class for interrupting fibers. These exceptions allow
6
- # control of fibers. BaseException exceptions can encapsulate a value and thus
7
- # provide a way to interrupt long-running blocking operations while still
8
- # passing a value back to the call site. BaseException exceptions can also
9
- # references a cancel scope in order to allow correct bubbling of exceptions
10
- # through nested cancel scopes.
11
- class BaseException < ::Exception
12
- attr_reader :value
13
-
14
- def initialize(value = nil)
15
- @caller_backtrace = caller
16
- @value = value
17
- end
18
-
19
- def backtrace
20
- sanitize(@caller_backtrace)
3
+ module Polyphony
4
+ # Common exception class for interrupting fibers. These exceptions allow
5
+ # control of fibers. BaseException exceptions can encapsulate a value and thus
6
+ # provide a way to interrupt long-running blocking operations while still
7
+ # passing a value back to the call site. BaseException exceptions can also
8
+ # references a cancel scope in order to allow correct bubbling of exceptions
9
+ # through nested cancel scopes.
10
+ class BaseException < ::Exception
11
+ attr_reader :value
12
+
13
+ def initialize(value = nil)
14
+ @caller_backtrace = caller
15
+ @value = value
16
+ end
17
+
18
+ def backtrace
19
+ sanitize(@caller_backtrace)
20
+ end
21
21
  end
22
- end
23
22
 
24
- # MoveOn is used to interrupt a long-running blocking operation, while
25
- # continuing the rest of the computation.
26
- class MoveOn < BaseException; end
23
+ # MoveOn is used to interrupt a long-running blocking operation, while
24
+ # continuing the rest of the computation.
25
+ class MoveOn < BaseException; end
27
26
 
28
- # Cancel is used to interrupt a long-running blocking operation, bubbling the
29
- # exception up through cancel scopes and supervisors.
30
- class Cancel < BaseException; end
27
+ # Cancel is used to interrupt a long-running blocking operation, bubbling the
28
+ # exception up through cancel scopes and supervisors.
29
+ class Cancel < BaseException; end
31
30
 
32
- # Terminate is used to interrupt a fiber once its parent fiber has terminated.
33
- class Terminate < BaseException; end
31
+ # Terminate is used to interrupt a fiber once its parent fiber has terminated.
32
+ class Terminate < BaseException; end
34
33
 
35
- # Restart is used to restart a fiber
36
- class Restart < BaseException; end
34
+ # Restart is used to restart a fiber
35
+ class Restart < BaseException; end
36
+ end
@@ -1,119 +1,122 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- export_default :API
4
-
5
- import '../extensions/core'
6
- import '../extensions/fiber'
7
-
8
- Exceptions = import '../core/exceptions'
9
- Throttler = import '../core/throttler'
3
+ require_relative '../extensions/core'
4
+ require_relative '../extensions/fiber'
5
+ require_relative './exceptions'
6
+ require_relative './throttler'
7
+
8
+ module Polyphony
9
+ # Global API methods to be included in ::Object
10
+ module GlobalAPI
11
+ def after(interval, &block)
12
+ spin do
13
+ sleep interval
14
+ block.()
15
+ end
16
+ end
10
17
 
11
- # Global API methods to be included in ::Object
12
- module API
13
- def after(interval, &block)
14
- spin do
15
- sleep interval
16
- block.()
18
+ def cancel_after(interval, &block)
19
+ fiber = ::Fiber.current
20
+ canceller = spin do
21
+ sleep interval
22
+ fiber.schedule Polyphony::Cancel.new
23
+ end
24
+ block ? cancel_after_wrap_block(canceller, &block) : canceller
17
25
  end
18
- end
19
26
 
20
- def cancel_after(interval, &block)
21
- fiber = ::Fiber.current
22
- canceller = spin do
23
- sleep interval
24
- fiber.schedule Exceptions::Cancel.new
27
+ def cancel_after_wrap_block(canceller, &block)
28
+ block.call
29
+ ensure
30
+ canceller.stop
25
31
  end
26
- block ? cancel_after_wrap_block(canceller, &block) : canceller
27
- end
28
32
 
29
- def cancel_after_wrap_block(canceller, &block)
30
- block.call
31
- ensure
32
- canceller.stop
33
- end
33
+ def spin(tag = nil, &block)
34
+ Fiber.current.spin(tag, caller, &block)
35
+ end
34
36
 
35
- def spin(tag = nil, &block)
36
- Fiber.current.spin(tag, caller, &block)
37
- end
37
+ def spin_loop(tag = nil, rate: nil, &block)
38
+ if rate
39
+ Fiber.current.spin(tag, caller) do
40
+ throttled_loop(rate, &block)
41
+ end
42
+ else
43
+ Fiber.current.spin(tag, caller) { loop(&block) }
44
+ end
45
+ end
38
46
 
39
- def spin_loop(tag = nil, rate: nil, &block)
40
- if rate
41
- Fiber.current.spin(tag, caller) do
42
- throttled_loop(rate, &block)
47
+ def every(interval)
48
+ next_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) + interval
49
+ loop do
50
+ now = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
51
+ Thread.current.agent.sleep(next_time - now)
52
+ yield
53
+ loop do
54
+ next_time += interval
55
+ break if next_time > now
56
+ end
43
57
  end
44
- else
45
- Fiber.current.spin(tag, caller) { loop(&block) }
46
58
  end
47
- end
48
59
 
49
- def every(interval)
50
- timer = Gyro::Timer.new(interval, interval)
51
- loop do
52
- timer.await
53
- yield
60
+ def move_on_after(interval, with_value: nil, &block)
61
+ fiber = ::Fiber.current
62
+ unless block
63
+ return spin do
64
+ sleep interval
65
+ fiber.schedule with_value
66
+ end
67
+ end
68
+
69
+ move_on_after_with_block(fiber, interval, with_value, &block)
54
70
  end
55
- ensure
56
- timer.stop
57
- end
58
71
 
59
- def move_on_after(interval, with_value: nil, &block)
60
- fiber = ::Fiber.current
61
- unless block
62
- return spin do
72
+ def move_on_after_with_block(fiber, interval, with_value, &block)
73
+ canceller = spin do
63
74
  sleep interval
64
- fiber.schedule with_value
75
+ fiber.schedule Polyphony::MoveOn.new(with_value)
65
76
  end
77
+ block.call
78
+ rescue Polyphony::MoveOn => e
79
+ e.value
80
+ ensure
81
+ canceller.stop
66
82
  end
67
83
 
68
- move_on_after_with_block(fiber, interval, with_value, &block)
69
- end
70
-
71
- def move_on_after_with_block(fiber, interval, with_value, &block)
72
- canceller = spin do
73
- sleep interval
74
- fiber.schedule Exceptions::MoveOn.new(with_value)
84
+ def receive
85
+ Fiber.current.receive
75
86
  end
76
- block.call
77
- rescue Exceptions::MoveOn => e
78
- e.value
79
- ensure
80
- canceller.stop
81
- end
82
87
 
83
- def receive
84
- Fiber.current.receive
85
- end
86
-
87
- def receive_pending
88
- Fiber.current.receive_pending
89
- end
88
+ def receive_pending
89
+ Fiber.current.receive_pending
90
+ end
90
91
 
91
- def supervise(*args, &block)
92
- Fiber.current.supervise(*args, &block)
93
- end
92
+ def supervise(*args, &block)
93
+ Fiber.current.supervise(*args, &block)
94
+ end
94
95
 
95
- def sleep(duration = nil)
96
- return sleep_forever unless duration
96
+ def sleep(duration = nil)
97
+ return sleep_forever unless duration
97
98
 
98
- timer = Gyro::Timer.new(duration, 0)
99
- timer.await
100
- end
99
+ Thread.current.agent.sleep duration
100
+ end
101
101
 
102
- def sleep_forever
103
- Thread.current.fiber_ref
104
- suspend
105
- ensure
106
- Thread.current.fiber_unref
107
- end
102
+ def sleep_forever
103
+ Thread.current.agent.ref
104
+ suspend
105
+ ensure
106
+ Thread.current.agent.unref
107
+ end
108
108
 
109
- def throttled_loop(rate, count: nil, &block)
110
- throttler = Throttler.new(rate)
111
- if count
112
- count.times { throttler.(&block) }
113
- else
114
- loop { throttler.(&block) }
109
+ def throttled_loop(rate, count: nil, &block)
110
+ throttler = Polyphony::Throttler.new(rate)
111
+ if count
112
+ count.times { |_i| throttler.(&block) }
113
+ else
114
+ loop { throttler.(&block) }
115
+ end
116
+ ensure
117
+ throttler&.stop
115
118
  end
116
- ensure
117
- throttler.stop
118
119
  end
119
120
  end
121
+
122
+ Object.include Polyphony::GlobalAPI