Skip to content

Commit aec0e97

Browse files
committed
asdf
1 parent 3d920a4 commit aec0e97

File tree

2 files changed

+111
-104
lines changed

2 files changed

+111
-104
lines changed

notes.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,10 @@ describe IO with #close it can interrupt reading thread when closing from a fibe
7676
test/io.rb:178 IO#read
7777
test/io.rb:178 block (5 levels) in <top (required)>
7878
```
79+
80+
Analysis:
81+
82+
- `read_thread` has no fiber scheduler (`thread->scheduler == Qnil`), so `rb_fiber_scheduler_fiber_interrupt` is *not* called. The fallback (`rb_threadptr_pending_interrupt_enque` + `rb_threadptr_interrupt`) fires correctly. That part is intentional.
83+
- The `` is a sus warning, not an assertion failure. The test sets `report_on_exception = false` inside the thread but there is a race: if `r.close` delivers the IOError before that line executes, Ruby prints the exception.
84+
- More structurally: `close_task.wait` blocks until `rb_thread_io_close_wait` returns. That function calls `rb_mutex_sleep(wakeup_mutex, Qnil)`, waiting for `read_thread` to clear its blocking operation and signal the mutex. If `read_thread` doesn't properly wake and signal (e.g. due to GVL contention or scheduler interaction), the close task hangs and the test never reaches the `expect { read_thread.join }` assertion.
85+
- This failure may therefore be a separate liveness issue in the close/wait handshake rather than the stale-interrupt problem in Failures 1–3, but both are triggered by the same `rb_thread_io_close_interrupt` / `rb_thread_io_close_wait` mechanism.

test/io.rb

Lines changed: 104 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -92,132 +92,132 @@
9292
end
9393
end
9494

95-
# with "#close" do
96-
# it "can interrupt reading fiber when closing" do
97-
# skip_unless_minimum_ruby_version("4")
95+
with "#close" do
96+
# it "can interrupt reading fiber when closing" do
97+
# skip_unless_minimum_ruby_version("4")
9898

99-
# r, w = IO.pipe
99+
# r, w = IO.pipe
100100

101-
# read_task = Async do
102-
# expect do
103-
# r.read(5)
104-
# end.to raise_exception(IOError, message: be =~ /closed/)
105-
# end
101+
# read_task = Async do
102+
# expect do
103+
# r.read(5)
104+
# end.to raise_exception(IOError, message: be =~ /closed/)
105+
# end
106106

107-
# r.close
108-
# read_task.wait
109-
# end
107+
# r.close
108+
# read_task.wait
109+
# end
110110

111-
# it "can interrupt reading fiber when closing from another fiber" do
112-
# skip_unless_minimum_ruby_version("4")
111+
# it "can interrupt reading fiber when closing from another fiber" do
112+
# skip_unless_minimum_ruby_version("4")
113113

114-
# r, w = IO.pipe
114+
# r, w = IO.pipe
115115

116-
# read_task = Async do
117-
# expect do
118-
# r.read(5)
119-
# end.to raise_exception(IOError, message: be =~ /closed/)
120-
# end
116+
# read_task = Async do
117+
# expect do
118+
# r.read(5)
119+
# end.to raise_exception(IOError, message: be =~ /closed/)
120+
# end
121121

122-
# close_task = Async do
123-
# r.close
124-
# end
122+
# close_task = Async do
123+
# r.close
124+
# end
125125

126-
# close_task.wait
127-
# read_task.wait
128-
# end
126+
# close_task.wait
127+
# read_task.wait
128+
# end
129129

130-
# it "can interrupt reading fiber when closing from a new thread" do
131-
# skip_unless_minimum_ruby_version("4")
130+
# it "can interrupt reading fiber when closing from a new thread" do
131+
# skip_unless_minimum_ruby_version("4")
132132

133-
# r, w = IO.pipe
133+
# r, w = IO.pipe
134134

135-
# read_task = Async do
136-
# expect do
137-
# r.read(5)
138-
# end.to raise_exception(IOError, message: be =~ /closed/)
139-
# end
135+
# read_task = Async do
136+
# expect do
137+
# r.read(5)
138+
# end.to raise_exception(IOError, message: be =~ /closed/)
139+
# end
140140

141-
# close_thread = Thread.new do
142-
# r.close
143-
# end
141+
# close_thread = Thread.new do
142+
# r.close
143+
# end
144144

145-
# close_thread.value
146-
# read_task.wait
147-
# end
145+
# close_thread.value
146+
# read_task.wait
147+
# end
148148

149-
# it "can interrupt reading fiber when closing from a fiber in a new thread" do
150-
# skip_unless_minimum_ruby_version("4")
151-
152-
# r, w = IO.pipe
153-
154-
# read_task = Async do
155-
# expect do
156-
# r.read(5)
157-
# end.to raise_exception(IOError, message: be =~ /closed/)
158-
# end
159-
160-
# close_thread = Thread.new do
161-
# close_task = Async do
162-
# r.close
163-
# end
164-
# close_task.wait
165-
# end
166-
167-
# close_thread.value
168-
# read_task.wait
169-
# end
149+
# it "can interrupt reading fiber when closing from a fiber in a new thread" do
150+
# skip_unless_minimum_ruby_version("4")
151+
152+
# r, w = IO.pipe
153+
154+
# read_task = Async do
155+
# expect do
156+
# r.read(5)
157+
# end.to raise_exception(IOError, message: be =~ /closed/)
158+
# end
159+
160+
# close_thread = Thread.new do
161+
# close_task = Async do
162+
# r.close
163+
# end
164+
# close_task.wait
165+
# end
166+
167+
# close_thread.value
168+
# read_task.wait
169+
# end
170170

171-
# it "can interrupt reading thread when closing from a fiber" do
172-
# skip_unless_minimum_ruby_version("4")
171+
# it "can interrupt reading thread when closing from a fiber" do
172+
# skip_unless_minimum_ruby_version("4")
173173

174-
# r, w = IO.pipe
174+
# r, w = IO.pipe
175175

176-
# read_thread = Thread.new do
177-
# Thread.current.report_on_exception = false
178-
# r.read(5)
179-
# end
176+
# read_thread = Thread.new do
177+
# Thread.current.report_on_exception = false
178+
# r.read(5)
179+
# end
180180

181-
# # Wait until read_thread blocks on I/O
182-
# Thread.pass until read_thread.status == "sleep"
181+
# # Wait until read_thread blocks on I/O
182+
# Thread.pass until read_thread.status == "sleep"
183183

184-
# close_task = Async do
185-
# r.close
186-
# end
184+
# close_task = Async do
185+
# r.close
186+
# end
187187

188-
# close_task.wait
188+
# close_task.wait
189189

190-
# expect do
191-
# read_thread.join
192-
# end.to raise_exception(IOError, message: be =~ /closed/)
193-
# end
190+
# expect do
191+
# read_thread.join
192+
# end.to raise_exception(IOError, message: be =~ /closed/)
193+
# end
194194

195-
# it "can interrupt reading fiber in a new thread when closing from a fiber" do
196-
# skip_unless_minimum_ruby_version("4")
197-
198-
# r, w = IO.pipe
199-
200-
# read_thread = Thread.new do
201-
# Thread.current.report_on_exception = false
202-
# read_task = Async do
203-
# expect do
204-
# r.read(5)
205-
# end.to raise_exception(IOError, message: be =~ /closed/)
206-
# end
207-
# read_task.wait
208-
# end
209-
210-
# # Wait until read_thread blocks on I/O
211-
# Thread.pass until read_thread.status == "sleep"
212-
213-
# close_task = Async do
214-
# r.close
215-
# end
216-
# close_task.wait
217-
218-
# read_thread.value
219-
# end
220-
# end
195+
# it "can interrupt reading fiber in a new thread when closing from a fiber" do
196+
# skip_unless_minimum_ruby_version("4")
197+
198+
# r, w = IO.pipe
199+
200+
# read_thread = Thread.new do
201+
# Thread.current.report_on_exception = false
202+
# read_task = Async do
203+
# expect do
204+
# r.read(5)
205+
# end.to raise_exception(IOError, message: be =~ /closed/)
206+
# end
207+
# read_task.wait
208+
# end
209+
210+
# # Wait until read_thread blocks on I/O
211+
# Thread.pass until read_thread.status == "sleep"
212+
213+
# close_task = Async do
214+
# r.close
215+
# end
216+
# close_task.wait
217+
218+
# read_thread.value
219+
# end
220+
end
221221

222222
describe ".select" do
223223
it "can select readable IO" do

0 commit comments

Comments
 (0)