Remove round-7 stubs: todo!(), unimplemented!(), silent no-ops

Six items fixed from the round-7 relibc stub scan:

1. set_scheduler todo!() (mod.rs:1487) — replaced panic with proper
   policy validation: SCHED_OTHER is a no-op (kernel default), RT
   policies (FIFO/RR) return ENOSYS (need kernel support Redox lacks),
   invalid policies return EINVAL. Made posix_spawnattr_t.policy
   pub(crate) so the platform layer can read it.

2. F_SETLKW silent no-op (mod.rs:474) — merged into the F_SETLK |
   F_OFD_SETLK match arm. Redox's StdFsCallKind::Lock blocks at the
   kernel level, so F_SETLKW uses the same code path as F_SETLK. The
   is_ofd flag correctly evaluates to false for F_SETLKW.

3. relative_to_absolute_foffset silent (0,0) (mod.rs:1989) — implemented
   SEEK_CUR via lseek(fd, 0, SEEK_CUR) and SEEK_END via fstat(fd).
   Both apply the same negative-len normalization as SEEK_SET. Invalid
   whence values now return EINVAL instead of corrupting offsets.

4. setitimer ENOSYS (signal.rs:96) — replaced todo_skip! stub with a
   real implementation using a process-global POSIX timer (timer_create
   with CLOCK_REALTIME + SIGEV_SIGNAL/SIGALRM). Supports intervals
   (periodic timers), disarm (value=0), and old-value retrieval.
   getitimer also updated to read from the real timer instead of
   returning defaults.

5. ptrace unimplemented!() (ptrace.rs:127,138,279) — replaced three
   panics on aarch64/x86/riscv64 with Err(io::Error::from_raw_os_error(
   ENOSYS)). The caller maps this to Errno(ENOSYS), the proper POSIX
   response for architecture-specific ptrace on unsupported arches.

6. todo_skip! macro verified (macros.rs:47) — confirmed it is
   non-panicking (logs via log::info! and evaluates to ()). The
   setitimer stub was safe in that it returned ENOSYS after the log,
   but the real implementation is strictly better.
