gex-kernel: a blocking writev to a full stream waits, as write does

blocking_op parked a full-pipe write but not a writev, which went
straight to EAGAIN. Wine's send_request writes requests to the server
with writev: once winedevice's drivers really loaded (pelink's
ZwLoadDriver fix), NDIS's thread found the request pipe full and died
with "wine client error: write: Resource temporarily unavailable", and
services waited 10 s for NDIS. Now the first non-empty vector is written
as a WriteStream (a short write the caller retries); PlugPlay, Eventlog,
nsiproxy and NDIS all start.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_781bad2ec05143db9067c86b4b2678e2
This commit is contained in:
velzieandClaude Opus 5.5 committed 2026-10-10 12:55:56 -04:00
1 parent bd98b866c3
commit b8f708f789
1 file changed
+20
+20
View File
@@ -2219,6 +2219,26 @@ impl Kernel {
len: a[2].min(1 << 24) as usize,
})
}
// A `writev` to a full stream that should block waits as a
// `write` of its first non-empty vector does: the call returns
// that vector's count, a short write the caller retries. (It
// went straight to `EAGAIN`, and Wine's `send_request` writes
// its requests to the server with `writev`: a thread that found
// the request pipe full died with "wine client error: write:
// Resource temporarily unavailable", hanging NDIS's start.)
nr::WRITEV => {
let file = self.fds.get(a[0] as i32).ok()?;
if !file.write_is_atomic() || !file.write_would_block() {
return None;
}
let vecs = Self::read_iovecs(m, a[1], a[2], self.compat).ok()?;
let (buf, len) = vecs.into_iter().find(|&(_, len)| len != 0)?;
Some(BlockOp::WriteStream {
handle: Arc::clone(&file.handle),
buf,
len: (len as usize).min(1 << 24),
})
}
nr::ACCEPT | nr::ACCEPT4 => {
let file = self.fds.get(a[0] as i32).ok()?;
let socket: Arc<dyn crate::vfs::FileHandle> = Arc::clone(&file.handle);