polyphony 0.99.4 → 0.99.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +10 -0
  3. data/examples/pipes/gzip_http_server.rb +2 -2
  4. data/examples/pipes/http_server.rb +1 -1
  5. data/examples/pipes/tcp_proxy.rb +1 -1
  6. data/ext/polyphony/backend_common.c +4 -4
  7. data/ext/polyphony/backend_io_uring.c +8 -8
  8. data/ext/polyphony/backend_libev.c +5 -5
  9. data/ext/polyphony/fiber.c +32 -41
  10. data/ext/polyphony/io_extensions.c +50 -37
  11. data/ext/polyphony/pipe.c +6 -18
  12. data/ext/polyphony/polyphony.c +63 -133
  13. data/ext/polyphony/queue.c +25 -63
  14. data/ext/polyphony/thread.c +3 -12
  15. data/lib/polyphony/adapters/process.rb +1 -2
  16. data/lib/polyphony/adapters/sequel.rb +2 -2
  17. data/lib/polyphony/core/debug.rb +1 -1
  18. data/lib/polyphony/core/exceptions.rb +1 -1
  19. data/lib/polyphony/core/global_api.rb +24 -38
  20. data/lib/polyphony/core/resource_pool.rb +7 -8
  21. data/lib/polyphony/core/sync.rb +1 -2
  22. data/lib/polyphony/core/thread_pool.rb +2 -5
  23. data/lib/polyphony/core/throttler.rb +1 -5
  24. data/lib/polyphony/core/timer.rb +24 -25
  25. data/lib/polyphony/extensions/fiber.rb +507 -540
  26. data/lib/polyphony/extensions/io.rb +3 -12
  27. data/lib/polyphony/extensions/openssl.rb +2 -23
  28. data/lib/polyphony/extensions/pipe.rb +4 -15
  29. data/lib/polyphony/extensions/socket.rb +15 -109
  30. data/lib/polyphony/extensions/thread.rb +0 -13
  31. data/lib/polyphony/extensions/timeout.rb +0 -1
  32. data/lib/polyphony/net.rb +5 -8
  33. data/lib/polyphony/version.rb +1 -1
  34. data/lib/polyphony.rb +2 -6
  35. data/test/test_io.rb +221 -221
  36. data/test/test_socket.rb +3 -3
  37. data/test/test_trace.rb +2 -2
  38. metadata +1 -1
@@ -8,12 +8,11 @@ module Polyphony
8
8
  # Watches a forked or spawned process, waiting for it to terminate. If
9
9
  # `cmd` is given it is spawned, otherwise the process is forked with the
10
10
  # given block.
11
- #
11
+ #
12
12
  # If the operation is interrupted for any reason, the spawned or forked
13
13
  # process is killed.
14
14
  #
15
15
  # @param cmd [String, nil] command to spawn
16
- # @yield [] block to fork
17
16
  # @return [void]
18
17
  def watch(cmd = nil, &block)
19
18
  terminated = nil
@@ -4,10 +4,10 @@ require_relative '../../polyphony'
4
4
  require 'sequel'
5
5
 
6
6
  module Polyphony
7
-
7
+
8
8
  # Sequel ConnectionPool that delegates to Polyphony::ResourcePool.
9
9
  class FiberConnectionPool < Sequel::ConnectionPool
10
-
10
+
11
11
  # Initializes the connection pool.
12
12
  #
13
13
  # @param db [any] db to connect to
@@ -32,7 +32,7 @@ module Polyphony
32
32
  # If an IO instance is given, events are dumped to it instead.
33
33
  #
34
34
  # @param io [IO, nil] IO instance
35
- # @yield [Hash] event handler block
35
+ # @yield [Hash] event information
36
36
  # @return [void]
37
37
  def start_event_firehose(io = nil, &block)
38
38
  Thread.backend.trace_proc = firehose_proc(io, block)
@@ -40,7 +40,7 @@ module Polyphony
40
40
 
41
41
  # Interjection is used to run arbitrary code on arbitrary fibers at any point
42
42
  class Interjection < BaseException
43
-
43
+
44
44
  # Initializes an Interjection with the given proc.
45
45
  #
46
46
  # @param proc [Proc] interjection proc
