Skip to content

Commit 7460808

Browse files
committed
🥅 Work around JRuby IO#close thread-safety issue
In CRuby, the same IO object generally can't be closed concurrently from multiple threads thanks to the GVL. But also, it checks and double checks whether or not the IO object has already been closed around critical sections, and simply returns if it's already been closed. JRuby seems to handle concurrent `IO#close` similarly to if the losing thread were trying to read or write. So it can easily be triggered into raise an IOError with "closed stream".
1 parent 3a7f16c commit 7460808

1 file changed

Lines changed: 11 additions & 1 deletion

File tree

lib/net/imap.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1215,10 +1215,20 @@ def disconnect(timeout: nil)
12151215
@sock.to_io.shutdown
12161216
rescue Errno::ENOTCONN
12171217
# ignore `Errno::ENOTCONN: Socket is not connected' on some platforms.
1218+
rescue IOError => e
1219+
# IO#close should be safe against being closed by another thread, but
1220+
# JRuby raises this error sometimes.
1221+
raise unless e.message == "closed stream"
12181222
rescue Exception => e
12191223
@receiver_thread.raise(e) unless in_receiver_thread
12201224
end
1221-
@sock.close
1225+
begin
1226+
@sock.close
1227+
rescue IOError => e
1228+
# IO#close should be safe against being closed by another thread, but
1229+
# JRuby raises this error sometimes.
1230+
raise unless e.message == "closed stream"
1231+
end
12221232
@receiver_thread.join(timeout) unless mon_owned? || in_receiver_thread
12231233
raise e if e
12241234
ensure

0 commit comments

Comments
 (0)