polyphony 0.77 → 0.80
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/.github/workflows/test.yml +1 -1
- data/CHANGELOG.md +18 -0
- data/Gemfile.lock +2 -1
- data/examples/core/pingpong.rb +7 -4
- data/examples/core/zlib_stream.rb +15 -0
- data/ext/polyphony/backend_common.c +16 -8
- data/ext/polyphony/backend_common.h +8 -3
- data/ext/polyphony/backend_io_uring.c +19 -3
- data/ext/polyphony/backend_libev.c +33 -17
- data/ext/polyphony/fiber.c +28 -28
- data/ext/polyphony/polyphony.c +1 -8
- data/ext/polyphony/polyphony.h +11 -8
- data/ext/polyphony/queue.c +82 -6
- data/ext/polyphony/thread.c +6 -2
- data/lib/polyphony/adapters/fs.rb +4 -0
- data/lib/polyphony/adapters/process.rb +14 -1
- data/lib/polyphony/adapters/redis.rb +28 -0
- data/lib/polyphony/adapters/sequel.rb +19 -1
- data/lib/polyphony/core/debug.rb +203 -0
- data/lib/polyphony/core/exceptions.rb +21 -6
- data/lib/polyphony/core/global_api.rb +228 -73
- data/lib/polyphony/core/resource_pool.rb +65 -20
- data/lib/polyphony/core/sync.rb +57 -12
- data/lib/polyphony/core/thread_pool.rb +42 -5
- data/lib/polyphony/core/throttler.rb +21 -5
- data/lib/polyphony/core/timer.rb +125 -1
- data/lib/polyphony/extensions/exception.rb +36 -6
- data/lib/polyphony/extensions/fiber.rb +244 -61
- data/lib/polyphony/extensions/io.rb +4 -2
- data/lib/polyphony/extensions/kernel.rb +9 -4
- data/lib/polyphony/extensions/object.rb +8 -0
- data/lib/polyphony/extensions/openssl.rb +3 -1
- data/lib/polyphony/extensions/socket.rb +458 -39
- data/lib/polyphony/extensions/thread.rb +108 -43
- data/lib/polyphony/extensions/timeout.rb +12 -1
- data/lib/polyphony/extensions.rb +1 -0
- data/lib/polyphony/net.rb +59 -0
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +0 -2
- data/test/test_backend.rb +6 -2
- data/test/test_global_api.rb +0 -23
- data/test/test_io.rb +7 -7
- data/test/test_queue.rb +103 -1
- data/test/test_resource_pool.rb +1 -1
- data/test/test_signal.rb +15 -15
- data/test/test_supervise.rb +27 -0
- data/test/test_thread.rb +1 -1
- data/test/test_throttler.rb +0 -6
- data/test/test_trace.rb +189 -24
- metadata +9 -8
- data/lib/polyphony/core/channel.rb +0 -15
@@ -3,12 +3,13 @@
|
|
3
3
|
require_relative '../core/exceptions'
|
4
4
|
|
5
5
|
module Polyphony
|
6
|
-
|
6
|
+
|
7
|
+
# Fiber control methods
|
7
8
|
module FiberControl
|
8
9
|
# Returns the fiber's monitoring mailbox queue, used for receiving fiber
|
9
10
|
# monitoring messages.
|
10
11
|
#
|
11
|
-
# @return [Polyphony::Queue]
|
12
|
+
# @return [Polyphony::Queue] monitoring mailbox queue
|
12
13
|
def monitor_mailbox
|
13
14
|
@monitor_mailbox ||= Polyphony::Queue.new
|
14
15
|
end
|
@@ -16,12 +17,13 @@ module Polyphony
|
|
16
17
|
# call-seq:
|
17
18
|
# fiber.stop(value = nil) -> fiber
|
18
19
|
# Fiber.interrupt(value = nil) -> fiber
|
20
|
+
# Fiber.move_on(value = nil) -> fiber
|
19
21
|
#
|
20
|
-
# Stops the fiber by raising a Polyphony::MoveOn exception. The given
|
21
|
-
# will become the fiber's return value.
|
22
|
+
# Stops the fiber by raising a `Polyphony::MoveOn` exception. The given
|
23
|
+
# value will become the fiber's return value.
|
22
24
|
#
|
23
|
-
# @param value [any]
|
24
|
-
# @return [Fiber]
|
25
|
+
# @param value [any] fiber's eventual return value
|
26
|
+
# @return [Fiber] self
|
25
27
|
def interrupt(value = nil)
|
26
28
|
return if @running == false
|
27
29
|
|
@@ -29,6 +31,7 @@ module Polyphony
|
|
29
31
|
self
|
30
32
|
end
|
31
33
|
alias_method :stop, :interrupt
|
34
|
+
alias_method :move_on, :interrupt
|
32
35
|
|
33
36
|
# call-seq:
|
34
37
|
# fiber.reset(value = nil) -> fiber
|
@@ -56,24 +59,27 @@ module Polyphony
|
|
56
59
|
|
57
60
|
# Stops a fiber by raising a Polyphony::Cancel exception.
|
58
61
|
#
|
59
|
-
# @
|
60
|
-
|
62
|
+
# @param exception [Class, Exception] exception or exception class
|
63
|
+
# @return [Fiber] self
|
64
|
+
def cancel(exception = Polyphony::Cancel)
|
61
65
|
return if @running == false
|
62
66
|
|
63
|
-
|
67
|
+
value = (Class === exception) ? exception.new : exception
|
68
|
+
schedule value
|
64
69
|
self
|
65
70
|
end
|
66
71
|
|
67
72
|
# Sets the graceful shutdown flag for the fiber.
|
68
73
|
#
|
69
74
|
# @param graceful [bool] Whether or not to perform a graceful shutdown
|
75
|
+
# @return [bool] graceful
|
70
76
|
def graceful_shutdown=(graceful)
|
71
77
|
@graceful_shutdown = graceful
|
72
78
|
end
|
73
79
|
|
74
80
|
# Returns the graceful shutdown flag for the fiber.
|
75
81
|
#
|
76
|
-
# @return [bool]
|
82
|
+
# @return [bool] true if graceful shutdown, otherwise false
|
77
83
|
def graceful_shutdown?
|
78
84
|
@graceful_shutdown
|
79
85
|
end
|
@@ -81,7 +87,7 @@ module Polyphony
|
|
81
87
|
# Terminates the fiber, optionally setting the graceful shutdown flag.
|
82
88
|
#
|
83
89
|
# @param graceful [bool] Whether to perform a graceful shutdown
|
84
|
-
# @return [Fiber]
|
90
|
+
# @return [Fiber] self
|
85
91
|
def terminate(graceful = false)
|
86
92
|
return if @running == false
|
87
93
|
|
@@ -96,15 +102,36 @@ module Polyphony
|
|
96
102
|
# fiber.raise(exception_class, exception_message) -> fiber
|
97
103
|
# fiber.raise(exception) -> fiber
|
98
104
|
#
|
99
|
-
# Raises an exception in the context of the fiber
|
105
|
+
# Raises an exception in the context of the fiber
|
100
106
|
#
|
101
|
-
# @return [Fiber]
|
107
|
+
# @return [Fiber] self
|
102
108
|
def raise(*args)
|
103
109
|
error = error_from_raise_args(args)
|
104
110
|
schedule(error)
|
105
111
|
self
|
106
112
|
end
|
107
113
|
|
114
|
+
# Adds an interjection to the fiber. The current operation undertaken by the
|
115
|
+
# fiber will be interrupted, and the given block will be executed, and the
|
116
|
+
# operation will be resumed. This API is experimental and might be removed
|
117
|
+
# in the future.
|
118
|
+
#
|
119
|
+
# @param &block [Proc] given block
|
120
|
+
# @return [Fiber] self
|
121
|
+
def interject(&block)
|
122
|
+
raise Polyphony::Interjection.new(block)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Blocks until the fiber has terminated, returning its return value.
|
126
|
+
#
|
127
|
+
# @return [any] fiber's return value
|
128
|
+
def await
|
129
|
+
Fiber.await(self).first
|
130
|
+
end
|
131
|
+
alias_method :join, :await
|
132
|
+
|
133
|
+
private
|
134
|
+
|
108
135
|
# :no-doc:
|
109
136
|
def error_from_raise_args(args)
|
110
137
|
case (arg = args.shift)
|
@@ -114,19 +141,41 @@ module Polyphony
|
|
114
141
|
else RuntimeError.new
|
115
142
|
end
|
116
143
|
end
|
117
|
-
|
118
|
-
def interject(&block)
|
119
|
-
raise Polyphony::Interjection.new(block)
|
120
|
-
end
|
121
|
-
|
122
|
-
def await
|
123
|
-
Fiber.await(self).first
|
124
|
-
end
|
125
|
-
alias_method :join, :await
|
126
144
|
end
|
127
145
|
|
128
|
-
# Fiber supervision
|
146
|
+
# Fiber supervision methods
|
129
147
|
module FiberSupervision
|
148
|
+
|
149
|
+
# call-seq:
|
150
|
+
# fiber.supervise
|
151
|
+
# fiber.supervise(fiber_a, fiber_b)
|
152
|
+
# fiber.supervise { |f, r| handle_terminated_fiber(f, r) }
|
153
|
+
# fiber.supervise(on_done: ->(f, r) { handle_terminated_fiber(f, r) })
|
154
|
+
# fiber.supervise(on_error: ->(f, e) { handle_error(f, e) })
|
155
|
+
# fiber.supervise(*fibers, restart: always)
|
156
|
+
# fiber.supervise(*fibers, restart: on_error)
|
157
|
+
#
|
158
|
+
# Supervises the given fibers or all child fibers. The fiber is put in
|
159
|
+
# supervision mode, which means any child added after calling `#supervise`
|
160
|
+
# will automatically be supervised. Depending on the given options, fibers
|
161
|
+
# may be automatically restarted.
|
162
|
+
#
|
163
|
+
# If a block is given, the block is called whenever a supervised fiber has
|
164
|
+
# terminated. If the `:on_done` option is given, that proc will be called
|
165
|
+
# when a supervised fiber has terminated. If the `:on_error` option is
|
166
|
+
# given, that proc will be called when a supervised fiber has terminated
|
167
|
+
# with an uncaught exception. If the `:restart` option equals `:always`,
|
168
|
+
# fibers will always be restarted. If the `:restart` option equals
|
169
|
+
# `:on_error`, fibers will be restarted only when terminated with an
|
170
|
+
# uncaught exception.
|
171
|
+
#
|
172
|
+
# This method blocks indefinitely.
|
173
|
+
#
|
174
|
+
# @param *fibers [Array<Fiber>] fibers to supervise
|
175
|
+
# @param on_done: [Proc, nil] proc to call when a supervised fiber is terminated
|
176
|
+
# @param on_error: [Proc, nil] proc to call when a supervised fiber is terminated with an exception
|
177
|
+
# @param restart: [:always, :on_error, nil] whether to restart terminated fibers
|
178
|
+
# @return [void]
|
130
179
|
def supervise(*fibers, **opts, &block)
|
131
180
|
block ||= supervise_opts_to_block(opts)
|
132
181
|
|
@@ -147,6 +196,9 @@ module Polyphony
|
|
147
196
|
@supervise_mode = false
|
148
197
|
end
|
149
198
|
|
199
|
+
private
|
200
|
+
|
201
|
+
# :no-doc:
|
150
202
|
def supervise_opts_to_block(opts)
|
151
203
|
block = opts[:on_done] || opts[:on_error]
|
152
204
|
restart = opts[:restart]
|
@@ -164,8 +216,9 @@ module Polyphony
|
|
164
216
|
end
|
165
217
|
end
|
166
218
|
|
167
|
-
#
|
219
|
+
# Fiber control class methods
|
168
220
|
module FiberControlClassMethods
|
221
|
+
|
169
222
|
# call-seq:
|
170
223
|
# Fiber.await(*fibers) -> [*results]
|
171
224
|
# Fiber.join(*fibers) -> [*results]
|
@@ -247,22 +300,29 @@ module Polyphony
|
|
247
300
|
# running, it will bubble up to the main thread's main fiber, which will
|
248
301
|
# also be scheduled with priority. This method is mainly used trapping
|
249
302
|
# signals (see also the patched `Kernel#trap`)
|
303
|
+
#
|
304
|
+
# @param &block [Proc] given block
|
305
|
+
# @return [void]
|
250
306
|
def schedule_priority_oob_fiber(&block)
|
251
307
|
oob_fiber = Fiber.new do
|
252
308
|
Fiber.current.setup_raw
|
309
|
+
Thread.backend.trace(:unblock, oob_fiber, nil, @caller)
|
253
310
|
result = block.call
|
254
311
|
rescue Exception => e
|
255
312
|
Thread.current.schedule_and_wakeup(Thread.main.main_fiber, e)
|
256
313
|
result = e
|
257
314
|
ensure
|
258
|
-
Thread.backend.trace(:
|
315
|
+
Thread.backend.trace(:terminate, Fiber.current, result)
|
259
316
|
suspend
|
260
317
|
end
|
261
318
|
prepare_oob_fiber(oob_fiber, block)
|
262
|
-
Thread.backend.trace(:
|
319
|
+
Thread.backend.trace(:spin, oob_fiber, caller)
|
263
320
|
oob_fiber.schedule_with_priority(nil)
|
264
321
|
end
|
265
322
|
|
323
|
+
private
|
324
|
+
|
325
|
+
# :no-doc:
|
266
326
|
def prepare_oob_fiber(fiber, block)
|
267
327
|
fiber.oob = true
|
268
328
|
fiber.tag = :oob
|
@@ -272,21 +332,24 @@ module Polyphony
|
|
272
332
|
end
|
273
333
|
end
|
274
334
|
|
275
|
-
#
|
335
|
+
# Child fiber control methods
|
276
336
|
module ChildFiberControl
|
337
|
+
|
338
|
+
# Returns the fiber's children.
|
339
|
+
#
|
340
|
+
# @return [Array<Fiber>] child fibers
|
277
341
|
def children
|
278
342
|
(@children ||= {}).keys
|
279
343
|
end
|
280
344
|
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
345
|
+
# Creates a new child fiber.
|
346
|
+
#
|
347
|
+
# child = fiber.spin { sleep 10; fiber.stop }
|
348
|
+
#
|
349
|
+
# @param tag [any] child fiber's tag
|
350
|
+
# @param orig_caller [Array<String>] caller to set for fiber
|
351
|
+
# @param &block [Proc] child fiber's block
|
352
|
+
# @return [Fiber] child fiber
|
290
353
|
def spin(tag = nil, orig_caller = Kernel.caller, &block)
|
291
354
|
f = Fiber.new { |v| f.run(v) }
|
292
355
|
f.prepare(tag, block, orig_caller, self)
|
@@ -295,24 +358,37 @@ module Polyphony
|
|
295
358
|
f
|
296
359
|
end
|
297
360
|
|
361
|
+
# Terminates all child fibers. This method will return before the fibers are
|
362
|
+
# actually terminated.
|
363
|
+
#
|
364
|
+
# @param graceful [bool] whether to perform a graceful termination
|
365
|
+
# @return [Fiber] self
|
298
366
|
def terminate_all_children(graceful = false)
|
299
|
-
return unless @children
|
367
|
+
return self unless @children
|
300
368
|
|
301
369
|
e = Polyphony::Terminate.new
|
302
370
|
@children.each_key do |c|
|
303
371
|
c.graceful_shutdown = true if graceful
|
304
372
|
c.raise e
|
305
373
|
end
|
374
|
+
self
|
306
375
|
end
|
307
376
|
|
377
|
+
# Block until all child fibers have terminated. Returns the return values
|
378
|
+
# for all child fibers.
|
379
|
+
#
|
380
|
+
# @return [Array<any>] return values of child fibers
|
308
381
|
def await_all_children
|
309
382
|
return unless @children && !@children.empty?
|
310
383
|
|
311
384
|
Fiber.await(*@children.keys.reject { |c| c.dead? })
|
312
385
|
end
|
313
386
|
|
387
|
+
# Terminates and blocks until all child fibers have terminated.
|
388
|
+
#
|
389
|
+
# @return [Fiber] self
|
314
390
|
def shutdown_all_children(graceful = false)
|
315
|
-
return unless @children
|
391
|
+
return self unless @children
|
316
392
|
|
317
393
|
@children.keys.each do |c|
|
318
394
|
next if c.dead?
|
@@ -320,12 +396,22 @@ module Polyphony
|
|
320
396
|
c.terminate(graceful)
|
321
397
|
c.await
|
322
398
|
end
|
399
|
+
self
|
323
400
|
end
|
324
401
|
|
325
|
-
|
326
|
-
|
402
|
+
# Attaches all child fibers to a new parent.
|
403
|
+
#
|
404
|
+
# @param parent [Fiber] new parent
|
405
|
+
# @return [Fiber] self
|
406
|
+
def attach_all_children_to(parent)
|
407
|
+
@children&.keys.each { |c| c.attach_to(parent) }
|
408
|
+
self
|
327
409
|
end
|
328
410
|
|
411
|
+
# Detaches the fiber from its current parent. The fiber will be made a child
|
412
|
+
# of the main fiber (for the current thread.)
|
413
|
+
#
|
414
|
+
# @return [Fiber] self
|
329
415
|
def detach
|
330
416
|
@parent.remove_child(self)
|
331
417
|
@parent = @thread.main_fiber
|
@@ -333,60 +419,102 @@ module Polyphony
|
|
333
419
|
self
|
334
420
|
end
|
335
421
|
|
336
|
-
|
422
|
+
# Attaches the fiber to a new parent.
|
423
|
+
#
|
424
|
+
# @param parent [Fiber] new parent
|
425
|
+
# @return [Fiber] self
|
426
|
+
def attach_to(parent)
|
337
427
|
@parent.remove_child(self)
|
338
|
-
@parent =
|
339
|
-
|
428
|
+
@parent = parent
|
429
|
+
parent.add_child(self)
|
430
|
+
self
|
340
431
|
end
|
341
432
|
|
342
|
-
|
433
|
+
# Attaches the fiber to the new parent and monitors the new parent.
|
434
|
+
#
|
435
|
+
# @param parent [Fiber] new parent
|
436
|
+
# @return [Fiber] self
|
437
|
+
def attach_and_monitor(parent)
|
343
438
|
@parent.remove_child(self)
|
344
|
-
@parent =
|
345
|
-
|
346
|
-
monitor(
|
439
|
+
@parent = parent
|
440
|
+
parent.add_child(self)
|
441
|
+
monitor(parent)
|
442
|
+
self
|
443
|
+
end
|
444
|
+
|
445
|
+
# Adds a child fiber reference. Used internally.
|
446
|
+
#
|
447
|
+
# @param child_fiber [Fiber] child fiber
|
448
|
+
# @return [Fiber] self
|
449
|
+
def add_child(child_fiber)
|
450
|
+
(@children ||= {})[child_fiber] = true
|
451
|
+
child_fiber.monitor(self) if @supervise_mode
|
452
|
+
self
|
453
|
+
end
|
454
|
+
|
455
|
+
# Removes a child fiber reference. Used internally.
|
456
|
+
#
|
457
|
+
# @param parent [Fiber] new parent
|
458
|
+
# @return [Fiber] self
|
459
|
+
def remove_child(child_fiber)
|
460
|
+
@children.delete(child_fiber) if @children
|
347
461
|
end
|
348
462
|
end
|
349
463
|
|
350
464
|
# Fiber life cycle methods
|
351
465
|
module FiberLifeCycle
|
466
|
+
|
467
|
+
# Prepares a fiber for running.
|
468
|
+
#
|
469
|
+
# @param tag [any] fiber's tag
|
470
|
+
# @param block [Proc] fiber's block
|
471
|
+
# @param caller [Array<String>] fiber's caller
|
472
|
+
# @param parent [Fiber] fiber's parent
|
473
|
+
# @return [void]
|
352
474
|
def prepare(tag, block, caller, parent)
|
353
475
|
@thread = Thread.current
|
354
476
|
@tag = tag
|
355
477
|
@parent = parent
|
356
478
|
@caller = caller
|
357
479
|
@block = block
|
358
|
-
Thread.backend.trace(:
|
480
|
+
Thread.backend.trace(:spin, self, Kernel.caller[1..-1])
|
359
481
|
schedule
|
360
482
|
end
|
361
483
|
|
484
|
+
# Runs the fiber's block and handles uncaught exceptions.
|
485
|
+
#
|
486
|
+
# @param first_value [any] value passed to fiber on first resume
|
487
|
+
# @return [void]
|
362
488
|
def run(first_value)
|
363
|
-
|
489
|
+
Kernel.raise first_value if first_value.is_a?(Exception)
|
490
|
+
@running = true
|
491
|
+
|
492
|
+
Thread.backend.trace(:unblock, self, first_value, @caller)
|
364
493
|
result = @block.(first_value)
|
365
|
-
finalize
|
494
|
+
finalize(result)
|
366
495
|
rescue Polyphony::Restart => e
|
367
496
|
restart_self(e.value)
|
368
497
|
rescue Polyphony::MoveOn, Polyphony::Terminate => e
|
369
|
-
finalize
|
498
|
+
finalize(e.value)
|
370
499
|
rescue Exception => e
|
371
500
|
e.source_fiber = self
|
372
|
-
finalize
|
373
|
-
end
|
374
|
-
|
375
|
-
def setup(first_value)
|
376
|
-
Kernel.raise first_value if first_value.is_a?(Exception)
|
377
|
-
|
378
|
-
@running = true
|
501
|
+
finalize(e, true)
|
379
502
|
end
|
380
503
|
|
381
504
|
# Performs setup for a "raw" Fiber created using Fiber.new. Note that this
|
382
505
|
# fiber is an orphan fiber (has no parent), since we cannot control how the
|
383
506
|
# fiber terminates after it has already been created. Calling #setup_raw
|
384
507
|
# allows the fiber to be scheduled and to receive messages.
|
508
|
+
#
|
509
|
+
# @return [void]
|
385
510
|
def setup_raw
|
386
511
|
@thread = Thread.current
|
387
512
|
@running = true
|
388
513
|
end
|
389
514
|
|
515
|
+
# Sets up the fiber as the main fiber for the current thread.
|
516
|
+
#
|
517
|
+
# @return [void]
|
390
518
|
def setup_main_fiber
|
391
519
|
@main = true
|
392
520
|
@tag = :main
|
@@ -395,14 +523,23 @@ module Polyphony
|
|
395
523
|
@children&.clear
|
396
524
|
end
|
397
525
|
|
526
|
+
# Resets the fiber's state and reruns the fiber.
|
527
|
+
#
|
528
|
+
# @param first_value [Fiber] first_value to pass to fiber after restarting
|
529
|
+
# @return [void]
|
398
530
|
def restart_self(first_value)
|
399
531
|
@mailbox = nil
|
400
532
|
run(first_value)
|
401
533
|
end
|
402
534
|
|
535
|
+
# Finalizes the fiber, handling its return value or any uncaught exception.
|
536
|
+
#
|
537
|
+
# @param result [any] return value
|
538
|
+
# @param uncaught_exception [Exception, nil] uncaught exception
|
539
|
+
# @return [void]
|
403
540
|
def finalize(result, uncaught_exception = false)
|
404
541
|
result, uncaught_exception = finalize_children(result, uncaught_exception)
|
405
|
-
Thread.backend.trace(:
|
542
|
+
Thread.backend.trace(:terminate, self, result)
|
406
543
|
@result = result
|
407
544
|
|
408
545
|
inform_monitors(result, uncaught_exception)
|
@@ -417,6 +554,10 @@ module Polyphony
|
|
417
554
|
# Shuts down all children of the current fiber. If any exception occurs while
|
418
555
|
# the children are shut down, it is returned along with the uncaught_exception
|
419
556
|
# flag set. Otherwise, it returns the given arguments.
|
557
|
+
#
|
558
|
+
# @param result [any] fiber's return value
|
559
|
+
# @param uncaught_exception [Exception, nil] uncaught exception
|
560
|
+
# @return [void]
|
420
561
|
def finalize_children(result, uncaught_exception)
|
421
562
|
shutdown_all_children(graceful_shutdown?)
|
422
563
|
[result, uncaught_exception]
|
@@ -424,6 +565,11 @@ module Polyphony
|
|
424
565
|
[e, true]
|
425
566
|
end
|
426
567
|
|
568
|
+
# Informs the fiber's monitors it is terminated.
|
569
|
+
#
|
570
|
+
# @param result [any] fiber's return value
|
571
|
+
# @param uncaught_exception [Exception, nil] uncaught exception
|
572
|
+
# @return [void]
|
427
573
|
def inform_monitors(result, uncaught_exception)
|
428
574
|
if @monitors
|
429
575
|
msg = [self, result]
|
@@ -436,18 +582,35 @@ module Polyphony
|
|
436
582
|
end
|
437
583
|
end
|
438
584
|
|
585
|
+
# Adds a fiber to the list of monitoring fibers. Monitoring fibers will be
|
586
|
+
# notified on their monitor mailboxes when the fiber is terminated.
|
587
|
+
#
|
588
|
+
# @param fiber [Fiber] monitoring fiber
|
589
|
+
# @return [Fiber] self
|
439
590
|
def monitor(fiber)
|
440
591
|
(@monitors ||= {})[fiber] = true
|
592
|
+
self
|
441
593
|
end
|
442
594
|
|
595
|
+
# Removes a monitor fiber.
|
596
|
+
#
|
597
|
+
# @param fiber [Fiber] monitoring fiber
|
598
|
+
# @return [Fiber] self
|
443
599
|
def unmonitor(fiber)
|
444
600
|
(@monitors ||= []).delete(fiber)
|
601
|
+
self
|
445
602
|
end
|
446
603
|
|
604
|
+
# Returns the list of monitoring fibers.
|
605
|
+
#
|
606
|
+
# @return [Array<Fiber>] monitoring fibers
|
447
607
|
def monitors
|
448
608
|
@monitors&.keys || []
|
449
609
|
end
|
450
610
|
|
611
|
+
# Returns true if the fiber is dead.
|
612
|
+
#
|
613
|
+
# @return [bool] is fiber dead
|
451
614
|
def dead?
|
452
615
|
state == :dead
|
453
616
|
end
|
@@ -466,10 +629,16 @@ class ::Fiber
|
|
466
629
|
attr_accessor :tag, :thread, :parent, :oob
|
467
630
|
attr_reader :result
|
468
631
|
|
632
|
+
# Returns true if fiber is running.
|
633
|
+
#
|
634
|
+
# @return [bool] is fiber running
|
469
635
|
def running?
|
470
636
|
@running
|
471
637
|
end
|
472
638
|
|
639
|
+
# Returns a string representation of the fiber for debugging.
|
640
|
+
#
|
641
|
+
# @return [String] string representation
|
473
642
|
def inspect
|
474
643
|
if @tag
|
475
644
|
"#<Fiber #{tag}:#{object_id} #{location} (#{state})>"
|
@@ -479,6 +648,9 @@ class ::Fiber
|
|
479
648
|
end
|
480
649
|
alias_method :to_s, :inspect
|
481
650
|
|
651
|
+
# Returns the source location for the fiber based on its caller.
|
652
|
+
#
|
653
|
+
# @return [String] source location
|
482
654
|
def location
|
483
655
|
if @oob
|
484
656
|
"#{@caller[0]} (oob)"
|
@@ -487,6 +659,9 @@ class ::Fiber
|
|
487
659
|
end
|
488
660
|
end
|
489
661
|
|
662
|
+
# Returns the fiber's caller.
|
663
|
+
#
|
664
|
+
# @return [Array<String>] caller
|
490
665
|
def caller
|
491
666
|
spin_caller = @caller || []
|
492
667
|
if @parent
|
@@ -496,10 +671,18 @@ class ::Fiber
|
|
496
671
|
end
|
497
672
|
end
|
498
673
|
|
499
|
-
|
500
|
-
|
674
|
+
# Sets the fiber's caller.
|
675
|
+
#
|
676
|
+
# @param caller [Array<String>] new caller
|
677
|
+
# @return [Fiber] self
|
678
|
+
def set_caller(caller)
|
679
|
+
@caller = caller
|
680
|
+
self
|
501
681
|
end
|
502
682
|
|
683
|
+
# Returns true if the fiber is the main fiber for its thread.
|
684
|
+
#
|
685
|
+
# @return [bool] is main fiber
|
503
686
|
def main?
|
504
687
|
@main
|
505
688
|
end
|
@@ -2,10 +2,12 @@
|
|
2
2
|
|
3
3
|
require 'open3'
|
4
4
|
|
5
|
-
# IO
|
5
|
+
# IO extensions
|
6
6
|
class ::IO
|
7
7
|
class << self
|
8
8
|
alias_method :orig_binread, :binread
|
9
|
+
|
10
|
+
# TODO: add docs to all methods in this file
|
9
11
|
def binread(name, length = nil, offset = nil)
|
10
12
|
File.open(name, 'rb:ASCII-8BIT') do |f|
|
11
13
|
f.seek(offset) if offset
|
@@ -76,7 +78,7 @@ end
|
|
76
78
|
|
77
79
|
# IO instance method patches
|
78
80
|
class ::IO
|
79
|
-
def
|
81
|
+
def __read_method__
|
80
82
|
:backend_read
|
81
83
|
end
|
82
84
|
|
@@ -7,6 +7,8 @@ module ::Kernel
|
|
7
7
|
alias_method :orig_sleep, :sleep
|
8
8
|
|
9
9
|
alias_method :orig_backtick, :`
|
10
|
+
|
11
|
+
# TODO: add docs to all methods in this file
|
10
12
|
def `(cmd)
|
11
13
|
Open3.popen3(cmd) do |i, o, e, _t|
|
12
14
|
i.close
|
@@ -72,10 +74,6 @@ module ::Kernel
|
|
72
74
|
end
|
73
75
|
end
|
74
76
|
|
75
|
-
def pipe_to_eof(src, dest)
|
76
|
-
src.read_loop { |data| dest << data }
|
77
|
-
end
|
78
|
-
|
79
77
|
alias_method :orig_trap, :trap
|
80
78
|
def trap(sig, command = nil, &block)
|
81
79
|
return orig_trap(sig, command) if command.is_a? String
|
@@ -92,4 +90,11 @@ module ::Kernel
|
|
92
90
|
Fiber.schedule_priority_oob_fiber(&block)
|
93
91
|
end
|
94
92
|
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
# :no-doc:
|
97
|
+
def pipe_to_eof(src, dest)
|
98
|
+
src.read_loop { |data| dest << data }
|
99
|
+
end
|
95
100
|
end
|
@@ -5,11 +5,13 @@ require_relative './socket'
|
|
5
5
|
|
6
6
|
# OpenSSL socket helper methods (to make it compatible with Socket API) and overrides
|
7
7
|
class ::OpenSSL::SSL::SSLSocket
|
8
|
-
def
|
8
|
+
def __read_method__
|
9
9
|
:readpartial
|
10
10
|
end
|
11
11
|
|
12
12
|
alias_method :orig_initialize, :initialize
|
13
|
+
|
14
|
+
# TODO: add docs to all methods in this file
|
13
15
|
def initialize(socket, context = nil)
|
14
16
|
socket = socket.respond_to?(:io) ? socket.io || socket : socket
|
15
17
|
context ? orig_initialize(socket, context) : orig_initialize(socket)
|