@@ -3,7 +3,7 @@
3
3
  require_relative './throttler'
4
4
 
5
5
  module Polyphony
6
-
6
+
7
7
  # Global API methods to be included in `::Object`
8
8
  module GlobalAPI
9
9
 
@@ -11,7 +11,6 @@ module Polyphony
11
11
  # given delay.
12
12
  #
13
13
  # @param interval [Number] delay in seconds before running the given block
14
- # @yield [] block to run
15
14
  # @return [Fiber] spun fiber
16
15
  def after(interval, &block)
17
16
  spin do
@@ -20,14 +19,6 @@ module Polyphony
20
19
  end
21
20
  end
22
21
 
23
- # call-seq:
24
- # cancel_after(interval) { ... }
25
- # cancel_after(interval, with_exception: exception) { ... }
26
- # cancel_after(interval, with_exception: [klass, message]) { ... }
27
- # cancel_after(interval) { |timeout| ... }
28
- # cancel_after(interval, with_exception: exception) { |timeout| ... }
29
- # cancel_after(interval, with_exception: [klass, message]) { |timeout| ... }
30
- #
31
22
  # Runs the given block after setting up a cancellation timer for
32
23
  # cancellation. If the cancellation timer elapses, the execution will be
33
24
  # interrupted with an exception defaulting to `Polyphony::Cancel`.
@@ -55,10 +46,20 @@ module Polyphony
55
46
  # end
56
47
  # end
57
48
  #
58
- # @param interval [Number] timout in seconds
59
- # @param with_exception [Class, Exception] exception or exception class
60
- # @yield [Fiber] block to execute
61
- # @return [any] block's return value
49
+ # @overload cancel_after(interval)
50
+ # @param interval [Number] timout in seconds
51
+ # @yield [Fiber] timeout fiber
52
+ # @return [any] block's return value
53
+ # @overload cancel_after(interval, with_exception: exception)
54
+ # @param interval [Number] timout in seconds
55
+ # @param with_exception [Class, Exception] exception or exception class
56
+ # @yield [Fiber] timeout fiber
57
+ # @return [any] block's return value
58
+ # @overload cancel_after(interval, with_exception: [klass, message])
59
+ # @param interval [Number] timout in seconds
60
+ # @param with_exception [Array] array containing class and message to use as exception
61
+ # @yield [Fiber] timeout fiber
62
+ # @return [any] block's return value
62
63
  def cancel_after(interval, with_exception: Polyphony::Cancel, &block)
63
64
  if block.arity > 0
64
65
  cancel_after_with_optional_reset(interval, with_exception, &block)
@@ -70,7 +71,6 @@ module Polyphony
70
71
  # Spins up a new fiber.
71
72
  #
72
73
  # @param tag [any] optional tag for the new fiber
73
- # @yield [any] fiber block
74
74
  # @return [Fiber] new fiber
75
75
  def spin(tag = nil, &block)
76
76
  Fiber.current.spin(tag, caller, &block)
@@ -83,7 +83,6 @@ module Polyphony
83
83
  # @param tag [any] optional tag for the new fiber
84
84
  # @param rate [Number, nil] loop rate (times per second)
85
85
  # @param interval [Number, nil] interval between consecutive iterations in seconds
86
- # @yield [any] code to run
87
86
  # @return [Fiber] new fiber
88
87
  def spin_loop(tag = nil, rate: nil, interval: nil, &block)
89
88
  if rate || interval
@@ -98,7 +97,6 @@ module Polyphony
98
97
  # Runs the given code, then waits for any child fibers of the current fibers
99
98
  # to terminate.
100
99
  #
101
- # @yield [any] code to run
102
100
  # @return [any] given block's return value
103
101
  def spin_scope(&block)
104
102
  raise unless block
@@ -114,18 +112,11 @@ module Polyphony
114
112
  # consecutive iterations.
115
113
  #
116
114
  # @param interval [Number] interval between consecutive iterations in seconds
117
- # @yield [any] block to run
118
115
  # @return [void]
119
116
  def every(interval, &block)
120
117
  Polyphony.backend_timer_loop(interval, &block)
121
118
  end
122
119
 
