@@ -10,8 +10,7 @@ def initialize
1010 @root_fiber = Fiber . current
1111 @dns_cache = { }
1212
13- @alive_fibers = { }
14- @timeout_mutex = Mutex . new
13+ @alive_fibers = Hash . new { |h , k | h [ k ] = { } }
1514
1615 start_timeout_worker
1716 end
@@ -20,13 +19,6 @@ def io_wait(io, events, timeout = nil)
2019 f = Fiber . current
2120 ::Iodine ::Scheduler . attach ( io . fileno , events , timeout &.ceil ) { |err | f . resume ( err ) }
2221
23- timeout_deadline = Process . clock_gettime ( Process ::CLOCK_MONOTONIC ) + timeout
24- @alive_fibers [ f . __get_id ] = {
25- fiber : f ,
26- timeout_deadline : timeout_deadline ,
27- exception_class : RageTimeout ,
28- }
29-
3022 err = Fiber . defer ( io . fileno )
3123 if err == false || ( err && err < 0 )
3224 err
@@ -79,41 +71,21 @@ def kernel_sleep(duration = nil)
7971 Fiber . pause if duration . nil? || duration < 1
8072 end
8173
82- # TODO: GC works a little strange with this closure;
83- #
84- # def timeout_after(duration, exception_class = Timeout::Error, *exception_arguments, &block)
85- # fiber, block_status = Fiber.current, :running
86- # ::Iodine.run_after((duration * 1000).to_i) do
87- # fiber.raise(exception_class, exception_arguments) if block_status == :running
88- # end
89-
90- # result = block.call
91- # block_status = :finished
92-
93- # result
94- # end
9574 def timeout_after ( duration , exception_class = Timeout ::Error , *exception_arguments , &block )
9675 fiber = Fiber . current
9776 timeout_deadline = Process . clock_gettime ( Process ::CLOCK_MONOTONIC ) + duration
9877
99- p "duration #{ duration } "
100- p "fiber id #{ fiber . __get_id } "
101-
102- @timeout_mutex . synchronize do
103- @alive_fibers [ fiber . __get_id ] = {
104- fiber : fiber ,
105- timeout_deadline : timeout_deadline ,
106- exception_class : exception_class ,
107- exception_arguments : exception_arguments ,
108- }
109- end
78+ @alive_fibers [ fiber . __get_id ] [ timeout_deadline ] = {
79+ fiber : fiber ,
80+ timeout_deadline : timeout_deadline ,
81+ exception_class : exception_class ,
82+ exception_arguments : exception_arguments ,
83+ }
11084
11185 begin
11286 block . call
11387 ensure
114- @timeout_mutex . synchronize do
115- @alive_fibers . delete ( fiber . __get_id )
116- end
88+ @alive_fibers [ fiber . __get_id ] . delete ( timeout_deadline )
11789 end
11890 end
11991
@@ -189,36 +161,30 @@ def start_timeout_worker
189161 return unless ::Iodine . running?
190162
191163 ::Iodine . run_every ( Rage ::FiberScheduler ::TIMEOUT_WORKER_INTERVAL ) do
192- @timeout_mutex . synchronize do
193- check_timeouts
194- end
164+ check_timeouts
195165 end
196166 end
197167
198168 def check_timeouts
199- p @alive_fibers . count
169+ @alive_fibers . delete_if do |fiber_id , timeouts |
170+ timeouts . delete_if do |timeout_key , fiber_hash |
171+ current_time = Process . clock_gettime ( Process ::CLOCK_MONOTONIC )
200172
201- @alive_fibers . delete_if do |_ , fiber_hash |
202- current_time = Process . clock_gettime ( Process ::CLOCK_MONOTONIC )
173+ return false if current_time < fiber_hash [ :timeout_deadline ]
203174
204- p current_time
205- p "deadline #{ fiber_hash [ :timeout_deadline ] } "
206- p "fiber id #{ fiber_hash [ :fiber ] . __get_id } "
175+ fiber = fiber_hash [ :fiber ]
176+ unblock ( nil , fiber )
207177
208- return false if current_time < fiber_hash [ :timeout_deadline ]
178+ if fiber . alive?
179+ fiber . raise ( RageTimeout )
180+ else
181+ timeouts . delete ( timeout_key )
182+ end
209183
210- p 'after'
211-
212- fiber = fiber_hash [ :fiber ]
213- # unblock(nil, fiber)
214-
215- # if fiber.alive?
216- fiber . raise ( RageTimeout )
217- # else
218- # fiber.kill
219- # end
184+ true
185+ end
220186
221- true
187+ timeouts . length == 0
222188 end
223189 end
224190end
0 commit comments