page: the Wayland pump wakes parked Workers when it has written to a client

A reply the in-shim compositor writes (a frame callback, a buffer release,
input) is readiness for a thread parked in poll on that socket in another
Worker, and no syscall bumped the wake word for it. Wine's Wayland reader
thread waited out its 20 ms park bound: the park-late diag (M's f6978d6f) on
mspaint found 24 such parks, all 'net poll1' on that thread.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
This commit is contained in:
velzieandClaude Opus 5.5 committed 2026-10-12 05:56:10 -04:00
1 parent fd2ac62850
commit b638c27940
2 files changed
+19 -4

No files matched your search

+9 -1
View File
@@ -10607,7 +10607,15 @@ fn schedule() -> i32 {
let pick = with_host(|h| {
if let Some(w) = h.wayland.clone() {
let gm = GuestMem::new(guest_bytes());
w.pump(&h.kernel, &gm);
// What the pump wrote to a client's socket (a frame callback,
// a buffer release, input) is readiness for a thread parked in
// `poll` on that socket in another Worker -- Wine's Wayland
// reader thread -- and no syscall bumped the wake word for it:
// it waited out its park bound, 20 ms (the park-late diag on
// mspaint, 24 times on that one thread).
if w.pump(&h.kernel, &gm) && unsafe { k_present() } != 0 {
unsafe { k_wake() };
}
}
// Every thread gone ends this process, all this Worker has; the
// status is in the shared table for whoever waits.
+10 -3
View File
@@ -332,14 +332,17 @@ impl WaylandDevice {
}
/// Move bytes both ways for every client, hand the compositor this turn's
/// scene, and take its input. Run once per scheduler turn.
/// scene, and take its input. Run once per scheduler turn. Says whether it
/// sent any client anything: a reply written here is readiness no
/// syscall announced, so the caller wakes the parked Workers.
///
/// `kernel`/`mem` are how a buffer is found: a client maps its `wl_shm`
/// pool `MAP_SHARED`, which aliases a range of guest memory, so what the
/// compositor is told is the address of that range -- nothing is copied
/// here, and nothing is composited here either.
pub fn pump(&self, kernel: &Kernel, mem: &GuestMem<'_>) {
pub fn pump(&self, kernel: &Kernel, mem: &GuestMem<'_>) -> bool {
let mut sessions = self.inner.sessions.lock().unwrap();
let mut sent_any = false;
// Compositor input and control for this turn, addressed by client: a
// process can host Xwayland and a native client at once, and an event
// for one must not reach the other.
@@ -523,7 +526,10 @@ impl WaylandDevice {
while s.sent < s.out.len() {
match s.socket.send(&s.out[s.sent..]) {
Ok(0) | Err(_) => break,
Ok(n) => s.sent += n as usize,
Ok(n) => {
s.sent += n as usize;
sent_any = true;
}
}
}
if s.sent == s.out.len() {
@@ -582,6 +588,7 @@ impl WaylandDevice {
let count = (scene.len() / REC) as u32;
unsafe { wl_publish(scene.as_ptr() as u32, count) };
}
sent_any
}
/// Write every client's surfaces into the scene arena.