123
- # call-seq:
124
- # move_on_after(interval) { ... }
125
- # move_on_after(interval, with_value: value) { ... }
126
- # move_on_after(interval) { |canceller| ... }
127
- # move_on_after(interval, with_value: value) { |canceller| ... }
128
- #
129
120
  # Runs the given block after setting up a cancellation timer for
130
121
  # cancellation. If the cancellation timer elapses, the execution will be
131
122
  # interrupted with a `Polyphony::MoveOn` exception, which will be rescued,
@@ -159,10 +150,15 @@ module Polyphony
159
150
  # end
160
151
  # end
161
152
  #
162
- # @param interval [Number] timout in seconds
163
- # @param with_value [any] return value in case of timeout
164
- # @yield [Fiber] block to execute
165
- # @return [any] block's return value
153
+ # @overload move_on_after(interval) { ... }
154
+ # @param interval [Number] timout in seconds
155
+ # @yield [Fiber] timeout fiber
156
+ # @return [any] block's return value
157
+ # @overload move_on_after(interval, with_value: value) { ... }
158
+ # @param interval [Number] timout in seconds
159
+ # @param with_value [any] return value in case of timeout
160
+ # @yield [Fiber] timeout fiber
161
+ # @return [any] block's return value
166
162
  def move_on_after(interval, with_value: nil, &block)
167
163
  if block.arity > 0
168
164
  move_on_after_with_optional_reset(interval, with_value, &block)
@@ -191,7 +187,6 @@ module Polyphony
191
187
  #
192
188
  # @param args [Array] positional parameters
193
189
  # @param opts [Hash] named parameters
194
- # @yield [any] given block
195
190
  # @return [void]
196
191
  def supervise(*args, **opts, &block)
197
192
  Fiber.current.supervise(*args, **opts, &block)
@@ -207,12 +202,6 @@ module Polyphony
207
202
  Polyphony.backend_sleep(duration) : Polyphony.backend_wait_event(true)
208
203
  end
209
204
 
210
- # call-seq:
211
- # throttled_loop(rate) { ... }
212
- # throttled_loop(interval: value) { ... }
213
- # throttled_loop(rate: value) { ... }
214
- # throttled_loop(rate, count: value) { ... }
215
- #
216
205
  # Starts a throttled loop with the given rate. If `count:` is given, the
217
206
  # loop is run for the given number of times. Otherwise, the loop is
218
207
  # infinite. The loop rate (times per second) can be given as the rate
@@ -223,7 +212,6 @@ module Polyphony
223
212
  # @option opts [Number] :rate loop rate (times per second)
224
213
  # @option opts [Number] :interval loop interval in seconds
225
214
  # @option opts [Number] :count number of iterations (nil for infinite)
226
- # @yield [] code to run
227
215
  # @return [void]
228
216
  def throttled_loop(rate = nil, **opts, &block)
229
217
  throttler = Polyphony::Throttler.new(rate || opts)
@@ -244,7 +232,6 @@ module Polyphony
244
232
  #
245
233
  # @param interval [Number] timeout interval in seconds
246
234
  # @param exception [Exception, Class, Array<class, message>] exception spec
247
- # @yield [Fiber] block to run
248
235
  # @return [any] block's return value
249
236
  def cancel_after_with_optional_reset(interval, exception, &block)
250
237
  fiber = Fiber.current
@@ -290,7 +277,6 @@ module Polyphony
290
277
  #
291
278
  # @param interval [Number] timeout interval in seconds
292
279
  # @param value [any] return value in case of timeout
293
- # @yield [Fiber] code to run
294
280
  # @return [any] return value of given block or timeout value
295
281
  def move_on_after_with_optional_reset(interval, value, &block)
296
282
  fiber = Fiber.current
@@ -5,13 +5,15 @@ module Polyphony
5
5
  class ResourcePool
6
6
  attr_reader :limit, :size
7
7
 
8
- # Initializes a new resource pool.
8
+ # Initializes a new resource pool. The given block is used for creating a
9
+ # resource:
9
10
  #
10
- # @param opts [Hash] options
11
- # @yield [] allocator block
12
- def initialize(opts, &block)
11
+ # ResourcePool.new { Sequel.connect(DB_URL) }
12
+ #
13
+ # @param limit [Integer] maximum open resources
14
+ def initialize(limit: 4, &block)
13
15
  @allocator = block
14
- @limit = opts[:limit] || 4
16
+ @limit = limit
15
17
  @size = 0
16
18
  @stock = Polyphony::Queue.new
17
19
  @acquired_resources = {}
@@ -36,7 +38,6 @@ module Polyphony
36
38
  # db.query(sql).to_a
37
39
  # end
38
40
  #
39
- # @yield [any] code to run
40
41
  # @return [any] return value of block
41
42
  def acquire(&block)
42
43
  fiber = Fiber.current
@@ -55,7 +56,6 @@ module Polyphony
55
56
  #
56
57
  # @param sym [Symbol] method name
57
58
  # @param args [Array<any>] method arguments
58
- # @yield [any] block passed to method
59
59
  # @return [any] result of method call
60
60
  def method_missing(sym, *args, &block)
61
61
  acquire { |r| r.send(sym, *args, &block) }
@@ -88,7 +88,6 @@ module Polyphony
88
88
  # Acquires a resource from stock, yielding it to the given block.
89
89
  #
90
90
  # @param fiber [Fiber] the fiber the resource will be associated with
91
- # @yield [any] given block
92
91
  # @return [any] return value of block
93
92
  def acquire_from_stock(fiber)
94
93
  add_to_stock if (@stock.empty? || @stock.pending?) && @size < @limit
@@ -17,7 +17,6 @@ module Polyphony
17
17
  # This method is re-entrant. Recursive calls from the given block will not
18
18
  # block.
19
19
  #
20
- # @yield [] code to run
21
20
  # @return [any] return value of block
22
21
  def synchronize(&block)
23
22
  return yield if @holding_fiber == Fiber.current
@@ -64,7 +63,7 @@ module Polyphony
64
63
  # @return [Mutex] self
65
64
  def lock
66
65
  raise ThreadError if owned?
67
-
66
+
68
67
  @token = @store.shift
69
68
  @holding_fiber = Fiber.current
70
69
  self
@@ -3,16 +3,15 @@
3
3
  require 'etc'
4
4
 
5
5
  module Polyphony
6
-
6
+
7
7
  # Implements a pool of threads
8
8
  class ThreadPool
9
-
9
+
10
10
  # The pool size.
11
11
  attr_reader :size
12
12
 
13
13
  # Runs the given block on an available thread from the default thread pool.
14
14
  #
15
- # @yield [] given block
16
15
  # @return [any] return value of given block
17
16
  def self.process(&block)
18
17
  @default_pool ||= new
@@ -41,7 +40,6 @@ module Polyphony
41
40
 
42
41
  # Runs the given block on an available thread from the pool.
43
42
  #
44
- # @yield [] given block
45
43
  # @return [any] return value of block
46
44
  def process(&block)
47
45
  setup unless @task_queue
@@ -55,7 +53,6 @@ module Polyphony
55
53
  # method does not block. The task will be performed once a thread becomes
56
54
  # available.
57
55
  #
58
- # @yield [] given block
59
56
  # @return [Polyphony::ThreadPool] self
60
57
  def cast(&block)
61
58
  setup unless @task_queue
@@ -13,10 +13,6 @@ module Polyphony
13
13
  @next_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
14
14
  end
15
15
 
16
- # call-seq:
17
- # throttler.call { ... }
18
- # throttler.process { ... }
19
- #
20
16
  # Invokes the throttler with the given block. The throttler will
21
17
  # automatically introduce a delay to keep to the maximum specified rate.
22
18
  # The throttler instance is passed to the given block.
@@ -32,7 +28,7 @@ module Polyphony
32
28
  @next_time += @min_dt
33
29
  break if @next_time > now
34
30
  end
35
-
31
+
36
32
  result
37
33
  end
38
34
  alias_method :process, :call
@@ -44,7 +44,6 @@ module Polyphony
44
44
  # given delay.
45
45
  #
46
46
  # @param interval [Number] delay in seconds before running the given block
47
- # @yield [] block to run
48
47
  # @return [Fiber] spun fiber
49
48
  def after(interval, &block)
50
49
  spin do
@@ -57,7 +56,6 @@ module Polyphony
57
56
  # consecutive iterations.
