win32: Wait for the cancelled pipe I/O before returning

An interrupted pipe read or write returned right after `CancelIo`, which only requests the cancellation. Wait for the I/O to end and return what it transferred.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Hiroshi SHIBATAandClaude Opus 5.5 committed 2026-10-25 11:57:31 +09:00
1 parent 47c12f2060
commit c3b61b1243
2 files changed
+26 -10
Notes: git 2026-10-25 02:58:05 +00:00

No files matched your search

+10
View File
@@ -1739,6 +1739,16 @@ class TestIO < Test::Unit::TestCase
end
end if /cygwin/ !~ RUBY_PLATFORM
def test_read_interrupted_by_wakeup
with_pipe do |r, w|
t = Thread.new { r.read }
Thread.pass until t.stop?
100_000.times { t.wakeup; w.write("x") }
w.close
assert_equal(100_000, t.value.size)
end
end
def test_read
pipe(proc do |w|
w.write "foobarbaz"
+16 -10
View File
@@ -7464,13 +7464,17 @@ rb_w32_read_internal(int fd, void *buf, size_t size, rb_off_t *offset)
errno = EINTR;
else
errno = map_errno(GetLastError());
CloseHandle(ol.hEvent);
CancelIo((HANDLE)_osfhnd(fd));
rb_acrt_lowio_unlock_fh(fd);
return -1;
/* the read may have completed before the cancel, and the kernel
* writes ol and buf until it ends either way */
GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &read, TRUE);
if (!read) {
CloseHandle(ol.hEvent);
rb_acrt_lowio_unlock_fh(fd);
return -1;
}
}
if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &read, TRUE) &&
else if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &read, TRUE) &&
(err = GetLastError()) != ERROR_HANDLE_EOF) {
int ret = 0;
if (err != ERROR_BROKEN_PIPE) {
@@ -7577,13 +7581,15 @@ rb_w32_write_internal(int fd, const void *buf, size_t size, rb_off_t *offset)
errno = EINTR;
else
errno = map_errno(GetLastError());
CloseHandle(ol.hEvent);
CancelIo((HANDLE)_osfhnd(fd));
rb_acrt_lowio_unlock_fh(fd);
return -1;
GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &written, TRUE);
if (!written) {
CloseHandle(ol.hEvent);
rb_acrt_lowio_unlock_fh(fd);
return -1;
}
}
if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &written, TRUE)) {
else if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &written, TRUE)) {
errno = map_errno(GetLastError());
CloseHandle(ol.hEvent);
CancelIo((HANDLE)_osfhnd(fd));