|
5 | 5 | class Rage::FiberScheduler |
6 | 6 | MAX_READ = 65536 |
7 | 7 | TIMEOUT_WORKER_INTERVAL = 100 # miliseconds |
8 | | - FIBER_KILL_DELAY = 500 # miliseconds |
9 | 8 |
|
10 | 9 | def initialize |
11 | 10 | @root_fiber = Fiber.current |
12 | 11 | @dns_cache = {} |
13 | 12 |
|
14 | | - @alive_fibers = Hash.new { |h, k| h[k] = {} } |
15 | | - @fibers_mutex = Mutex.new |
| 13 | + @fiber_timeouts = Hash.new { |h, k| h[k] = {} } |
16 | 14 |
|
17 | 15 | start_timeout_worker |
18 | 16 | end |
@@ -75,23 +73,18 @@ def kernel_sleep(duration = nil) |
75 | 73 |
|
76 | 74 | def timeout_after(duration, exception_class = Timeout::Error, *exception_arguments, &block) |
77 | 75 | fiber = Fiber.current |
78 | | - timeout_deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + duration |
79 | | - |
80 | | - @fibers_mutex.synchronize do |
81 | | - @alive_fibers[fiber.__get_id][timeout_deadline] = { |
82 | | - fiber: fiber, |
83 | | - timeout_deadline: timeout_deadline, |
84 | | - exception_class: exception_class, |
85 | | - exception_arguments: exception_arguments |
86 | | - } |
87 | | - end |
| 76 | + timeout = Process.clock_gettime(Process::CLOCK_MONOTONIC) + duration |
| 77 | + |
| 78 | + @fiber_timeouts[fiber][timeout] = { |
| 79 | + exception_class: exception_class, |
| 80 | + exception_arguments: exception_arguments |
| 81 | + } |
88 | 82 |
|
89 | 83 | begin |
90 | 84 | block.call |
91 | 85 | ensure |
92 | | - @fibers_mutex.synchronize do |
93 | | - @alive_fibers[fiber.__get_id].delete(timeout_deadline) |
94 | | - end |
| 86 | + @fiber_timeouts[fiber].delete(timeout) |
| 87 | + @fiber_timeouts.delete(fiber) if @fiber_timeouts[fiber].empty? |
95 | 88 | end |
96 | 89 | end |
97 | 90 |
|
@@ -164,38 +157,19 @@ def close |
164 | 157 | private |
165 | 158 |
|
166 | 159 | def start_timeout_worker |
167 | | - return unless ::Iodine.running? |
168 | | - |
169 | 160 | ::Iodine.run_every(Rage::FiberScheduler::TIMEOUT_WORKER_INTERVAL) do |
170 | 161 | check_timeouts |
171 | 162 | end |
172 | 163 | end |
173 | 164 |
|
174 | 165 | def check_timeouts |
175 | | - @fibers_mutex.synchronize do |
176 | | - @alive_fibers.delete_if do |fiber_id, fiber_timeouts| |
177 | | - fiber_timeouts.delete_if do |timeout_key, fiber_context| |
178 | | - current_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) |
179 | | - |
180 | | - next false if current_time < fiber_context[:timeout_deadline] |
181 | | - |
182 | | - fiber = fiber_context[:fiber] |
183 | | - unblock(nil, fiber) |
184 | | - |
185 | | - if fiber.alive? |
186 | | - fiber.raise(fiber_context[:exception_class], *fiber_context[:exception_arguments]) |
187 | | - |
188 | | - ::Iodine.run_after(FIBER_KILL_DELAY) do |
189 | | - fiber.kill if fiber.alive? |
190 | | - end |
191 | | - else |
192 | | - fiber_timeouts.delete(timeout_key) |
193 | | - end |
| 166 | + @fiber_timeouts.each_pair do |fiber, timeouts| |
| 167 | + timeouts.delete_if do |timeout, context| |
| 168 | + next false if Process.clock_gettime(Process::CLOCK_MONOTONIC) < timeout |
194 | 169 |
|
195 | | - true |
196 | | - end |
| 170 | + fiber.raise(context[:exception_class], *context[:exception_arguments]) if fiber.alive? |
197 | 171 |
|
198 | | - fiber_timeouts.length == 0 |
| 172 | + true |
199 | 173 | end |
200 | 174 | end |
201 | 175 | end |
|
0 commit comments