polyphony 0.79 → 0.80
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/Gemfile.lock +2 -1
- data/examples/core/zlib_stream.rb +15 -0
- data/ext/polyphony/backend_common.c +2 -1
- data/ext/polyphony/backend_common.h +7 -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 +129 -72
- 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 +238 -57
- 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_resource_pool.rb +1 -1
- data/test/test_throttler.rb +0 -6
- data/test/test_trace.rb +87 -0
- metadata +9 -8
- data/lib/polyphony/core/channel.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cf3658689c8bb7614624ad75492b16fc31401c5c8ee37cd510bb4aab1c9d1449
|
4
|
+
data.tar.gz: 5e2520d758db10e9dfe8022d6a85df61e1702f2e1e6560a95968e37b6f4f6e82
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7bd42d8fed28064941281c0e010f86a7ff7fff56e28c8e8190c8bc5c68eebd26a8d568e03ce20120db64684a036afb8d9b8586668c59f39fadebdaba2624ba75
|
7
|
+
data.tar.gz: cd91d0394a0642fbb43d59cc3ba6a3100377be955f1cabeebc051f8f6159d6fb0e78fa7deedabc6bc4fabc20b12453c963b85ed9ce76002211d3423b05f51542
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## 0.80 2022-02-28
|
2
|
+
|
3
|
+
- Prevent reentry into `trace_proc`
|
4
|
+
- Rename `__parser_read_method__` to `__read_method__`
|
5
|
+
- Rename `ResourcePool#preheat!` to `#fill`.
|
6
|
+
- Remove ability to use `#cancel_after` or `#move_on` without a block
|
7
|
+
- Add #move_on alias to `Fiber#interrupt`
|
8
|
+
- Allow specifying exception in `Fiber#cancel`
|
9
|
+
- Remove deprecated `Polyphony::Channel` class
|
10
|
+
|
1
11
|
## 0.79 2022-02-19
|
2
12
|
|
3
13
|
- Overhaul trace events system (#73)
|
data/Gemfile.lock
CHANGED
@@ -17,6 +17,7 @@ inline void backend_base_initialize(struct Backend_base *base) {
|
|
17
17
|
base->idle_gc_last_time = 0;
|
18
18
|
base->idle_proc = Qnil;
|
19
19
|
base->trace_proc = Qnil;
|
20
|
+
base->in_trace_proc = 0;
|
20
21
|
}
|
21
22
|
|
22
23
|
inline void backend_base_finalize(struct Backend_base *base) {
|
@@ -137,7 +138,7 @@ inline void backend_base_unpark_fiber(struct Backend_base *base, VALUE fiber) {
|
|
137
138
|
}
|
138
139
|
|
139
140
|
inline void backend_trace(struct Backend_base *base, int argc, VALUE *argv) {
|
140
|
-
if (base->trace_proc == Qnil) return;
|
141
|
+
if (base->trace_proc == Qnil || base->in_trace_proc) return;
|
141
142
|
|
142
143
|
rb_funcallv(base->trace_proc, ID_call, argc, argv);
|
143
144
|
}
|
@@ -32,6 +32,7 @@ struct Backend_base {
|
|
32
32
|
double idle_gc_last_time;
|
33
33
|
VALUE idle_proc;
|
34
34
|
VALUE trace_proc;
|
35
|
+
unsigned int in_trace_proc;
|
35
36
|
};
|
36
37
|
|
37
38
|
void backend_base_initialize(struct Backend_base *base);
|
@@ -46,8 +47,12 @@ void backend_trace(struct Backend_base *base, int argc, VALUE *argv);
|
|
46
47
|
struct backend_stats backend_base_stats(struct Backend_base *base);
|
47
48
|
|
48
49
|
// tracing
|
49
|
-
#define SHOULD_TRACE(base) ((base)->trace_proc != Qnil)
|
50
|
-
#define TRACE(base, ...)
|
50
|
+
#define SHOULD_TRACE(base) ((base)->trace_proc != Qnil && !(base)->in_trace_proc)
|
51
|
+
#define TRACE(base, ...) { \
|
52
|
+
(base)->in_trace_proc = 1; \
|
53
|
+
rb_funcall((base)->trace_proc, ID_call, __VA_ARGS__); \
|
54
|
+
(base)->in_trace_proc = 0; \
|
55
|
+
}
|
51
56
|
#define COND_TRACE(base, ...) if (SHOULD_TRACE(base)) { TRACE(base, __VA_ARGS__); }
|
52
57
|
|
53
58
|
|
@@ -6,6 +6,8 @@ require_relative '../core/thread_pool'
|
|
6
6
|
|
7
7
|
::File.singleton_class.instance_eval do
|
8
8
|
alias_method :orig_stat, :stat
|
9
|
+
|
10
|
+
# Offloads `File.stat` to the default thread pool.
|
9
11
|
def stat(path)
|
10
12
|
ThreadPool.process { orig_stat(path) }
|
11
13
|
end
|
@@ -13,6 +15,8 @@ end
|
|
13
15
|
|
14
16
|
::IO.singleton_class.instance_eval do
|
15
17
|
alias_method :orig_read, :read
|
18
|
+
|
19
|
+
# Offloads `IO.read` to the default thread pool.
|
16
20
|
def read(path)
|
17
21
|
ThreadPool.process { orig_read(path) }
|
18
22
|
end
|
@@ -1,9 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Polyphony
|
4
|
-
# Process
|
4
|
+
# Process extensions
|
5
5
|
module Process
|
6
6
|
class << self
|
7
|
+
|
8
|
+
# Watches a forked or spawned process, waiting for it to terminate. If
|
9
|
+
# `cmd` is given it is spawned, otherwise the process is forked with the
|
10
|
+
# given block.
|
11
|
+
#
|
12
|
+
# If the operation is interrupted for any reason, the spawned or forked
|
13
|
+
# process is killed.
|
14
|
+
#
|
15
|
+
# @param cmd [String, nil] command to spawn
|
16
|
+
# @param &block [Proc] block to fork
|
17
|
+
# @return [void]
|
7
18
|
def watch(cmd = nil, &block)
|
8
19
|
terminated = nil
|
9
20
|
pid = cmd ? Kernel.spawn(cmd) : Polyphony.fork(&block)
|
@@ -13,6 +24,8 @@ module Polyphony
|
|
13
24
|
kill_process(pid) unless terminated || pid.nil?
|
14
25
|
end
|
15
26
|
|
27
|
+
private
|
28
|
+
|
16
29
|
def kill_process(pid)
|
17
30
|
cancel_after(5) do
|
18
31
|
kill_and_await('TERM', pid)
|
@@ -7,6 +7,10 @@ require 'hiredis/reader'
|
|
7
7
|
|
8
8
|
# Polyphony-based Redis driver
|
9
9
|
class Polyphony::RedisDriver
|
10
|
+
|
11
|
+
# Connects to a Redis server using the given config.
|
12
|
+
#
|
13
|
+
# @return [TCPSocket, UNIXSocket, SSLSocket] client connectio
|
10
14
|
def self.connect(config)
|
11
15
|
raise 'unix sockets not supported' if config[:scheme] == 'unix'
|
12
16
|
|
@@ -20,28 +24,49 @@ class Polyphony::RedisDriver
|
|
20
24
|
# connection.connect(config[:host], config[:port], connect_timeout)
|
21
25
|
end
|
22
26
|
|
27
|
+
# Initializes a Redis client connection.
|
28
|
+
#
|
29
|
+
# @param host [String] hostname
|
30
|
+
# @param port [Integer] port number
|
23
31
|
def initialize(host, port)
|
24
32
|
@connection = Polyphony::Net.tcp_connect(host, port)
|
25
33
|
@reader = ::Hiredis::Reader.new
|
26
34
|
end
|
27
35
|
|
36
|
+
# Returns true if connected to server.
|
37
|
+
#
|
38
|
+
# @return [bool] is connected to server
|
28
39
|
def connected?
|
29
40
|
@connection && !@connection.closed?
|
30
41
|
end
|
31
42
|
|
43
|
+
# Sets a timeout for the connection.
|
44
|
+
#
|
45
|
+
# @return [void]
|
32
46
|
def timeout=(timeout)
|
33
47
|
# ignore timeout for now
|
34
48
|
end
|
35
49
|
|
50
|
+
# Disconnects from the server.
|
51
|
+
#
|
52
|
+
# @return [void]
|
36
53
|
def disconnect
|
37
54
|
@connection.close
|
38
55
|
@connection = nil
|
39
56
|
end
|
40
57
|
|
58
|
+
# Sends a command to the server.
|
59
|
+
#
|
60
|
+
# @param command [Array] Redis command
|
61
|
+
# @return [void]
|
41
62
|
def write(command)
|
42
63
|
@connection.write(format_command(command))
|
43
64
|
end
|
44
65
|
|
66
|
+
# Formats a command for sending to server.
|
67
|
+
#
|
68
|
+
# @param args [Array] command
|
69
|
+
# @return [String] formatted command
|
45
70
|
def format_command(args)
|
46
71
|
args = args.flatten
|
47
72
|
(+"*#{args.size}\r\n").tap do |s|
|
@@ -52,6 +77,9 @@ class Polyphony::RedisDriver
|
|
52
77
|
end
|
53
78
|
end
|
54
79
|
|
80
|
+
# Reads from the connection, feeding incoming data to the parser.
|
81
|
+
#
|
82
|
+
# @return [void]
|
55
83
|
def read
|
56
84
|
reply = @reader.gets
|
57
85
|
return reply if reply
|
@@ -4,14 +4,23 @@ require_relative '../../polyphony'
|
|
4
4
|
require 'sequel'
|
5
5
|
|
6
6
|
module Polyphony
|
7
|
+
|
7
8
|
# Sequel ConnectionPool that delegates to Polyphony::ResourcePool.
|
8
9
|
class FiberConnectionPool < Sequel::ConnectionPool
|
10
|
+
|
11
|
+
# Initializes the connection pool.
|
12
|
+
#
|
13
|
+
# @param db [any] db to connect to
|
14
|
+
# @opts [Hash] connection pool options
|
9
15
|
def initialize(db, opts = OPTS)
|
10
16
|
super
|
11
17
|
max_size = Integer(opts[:max_connections] || 4)
|
12
18
|
@pool = Polyphony::ResourcePool.new(limit: max_size) { make_new(:default) }
|
13
19
|
end
|
14
20
|
|
21
|
+
# Holds a connection from the pool, passing it to the given block.
|
22
|
+
#
|
23
|
+
# @return [any] block's return value
|
15
24
|
def hold(_server = nil)
|
16
25
|
@pool.acquire do |conn|
|
17
26
|
yield conn
|
@@ -23,16 +32,25 @@ module Polyphony
|
|
23
32
|
end
|
24
33
|
end
|
25
34
|
|
35
|
+
# Returns the pool's size.
|
36
|
+
#
|
37
|
+
# @return [Integer] size of pool
|
26
38
|
def size
|
27
39
|
@pool.size
|
28
40
|
end
|
29
41
|
|
42
|
+
# Returns the pool's maximal size.
|
43
|
+
#
|
44
|
+
# @return [Integer] maximum pool size
|
30
45
|
def max_size
|
31
46
|
@pool.limit
|
32
47
|
end
|
33
48
|
|
49
|
+
# Fills pool and preconnects all db instances in pool.
|
50
|
+
#
|
51
|
+
# @return [void]
|
34
52
|
def preconnect(_concurrent = false)
|
35
|
-
@pool.
|
53
|
+
@pool.fill!
|
36
54
|
end
|
37
55
|
end
|
38
56
|
|
data/lib/polyphony/core/debug.rb
CHANGED
@@ -1,8 +1,15 @@
|
|
1
|
+
# Kernel extensions
|
1
2
|
module ::Kernel
|
3
|
+
# Prints a trace message to `STDOUT`, bypassing the Polyphony backend.
|
4
|
+
#
|
5
|
+
# @return [void]
|
2
6
|
def trace(*args)
|
3
7
|
STDOUT.orig_write(format_trace(args))
|
4
8
|
end
|
5
9
|
|
10
|
+
# Formats a trace message.
|
11
|
+
#
|
12
|
+
# @return [String] trace message
|
6
13
|
def format_trace(args)
|
7
14
|
if args.size > 1 && args.first.is_a?(String)
|
8
15
|
format("%s: %p\n", args.shift, args.size == 1 ? args.first : args)
|
@@ -15,14 +22,29 @@ module ::Kernel
|
|
15
22
|
end
|
16
23
|
|
17
24
|
module Polyphony
|
25
|
+
|
26
|
+
# Trace provides tools for tracing the activity of the current thread's
|
27
|
+
# backend.
|
18
28
|
module Trace
|
19
29
|
class << self
|
30
|
+
|
31
|
+
# Starts tracing, emitting events converted to hashes to the given block.
|
32
|
+
# If an IO instance is given, events are dumped to it instead.
|
33
|
+
#
|
34
|
+
# @param io [IO, nil] IO instance
|
35
|
+
# @param &block [Proc] event handler block
|
36
|
+
# @return [void]
|
20
37
|
def start_event_firehose(io = nil, &block)
|
21
38
|
Thread.backend.trace_proc = firehose_proc(io, block)
|
22
39
|
end
|
23
40
|
|
24
41
|
private
|
25
42
|
|
43
|
+
# Returns a firehose proc for the given io and block.
|
44
|
+
#
|
45
|
+
# @param io [IO, nil] IO instance
|
46
|
+
# @param block [Proc] event handler block
|
47
|
+
# @return [Proc] firehose proc
|
26
48
|
def firehose_proc(io, block)
|
27
49
|
if io
|
28
50
|
->(*e) { io.orig_write("#{trace_event_info(e).inspect}\n") }
|
@@ -33,53 +55,50 @@ module Polyphony
|
|
33
55
|
end
|
34
56
|
end
|
35
57
|
|
58
|
+
# Converts an event (expressed as an array) to a hash.
|
59
|
+
#
|
60
|
+
# @param e [Array] event as emitted by the backend
|
61
|
+
# @return [Hash] event hash
|
36
62
|
def trace_event_info(e)
|
37
63
|
{
|
38
|
-
stamp:
|
64
|
+
stamp: Time.now,
|
39
65
|
event: e[0]
|
40
66
|
}.merge(
|
41
67
|
send(:"event_props_#{e[0]}", e)
|
42
68
|
)
|
43
69
|
end
|
44
|
-
|
45
|
-
def format_trace_event_message(e)
|
46
|
-
props = send(:"event_props_#{e[0]}", e).merge(
|
47
|
-
timestamp: format_current_time,
|
48
|
-
event: e[0]
|
49
|
-
)
|
50
|
-
# templ = send(:"event_format_#{e[0]}", e)
|
51
|
-
|
52
|
-
# msg = format("%<timestamp>s #{templ}\n", **props)
|
53
|
-
end
|
54
|
-
|
55
|
-
def format_current_time
|
56
|
-
Time.now.strftime('%Y-%m-%d %H:%M:%S')
|
57
|
-
end
|
58
70
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
def
|
64
|
-
|
71
|
+
# Returns an event hash for a `:block` event.
|
72
|
+
#
|
73
|
+
# @param e [Array] event array
|
74
|
+
# @return [Hash] event hash
|
75
|
+
def event_props_block(e)
|
76
|
+
{
|
77
|
+
fiber: e[1],
|
78
|
+
caller: e[2]
|
79
|
+
}
|
65
80
|
end
|
66
81
|
|
82
|
+
# Returns an event hash for a `:enter_poll` event.
|
83
|
+
#
|
84
|
+
# @param e [Array] event array
|
85
|
+
# @return [Hash] event hash
|
67
86
|
def event_props_enter_poll(e)
|
68
87
|
{}
|
69
88
|
end
|
70
89
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
90
|
+
# Returns an event hash for a `:leave_poll` event.
|
91
|
+
#
|
92
|
+
# @param e [Array] event array
|
93
|
+
# @return [Hash] event hash
|
75
94
|
def event_props_leave_poll(e)
|
76
95
|
{}
|
77
96
|
end
|
78
97
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
98
|
+
# Returns an event hash for a `:schedule` event.
|
99
|
+
#
|
100
|
+
# @param e [Array] event array
|
101
|
+
# @return [Hash] event hash
|
83
102
|
def event_props_schedule(e)
|
84
103
|
{
|
85
104
|
fiber: e[1],
|
@@ -89,22 +108,22 @@ module Polyphony
|
|
89
108
|
}
|
90
109
|
end
|
91
110
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
def
|
111
|
+
# Returns an event hash for a `:spin` event.
|
112
|
+
#
|
113
|
+
# @param e [Array] event array
|
114
|
+
# @return [Hash] event hash
|
115
|
+
def event_props_spin(e)
|
97
116
|
{
|
98
117
|
fiber: e[1],
|
99
|
-
|
100
|
-
|
118
|
+
caller: e[2],
|
119
|
+
source_fiber: Fiber.current
|
101
120
|
}
|
102
121
|
end
|
103
122
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
123
|
+
# Returns an event hash for a `:terminate` event.
|
124
|
+
#
|
125
|
+
# @param e [Array] event array
|
126
|
+
# @return [Hash] event hash
|
108
127
|
def event_props_terminate(e)
|
109
128
|
{
|
110
129
|
fiber: e[1],
|
@@ -112,48 +131,86 @@ module Polyphony
|
|
112
131
|
}
|
113
132
|
end
|
114
133
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
def
|
134
|
+
# Returns an event hash for a `:unblock` event.
|
135
|
+
#
|
136
|
+
# @param e [Array] event array
|
137
|
+
# @return [Hash] event hash
|
138
|
+
def event_props_unblock(e)
|
120
139
|
{
|
121
140
|
fiber: e[1],
|
122
|
-
|
141
|
+
value: e[2],
|
142
|
+
caller: e[3],
|
123
143
|
}
|
124
144
|
end
|
125
145
|
|
126
|
-
|
127
|
-
|
128
|
-
|
146
|
+
# TODO: work on text formatting of events
|
147
|
+
# def format_trace_event_message(e)
|
148
|
+
# props = send(:"event_props_#{e[0]}", e).merge(
|
149
|
+
# timestamp: format_current_time,
|
150
|
+
# event: e[0]
|
151
|
+
# )
|
152
|
+
# templ = send(:"event_format_#{e[0]}", e)
|
153
|
+
# msg = format("%<timestamp>s #{templ}\n", **props)
|
154
|
+
# end
|
129
155
|
|
130
|
-
def
|
131
|
-
|
132
|
-
|
133
|
-
caller: e[2],
|
134
|
-
source_fiber: Fiber.current
|
135
|
-
}
|
136
|
-
end
|
156
|
+
# def format_current_time
|
157
|
+
# Time.now.strftime('%Y-%m-%d %H:%M:%S')
|
158
|
+
# end
|
137
159
|
|
138
|
-
def
|
139
|
-
|
140
|
-
end
|
160
|
+
# def generic_event_format
|
161
|
+
# '%<event>-12.12s'
|
162
|
+
# end
|
141
163
|
|
142
|
-
def
|
143
|
-
|
144
|
-
end
|
164
|
+
# def fiber_event_format
|
165
|
+
# "#{generic_event_format} %<fiber>-44.44s"
|
166
|
+
# end
|
145
167
|
|
146
|
-
def
|
147
|
-
|
148
|
-
|
149
|
-
else
|
150
|
-
format("%-6x %-.10s", fiber.object_id, "(#{fiber.state})")
|
151
|
-
end
|
152
|
-
end
|
168
|
+
# def event_format_enter_poll(e)
|
169
|
+
# generic_event_format
|
170
|
+
# end
|
153
171
|
|
154
|
-
def
|
155
|
-
|
156
|
-
end
|
172
|
+
# def event_format_leave_poll(e)
|
173
|
+
# generic_event_format
|
174
|
+
# end
|
175
|
+
|
176
|
+
|
177
|
+
# def event_format_schedule(e)
|
178
|
+
# "#{fiber_event_format} %<value>-24.24p %<caller>-120.120s <= %<origin_fiber>s"
|
179
|
+
# end
|
180
|
+
|
181
|
+
|
182
|
+
# def event_format_unblock(e)
|
183
|
+
# "#{fiber_event_format} %<value>-24.24p %<caller>-120.120s"
|
184
|
+
# end
|
185
|
+
|
186
|
+
# def event_format_terminate(e)
|
187
|
+
# "#{fiber_event_format} %<value>-24.24p"
|
188
|
+
# end
|
189
|
+
|
190
|
+
# def event_format_block(e)
|
191
|
+
# "#{fiber_event_format} #{' ' * 24} %<caller>-120.120s"
|
192
|
+
# end
|
193
|
+
|
194
|
+
|
195
|
+
# def event_format_spin(e)
|
196
|
+
# "#{fiber_event_format} #{' ' * 24} %<caller>-120.120s <= %<origin_fiber>s"
|
197
|
+
# end
|
198
|
+
|
199
|
+
# def fibe_repr(fiber)
|
200
|
+
# format("%-6x %-20.20s %-10.10s", fiber.object_id, fiber.tag, "(#{fiber.state})")
|
201
|
+
# end
|
202
|
+
|
203
|
+
# def fiber_compact_repr(fiber)
|
204
|
+
# if fiber.tag
|
205
|
+
# format("%-6x %-.20s %-.10s", fiber.object_id, fiber.tag, "(#{fiber.state})")
|
206
|
+
# else
|
207
|
+
# format("%-6x %-.10s", fiber.object_id, "(#{fiber.state})")
|
208
|
+
# end
|
209
|
+
# end
|
210
|
+
|
211
|
+
# def caller_repr(c)
|
212
|
+
# c.map { |i| i.gsub('/home/sharon/repo/polyphony/lib/polyphony', '') }.join(' ')
|
213
|
+
# end
|
157
214
|
end
|
158
215
|
end
|
159
216
|
end
|
@@ -1,15 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Polyphony
|
4
|
-
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# through nested
|
4
|
+
|
5
|
+
# Base exception class for interrupting fibers. These exceptions allow control
|
6
|
+
# of fibers. BaseException exceptions can encapsulate a value and thus provide
|
7
|
+
# a way to interrupt long-running blocking operations while still passing a
|
8
|
+
# value back to the call site. BaseException exceptions can also references a
|
9
|
+
# cancel scope in order to allow correct bubbling of exceptions through nested
|
10
|
+
# cancel scopes.
|
10
11
|
class BaseException < ::Exception
|
12
|
+
|
13
|
+
# Exception value, used mainly for `MoveOn` exceptions.
|
11
14
|
attr_reader :value
|
12
15
|
|
16
|
+
# Initializes the exception, setting the caller and the value.
|
17
|
+
#
|
18
|
+
# @param value [any] Exception value
|
19
|
+
# @return [void]
|
13
20
|
def initialize(value = nil)
|
14
21
|
@caller_backtrace = caller
|
15
22
|
@value = value
|
@@ -33,10 +40,18 @@ module Polyphony
|
|
33
40
|
|
34
41
|
# Interjection is used to run arbitrary code on arbitrary fibers at any point
|
35
42
|
class Interjection < BaseException
|
43
|
+
|
44
|
+
# Initializes an Interjection with the given proc.
|
45
|
+
#
|
46
|
+
# @param proc [Proc] interjection proc
|
47
|
+
# @return [void]
|
36
48
|
def initialize(proc)
|
37
49
|
@proc = proc
|
38
50
|
end
|
39
51
|
|
52
|
+
# Invokes the exception by calling the associated proc.
|
53
|
+
#
|
54
|
+
# @return [void]
|
40
55
|
def invoke
|
41
56
|
@proc.call
|
42
57
|
end
|