This commit is contained in:
Red Bear OS
2026-07-27 07:12:27 +09:00
parent 92f9d629c0
commit 07659b7f5f
4 changed files with 140 additions and 53 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ pub struct posix_spawnattr_t {
pub param: sched_param,
pub flags: c_short,
pub pgroup: c_int,
policy: c_int,
pub(crate) policy: c_int,
pub sigdefault: sigset_t,
pub sigmask: sigset_t,
}
+36 -10
View File
@@ -38,6 +38,7 @@ use crate::{
},
limits::{self},
pthread::{pthread_cancel, pthread_create},
sched::{SCHED_FIFO, SCHED_OTHER, SCHED_RR},
signal::{NSIG, SIGEV_NONE, SIGEV_SIGNAL, SIGEV_THREAD, SIGRTMIN, sigevent},
stdio::RENAME_NOREPLACE,
stdlib::posix_memalign,
@@ -56,7 +57,7 @@ use crate::{
time::{
CLOCK_MONOTONIC, CLOCK_REALTIME, TIMER_ABSTIME, itimerspec, timer_internal_t, timespec,
},
unistd::{F_OK, R_OK, SEEK_CUR, SEEK_SET, W_OK, X_OK},
unistd::{F_OK, R_OK, SEEK_CUR, SEEK_END, SEEK_SET, W_OK, X_OK},
},
io::{self, BufReader, prelude::*},
iter::NulTerminated,
@@ -367,7 +368,7 @@ impl Pal for Sys {
fn fcntl(fd: c_int, cmd: c_int, args: c_ulonglong) -> Result<c_int> {
match cmd {
F_SETLK | F_OFD_SETLK => {
F_SETLK | F_OFD_SETLK | F_SETLKW => {
let is_ofd = cmd == F_OFD_SETLK;
let flock = unsafe { &mut *(args as *mut flock) };
@@ -471,8 +472,6 @@ impl Pal for Sys {
return Ok(0);
}
F_SETLKW => log::warn!("F_SETLKW: not yet implemented"),
_ => {}
}
@@ -1484,7 +1483,15 @@ impl Pal for Sys {
Ok(())
}
};
let set_scheduler = || -> Result<()> { todo!() };
let set_scheduler = || -> Result<()> {
// SCHED_OTHER is the kernel default (no-op); RT policies need
// kernel support Redox lacks, so ENOSYS per POSIX.
match attr.policy {
SCHED_OTHER => Ok(()),
SCHED_FIFO | SCHED_RR => Err(Errno(ENOSYS)),
_ => Err(Errno(EINVAL)),
}
};
// scheduling paramters must be set regardless of whether the flag POSIX_SPAWN_SETSCHEDPARAM is set
if flags.contains(Flags::POSIX_SPAWN_SETSCHEDULER) {
@@ -1986,12 +1993,31 @@ impl Sys {
assert!(len >= 0);
Ok((start, len))
}
// FIXME: andypython: SEEK_CUR, SEEK_END
c if c == i32::from(SEEK_CUR) || c == i32::from(SEEK_END) => {
let base = if c == i32::from(SEEK_CUR) {
syscall::lseek(fd, 0, SEEK_CUR as usize)? as off_t
} else {
let mut st: stat = unsafe { mem::zeroed() };
unsafe { libredox::fstat(fd, &raw mut st) }?;
st.st_size as off_t
};
let abs_start = base + start;
let (abs_start, abs_len) = if len < 0 {
(abs_start + len, -len)
} else {
(abs_start, len)
};
if abs_start < 0 {
return Err(Errno(EINVAL));
}
assert!(abs_len >= 0);
Ok((abs_start, abs_len))
}
c => {
log::warn!(
"Sys::relative_to_absolute_foffset: whence={whence} not yet implemented"
);
Ok((0, 0))
return Err(Errno(EINVAL));
}
}
}
+16 -19
View File
@@ -14,7 +14,7 @@ use crate::{
error::Errno,
fs::File,
header::{
errno::{self as errnoh, EIO},
errno::{self as errnoh, EIO, ENOSYS},
fcntl,
},
io,
@@ -118,24 +118,22 @@ pub fn get_session(
#[cfg(target_arch = "aarch64")]
unsafe fn inner_ptrace(
request: c_int,
pid: pid_t,
addr: *mut c_void,
data: *mut c_void,
_request: c_int,
_pid: pid_t,
_addr: *mut c_void,
_data: *mut c_void,
) -> io::Result<c_int> {
//TODO: aarch64
unimplemented!("inner_ptrace not implemented on aarch64");
Err(io::Error::from_raw_os_error(ENOSYS))
}
#[cfg(target_arch = "x86")]
unsafe fn inner_ptrace(
request: c_int,
pid: pid_t,
addr: *mut c_void,
data: *mut c_void,
_request: c_int,
_pid: pid_t,
_addr: *mut c_void,
_data: *mut c_void,
) -> io::Result<c_int> {
//TODO: x86
unimplemented!("inner_ptrace not implemented on x86");
Err(io::Error::from_raw_os_error(ENOSYS))
}
#[cfg(target_arch = "x86_64")]
@@ -270,13 +268,12 @@ unsafe fn inner_ptrace(
#[cfg(target_arch = "riscv64")]
fn inner_ptrace(
request: c_int,
pid: pid_t,
addr: *mut c_void,
data: *mut c_void,
_request: c_int,
_pid: pid_t,
_addr: *mut c_void,
_data: *mut c_void,
) -> io::Result<c_int> {
//TODO: riscv64
unimplemented!("inner_ptrace not implemented on riscv64");
Err(io::Error::from_raw_os_error(ENOSYS))
}
impl PalPtrace for Sys {
+87 -23
View File
@@ -8,13 +8,16 @@ use crate::{
error::{Errno, Result},
header::{
bits_sigset_t::sigset_t,
errno::{EINVAL, ENOSYS},
errno::{EINVAL},
signal::{
SIG_BLOCK, SIG_DFL, SIG_IGN, SIG_SETMASK, SIG_UNBLOCK, SS_DISABLE, SS_ONSTACK,
sigaction, siginfo_t, sigval, stack_t, ucontext_t,
SIGALRM, SIG_BLOCK, SIG_DFL, SIG_IGN, SIG_SETMASK, SIG_UNBLOCK, SS_DISABLE,
SS_ONSTACK, SIGEV_SIGNAL, sigaction, sigevent, siginfo_t, sigval, stack_t,
ucontext_t,
},
time::timespec,
time::{CLOCK_REALTIME, itimerspec, timespec},
},
out::Out,
sync::Mutex,
};
use core::mem::offset_of;
use redox_protocols::protocol::ProcKillTarget;
@@ -22,6 +25,11 @@ use redox_rt::signal::{
PosixStackt, SigStack, Sigaction, SigactionFlags, SigactionKind, Sigaltstack, SignalHandler,
};
struct ItimerTimer(timer_t);
unsafe impl Send for ItimerTimer {}
static ITIMER_REAL_TIMER: Mutex<Option<ItimerTimer>> = Mutex::new(None);
const _: () = {
#[track_caller]
const fn assert_eq(a: usize, b: usize) {
@@ -47,20 +55,21 @@ const _: () = {
impl PalSignal for Sys {
#[allow(deprecated)]
fn getitimer(which: c_int, out: &mut itimerval) -> Result<()> {
let path = match which {
ITIMER_REAL => "/scheme/itimer/1",
_ => return Err(Errno(EINVAL)),
};
// TODO: implement setitimer
// let fd = FdGuard::new(redox_rt::sys::open(path, syscall::O_RDONLY | syscall::O_CLOEXEC)?);
// let count = syscall::read(*fd, &mut spec)?;
let spec = syscall::ITimerSpec::default();
out.it_interval.tv_sec = spec.it_interval.tv_sec as time_t;
out.it_interval.tv_usec = spec.it_interval.tv_nsec / 1000;
out.it_value.tv_sec = spec.it_value.tv_sec as time_t;
out.it_value.tv_usec = spec.it_value.tv_nsec / 1000;
if which != ITIMER_REAL {
return Err(Errno(EINVAL));
}
let guard = ITIMER_REAL_TIMER.lock();
if let Some(ref timer) = *guard {
let mut cur = itimerspec::default();
Sys::timer_gettime(timer.0, Out::from_mut(&mut cur))?;
out.it_interval.tv_sec = cur.it_interval.tv_sec as time_t;
out.it_interval.tv_usec = (cur.it_interval.tv_nsec / 1000) as suseconds_t;
out.it_value.tv_sec = cur.it_value.tv_sec as time_t;
out.it_value.tv_usec = (cur.it_value.tv_nsec / 1000) as suseconds_t;
} else {
*out = unsafe { core::mem::zeroed() };
}
Ok(())
}
@@ -89,12 +98,67 @@ impl PalSignal for Sys {
}
#[allow(deprecated)]
fn setitimer(which: c_int, _new: &itimerval, old: Option<&mut itimerval>) -> Result<()> {
// TODO: setitimer is no longer part of POSIX and should not be implemented in Redox
// Change the platform-independent implementation to use POSIX timers.
// For Redox, the timer should probably use "/scheme/time"
todo_skip!(0, "setitimer not implemented");
Err(Errno(ENOSYS))
fn setitimer(which: c_int, new: &itimerval, old: Option<&mut itimerval>) -> Result<()> {
if which != ITIMER_REAL {
return Err(Errno(EINVAL));
}
let mut guard = ITIMER_REAL_TIMER.lock();
if let Some(old_out) = old {
if let Some(ref timer) = *guard {
let mut cur = itimerspec::default();
if Sys::timer_gettime(timer.0, Out::from_mut(&mut cur)).is_ok() {
old_out.it_interval.tv_sec = cur.it_interval.tv_sec as time_t;
old_out.it_interval.tv_usec =
(cur.it_interval.tv_nsec / 1000) as suseconds_t;
old_out.it_value.tv_sec = cur.it_value.tv_sec as time_t;
old_out.it_value.tv_usec = (cur.it_value.tv_nsec / 1000) as suseconds_t;
} else {
*old_out = unsafe { core::mem::zeroed() };
}
} else {
*old_out = unsafe { core::mem::zeroed() };
}
}
let disarm = new.it_value.tv_sec == 0 && new.it_value.tv_usec == 0;
if disarm {
if let Some(ref timer) = *guard {
let zero = itimerspec::default();
let _ = Sys::timer_settime(timer.0, 0, &zero, None);
}
return Ok(());
}
if guard.is_none() {
let mut evp: sigevent = unsafe { core::mem::zeroed() };
evp.sigev_notify = SIGEV_SIGNAL;
evp.sigev_signo = SIGALRM as c_int;
let mut timer_id: timer_t = core::ptr::null_mut();
Sys::timer_create(CLOCK_REALTIME, &evp, Out::from_mut(&mut timer_id))?;
*guard = Some(ItimerTimer(timer_id));
}
let timer_id = guard
.as_ref()
.expect("itimer must exist after lazy init")
.0;
let spec = itimerspec {
it_value: timespec {
tv_sec: new.it_value.tv_sec,
tv_nsec: new.it_value.tv_usec as i64 * 1000,
},
it_interval: timespec {
tv_sec: new.it_interval.tv_sec,
tv_nsec: new.it_interval.tv_usec as i64 * 1000,
},
};
Sys::timer_settime(timer_id, 0, &spec, None)?;
Ok(())
}
fn sigaction(