polyphony 0.71 → 0.72
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +1 -0
- data/CHANGELOG.md +18 -4
- data/Gemfile.lock +1 -1
- data/TODO.md +1 -1
- data/bin/pdbg +1 -1
- data/bin/polyphony-debug +0 -0
- data/bin/stress.rb +0 -0
- data/bin/test +0 -0
- data/docs/_user-guide/all-about-timers.md +1 -1
- data/docs/api-reference/fiber.md +2 -2
- data/docs/faq.md +1 -1
- data/docs/getting-started/overview.md +8 -8
- data/docs/getting-started/tutorial.md +3 -3
- data/docs/main-concepts/concurrency.md +1 -1
- data/docs/main-concepts/extending.md +3 -3
- data/docs/main-concepts/fiber-scheduling.md +1 -1
- data/examples/core/calc.rb +37 -0
- data/examples/core/calc_with_restart.rb +40 -0
- data/examples/core/calc_with_supervise.rb +37 -0
- data/examples/core/message_based_supervision.rb +1 -1
- data/examples/io/rack_server.rb +1 -1
- data/examples/io/tunnel.rb +1 -1
- data/examples/performance/fiber_transfer.rb +1 -1
- data/examples/performance/line_splitting.rb +1 -1
- data/examples/performance/thread-vs-fiber/compare.rb +1 -1
- data/ext/polyphony/backend_common.c +8 -8
- data/ext/polyphony/backend_io_uring.c +26 -33
- data/ext/polyphony/backend_io_uring_context.c +1 -1
- data/ext/polyphony/backend_io_uring_context.h +1 -1
- data/ext/polyphony/backend_libev.c +11 -11
- data/ext/polyphony/extconf.rb +24 -13
- data/ext/polyphony/queue.c +2 -2
- data/ext/polyphony/runqueue_ring_buffer.c +3 -2
- data/lib/polyphony/adapters/irb.rb +11 -1
- data/lib/polyphony/core/global_api.rb +3 -3
- data/lib/polyphony/core/timer.rb +2 -2
- data/lib/polyphony/debugger.rb +3 -3
- data/lib/polyphony/extensions/fiber.rb +19 -8
- data/lib/polyphony/extensions/io.rb +2 -2
- data/lib/polyphony/extensions/openssl.rb +20 -5
- data/lib/polyphony/extensions/socket.rb +3 -4
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +1 -1
- data/test/coverage.rb +2 -2
- data/test/test_backend.rb +12 -12
- data/test/test_event.rb +1 -1
- data/test/test_ext.rb +1 -1
- data/test/test_fiber.rb +31 -7
- data/test/test_global_api.rb +2 -2
- data/test/test_io.rb +3 -3
- data/test/test_queue.rb +6 -6
- data/test/test_socket.rb +12 -10
- data/test/test_supervise.rb +85 -0
- data/test/test_sync.rb +2 -2
- data/test/test_thread.rb +22 -2
- data/test/test_thread_pool.rb +1 -1
- data/test/test_throttler.rb +1 -1
- data/test/test_timer.rb +2 -2
- data/test/test_trace.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2af189faeecbe2eecb367a7400005306ab74370e56c61de1d703edd40d851d92
|
4
|
+
data.tar.gz: c0888b10d03b9bf29f1d10a41b0050231db655c587d06035039b4c09e1c68baa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b86fd5682ce52e635658a8d620031f8ae841ef5f7876d6239f74772d8f700054eb3bb7732488e246433a91e5ab4279479c6f18bb0d1a154172d90f351ab8149e
|
7
|
+
data.tar.gz: 713ba61a64ef73c5c16971bd0d678d6575b7bd37062a29348f02ec8e0578821d7ec41f826f1868cd017bede9c70d47192e19a0217469b331f17ff66afac21054
|
data/.github/FUNDING.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
github: ciconia
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## 0.72 2021-11-22
|
2
|
+
|
3
|
+
- Add support for supervising added child fibers
|
4
|
+
- Do not use io_uring under LinuxKit (#66)
|
5
|
+
- Fix error message in `Fiber#restart`
|
6
|
+
- refactor `runqueue_ring_buffer_mark`
|
7
|
+
- Fix setting up test server on random port
|
8
|
+
- Enhance `Fiber#supervise`
|
9
|
+
- Add support for specifying `restart: true` (same as `restart: :always`)
|
10
|
+
- Add support for supervising child fibers (when fibers are not specified)
|
11
|
+
- Add `Fiber#attach_all_children_to`
|
12
|
+
- Improve `SSLServer#accept` when `servername_cb` is set
|
13
|
+
- Fix `#supervise` in Ruby 3.0
|
14
|
+
|
1
15
|
## 0.71 2021-08-20
|
2
16
|
|
3
17
|
- Fix compilation on Ruby 3.0
|
@@ -27,7 +41,7 @@
|
|
27
41
|
## 0.66 2021-08-01
|
28
42
|
|
29
43
|
- Fix all splicing APIs on non-linux OSes (#63)
|
30
|
-
- Add GC marking of buffers when cancelling read/write ops in io_uring backend
|
44
|
+
- Add GC marking of buffers when cancelling read/write ops in io_uring backend
|
31
45
|
|
32
46
|
## 0.65 2021-07-29
|
33
47
|
|
@@ -91,7 +105,7 @@
|
|
91
105
|
## 0.55.0 2021-06-17
|
92
106
|
|
93
107
|
- Finish io_uring implementation of Backend#chain
|
94
|
-
- Reimplement io_uring op_context acquire/release algorithm (using ref count)
|
108
|
+
- Reimplement io_uring op_context acquire/release algorithm (using ref count)
|
95
109
|
- Fix #gets on sockets
|
96
110
|
- Redesign event anti-starvation mechanism
|
97
111
|
|
@@ -186,7 +200,7 @@
|
|
186
200
|
|
187
201
|
## 0.47.0 2020-11-10
|
188
202
|
|
189
|
-
- Implement `#spin_scope` used for creating blocking fiber scopes
|
203
|
+
- Implement `#spin_scope` used for creating blocking fiber scopes
|
190
204
|
- Reimplement `move_on_after`, `cancel_after`, `Timeout.timeout` using
|
191
205
|
`Backend#timeout` (avoids creating canceller fiber for most common use case)
|
192
206
|
- Implement `Backend#timeout` API
|
@@ -281,7 +295,7 @@
|
|
281
295
|
- Reimplement Event using `Agent#wait_event`
|
282
296
|
- Improve Queue shift queue performance
|
283
297
|
- Introduce `Agent#wait_event` API for waiting on asynchronous events
|
284
|
-
- Minimize `fcntl` syscalls in IO operations
|
298
|
+
- Minimize `fcntl` syscalls in IO operations
|
285
299
|
|
286
300
|
## 0.43.7 2020-07-20
|
287
301
|
|
data/Gemfile.lock
CHANGED
data/TODO.md
CHANGED
@@ -107,7 +107,7 @@
|
|
107
107
|
|
108
108
|
Hitting the breakpoint will show the current location in the source code
|
109
109
|
(with few lines before and after), and present a prompt for commands.
|
110
|
-
|
110
|
+
|
111
111
|
- commands:
|
112
112
|
- `step` / `up` / `skip` / `continue` etc. - step into, step out, step over, run
|
113
113
|
- `switch` - switch fiber
|
data/bin/pdbg
CHANGED
data/bin/polyphony-debug
CHANGED
File without changes
|
data/bin/stress.rb
CHANGED
File without changes
|
data/bin/test
CHANGED
File without changes
|
@@ -44,7 +44,7 @@ The `#sleep` forever call can be used for example in the main fiber when we do
|
|
44
44
|
all our work in other fibers, since once the main fiber terminates the program
|
45
45
|
exits.
|
46
46
|
|
47
|
-
## Doing Work Later
|
47
|
+
## Doing Work Later
|
48
48
|
|
49
49
|
While `#sleep` allows you to block execution of the current fiber, sometimes you
|
50
50
|
want to perform some work later, while not blocking the current fiber. This is done simply by spinning off another fiber:
|
data/docs/api-reference/fiber.md
CHANGED
@@ -205,7 +205,7 @@ f.raise
|
|
205
205
|
Pops the first message from the fiber's mailbox. If no message is available,
|
206
206
|
`#receive` will block until a message is pushed to the mailbox. The received
|
207
207
|
message can be any kind of object. This method is complemented by
|
208
|
-
`Fiber#<<`/`Fiber#send`.
|
208
|
+
`Fiber#<<`/`Fiber#send`.
|
209
209
|
|
210
210
|
```ruby
|
211
211
|
spin { Fiber.current.parent << 'hello from child' }
|
@@ -328,7 +328,7 @@ Returns the fiber's current state, which can be any of the following:
|
|
328
328
|
Supervises all child fibers, optionally restarting any fiber that terminates.
|
329
329
|
|
330
330
|
The given `opts` argument controls the behaviour of the supervision. The
|
331
|
-
following options are currently supported:
|
331
|
+
following options are currently supported:
|
332
332
|
|
333
333
|
- `:restart`: restart options
|
334
334
|
- `nil` - Child fibers are not restarted (default behaviour).
|
data/docs/faq.md
CHANGED
@@ -99,7 +99,7 @@ In conclusion:
|
|
99
99
|
|
100
100
|
## If callbacks suck, why not use promises?
|
101
101
|
|
102
|
-
Promises have gained a lot of traction during the last few years as an
|
102
|
+
Promises have gained a lot of traction during the last few years as an
|
103
103
|
alternative to callbacks, above all in the Javascript community. While promises
|
104
104
|
have been at a certain point considered for use in Polyphony, they were not
|
105
105
|
found to offer enough of a benefit. Promises still cause split logic, are quite
|
@@ -114,7 +114,7 @@ single CPU core.
|
|
114
114
|
|
115
115
|
Nevertheless, Polyphony fully supports multithreading, with each thread having
|
116
116
|
its own fiber run queue and its own libev event loop. Polyphony even enables
|
117
|
-
cross-thread communication using [fiber messaging](#message-passing).
|
117
|
+
cross-thread communication using [fiber messaging](#message-passing).
|
118
118
|
|
119
119
|
## Fibers vs Callbacks
|
120
120
|
|
@@ -138,7 +138,7 @@ Fibers, in contrast, let the developer express the business logic in a
|
|
138
138
|
sequential, easy to read manner: do this, then that. State can be stored right
|
139
139
|
in the business logic, as local variables. And finally, the sequential
|
140
140
|
programming style makes it much easier to debug your code, since stack traces
|
141
|
-
contain the entire history of execution from the app's inception.
|
141
|
+
contain the entire history of execution from the app's inception.
|
142
142
|
|
143
143
|
## Structured Concurrency
|
144
144
|
|
@@ -229,7 +229,7 @@ normally or with an exception:
|
|
229
229
|
fiber1 = spin { sleep 1; raise 'foo' }
|
230
230
|
fiber2 = spin { sleep 1 }
|
231
231
|
|
232
|
-
supervise # blocks and then propagates the error raised in fiber1
|
232
|
+
supervise # blocks and then propagates the error raised in fiber1
|
233
233
|
```
|
234
234
|
|
235
235
|
## Message Passing
|
@@ -266,7 +266,7 @@ end
|
|
266
266
|
Notice how the state (the `subscribers` variable) stays local, and how the logic
|
267
267
|
of the chat room is expressed in a way that is both compact and easy to extend.
|
268
268
|
Also notice how the chat room is written as an infinite loop. This is a common
|
269
|
-
pattern in Polyphony, since fibers can always be stopped at any moment.
|
269
|
+
pattern in Polyphony, since fibers can always be stopped at any moment.
|
270
270
|
|
271
271
|
The code for handling a chat room user might be expressed as follows:
|
272
272
|
|
@@ -350,14 +350,14 @@ operations.
|
|
350
350
|
|
351
351
|
While a standard event loop-based solution would implement a blocking call
|
352
352
|
separately from the fiber scheduling, the system backend integrates the two to
|
353
|
-
create a blocking call that
|
353
|
+
create a blocking call that already knows how to switch and schedule fibers.
|
354
354
|
For example, in Polyphony all APIs having to do with reading from files or
|
355
355
|
sockets end up calling `Thread.current.backend.read`, which does all the work.
|
356
356
|
|
357
357
|
This design offers some major advantages over other designs. It minimizes memory
|
358
|
-
allocations
|
358
|
+
allocations of both Ruby objects and C structures. For example, instead of
|
359
359
|
having to allocate libev watchers on the heap and then pass them around, they
|
360
|
-
are allocated on the stack instead, which saves
|
360
|
+
are allocated on the stack instead, which saves both memory and CPU cycles.
|
361
361
|
|
362
362
|
In addition, the backend interface includes two methods that allow maximizing
|
363
363
|
server performance by accepting connections and reading from sockets in a tight
|
@@ -482,5 +482,5 @@ reach version 1.0. Here are some of the exciting directions we're working on.
|
|
482
482
|
|
483
483
|
- Support for more core and stdlib APIs
|
484
484
|
- More adapters for gems with C-extensions, such as `mysql`, `sqlite3` etc
|
485
|
-
- Use `io_uring` backend as alternative to the libev backend
|
485
|
+
- Use `io_uring` backend as alternative to the libev backend
|
486
486
|
- More concurrency constructs for building highly concurrent applications
|
@@ -51,7 +51,7 @@ multiple threads or processes, but this approach has numerous disavantages:
|
|
51
51
|
- Both threads and processes are limited to a few thousand at best on a single
|
52
52
|
machine. Trying to spawn a thread per client essentially limits the scaling
|
53
53
|
capacity of your system.
|
54
|
-
|
54
|
+
|
55
55
|
Polyphony eschews both threads and processes in favor of fibers as the basic
|
56
56
|
unit of concurrency. The idea is that any time a blocking I/O operation occurs,
|
57
57
|
the current fiber is paused, and another fiber which has been marked as
|
@@ -117,7 +117,7 @@ Here's the actual sequence of execution (in pseudo-code)
|
|
117
117
|
sleeper = spin { ... } # The main fiber spins up a new fiber marked as runnable
|
118
118
|
suspend # The main fiber suspends, waiting for all other work to finish
|
119
119
|
Thread.current.switch_fiber # Polyphony looks for other runnable fibers
|
120
|
-
|
120
|
+
|
121
121
|
# (sleeper fiber)
|
122
122
|
puts "Going to sleep..." # The sleeper fiber starts running
|
123
123
|
sleep 1 # The sleeper fiber goes to sleep
|
@@ -280,7 +280,7 @@ def handle_client(client)
|
|
280
280
|
rescue Polyphony::Cancel
|
281
281
|
client.puts 'Closing connection due to inactivity.'
|
282
282
|
rescue Polyphony::Terminate
|
283
|
-
# We add a handler for the Terminate exception, and give
|
283
|
+
# We add a handler for the Terminate exception, and give
|
284
284
|
client.puts 'Server is shutting down. You have 5 more seconds...'
|
285
285
|
move_on_after(5) do
|
286
286
|
client_loop(client)
|
@@ -133,7 +133,7 @@ fiber that's blocking on any arbitrary operation.
|
|
133
133
|
Some other constructs offered by Polyphony:
|
134
134
|
|
135
135
|
* `Mutex` - a mutex used to synchronize access to a single shared resource.
|
136
|
-
* `ResourcePool` - used for synchronizing access to a limited amount of shared
|
136
|
+
* `ResourcePool` - used for synchronizing access to a limited amount of shared
|
137
137
|
resources, for example a pool of database connections.
|
138
138
|
* `Throttler` - used for throttling repeating operations, for example throttling
|
139
139
|
access to a shared resource, or throttling incoming requests.
|
@@ -9,9 +9,9 @@ next_title: The Design of Polyphony
|
|
9
9
|
---
|
10
10
|
# Extending Polyphony
|
11
11
|
|
12
|
-
Polyphony was designed to ease the transition from blocking APIs and
|
12
|
+
Polyphony was designed to ease the transition from blocking APIs and
|
13
13
|
callback-based API to non-blocking, fiber-based ones. It is important to
|
14
|
-
understand that not all blocking calls can be easily converted into
|
14
|
+
understand that not all blocking calls can be easily converted into
|
15
15
|
non-blocking calls. That might be the case with Ruby gems based on C-extensions,
|
16
16
|
such as database libraries. In that case, Polyphony's built-in
|
17
17
|
[thread pool](#threadpool) might be used for offloading such blocking calls.
|
@@ -22,7 +22,7 @@ Some of the most common patterns in Ruby APIs is the callback pattern, in which
|
|
22
22
|
the API takes a block as a callback to be called upon completion of a task. One
|
23
23
|
such example can be found in the excellent
|
24
24
|
[http_parser.rb](https://github.com/tmm1/http_parser.rb/) gem, which is used by
|
25
|
-
Polyphony itself to provide HTTP 1 functionality. The `HTTP:Parser` provides
|
25
|
+
Polyphony itself to provide HTTP 1 functionality. The `HTTP:Parser` provides
|
26
26
|
multiple hooks, or callbacks, for being notified when an HTTP request is
|
27
27
|
complete. The typical callback-based setup is as follows:
|
28
28
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
# Kernel#spin starts a new fiber
|
7
|
+
@controller = spin do
|
8
|
+
@worker = spin do
|
9
|
+
loop do
|
10
|
+
# Each fiber has a mailbox for receiving messages
|
11
|
+
peer, op, x, y = receive
|
12
|
+
result = x.send(op, y)
|
13
|
+
# The result is sent back to the "client"
|
14
|
+
peer << result
|
15
|
+
end
|
16
|
+
end
|
17
|
+
# The controller fiber will block until the worker is done (but notice that
|
18
|
+
# the worker runs an infinite loop.)
|
19
|
+
@worker.await
|
20
|
+
end
|
21
|
+
|
22
|
+
def calc(op, x, y)
|
23
|
+
# Send the job to the worker fiber...
|
24
|
+
@worker << [Fiber.current, op, x, y]
|
25
|
+
# ... and wait for the result
|
26
|
+
receive
|
27
|
+
end
|
28
|
+
|
29
|
+
# wait for worker to start
|
30
|
+
snooze until @worker
|
31
|
+
|
32
|
+
p calc(:+, 2, 3)
|
33
|
+
p calc(:**, 2, 3)
|
34
|
+
p calc(:+, 2, nil)
|
35
|
+
|
36
|
+
# wait for the controller to terminate
|
37
|
+
@controller.await
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
# Kernel#spin starts a new fiber
|
7
|
+
@controller = spin do
|
8
|
+
@worker = spin do
|
9
|
+
loop do
|
10
|
+
# Each fiber has a mailbox for receiving messages
|
11
|
+
peer, op, x, y = receive
|
12
|
+
result = x.send(op, y)
|
13
|
+
# The result is sent back to the "client"
|
14
|
+
peer << result
|
15
|
+
end
|
16
|
+
end
|
17
|
+
# The controller fiber will block until the worker is done (but notice that
|
18
|
+
# the worker runs an infinite loop.)
|
19
|
+
@worker.await
|
20
|
+
rescue => e
|
21
|
+
puts "Uncaught exception in worker: #{e}. Restarting..."
|
22
|
+
@worker.restart
|
23
|
+
end
|
24
|
+
|
25
|
+
def calc(op, x, y)
|
26
|
+
# Send the job to the worker fiber...
|
27
|
+
@worker << [Fiber.current, op, x, y]
|
28
|
+
# ... and wait for the result
|
29
|
+
receive
|
30
|
+
end
|
31
|
+
|
32
|
+
# wait for worker to start
|
33
|
+
snooze until @worker
|
34
|
+
|
35
|
+
p calc(:+, 2, 3)
|
36
|
+
p calc(:**, 2, 3)
|
37
|
+
p calc(:+, 2, nil)
|
38
|
+
|
39
|
+
# wait for the controller to terminate
|
40
|
+
@controller.await
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
# Kernel#spin starts a new fiber
|
7
|
+
@controller = spin do
|
8
|
+
@worker = spin do
|
9
|
+
loop do
|
10
|
+
# Each fiber has a mailbox for receiving messages
|
11
|
+
peer, op, x, y = receive
|
12
|
+
result = x.send(op, y)
|
13
|
+
# The result is sent back to the "client"
|
14
|
+
peer << result
|
15
|
+
end
|
16
|
+
end
|
17
|
+
# The controller fiber will block until the worker is done (but notice that
|
18
|
+
# the worker runs an infinite loop.)
|
19
|
+
@worker.supervise(@worker, restart: :always)
|
20
|
+
end
|
21
|
+
|
22
|
+
def calc(op, x, y)
|
23
|
+
# Send the job to the worker fiber...
|
24
|
+
@worker << [Fiber.current, op, x, y]
|
25
|
+
# ... and wait for the result
|
26
|
+
receive
|
27
|
+
end
|
28
|
+
|
29
|
+
# wait for worker to start
|
30
|
+
snooze until @worker
|
31
|
+
|
32
|
+
p calc(:+, 2, 3)
|
33
|
+
p calc(:**, 2, 3)
|
34
|
+
p calc(:+, 2, nil)
|
35
|
+
|
36
|
+
# wait for the controller to terminate
|
37
|
+
@controller.await
|
data/examples/io/rack_server.rb
CHANGED
data/examples/io/tunnel.rb
CHANGED
@@ -34,7 +34,7 @@ inline void backend_base_mark(struct Backend_base *base) {
|
|
34
34
|
void backend_base_reset(struct Backend_base *base) {
|
35
35
|
runqueue_finalize(&base->runqueue);
|
36
36
|
runqueue_finalize(&base->parked_runqueue);
|
37
|
-
|
37
|
+
|
38
38
|
runqueue_initialize(&base->runqueue);
|
39
39
|
runqueue_initialize(&base->parked_runqueue);
|
40
40
|
|
@@ -46,13 +46,13 @@ void backend_base_reset(struct Backend_base *base) {
|
|
46
46
|
base->idle_gc_period = 0;
|
47
47
|
base->idle_gc_last_time = 0;
|
48
48
|
base->idle_proc = Qnil;
|
49
|
-
base->trace_proc = Qnil;
|
49
|
+
base->trace_proc = Qnil;
|
50
50
|
}
|
51
51
|
|
52
52
|
const unsigned int ANTI_STARVE_SWITCH_COUNT_THRESHOLD = 64;
|
53
53
|
|
54
54
|
inline void conditional_nonblocking_poll(VALUE backend, struct Backend_base *base, VALUE current, VALUE next) {
|
55
|
-
if ((base->switch_count % ANTI_STARVE_SWITCH_COUNT_THRESHOLD) == 0 || next == current)
|
55
|
+
if ((base->switch_count % ANTI_STARVE_SWITCH_COUNT_THRESHOLD) == 0 || next == current)
|
56
56
|
Backend_poll(backend, Qnil);
|
57
57
|
}
|
58
58
|
|
@@ -62,7 +62,7 @@ VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base) {
|
|
62
62
|
unsigned int pending_ops_count = base->pending_count;
|
63
63
|
unsigned int backend_was_polled = 0;
|
64
64
|
unsigned int idle_tasks_run_count = 0;
|
65
|
-
|
65
|
+
|
66
66
|
base->switch_count++;
|
67
67
|
COND_TRACE(base, 2, SYM_fiber_switchpoint, current_fiber);
|
68
68
|
|
@@ -82,7 +82,7 @@ VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base) {
|
|
82
82
|
|
83
83
|
break;
|
84
84
|
}
|
85
|
-
|
85
|
+
|
86
86
|
if (!idle_tasks_run_count) {
|
87
87
|
idle_tasks_run_count++;
|
88
88
|
backend_run_idle_tasks(base);
|
@@ -112,7 +112,7 @@ void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_bas
|
|
112
112
|
|
113
113
|
COND_TRACE(base, 4, SYM_fiber_schedule, fiber, value, prioritize ? Qtrue : Qfalse);
|
114
114
|
|
115
|
-
runqueue_t *runqueue = rb_ivar_get(fiber, ID_ivar_parked) == Qtrue ?
|
115
|
+
runqueue_t *runqueue = rb_ivar_get(fiber, ID_ivar_parked) == Qtrue ?
|
116
116
|
&base->parked_runqueue : &base->runqueue;
|
117
117
|
|
118
118
|
(prioritize ? runqueue_unshift : runqueue_push)(runqueue, fiber, value, already_runnable);
|
@@ -300,7 +300,7 @@ inline void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking) {
|
|
300
300
|
int flags = fcntl(fptr->fd, F_GETFL);
|
301
301
|
if (flags == -1) return;
|
302
302
|
int is_nonblocking = flags & O_NONBLOCK;
|
303
|
-
|
303
|
+
|
304
304
|
if (blocking == Qtrue) {
|
305
305
|
if (!is_nonblocking) return;
|
306
306
|
flags &= ~O_NONBLOCK;
|
@@ -375,7 +375,7 @@ void backend_setup_stats_symbols() {
|
|
375
375
|
SYM_switch_count = ID2SYM(rb_intern("switch_count"));
|
376
376
|
SYM_poll_count = ID2SYM(rb_intern("poll_count"));
|
377
377
|
SYM_pending_ops = ID2SYM(rb_intern("pending_ops"));
|
378
|
-
|
378
|
+
|
379
379
|
rb_global_variable(&SYM_runqueue_size);
|
380
380
|
rb_global_variable(&SYM_runqueue_length);
|
381
381
|
rb_global_variable(&SYM_runqueue_max_length);
|