Initial commit: phases 1-3 du portage Wayland Rust pour Redox OS
Plan directeur 14 phases / 5 ans (REDOX_COSMIC_XWAYLAND_RS_PLAN.md).
Phase 1 — Audit Redox (docs/existing-redox-gui.md, 486 lignes) :
- Orbital, graphics-ipc (API DRM compatible Linux subset KMS), inputd, vesad
- relibc support : AF_UNIX, SCM_RIGHTS, shm_open, mmap, poll
- 3 manques identifiés : memfd_create, keymap XKB, AT-SPI
Phase 2 — Validation primitives sur Redox via redoxer (5 tests + 1 POC) :
- test-unix-socket : SOCK_STREAM Wayland-shaped roundtrip
- test-fd-passing : SCM_RIGHTS mono-process (artefact kernel)
- test-fd-passing-fork : SCM_RIGHTS multi-process (validation Wayland critique)
- test-shm-open : shm_open + mmap + persistance + unlink
- test-poll-multifd : poll() multiplexing + POLLHUP
- poc-pixels : datapath shm + SCM_RIGHTS bout en bout (10000 pixels ARGB)
Phase 3 — wayland-rs sur Redox (compile + runtime) :
- wayland-{scanner,backend,server,client} compilent pour x86_64-unknown-redox
sans patch upstream (rustix supporte Redox via libc backend)
- test-handshake : server/client wl_registry handshake roundtrip
- test-shm-pipeline : pipeline complet (ListeningSocket Unix réel + fd passing
via wl_shm.create_pool + wl_shm_pool + wl_buffer + wl_surface + commit +
serveur lit pixels via fd reçu, validation pixel-perfect)
Verdict phase 3 : wayland-rs upstream est viable sur Redox out-of-the-box,
le port "Wayland sur Redox" est désormais un problème de compositor à écrire,
pas de stack à porter.
Prérequis build : redoxer (pas cargo direct, car CMSG_NXTHDR/CMSG_DATA
ne sont pas linkés autrement vers librelibc.a).
Leyoda 2026 – GPLv3
This commit is contained in:
commit
53e6626231
21 changed files with 3676 additions and 0 deletions
142
crates/redox-wl-test-shm-open/src/main.rs
Normal file
142
crates/redox-wl-test-shm-open/src/main.rs
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
//! Test 3 — shm_open + mmap MAP_SHARED.
|
||||
//!
|
||||
//! Wayland clients use shm_open + ftruncate + mmap to create wl_shm pools.
|
||||
//! The compositor then receives the fd via SCM_RIGHTS and mmaps the same region.
|
||||
//!
|
||||
//! relibc Redox maps shm_open("/foo") to open("/scheme/shm/foo").
|
||||
//! This test validates:
|
||||
//! 1. shm_open with O_RDWR | O_CREAT works
|
||||
//! 2. ftruncate sets the size
|
||||
//! 3. mmap MAP_SHARED returns a writable region
|
||||
//! 4. writes are persistent: close + reopen + remap reads back the data
|
||||
//! 5. shm_unlink removes the segment
|
||||
//!
|
||||
//! Two passes (write then read-back) simulate the producer/consumer pattern
|
||||
//! used by Wayland: client writes pixels, compositor reads them.
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::io;
|
||||
use std::os::fd::RawFd;
|
||||
use std::process::ExitCode;
|
||||
use std::ptr;
|
||||
|
||||
const SHM_NAME: &str = "/redox-wl-test-03";
|
||||
const SIZE: usize = 4096;
|
||||
|
||||
fn errno_str() -> String {
|
||||
let e = io::Error::last_os_error();
|
||||
format!("{e} (errno={})", e.raw_os_error().unwrap_or(0))
|
||||
}
|
||||
|
||||
unsafe fn shm_open_rw_create(name: &str, mode: libc::mode_t) -> Result<RawFd, String> {
|
||||
let cname = CString::new(name).unwrap();
|
||||
let fd = libc::shm_open(
|
||||
cname.as_ptr(),
|
||||
libc::O_RDWR | libc::O_CREAT,
|
||||
mode as _,
|
||||
);
|
||||
if fd < 0 {
|
||||
return Err(format!("shm_open({name}): {}", errno_str()));
|
||||
}
|
||||
Ok(fd)
|
||||
}
|
||||
|
||||
unsafe fn shm_open_rw(name: &str) -> Result<RawFd, String> {
|
||||
let cname = CString::new(name).unwrap();
|
||||
let fd = libc::shm_open(cname.as_ptr(), libc::O_RDWR, 0);
|
||||
if fd < 0 {
|
||||
return Err(format!("shm_open(reopen {name}): {}", errno_str()));
|
||||
}
|
||||
Ok(fd)
|
||||
}
|
||||
|
||||
unsafe fn map_rw(fd: RawFd, size: usize) -> Result<*mut u8, String> {
|
||||
let p = libc::mmap(
|
||||
ptr::null_mut(),
|
||||
size,
|
||||
libc::PROT_READ | libc::PROT_WRITE,
|
||||
libc::MAP_SHARED,
|
||||
fd,
|
||||
0,
|
||||
);
|
||||
if p == libc::MAP_FAILED {
|
||||
return Err(format!("mmap MAP_SHARED: {}", errno_str()));
|
||||
}
|
||||
Ok(p as *mut u8)
|
||||
}
|
||||
|
||||
fn run() -> Result<(), String> {
|
||||
println!("[test-03] shm_open + mmap MAP_SHARED");
|
||||
|
||||
unsafe {
|
||||
// Phase 1: create + write
|
||||
let fd1 = shm_open_rw_create(SHM_NAME, 0o600)?;
|
||||
println!("[test-03] phase1: shm_open created, fd={fd1}");
|
||||
|
||||
if libc::ftruncate(fd1, SIZE as _) != 0 {
|
||||
return Err(format!("ftruncate: {}", errno_str()));
|
||||
}
|
||||
|
||||
let map1 = map_rw(fd1, SIZE)?;
|
||||
println!("[test-03] phase1: mmap at {:p}", map1);
|
||||
|
||||
// Write a recognisable pattern (ARGB8888 simulation: 256 pixels of 0xDEADBEEF)
|
||||
let pixels = std::slice::from_raw_parts_mut(map1 as *mut u32, SIZE / 4);
|
||||
for (i, p) in pixels.iter_mut().enumerate() {
|
||||
*p = 0xDEAD_BEEF_u32.wrapping_add(i as u32);
|
||||
}
|
||||
println!("[test-03] phase1: wrote {} u32 pixels", pixels.len());
|
||||
|
||||
if libc::munmap(map1 as *mut _, SIZE) != 0 {
|
||||
return Err(format!("munmap phase1: {}", errno_str()));
|
||||
}
|
||||
libc::close(fd1);
|
||||
|
||||
// Phase 2: reopen + check pattern
|
||||
let fd2 = shm_open_rw(SHM_NAME)?;
|
||||
println!("[test-03] phase2: shm_open reopened, fd={fd2}");
|
||||
|
||||
let map2 = map_rw(fd2, SIZE)?;
|
||||
println!("[test-03] phase2: mmap at {:p}", map2);
|
||||
|
||||
let pixels2 = std::slice::from_raw_parts(map2 as *const u32, SIZE / 4);
|
||||
for (i, &p) in pixels2.iter().enumerate() {
|
||||
let expected = 0xDEAD_BEEF_u32.wrapping_add(i as u32);
|
||||
if p != expected {
|
||||
libc::munmap(map2 as *mut _, SIZE);
|
||||
libc::close(fd2);
|
||||
let cname = CString::new(SHM_NAME).unwrap();
|
||||
libc::shm_unlink(cname.as_ptr());
|
||||
return Err(format!("pixel {i} mismatch: got {p:#x}, expected {expected:#x}"));
|
||||
}
|
||||
}
|
||||
println!("[test-03] phase2: pattern verified across close/reopen");
|
||||
|
||||
if libc::munmap(map2 as *mut _, SIZE) != 0 {
|
||||
return Err(format!("munmap phase2: {}", errno_str()));
|
||||
}
|
||||
libc::close(fd2);
|
||||
|
||||
// Cleanup
|
||||
let cname = CString::new(SHM_NAME).unwrap();
|
||||
if libc::shm_unlink(cname.as_ptr()) != 0 {
|
||||
return Err(format!("shm_unlink: {}", errno_str()));
|
||||
}
|
||||
println!("[test-03] cleanup: shm_unlink OK");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> ExitCode {
|
||||
match run() {
|
||||
Ok(()) => {
|
||||
println!("[test-03] PASS: shm_open/mmap/persistence/unlink all work");
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("[test-03] FAIL: {e}");
|
||||
ExitCode::FAILURE
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue