polyphony 0.99.4 → 0.99.6

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +11 -0
  3. data/.yardopts +0 -2
  4. data/README.md +1 -1
  5. data/docs/readme.md +1 -1
  6. data/docs/tutorial.md +2 -2
  7. data/examples/pipes/gzip_http_server.rb +2 -2
  8. data/examples/pipes/http_server.rb +1 -1
  9. data/examples/pipes/tcp_proxy.rb +1 -1
  10. data/ext/polyphony/backend_common.c +4 -4
  11. data/ext/polyphony/backend_io_uring.c +8 -8
  12. data/ext/polyphony/backend_libev.c +5 -5
  13. data/ext/polyphony/fiber.c +33 -42
  14. data/ext/polyphony/io_extensions.c +50 -37
  15. data/ext/polyphony/pipe.c +6 -20
  16. data/ext/polyphony/polyphony.c +72 -144
  17. data/ext/polyphony/queue.c +23 -63
  18. data/ext/polyphony/thread.c +4 -13
  19. data/lib/polyphony/adapters/process.rb +2 -5
  20. data/lib/polyphony/adapters/sequel.rb +2 -2
  21. data/lib/polyphony/core/debug.rb +1 -4
  22. data/lib/polyphony/core/exceptions.rb +1 -5
  23. data/lib/polyphony/core/resource_pool.rb +7 -8
  24. data/lib/polyphony/core/sync.rb +5 -8
  25. data/lib/polyphony/core/thread_pool.rb +3 -10
  26. data/lib/polyphony/core/throttler.rb +1 -5
  27. data/lib/polyphony/core/timer.rb +23 -30
  28. data/lib/polyphony/extensions/fiber.rb +513 -543
  29. data/lib/polyphony/extensions/io.rb +5 -14
  30. data/lib/polyphony/extensions/object.rb +283 -2
  31. data/lib/polyphony/extensions/openssl.rb +5 -26
  32. data/lib/polyphony/extensions/pipe.rb +6 -17
  33. data/lib/polyphony/extensions/socket.rb +24 -118
  34. data/lib/polyphony/extensions/thread.rb +3 -18
  35. data/lib/polyphony/extensions/timeout.rb +0 -1
  36. data/lib/polyphony/net.rb +5 -9
  37. data/lib/polyphony/version.rb +1 -1
  38. data/lib/polyphony.rb +2 -6
  39. data/test/test_io.rb +221 -221
  40. data/test/test_socket.rb +3 -3
  41. data/test/test_trace.rb +2 -2
  42. metadata +5 -9
  43. data/docs/index.md +0 -94
  44. data/docs/link_rewriter.rb +0 -17
  45. data/docs/main-concepts/index.md +0 -9
  46. data/lib/polyphony/core/global_api.rb +0 -309
  47. /data/{assets → docs/assets}/echo-fibers.svg +0 -0
  48. /data/{assets → docs/assets}/polyphony-logo.png +0 -0
  49. /data/{assets → docs/assets}/sleeping-fiber.svg +0 -0
@@ -19,11 +19,8 @@ inline void schedule_fiber(VALUE self, VALUE fiber, VALUE value, int prioritize)
19
19
  Backend_schedule_fiber(self, rb_ivar_get(self, ID_ivar_backend), fiber, value, prioritize);
20
20
  }
21
21
 
22
- /* call-seq:
23
- * thread.unschedule_fiber(fiber)
22
+ /* Removes the given fiber from the thread's runqueue.
24
23
  *
25
- * Removes the given fiber from the thread's runqueue.
26
- *
27
24
  * @param fiber [Fiber] fiber to unschedule
28
25
  * @return [Thread] self
29
26
  */
@@ -45,12 +42,9 @@ inline void Thread_schedule_fiber_with_priority(VALUE self, VALUE fiber, VALUE v
45
42
  // schedule_fiber(self, fiber, value, 1);
46
43
  }
47
44
 
48
- /* call-seq:
49
- * thread.switch_fiber()
45
+ /* Switches to the next fiber in the thread's runqueue.
50
46
  *
51
- * Switches to the next fiber in the thread's runqueue.
52
- *
53
- * @return [void]
47
+ * @return [any] resume value
54
48
  */
55
49
 
56
50
  VALUE Thread_switch_fiber(VALUE self) {
@@ -80,11 +74,8 @@ VALUE Thread_debug(VALUE self) {
80
74
  return self;
81
75
  }
82
76
 
83
- /* call-seq:
84
- * Thread.backend
77
+ /* Returns the backend for the current thread.
85
78
  *
86
- * Returns the backend for the current thread.
87
- *
88
79
  * @return [Polyphony::Backend] backend for the current thread
89
80
  */
90
81
 
@@ -8,13 +8,12 @@ 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
- # @return [void]
16
+ # @return [true]
18
17
  def watch(cmd = nil, &block)
19
18
  terminated = nil
20
19
  pid = cmd ? Kernel.spawn(cmd) : Polyphony.fork(&block)
@@ -28,7 +27,6 @@ module Polyphony
28
27
  # seconds.
29
28
  #
30
29
  # @param pid [Integer] pid
31
- # @return [void]
32
30
  def kill_process(pid)
33
31
  cancel_after(5) do
34
32
  kill_and_await('TERM', pid)
@@ -43,7 +41,6 @@ module Polyphony
43
41
  #
44
42
  # @param sig [String, Symbol, Integer] signal to use
45
43
  # @param pid [Integer] pid
46
- # @return [void]
47
44
  def kill_and_await(sig, pid)
48
45
  ::Process.kill(sig, pid)
49
46
  Polyphony.backend_waitpid(pid)
@@ -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
@@ -1,8 +1,6 @@
1
1
  # Kernel extensions
2
2
  module ::Kernel
3
3
  # Prints a trace message to `STDOUT`, bypassing the Polyphony backend.
4
- #
5
- # @return [void]
6
4
  def trace(*args)
7
5
  STDOUT.orig_write(format_trace(args))
8
6
  end
@@ -32,8 +30,7 @@ module Polyphony
32
30
  # If an IO instance is given, events are dumped to it instead.
33
31
  #
34
32
  # @param io [IO, nil] IO instance
35
- # @yield [Hash] event handler block
36
- # @return [void]
33
+ # @yield [Hash] event information
37
34
  def start_event_firehose(io = nil, &block)
38
35
  Thread.backend.trace_proc = firehose_proc(io, block)
39
36
  end
@@ -16,7 +16,6 @@ module Polyphony
16
16
  # Initializes the exception, setting the caller and the value.
17
17
  #
18
18
  # @param value [any] Exception value
19
- # @return [void]
20
19
  def initialize(value = nil)
21
20
  @caller_backtrace = caller
22
21
  @value = value
@@ -40,18 +39,15 @@ module Polyphony
40
39
 
41
40
  # Interjection is used to run arbitrary code on arbitrary fibers at any point
42
41
  class Interjection < BaseException
43
-
42
+
44
43
  # Initializes an Interjection with the given proc.
45
44
  #
46
45
  # @param proc [Proc] interjection proc
47
- # @return [void]
48
46
  def initialize(proc)
49
47
  @proc = proc
50
48
  end
51
49
 
52
50
  # Invokes the exception by calling the associated proc.
53
- #
54
- # @return [void]
55
51
  def invoke
56
52
  @proc.call
57
53
  end
@@ -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
@@ -28,7 +27,7 @@ module Polyphony
28
27
  # Conditionally releases the mutex. This method is used by condition
29
28
  # variables.
30
29
  #
31
- # @return [void]
30
+ # @return [nil]
32
31
  def conditional_release
33
32
  @store << @token
34
33
  @token = nil
@@ -38,7 +37,7 @@ module Polyphony
38
37
  # Conditionally reacquires the mutex. This method is used by condition
39
38
  # variables.
40
39
  #
41
- # @return [void]
40
+ # @return [Fiber] current fiber
42
41
  def conditional_reacquire
43
42
  @token = @store.shift
44
43
  @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
@@ -141,7 +140,7 @@ module Polyphony
141
140
  #
142
141
  # @param mutex [Polyphony::Mutex] mutex to release while waiting for signal
143
142
  # @param _timeout [Number, nil] timeout in seconds (currently not implemented)
144
- # @return [void]
143
+ # @return [any]
145
144
  def wait(mutex, _timeout = nil)
146
145
  mutex.conditional_release
147
146
  @queue << Fiber.current
@@ -152,7 +151,7 @@ module Polyphony
152
151
  # Signals the condition variable, causing the first fiber in the waiting
153
152
  # queue to be resumed.
154
153
  #
155
- # @return [void]
154
+ # @return [Fiber] resumed fiber
156
155
  def signal
157
156
  return if @queue.empty?
158
157
 
@@ -161,8 +160,6 @@ module Polyphony
161
160
  end
162
161
 
163
162
  # Resumes all waiting fibers.
164
- #
165
- # @return [void]
166
163
  def broadcast
167
164
  return if @queue.empty?
168
165
 
@@ -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
@@ -21,7 +20,7 @@ module Polyphony
21
20
 
22
21
  # Resets the default thread pool.
23
22
  #
24
- # @return [void]
23
+ # @return [nil]
25
24
  def self.reset
26
25
  return unless @default_pool
27
26
 
@@ -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
@@ -81,8 +78,6 @@ module Polyphony
81
78
  private
82
79
 
83
80
  # Runs a processing loop on a worker thread.
84
- #
85
- # @return [void]
86
81
  def thread_loop
87
82
  while true
88
83
  run_queued_task
@@ -90,8 +85,6 @@ module Polyphony
90
85
  end
91
86
 
92
87
  # Runs the first queued task in the task queue.
93
- #
94
- # @return [void]
95
88
  def run_queued_task
96
89
  (block, watcher) = @task_queue.shift
97
90
  result = block.()
@@ -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
@@ -28,7 +28,6 @@ module Polyphony
28
28
  # Sleeps for the given duration.
29
29
  #
30
30
  # @param duration [Number] sleep duration in seconds
31
- # @return [void]
32
31
  def sleep(duration)
33
32
  fiber = Fiber.current
34
33
  @timeouts[fiber] = {
@@ -44,7 +43,6 @@ module Polyphony
44
43
  # given delay.
45
44
  #
46
45
  # @param interval [Number] delay in seconds before running the given block
47
- # @yield [] block to run
48
46
  # @return [Fiber] spun fiber
49
47
  def after(interval, &block)
50
48
  spin do
@@ -57,8 +55,6 @@ module Polyphony
57
55
  # consecutive iterations.
58
56
  #
59
57
  # @param interval [Number] interval between consecutive iterations in seconds
60
- # @yield [] block to run
61
- # @return [void]
62
58
  def every(interval)
63
59
  fiber = Fiber.current
64
60
  @timeouts[fiber] = {
@@ -74,14 +70,6 @@ module Polyphony
74
70
  @timeouts.delete(fiber)
75
71
  end
76
72
 
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
73
  # Runs the given block after setting up a cancellation timer for
86
74
  # cancellation. If the cancellation timer elapses, the execution will be
87
75
  # interrupted with an exception defaulting to `Polyphony::Cancel`.
@@ -108,10 +96,20 @@ module Polyphony
108
96
  # end
109
97
  # end
110
98
  #
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
99
+ # @overload cancel_after(interval)
100
+ # @param interval [Number] timout in seconds
101
+ # @yield [Fiber] timeout fiber
102
+ # @return [any] block's return value
103
+ # @overload cancel_after(interval, with_exception: exception)
104
+ # @param interval [Number] timout in seconds
105
+ # @param with_exception [Class, Exception] exception or exception class
106
+ # @yield [Fiber] timeout fiber
107
+ # @return [any] block's return value
108
+ # @overload cancel_after(interval, with_exception: [klass, message])
109
+ # @param interval [Number] timout in seconds
110
+ # @param with_exception [Array] array containing class and message to use as exception
111
+ # @yield [Fiber] timeout fiber
112
+ # @return [any] block's return value
115
113
  def cancel_after(interval, with_exception: Polyphony::Cancel)
116
114
  fiber = Fiber.current
117
115
  @timeouts[fiber] = {
@@ -124,12 +122,6 @@ module Polyphony
124
122
  @timeouts.delete(fiber)
125
123
  end
126
124
 
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
125
  # Runs the given block after setting up a cancellation timer for
134
126
  # cancellation. If the cancellation timer elapses, the execution will be
135
127
  # interrupted with a `Polyphony::MoveOn` exception, which will be rescued,
@@ -162,10 +154,15 @@ module Polyphony
162
154
  # end
163
155
  # end
164
156
  #
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
157
+ # @overload move_on_after(interval) { ... }
158
+ # @param interval [Number] timout in seconds
159
+ # @yield [Fiber] timeout fiber
160
+ # @return [any] block's return value
161
+ # @overload move_on_after(interval, with_value: value) { ... }
162
+ # @param interval [Number] timout in seconds
163
+ # @param with_value [any] return value in case of timeout
164
+ # @yield [Fiber] timeout fiber
165
+ # @return [any] block's return value
169
166
  def move_on_after(interval, with_value: nil)
170
167
  fiber = Fiber.current
171
168
  @timeouts[fiber] = {
@@ -181,8 +178,6 @@ module Polyphony
181
178
  end
182
179
 
183
180
  # Resets the timeout for the current fiber.
184
- #
185
- # @return [void]
186
181
  def reset
187
182
  record = @timeouts[Fiber.current]
188
183
  return unless record
@@ -217,8 +212,6 @@ module Polyphony
217
212
  end
218
213
 
219
214
  # Runs a timer iteration, invoking any timeouts that are due.
220
- #
221
- # @return [void]
222
215
  def update
223
216
  return if @timeouts.empty?
224
217