58
57
  #
59
58
  # @param interval [Number] interval between consecutive iterations in seconds
60
- # @yield [] block to run
61
59
  # @return [void]
62
60
  def every(interval)
63
61
  fiber = Fiber.current
@@ -74,14 +72,6 @@ module Polyphony
74
72
  @timeouts.delete(fiber)
75
73
  end
76
74
 
77
- # call-seq:
78
- # timer.cancel_after(interval) { ... }
79
- # timer.cancel_after(interval, with_exception: exception) { ... }
80
- # timer.cancel_after(interval, with_exception: [klass, message]) { ... }
81
- # timer.cancel_after(interval) { |timeout| ... }
82
- # timer.cancel_after(interval, with_exception: exception) { |timeout| ... }
83
- # timer.cancel_after(interval, with_exception: [klass, message]) { |timeout| ... }
84
- #
85
75
  # Runs the given block after setting up a cancellation timer for
86
76
  # cancellation. If the cancellation timer elapses, the execution will be
87
77
  # interrupted with an exception defaulting to `Polyphony::Cancel`.
@@ -108,10 +98,20 @@ module Polyphony
108
98
  # end
109
99
  # end
110
100
  #
111
- # @param interval [Number] timout in seconds
112
- # @param with_exception [Class, Exception] exception or exception class
113
- # @yield [Canceller] block to execute
114
- # @return [any] block's return value
101
+ # @overload cancel_after(interval)
102
+ # @param interval [Number] timout in seconds
103
+ # @yield [Fiber] timeout fiber
104
+ # @return [any] block's return value
105
+ # @overload cancel_after(interval, with_exception: exception)
106
+ # @param interval [Number] timout in seconds
107
+ # @param with_exception [Class, Exception] exception or exception class
108
+ # @yield [Fiber] timeout fiber
109
+ # @return [any] block's return value
110
+ # @overload cancel_after(interval, with_exception: [klass, message])
111
+ # @param interval [Number] timout in seconds
112
+ # @param with_exception [Array] array containing class and message to use as exception
113
+ # @yield [Fiber] timeout fiber
114
+ # @return [any] block's return value
115
115
  def cancel_after(interval, with_exception: Polyphony::Cancel)
116
116
  fiber = Fiber.current
117
117
  @timeouts[fiber] = {
@@ -124,12 +124,6 @@ module Polyphony
124
124
  @timeouts.delete(fiber)
125
125
  end
126
126
 
127
- # call-seq:
128
- # timer.move_on_after(interval) { ... }
129
- # timer.move_on_after(interval, with_value: value) { ... }
130
- # timer.move_on_after(interval) { |canceller| ... }
131
- # timer.move_on_after(interval, with_value: value) { |canceller| ... }
132
- #
133
127
  # Runs the given block after setting up a cancellation timer for
134
128
  # cancellation. If the cancellation timer elapses, the execution will be
135
129
  # interrupted with a `Polyphony::MoveOn` exception, which will be rescued,
@@ -162,10 +156,15 @@ module Polyphony
162
156
  # end
163
157
  # end
164
158
  #
165
- # @param interval [Number] timout in seconds
166
- # @param with_value [any] return value in case of timeout
167
- # @yield [Fiber] block to execute
168
- # @return [any] block's return value
159
+ # @overload move_on_after(interval) { ... }
160
+ # @param interval [Number] timout in seconds
161
+ # @yield [Fiber] timeout fiber
162
+ # @return [any] block's return value
163
+ # @overload move_on_after(interval, with_value: value) { ... }
164
+ # @param interval [Number] timout in seconds
165
+ # @param with_value [any] return value in case of timeout
166
+ # @yield [Fiber] timeout fiber
167
+ # @return [any] block's return value
169
168
  def move_on_after(interval, with_value: nil)
170
169
  fiber = Fiber.current
171
170
  @timeouts[fiber] = {
@@ -218,7 +217,7 @@ module Polyphony
218
217
 
219
218
  # Runs a timer iteration, invoking any timeouts that are due.
220
219
  #
221
- # @return [void]
220
+ # @return [void]
222
221
  def update
223
222
  return if @timeouts.empty?
224
223