redox-wayland-compositor/crates/redox-wl-test-poll-multifd/src/main.rs
Votre Nom 8795f39f08 Sprint 0 — industrialisation : CI, tracing, tests xdg-shell, GPLv3
5 livrables d'industrialisation posés avant la phase 13 (client réel).

- .gitlab-ci.yml : pipeline minimal (fmt-check + tests core +
  tests frontend nightly). Pas de cross-compile Redox dans le MVP.
- rustfmt.toml + fmt.sh : config formatter racine + boucle sur les 23
  crates ; fmt sweep appliqué (d'où les diffs cosmétiques).
- tracing dans wayland-frontend : 22 println/eprintln remplacés par
  debug/info/warn/error selon sévérité. Préfixe "[frontend]"
  supprimé (le target tracing le fournit).
- tracing-subscriber dans le compositor : TeeWriter écrit sur
  stdout + /scheme/debug, filtre via RUST_LOG (défaut info).
  DebugSink/dlog supprimés.
- 15 tests unitaires xdg-shell après extraction de 2 helpers libres
  (clamp_to_min_max + should_throttle_configure). Couvre
  compute_resize_geom, contraintes min/max et throttling configure.
- LICENSE (GPLv3 texte officiel FSF) + .editorconfig.

Total tests : 27 → 42 automatisés (compositor-core + frontend).

Leyoda 2026 – GPLv3
2026-05-14 20:46:07 +02:00

147 lines
4.4 KiB
Rust

//! Test 4 — poll() over multiple fds.
//!
//! A Wayland compositor multiplexes many fds: the listening socket,
//! each connected client, the input device(s), idle timers, signals.
//! This test validates that poll() correctly demultiplexes.
//!
//! Setup: 3 pipes (a, b, c). We write into b only, then poll all 3.
//! Only fd_b should report POLLIN. We read it. Then we close a, expecting
//! POLLHUP on a-read side. Finally we test timeout-only behaviour.
use std::io;
use std::os::fd::RawFd;
use std::process::ExitCode;
fn errno_str() -> String {
let e = io::Error::last_os_error();
format!("{e} (errno={})", e.raw_os_error().unwrap_or(0))
}
unsafe fn make_pipe() -> Result<(RawFd, RawFd), String> {
let mut fds: [RawFd; 2] = [-1, -1];
if libc::pipe(fds.as_mut_ptr()) != 0 {
return Err(format!("pipe: {}", errno_str()));
}
Ok((fds[0], fds[1]))
}
unsafe fn poll_revents(fds: &mut [libc::pollfd], timeout_ms: i32) -> Result<i32, String> {
let r = libc::poll(fds.as_mut_ptr(), fds.len() as _, timeout_ms);
if r < 0 {
return Err(format!("poll: {}", errno_str()));
}
Ok(r)
}
fn run() -> Result<(), String> {
println!("[test-04] poll() multi-fd multiplexing");
unsafe {
// 3 pipes; we'll only watch the read ends.
let (ra, wa) = make_pipe()?;
let (rb, wb) = make_pipe()?;
let (rc, wc) = make_pipe()?;
println!("[test-04] pipes: ra={ra} rb={rb} rc={rc}");
// ---- Subtest A: timeout-only, no fd ready ----
let mut pfds = [
libc::pollfd {
fd: ra,
events: libc::POLLIN,
revents: 0,
},
libc::pollfd {
fd: rb,
events: libc::POLLIN,
revents: 0,
},
libc::pollfd {
fd: rc,
events: libc::POLLIN,
revents: 0,
},
];
let n = poll_revents(&mut pfds, 50)?;
if n != 0 {
return Err(format!("expected timeout (0), got {n}"));
}
println!("[test-04] A: timeout 50ms with no data → poll returned 0 OK");
// ---- Subtest B: write into pipe B only ----
let payload = b"X";
let n = libc::write(wb, payload.as_ptr() as *const _, 1);
if n != 1 {
return Err(format!("write to wb: {}", errno_str()));
}
for p in pfds.iter_mut() {
p.revents = 0;
}
let n = poll_revents(&mut pfds, 1000)?;
if n != 1 {
return Err(format!("expected 1 ready fd, got {n}"));
}
let ready: Vec<_> = pfds
.iter()
.enumerate()
.filter(|(_, p)| p.revents & libc::POLLIN != 0)
.map(|(i, _)| i)
.collect();
if ready != [1] {
return Err(format!("expected only index 1 (rb) ready, got {ready:?}"));
}
println!("[test-04] B: poll detected only rb (index 1) ready, as expected");
let mut buf = [0u8; 1];
let r = libc::read(rb, buf.as_mut_ptr() as *mut _, 1);
if r != 1 || buf[0] != b'X' {
return Err(format!("read rb: r={r} buf={:?}", buf));
}
println!("[test-04] B: read 1 byte 'X' from rb OK");
// ---- Subtest C: close write end of A, expect HUP on read end ----
libc::close(wa);
for p in pfds.iter_mut() {
p.revents = 0;
}
let n = poll_revents(&mut pfds, 100)?;
if n < 1 {
return Err(format!(
"expected at least 1 ready (POLLHUP on ra), got {n}"
));
}
let hup_a = pfds[0].revents & (libc::POLLHUP | libc::POLLIN) != 0;
if !hup_a {
return Err(format!(
"expected HUP/IN on ra, revents={:#x}",
pfds[0].revents
));
}
println!(
"[test-04] C: closing wa caused POLLHUP/POLLIN on ra (revents={:#x})",
pfds[0].revents
);
// Cleanup
libc::close(ra);
libc::close(rb);
libc::close(wb);
libc::close(rc);
libc::close(wc);
}
Ok(())
}
fn main() -> ExitCode {
match run() {
Ok(()) => {
println!("[test-04] PASS: poll() multiplexes correctly across fds and detects HUP");
ExitCode::SUCCESS
}
Err(e) => {
eprintln!("[test-04] FAIL: {e}");
ExitCode::FAILURE
}
}
}