polyphony 0.30 → 0.31
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +36 -55
- data/Gemfile.lock +5 -3
- data/Rakefile +0 -4
- data/TODO.md +61 -9
- data/examples/{interfaces → adapters}/pg_client.rb +1 -1
- data/examples/{interfaces → adapters}/pg_notify.rb +1 -1
- data/examples/{interfaces → adapters}/pg_pool.rb +1 -1
- data/examples/{interfaces → adapters}/pg_transaction.rb +1 -1
- data/examples/{interfaces → adapters}/redis_channels.rb +1 -2
- data/examples/{interfaces → adapters}/redis_client.rb +1 -1
- data/examples/{interfaces → adapters}/redis_pubsub.rb +1 -2
- data/examples/{interfaces → adapters}/redis_pubsub_perf.rb +1 -2
- data/ext/gyro/thread.c +36 -1
- data/ext/gyro/timer.c +2 -1
- data/lib/polyphony.rb +2 -2
- data/lib/polyphony/{fs.rb → adapters/fs.rb} +0 -0
- data/lib/polyphony/adapters/irb.rb +51 -0
- data/lib/polyphony/{postgres.rb → adapters/postgres.rb} +1 -1
- data/lib/polyphony/{redis.rb → adapters/redis.rb} +1 -1
- data/lib/polyphony/{trace.rb → adapters/trace.rb} +0 -0
- data/lib/polyphony/core/global_api.rb +2 -2
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +1 -1
- data/test/test_fiber.rb +1 -1
- data/test/test_global_api.rb +13 -0
- data/test/test_signal.rb +73 -0
- metadata +17 -17
- data/lib/polyphony/irb.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 24126ff67fd9fd240299e1af8567da58f072c6c60df3f77b40f87ac108010f80
|
4
|
+
data.tar.gz: 95bcac53f361d65718aea1b55b557a7f68624d9815c38ee7c0cb79e11cb7bc96
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8849c26d4c2eccba56e786ac7ad76c2e2129244b619b988d649dca636491dd6158c0bed8feac191df9a7958f946592a8987a1e6709f27ef1383403b279f5595d
|
7
|
+
data.tar.gz: e8797e0b6e3852a208488213634b1360fc297e3ee9efa5c5e05d538a2684a02dfdf5efb00aca82b72064fc996a50c91de5c477a55ef5fd9dbf85275fd10e1f42
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,16 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
* Fix adapter requires (redis and postgres).
|
2
|
+
|
3
|
+
## 0.31 2020-02-20
|
4
|
+
|
5
|
+
* Fix signal handling race condition (#13)
|
6
|
+
* Move adapter code into polyphony/adapters
|
7
|
+
* Fix spin_loop caller, add tag parameter
|
8
|
+
|
9
|
+
## 0.30 2020-02-04
|
3
10
|
|
4
11
|
* Add support for awaiting a fiber from multiple monitor fibers at once
|
5
12
|
* Implemented child fibers
|
6
|
-
* Fix TERM and INT signal handling (
|
13
|
+
* Fix TERM and INT signal handling (#11)
|
7
14
|
* Fix compiling on Linux
|
8
15
|
* Do not reset runnable value in Gyro_suspend (prevents interrupting timers)
|
9
16
|
* Don't snooze when stopping a fiber
|
@@ -12,8 +19,7 @@
|
|
12
19
|
* Prevent signalling of inactive async watcher
|
13
20
|
* Better fiber messaging
|
14
21
|
|
15
|
-
0.29 2020-02-02
|
16
|
-
---------------
|
22
|
+
## 0.29 2020-02-02
|
17
23
|
|
18
24
|
* Pass SignalException to main fiber
|
19
25
|
* Add (restore) default thread pool
|
@@ -24,8 +30,7 @@
|
|
24
30
|
* Improve tracing
|
25
31
|
* Fix IRB adapter
|
26
32
|
|
27
|
-
0.28 2020-01-27
|
28
|
-
---------------
|
33
|
+
## 0.28 2020-01-27
|
29
34
|
|
30
35
|
* Accept block in Supervisor#initialize
|
31
36
|
* Refactor `ThreadPool`
|
@@ -37,37 +42,32 @@
|
|
37
42
|
* Use `:waiting`, `:runnable`, `:running`, `:dead` for fiber states
|
38
43
|
* Move docs to https://digital-fabric.github.io/polyphony/
|
39
44
|
|
40
|
-
0.27 2020-01-19
|
41
|
-
---------------
|
45
|
+
## 0.27 2020-01-19
|
42
46
|
|
43
47
|
* Reimplement `Throttler` using recurring timer
|
44
48
|
* Add `Gyro::Selector` for wrapping libev
|
45
49
|
* Add `Gyro::Queue`, a fiber-aware thread-safe queue
|
46
50
|
* Implement multithreaded fiber scheduling
|
47
51
|
|
48
|
-
0.26 2020-01-12
|
49
|
-
---------------
|
52
|
+
## 0.26 2020-01-12
|
50
53
|
|
51
54
|
* Optimize `IO#read_watcher`, `IO#write_watcher`
|
52
55
|
* Implement `Fiber#raise`
|
53
56
|
* Fix `Kernel#gets` with `ARGV`
|
54
57
|
* Return `[pid, exit_status]` from `Gyro::Child#await`
|
55
58
|
|
56
|
-
0.25 2020-01-10
|
57
|
-
---------------
|
59
|
+
## 0.25 2020-01-10
|
58
60
|
|
59
61
|
* Fold `Coprocess` functionality into `Fiber`
|
60
62
|
* Add support for indefinite `#sleep`
|
61
63
|
|
62
|
-
0.24 2020-01-08
|
63
|
-
---------------
|
64
|
+
## 0.24 2020-01-08
|
64
65
|
|
65
66
|
* Extract HTTP code into separate polyphony-http gem
|
66
67
|
* Cull core, io examples
|
67
68
|
* Remove `SIGINT` handler
|
68
69
|
|
69
|
-
0.23 2020-01-07
|
70
|
-
---------------
|
70
|
+
## 0.23 2020-01-07
|
71
71
|
|
72
72
|
* Remove `API#pulse`
|
73
73
|
* Better repeat timer, reimplement `API#every`
|
@@ -91,8 +91,7 @@
|
|
91
91
|
* Add Gyro.run
|
92
92
|
* Move away from callback-based API for `Gyro::Timer`, `Gyro::Signal`
|
93
93
|
|
94
|
-
0.22 2020-01-02
|
95
|
-
---------------
|
94
|
+
## 0.22 2020-01-02
|
96
95
|
|
97
96
|
* Redesign Gyro scheduling subsystem, go scheduler-less
|
98
97
|
* More docs
|
@@ -102,8 +101,7 @@
|
|
102
101
|
* Fix socket extensions
|
103
102
|
* Fix ALPN setup in Net.secure_socket
|
104
103
|
|
105
|
-
0.21 2019-12-12
|
106
|
-
---------------
|
104
|
+
## 0.21 2019-12-12
|
107
105
|
|
108
106
|
* Add Coprocess.await (for waiting for multiple coprocesses)
|
109
107
|
* Add Coprocess#caller, Coprocess#location methods
|
@@ -112,8 +110,7 @@
|
|
112
110
|
* Improve error handling in HTTP/2 adapter
|
113
111
|
* More documentation
|
114
112
|
|
115
|
-
0.20 2019-11-27
|
116
|
-
---------------
|
113
|
+
## 0.20 2019-11-27
|
117
114
|
|
118
115
|
* Refactor and improve CancelScope, ResourcePool
|
119
116
|
* Reimplement cancel_after, move_on_after using plain timers
|
@@ -147,8 +144,7 @@
|
|
147
144
|
* Fix HTTP1 adapter
|
148
145
|
* Better support for debugging with ruby-debug-ide (WIP)
|
149
146
|
|
150
|
-
0.19 2019-06-12
|
151
|
-
---------------
|
147
|
+
## 0.19 2019-06-12
|
152
148
|
|
153
149
|
* Rewrite HTTP server for better concurrency, sequential API
|
154
150
|
* Support 204 no-content response in HTTP 1
|
@@ -156,14 +152,12 @@
|
|
156
152
|
* Implement Fiber#safe_transfer in C
|
157
153
|
* Optimize Kernel#next_tick implementation using ev_idle instead of ev_timer
|
158
154
|
|
159
|
-
0.18 2019-06-08
|
160
|
-
---------------
|
155
|
+
## 0.18 2019-06-08
|
161
156
|
|
162
157
|
* Rename Kernel#coproc to Kernel#spin
|
163
158
|
* Rewrite Supervisor#spin
|
164
159
|
|
165
|
-
0.17 2019-05-24
|
166
|
-
---------------
|
160
|
+
## 0.17 2019-05-24
|
167
161
|
|
168
162
|
* Implement IO#read_watcher, IO#write_watcher in C for better performance
|
169
163
|
* Implement nonblocking (yielding) versions of Kernel#system, IO.popen,
|
@@ -173,14 +167,12 @@
|
|
173
167
|
* Fix encoding of strings read with IO#read, IO#readpartial
|
174
168
|
* Fix non-blocking behaviour of IO#read, IO#readpartial, IO#write
|
175
169
|
|
176
|
-
0.16 2019-05-22
|
177
|
-
---------------
|
170
|
+
## 0.16 2019-05-22
|
178
171
|
|
179
172
|
* Reorganize and refactor code
|
180
173
|
* Allow opening secure socket without OpenSSL context
|
181
174
|
|
182
|
-
0.15 2019-05-20
|
183
|
-
---------------
|
175
|
+
## 0.15 2019-05-20
|
184
176
|
|
185
177
|
* Optimize `#next_tick` callback (about 6% faster than before)
|
186
178
|
* Fix IO#<< to return self
|
@@ -188,8 +180,7 @@
|
|
188
180
|
* Fix race condition in `Supervisor#stop!`
|
189
181
|
* Add `Kernel#snooze` method (`EV.snooze` will be deprecated eventually)
|
190
182
|
|
191
|
-
0.14 2019-05-17
|
192
|
-
---------------
|
183
|
+
## 0.14 2019-05-17
|
193
184
|
|
194
185
|
* Use chunked encoding in HTTP 1 response
|
195
186
|
* Rewrite `IO#read`, `#readpartial`, `#write` in C (about 30% performance improvement)
|
@@ -199,13 +190,11 @@
|
|
199
190
|
* Preliminary support for websocket (see `examples/io/http_ws_server.rb`)
|
200
191
|
* Rename `Coroutine` to `Coprocess`
|
201
192
|
|
202
|
-
0.13 2019-01-05
|
203
|
-
---------------
|
193
|
+
## 0.13 2019-01-05
|
204
194
|
|
205
195
|
* Rename Rubato to Polyphony (I know, this is getting silly...)
|
206
196
|
|
207
|
-
0.12 2019-01-01
|
208
|
-
---------------
|
197
|
+
## 0.12 2019-01-01
|
209
198
|
|
210
199
|
* Add Coroutine#resume
|
211
200
|
* Improve startup time
|
@@ -214,8 +203,7 @@
|
|
214
203
|
* Improve handling of uncaught raised errors
|
215
204
|
* Implement HTTP 1.1/2 client agent with connection management
|
216
205
|
|
217
|
-
0.11 2018-12-27
|
218
|
-
---------------
|
206
|
+
## 0.11 2018-12-27
|
219
207
|
|
220
208
|
* Move reactor loop to secondary fiber, allow blocking operations on main
|
221
209
|
fiber.
|
@@ -225,8 +213,7 @@
|
|
225
213
|
for message passing
|
226
214
|
* Add Coroutine.current for getting current coroutine
|
227
215
|
|
228
|
-
0.10 2018-11-20
|
229
|
-
---------------
|
216
|
+
## 0.10 2018-11-20
|
230
217
|
|
231
218
|
* Rewrite Rubato core for simpler code and better performance
|
232
219
|
* Implement EV.snooze (sleep until next tick)
|
@@ -236,20 +223,17 @@
|
|
236
223
|
* Rate throttling
|
237
224
|
* Implement async SSL server
|
238
225
|
|
239
|
-
0.9 2018-11-14
|
240
|
-
--------------
|
226
|
+
## 0.9 2018-11-14
|
241
227
|
|
242
228
|
* Rename Nuclear to Rubato
|
243
229
|
|
244
|
-
0.8 2018-10-04
|
245
|
-
--------------
|
230
|
+
## 0.8 2018-10-04
|
246
231
|
|
247
232
|
* Replace nio4r with in-house extension based on libev, with better API,
|
248
233
|
better performance, support for IO, timer, signal and async watchers
|
249
234
|
* Fix mem leak coming from nio4r (probably related to code in Selector#select)
|
250
235
|
|
251
|
-
0.7 2018-09-13
|
252
|
-
--------------
|
236
|
+
## 0.7 2018-09-13
|
253
237
|
|
254
238
|
* Implement resource pool
|
255
239
|
* transaction method for pg cient
|
@@ -258,22 +242,19 @@
|
|
258
242
|
* Improve HTTP server performance
|
259
243
|
* Proper promise chaining
|
260
244
|
|
261
|
-
0.6 2018-09-11
|
262
|
-
--------------
|
245
|
+
## 0.6 2018-09-11
|
263
246
|
|
264
247
|
* Add http, redis, pg dependencies
|
265
248
|
* Move ALPN code inside net module
|
266
249
|
|
267
|
-
0.4 2018-09-10
|
268
|
-
--------------
|
250
|
+
## 0.4 2018-09-10
|
269
251
|
|
270
252
|
* Code refactored and reogranized
|
271
253
|
* Fix recursion in next_tick
|
272
254
|
* HTTP 2 server with support for ALPN protocol negotiation and HTTP upgrade
|
273
255
|
* OpenSSL server
|
274
256
|
|
275
|
-
0.3 2018-09-06
|
276
|
-
--------------
|
257
|
+
## 0.3 2018-09-06
|
277
258
|
|
278
259
|
* Event reactor
|
279
260
|
* Timers
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
polyphony (0.
|
4
|
+
polyphony (0.31)
|
5
5
|
modulation (~> 1.0)
|
6
6
|
|
7
7
|
GEM
|
@@ -90,12 +90,14 @@ GEM
|
|
90
90
|
rb-inotify (0.10.1)
|
91
91
|
ffi (~> 1.0)
|
92
92
|
redis (4.1.0)
|
93
|
+
rexml (3.2.4)
|
93
94
|
rouge (3.15.0)
|
94
|
-
rubocop (0.
|
95
|
+
rubocop (0.80.0)
|
95
96
|
jaro_winkler (~> 1.5.1)
|
96
97
|
parallel (~> 1.10)
|
97
98
|
parser (>= 2.7.0.1)
|
98
99
|
rainbow (>= 2.2.2, < 4.0)
|
100
|
+
rexml
|
99
101
|
ruby-progressbar (~> 1.7)
|
100
102
|
unicode-display_width (>= 1.4.0, < 1.7)
|
101
103
|
ruby-progressbar (1.10.1)
|
@@ -131,7 +133,7 @@ DEPENDENCIES
|
|
131
133
|
polyphony!
|
132
134
|
rake-compiler (= 1.0.5)
|
133
135
|
redis (= 4.1.0)
|
134
|
-
rubocop (= 0.
|
136
|
+
rubocop (= 0.80.0)
|
135
137
|
simplecov (= 0.17.1)
|
136
138
|
|
137
139
|
BUNDLED WITH
|
data/Rakefile
CHANGED
@@ -3,8 +3,6 @@
|
|
3
3
|
require "bundler/gem_tasks"
|
4
4
|
require "rake/clean"
|
5
5
|
|
6
|
-
# frozen_string_literal: true
|
7
|
-
|
8
6
|
require "rake/extensiontask"
|
9
7
|
Rake::ExtensionTask.new("gyro_ext") do |ext|
|
10
8
|
ext.ext_dir = "ext/gyro"
|
@@ -21,6 +19,4 @@ task :docs do
|
|
21
19
|
exec 'RUBYOPT=-W0 jekyll serve -s docs'
|
22
20
|
end
|
23
21
|
|
24
|
-
task default: %w[compile]
|
25
|
-
|
26
22
|
CLEAN.include "**/*.o", "**/*.so", "**/*.bundle", "**/*.jar", "pkg", "tmp"
|
data/TODO.md
CHANGED
@@ -1,4 +1,47 @@
|
|
1
|
-
## 0.
|
1
|
+
## 0.32 Working Sinatra application
|
2
|
+
|
3
|
+
- Introduce mailbox limiting:
|
4
|
+
- add API for limiting mailbox size:
|
5
|
+
|
6
|
+
```ruby
|
7
|
+
Fiber.current.mailbox_limit = 1000
|
8
|
+
```
|
9
|
+
|
10
|
+
- Add the limit for `Gyro::Queue`
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
Gyro::Queue.new(1000)
|
14
|
+
```
|
15
|
+
|
16
|
+
- Pushing to a limited queue will block if limit is reached
|
17
|
+
|
18
|
+
- Introduce selective receive:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
# returns (or waits for) the first message for which the block returns true
|
22
|
+
(_, item) = receive { |msg| msg.first == ref }
|
23
|
+
```
|
24
|
+
|
25
|
+
Possible implementation:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
def receive
|
29
|
+
return @mailbox.shift unless block_given?
|
30
|
+
|
31
|
+
loop
|
32
|
+
msg = @mailbox.shift
|
33
|
+
return msg if yield(msg)
|
34
|
+
|
35
|
+
# message didn't match condition, put it back in queue
|
36
|
+
@mailbox.push msg
|
37
|
+
end
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
- Test hypothetical situation 1:
|
42
|
+
- fiber A sends a request to fiber B
|
43
|
+
- fiber B terminates on a raised exception
|
44
|
+
- What happens to fiber A? (it should get the exception)
|
2
45
|
|
3
46
|
- Accept rate/interval in `spin_loop` and `spin_worker_loop`:
|
4
47
|
|
@@ -8,13 +51,22 @@
|
|
8
51
|
spin_loop(interval: 10) { ... } # once every ten seconds
|
9
52
|
```
|
10
53
|
|
11
|
-
- Docs
|
54
|
+
- Docs
|
55
|
+
- landing page:
|
56
|
+
- links to the interesting stuff
|
57
|
+
- concurrency overview
|
58
|
+
- faq
|
59
|
+
- benchmarks
|
60
|
+
- explain difference between `sleep` and `suspend`
|
61
|
+
- concurrency overview: add explanation about async vs sync
|
62
|
+
|
63
|
+
- move all adapters into polyphony/adapters
|
64
|
+
|
12
65
|
- Check why first call to `#sleep` returns too early in tests. Check the
|
13
66
|
sleep behaviour in a spawned thread.
|
14
|
-
- app with database access (postgresql)
|
15
|
-
- benchmarks!
|
67
|
+
- sintra app with database access (postgresql)
|
16
68
|
|
17
|
-
## 0.
|
69
|
+
## 0.33 Sidekick
|
18
70
|
|
19
71
|
Plan of action:
|
20
72
|
|
@@ -22,13 +74,13 @@ Plan of action:
|
|
22
74
|
- test performance
|
23
75
|
- proceed from there
|
24
76
|
|
25
|
-
## 0.
|
77
|
+
## 0.34 Testing && Docs
|
26
78
|
|
27
79
|
- Pull out redis/postgres code, put into new `polyphony-xxx` gems
|
28
80
|
|
29
|
-
## 0.
|
81
|
+
## 0.35 Integration
|
30
82
|
|
31
|
-
## 0.
|
83
|
+
## 0.36 Real IO#gets and IO#read
|
32
84
|
|
33
85
|
- More tests
|
34
86
|
- Implement some basic stuff missing:
|
@@ -38,7 +90,7 @@ Plan of action:
|
|
38
90
|
- `IO.foreach`
|
39
91
|
- `Process.waitpid`
|
40
92
|
|
41
|
-
## 0.
|
93
|
+
## 0.37 Rails
|
42
94
|
|
43
95
|
- Rails?
|
44
96
|
|
data/ext/gyro/thread.c
CHANGED
@@ -129,6 +129,39 @@ VALUE Thread_schedule_fiber(VALUE self, VALUE fiber, VALUE value) {
|
|
129
129
|
return self;
|
130
130
|
}
|
131
131
|
|
132
|
+
VALUE Thread_schedule_fiber_with_priority(VALUE self, VALUE fiber, VALUE value) {
|
133
|
+
if (rb_fiber_alive_p(fiber) != Qtrue) {
|
134
|
+
return self;
|
135
|
+
}
|
136
|
+
FIBER_TRACE(3, SYM_fiber_schedule, fiber, value);
|
137
|
+
rb_ivar_set(fiber, ID_runnable_value, value);
|
138
|
+
|
139
|
+
VALUE queue = rb_ivar_get(self, ID_run_queue);
|
140
|
+
|
141
|
+
// if fiber is already scheduled, remove it from the run queue
|
142
|
+
if (rb_ivar_get(fiber, ID_runnable) != Qnil) {
|
143
|
+
rb_ary_delete(queue, fiber);
|
144
|
+
} else {
|
145
|
+
rb_ivar_set(fiber, ID_runnable, Qtrue);
|
146
|
+
}
|
147
|
+
|
148
|
+
// the fiber is given priority by putting it at the front of the run queue
|
149
|
+
rb_ary_unshift(queue, fiber);
|
150
|
+
|
151
|
+
if (rb_thread_current() != self) {
|
152
|
+
// if the fiber scheduling is done across threads, we need to make sure the
|
153
|
+
// target thread is woken up in case it is in the middle of running its
|
154
|
+
// event selector. Otherwise it's gonna be stuck waiting for an event to
|
155
|
+
// happen, not knowing that it there's already a fiber ready to run in its
|
156
|
+
// run queue.
|
157
|
+
VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
|
158
|
+
if (selector != Qnil) {
|
159
|
+
Gyro_Selector_break_out_of_ev_loop(selector);
|
160
|
+
}
|
161
|
+
}
|
162
|
+
return self;
|
163
|
+
}
|
164
|
+
|
132
165
|
VALUE Thread_switch_fiber(VALUE self) {
|
133
166
|
VALUE current_fiber = rb_fiber_current();
|
134
167
|
if (__tracing_enabled__) {
|
@@ -202,7 +235,7 @@ VALUE Thread_current_event_selector() {
|
|
202
235
|
|
203
236
|
VALUE Thread_fiber_break_out_of_ev_loop(VALUE self, VALUE resume_obj) {
|
204
237
|
VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
|
205
|
-
|
238
|
+
Thread_schedule_fiber_with_priority(self, rb_fiber_current(), resume_obj);
|
206
239
|
|
207
240
|
if (Gyro_Selector_break_out_of_ev_loop(selector) == Qnil) {
|
208
241
|
// we're not inside the ev_loop, so we just do a switchpoint
|
@@ -243,6 +276,8 @@ void Init_Thread() {
|
|
243
276
|
rb_define_method(rb_cThread, "break_out_of_ev_loop", Thread_fiber_break_out_of_ev_loop, 1);
|
244
277
|
|
245
278
|
rb_define_method(rb_cThread, "schedule_fiber", Thread_schedule_fiber, 2);
|
279
|
+
rb_define_method(rb_cThread, "schedule_fiber_with_priority",
|
280
|
+
Thread_schedule_fiber_with_priority, 2);
|
246
281
|
rb_define_method(rb_cThread, "switch_fiber", Thread_switch_fiber, 0);
|
247
282
|
|
248
283
|
rb_define_method(rb_cThread, "join_perform", Thread_join_perform, 0);
|
data/ext/gyro/timer.c
CHANGED
@@ -131,11 +131,12 @@ VALUE Gyro_Timer_await(VALUE self) {
|
|
131
131
|
ev_timer_stop(timer->ev_loop, &timer->ev_timer);
|
132
132
|
timer->ev_loop = 0;
|
133
133
|
}
|
134
|
-
RB_GC_GUARD(self);
|
135
134
|
|
136
135
|
// fiber is resumed, check if resumed value is an exception
|
137
136
|
timer->fiber = Qnil;
|
138
137
|
timer->selector = Qnil;
|
138
|
+
|
139
|
+
RB_GC_GUARD(self);
|
139
140
|
if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
|
140
141
|
return rb_funcall(rb_mKernel, ID_raise, 1, ret);
|
141
142
|
}
|
data/lib/polyphony.rb
CHANGED
@@ -30,12 +30,12 @@ module Polyphony
|
|
30
30
|
auto_import(
|
31
31
|
CancelScope: './polyphony/core/cancel_scope',
|
32
32
|
Channel: './polyphony/core/channel',
|
33
|
-
FS: './polyphony/fs',
|
33
|
+
FS: './polyphony/adapters/fs',
|
34
34
|
ResourcePool: './polyphony/core/resource_pool',
|
35
35
|
Sync: './polyphony/core/sync',
|
36
36
|
ThreadPool: './polyphony/core/thread_pool',
|
37
37
|
Throttler: './polyphony/core/throttler',
|
38
|
-
Trace: './polyphony/trace',
|
38
|
+
Trace: './polyphony/adapters/trace',
|
39
39
|
Websocket: './polyphony/websocket'
|
40
40
|
)
|
41
41
|
|
File without changes
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'polyphony'
|
4
|
+
|
5
|
+
if Object.constants.include?(:Reline)
|
6
|
+
class Reline::ANSI
|
7
|
+
def self.select(read_ios = [], write_ios = [], error_ios = [], timeout = nil)
|
8
|
+
p [:select, read_ios]
|
9
|
+
raise if read_ios.size > 1
|
10
|
+
raise if write_ios.size > 0
|
11
|
+
raise if error_ios.size > 0
|
12
|
+
|
13
|
+
fiber = Fiber.current
|
14
|
+
timer = spin do
|
15
|
+
sleep timeout
|
16
|
+
fiber.cancel!
|
17
|
+
end
|
18
|
+
read_ios.each do |io|
|
19
|
+
io.read_watcher.await
|
20
|
+
return [io]
|
21
|
+
end
|
22
|
+
rescue Polyphony::Cancel
|
23
|
+
return nil
|
24
|
+
ensure
|
25
|
+
timer.stop
|
26
|
+
end
|
27
|
+
end
|
28
|
+
else
|
29
|
+
# readline blocks the current thread, so we offload it to the blocking-ops
|
30
|
+
# thread pool. That way, the reactor loop can keep running while waiting for
|
31
|
+
# readline to return
|
32
|
+
module ::Readline
|
33
|
+
alias_method :orig_readline, :readline
|
34
|
+
|
35
|
+
Workers = Polyphony::ThreadPool.new
|
36
|
+
|
37
|
+
def readline(*args)
|
38
|
+
p :readline
|
39
|
+
# caller.each do |l|
|
40
|
+
# STDOUT.orig_puts l
|
41
|
+
# end
|
42
|
+
Workers.process { orig_readline(*args) }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class ::RubyLex
|
47
|
+
class TerminateLineInput2 < RuntimeError
|
48
|
+
end
|
49
|
+
const_set(:TerminateLineInput, TerminateLineInput2)
|
50
|
+
end
|
51
|
+
end
|
File without changes
|
data/lib/polyphony/version.rb
CHANGED
data/polyphony.gemspec
CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.add_development_dependency 'minitest', '5.13.0'
|
29
29
|
s.add_development_dependency 'minitest-reporters', '1.4.2'
|
30
30
|
s.add_development_dependency 'simplecov', '0.17.1'
|
31
|
-
s.add_development_dependency 'rubocop', '0.
|
31
|
+
s.add_development_dependency 'rubocop', '0.80.0'
|
32
32
|
s.add_development_dependency 'pg', '1.1.3'
|
33
33
|
s.add_development_dependency 'rake-compiler', '1.0.5'
|
34
34
|
s.add_development_dependency 'redis', '4.1.0'
|
data/test/test_fiber.rb
CHANGED
data/test/test_global_api.rb
CHANGED
@@ -230,6 +230,19 @@ class MoveOnAfterTest < MiniTest::Test
|
|
230
230
|
assert_equal [1, 2, 3], buffer
|
231
231
|
end
|
232
232
|
|
233
|
+
def test_spin_loop_location
|
234
|
+
location = /^#{__FILE__}:#{__LINE__ + 1}/
|
235
|
+
f = spin_loop {}
|
236
|
+
|
237
|
+
assert_match location, f.location
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_spin_loop_tag
|
241
|
+
f = spin_loop(:my_loop) {}
|
242
|
+
|
243
|
+
assert_equal :my_loop, f.tag
|
244
|
+
end
|
245
|
+
|
233
246
|
def test_throttled_loop
|
234
247
|
buffer = []
|
235
248
|
counter = 0
|
data/test/test_signal.rb
CHANGED
@@ -36,3 +36,76 @@ class SignalTest < MiniTest::Test
|
|
36
36
|
assert_equal 1, count
|
37
37
|
end
|
38
38
|
end
|
39
|
+
|
40
|
+
class SignalTrapTest < Minitest::Test
|
41
|
+
def test_signal_exception_propagation
|
42
|
+
i, o = IO.pipe
|
43
|
+
pid = Polyphony.fork do
|
44
|
+
i.close
|
45
|
+
spin do
|
46
|
+
spin do
|
47
|
+
sleep 1
|
48
|
+
rescue ::Interrupt => e
|
49
|
+
o.puts "1-interrupt"
|
50
|
+
raise e
|
51
|
+
end.await
|
52
|
+
rescue ::Interrupt => e
|
53
|
+
o.puts "2-interrupt"
|
54
|
+
raise e
|
55
|
+
end.await
|
56
|
+
rescue ::Interrupt => e
|
57
|
+
o.puts "3-interrupt"
|
58
|
+
ensure
|
59
|
+
o.close
|
60
|
+
end
|
61
|
+
sleep 0.01
|
62
|
+
o.close
|
63
|
+
watcher = Gyro::Child.new(pid)
|
64
|
+
Process.kill('INT', pid)
|
65
|
+
watcher.await
|
66
|
+
buffer = i.read
|
67
|
+
assert_equal "1-interrupt\n2-interrupt\n3-interrupt\n", buffer
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_signal_exception_possible_race_condition
|
71
|
+
i, o = IO.pipe
|
72
|
+
pid = Polyphony.fork do
|
73
|
+
i.close
|
74
|
+
f1 = nil
|
75
|
+
f2 = spin do
|
76
|
+
# this fiber will try to create a race condition by
|
77
|
+
# - being scheduled before f1 is scheduled with the Interrupt exception
|
78
|
+
# - scheduling f1 without an exception
|
79
|
+
suspend
|
80
|
+
f1.schedule
|
81
|
+
rescue ::Interrupt => e
|
82
|
+
o.puts '2-interrupt'
|
83
|
+
raise e
|
84
|
+
end
|
85
|
+
f1 = spin do
|
86
|
+
# this fiber is the one that will be current when the
|
87
|
+
# signal is trapped
|
88
|
+
sleep 1
|
89
|
+
o << 'boom'
|
90
|
+
rescue ::Interrupt => e
|
91
|
+
o.puts '1-interrupt'
|
92
|
+
raise e
|
93
|
+
end
|
94
|
+
old_trap = trap('INT') do
|
95
|
+
f2.schedule
|
96
|
+
old_trap.()
|
97
|
+
end
|
98
|
+
Fiber.current.await_all_children
|
99
|
+
rescue ::Interrupt => e
|
100
|
+
o.puts '3-interrupt'
|
101
|
+
ensure
|
102
|
+
o.close
|
103
|
+
end
|
104
|
+
o.close
|
105
|
+
sleep 0.1
|
106
|
+
Process.kill('INT', pid)
|
107
|
+
Gyro::Child.new(pid).await
|
108
|
+
buffer = i.read
|
109
|
+
assert_equal "1-interrupt\n3-interrupt\n", buffer
|
110
|
+
end
|
111
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: polyphony
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.31'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-02-
|
11
|
+
date: 2020-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: modulation
|
@@ -100,14 +100,14 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - '='
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 0.
|
103
|
+
version: 0.80.0
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - '='
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 0.
|
110
|
+
version: 0.80.0
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: pg
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -275,6 +275,14 @@ files:
|
|
275
275
|
- docs/user-guide.md
|
276
276
|
- docs/user-guide/all-about-timers.md
|
277
277
|
- docs/user-guide/web-server.md
|
278
|
+
- examples/adapters/pg_client.rb
|
279
|
+
- examples/adapters/pg_notify.rb
|
280
|
+
- examples/adapters/pg_pool.rb
|
281
|
+
- examples/adapters/pg_transaction.rb
|
282
|
+
- examples/adapters/redis_channels.rb
|
283
|
+
- examples/adapters/redis_client.rb
|
284
|
+
- examples/adapters/redis_pubsub.rb
|
285
|
+
- examples/adapters/redis_pubsub_perf.rb
|
278
286
|
- examples/core/01-spinning-up-fibers.rb
|
279
287
|
- examples/core/02-awaiting-fibers.rb
|
280
288
|
- examples/core/03-interrupting.rb
|
@@ -310,14 +318,6 @@ files:
|
|
310
318
|
- examples/core/xx-trace.rb
|
311
319
|
- examples/core/xx-using-a-mutex.rb
|
312
320
|
- examples/core/xx-worker-thread.rb
|
313
|
-
- examples/interfaces/pg_client.rb
|
314
|
-
- examples/interfaces/pg_notify.rb
|
315
|
-
- examples/interfaces/pg_pool.rb
|
316
|
-
- examples/interfaces/pg_transaction.rb
|
317
|
-
- examples/interfaces/redis_channels.rb
|
318
|
-
- examples/interfaces/redis_client.rb
|
319
|
-
- examples/interfaces/redis_pubsub.rb
|
320
|
-
- examples/interfaces/redis_pubsub_perf.rb
|
321
321
|
- examples/io/xx-backticks.rb
|
322
322
|
- examples/io/xx-echo_client.rb
|
323
323
|
- examples/io/xx-echo_client_from_stdin.rb
|
@@ -378,6 +378,11 @@ files:
|
|
378
378
|
- ext/libev/ev_wrap.h
|
379
379
|
- ext/libev/test_libev_win32.c
|
380
380
|
- lib/polyphony.rb
|
381
|
+
- lib/polyphony/adapters/fs.rb
|
382
|
+
- lib/polyphony/adapters/irb.rb
|
383
|
+
- lib/polyphony/adapters/postgres.rb
|
384
|
+
- lib/polyphony/adapters/redis.rb
|
385
|
+
- lib/polyphony/adapters/trace.rb
|
381
386
|
- lib/polyphony/core/cancel_scope.rb
|
382
387
|
- lib/polyphony/core/channel.rb
|
383
388
|
- lib/polyphony/core/exceptions.rb
|
@@ -392,12 +397,7 @@ files:
|
|
392
397
|
- lib/polyphony/extensions/openssl.rb
|
393
398
|
- lib/polyphony/extensions/socket.rb
|
394
399
|
- lib/polyphony/extensions/thread.rb
|
395
|
-
- lib/polyphony/fs.rb
|
396
|
-
- lib/polyphony/irb.rb
|
397
400
|
- lib/polyphony/net.rb
|
398
|
-
- lib/polyphony/postgres.rb
|
399
|
-
- lib/polyphony/redis.rb
|
400
|
-
- lib/polyphony/trace.rb
|
401
401
|
- lib/polyphony/version.rb
|
402
402
|
- polyphony.gemspec
|
403
403
|
- test/coverage.rb
|
data/lib/polyphony/irb.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'polyphony'
|
4
|
-
|
5
|
-
# readline blocks the current thread, so we offload it to the blocking-ops
|
6
|
-
# thread pool. That way, the reactor loop can keep running while waiting for
|
7
|
-
# readline to return
|
8
|
-
module ::Readline
|
9
|
-
alias_method :orig_readline, :readline
|
10
|
-
|
11
|
-
def readline(*args)
|
12
|
-
async = Gyro::Async.new
|
13
|
-
Thread.new do
|
14
|
-
result = orig_readline(*args)
|
15
|
-
async.signal!(result)
|
16
|
-
end
|
17
|
-
async.await
|
18
|
-
end
|
19
|
-
end
|