diff --git a/src/syscall/abi/registry/mk.rs b/src/syscall/abi/registry/mk.rs index 2120da5789..44aaff07d1 100644 --- a/src/syscall/abi/registry/mk.rs +++ b/src/syscall/abi/registry/mk.rs @@ -40,6 +40,7 @@ pub(super) const ENTRIES: &[AbiEntry] = &[ e(b"MKAR", SyscallNumber::MkArgs, "MkArgs"), e(b"MTSP", SyscallNumber::MkThreadSpawn, "MkThreadSpawn"), e(b"MYLD", SyscallNumber::MkYield, "MkYield"), + e(b"MSLP", SyscallNumber::MkSleepMs, "MkSleepMs"), e(b"MTMS", SyscallNumber::MkTimeMillis, "MkTimeMillis"), e(b"MTRT", SyscallNumber::MkTimeRtc, "MkTimeRtc"), e(b"MBAT", SyscallNumber::MkBatteryStatus, "MkBatteryStatus"), diff --git a/src/syscall/contract/cap_table/mk.rs b/src/syscall/contract/cap_table/mk.rs index e0baa06fc4..f4a88c57db 100644 --- a/src/syscall/contract/cap_table/mk.rs +++ b/src/syscall/contract/cap_table/mk.rs @@ -22,6 +22,7 @@ pub(super) fn check(caps: &CapabilityToken, number: SyscallNumber) -> Option bool { | MkArgs | MkThreadSpawn | MkYield + | MkSleepMs | MkTimeMillis | MkTimeRtc | MkBatteryStatus diff --git a/src/syscall/microkernel/dispatch/process.rs b/src/syscall/microkernel/dispatch/process.rs index 7aae887ba4..dce4efab63 100644 --- a/src/syscall/microkernel/dispatch/process.rs +++ b/src/syscall/microkernel/dispatch/process.rs @@ -22,7 +22,8 @@ use crate::syscall::microkernel::memory::{sys_mmap, sys_munmap}; use crate::syscall::microkernel::numbers::*; use crate::syscall::microkernel::proc_output::sys_proc_output; use crate::syscall::microkernel::process::{ - sys_args, sys_exit, sys_getpid, sys_pid_alive, sys_spawn, sys_thread_spawn, sys_yield, + sys_args, sys_exit, sys_getpid, sys_pid_alive, sys_sleep_ms, sys_spawn, sys_thread_spawn, + sys_yield, }; use crate::syscall::microkernel::procstat::sys_proc_stat; use crate::syscall::microkernel::time::{sys_time_millis, sys_time_rtc}; @@ -39,6 +40,7 @@ pub(super) fn handle(nr: u64, a: Args) -> Option { SYS_ARGS => sys_args(a.a0, a.a1 as usize), SYS_THREAD_SPAWN => sys_thread_spawn(a.a0, a.a1), SYS_YIELD => sys_yield(), + SYS_SLEEP_MS => sys_sleep_ms(a.a0), SYS_TIME_MILLIS => sys_time_millis(), SYS_TIME_RTC => sys_time_rtc(a.a0), SYS_BATTERY_STATUS => sys_battery_status(), diff --git a/src/syscall/microkernel/numbers.rs b/src/syscall/microkernel/numbers.rs index 21b75c947f..5cf98003af 100644 --- a/src/syscall/microkernel/numbers.rs +++ b/src/syscall/microkernel/numbers.rs @@ -37,6 +37,7 @@ pub const SYS_GETPID: u64 = tag4(b"MGPD"); pub const SYS_ARGS: u64 = tag4(b"MKAR"); pub const SYS_THREAD_SPAWN: u64 = tag4(b"MTSP"); pub const SYS_YIELD: u64 = tag4(b"MYLD"); +pub const SYS_SLEEP_MS: u64 = tag4(b"MSLP"); pub const SYS_TIME_MILLIS: u64 = tag4(b"MTMS"); pub const SYS_TIME_RTC: u64 = tag4(b"MTRT"); pub const SYS_BATTERY_STATUS: u64 = tag4(b"MBAT"); diff --git a/src/syscall/microkernel/process.rs b/src/syscall/microkernel/process.rs index 2c7d9f6dbb..797ffb5e95 100644 --- a/src/syscall/microkernel/process.rs +++ b/src/syscall/microkernel/process.rs @@ -80,6 +80,27 @@ pub fn sys_yield() -> i64 { 0 } +// Deschedule the caller for `ms` milliseconds. Unlike yield, which leaves +// the task runnable and so keeps a busy backoff loop pinning the CPU, this +// parks the task until its wake deadline so the core can idle. Service +// capsules that poll for a dependency to come up use this instead of a tight +// yield loop, which is what used to peg the host core and starve the desktop. +pub fn sys_sleep_ms(ms: u64) -> i64 { + let Some(pid) = current_pid() else { + return ERRNO_PERM; + }; + if ms == 0 { + crate::sched::yield_now(); + return 0; + } + let deadline = crate::time::timestamp_millis().saturating_add(ms); + while crate::time::timestamp_millis() < deadline { + crate::sched::sleep_until(pid, deadline); + crate::sched::yield_now(); + } + 0 +} + pub fn sys_getpid() -> i64 { match current_pid() { Some(pid) => pid as i64, diff --git a/src/syscall/numbers/defs.rs b/src/syscall/numbers/defs.rs index 02f0196f8b..843c952108 100644 --- a/src/syscall/numbers/defs.rs +++ b/src/syscall/numbers/defs.rs @@ -59,6 +59,7 @@ pub enum SyscallNumber { MkArgs = tag4(b"MKAR"), MkThreadSpawn = tag4(b"MTSP"), MkYield = tag4(b"MYLD"), + MkSleepMs = tag4(b"MSLP"), MkTimeMillis = tag4(b"MTMS"), MkTimeRtc = tag4(b"MTRT"), MkBatteryStatus = tag4(b"MBAT"), diff --git a/toolchain/nonos-std/sys/pal/nonos/os.rs b/toolchain/nonos-std/sys/pal/nonos/os.rs index 8065974e23..98f1720eb9 100644 --- a/toolchain/nonos-std/sys/pal/nonos/os.rs +++ b/toolchain/nonos-std/sys/pal/nonos/os.rs @@ -16,7 +16,11 @@ const N_MK_EXIT: i64 = tag4(b"MEXT"); const N_MK_GETPID: i64 = tag4(b"MGPD"); pub fn getcwd() -> io::Result { - unsupported() + // NONOS capsules run with a fixed root working directory. Returning "/" + // rather than an error lets unmodified crates.io tools that query the CWD + // at startup (ripgrep among them) initialize instead of bailing out with + // "failed to get current working directory". + Ok(PathBuf::from("/")) } pub fn chdir(_: &path::Path) -> io::Result<()> { diff --git a/userland/libc/src/lib.rs b/userland/libc/src/lib.rs index 56f9c2923c..554005064f 100644 --- a/userland/libc/src/lib.rs +++ b/userland/libc/src/lib.rs @@ -23,6 +23,7 @@ pub mod broker; pub mod capsule_load; pub mod crypto; pub mod debug; +pub mod fuzz; pub mod graphics; pub mod heap; pub mod ipc; @@ -80,4 +81,4 @@ pub use surface_registry::{ }; pub use syscall::call_raw as mk_syscall_raw; pub use time::{mk_time_millis, mk_time_rtc, RtcTime}; -pub use unistd::{mk_exit, mk_yield}; +pub use unistd::{mk_exit, mk_sleep_ms, mk_yield}; diff --git a/userland/libc/src/syscall/mod.rs b/userland/libc/src/syscall/mod.rs index 723e27cdea..ff4b8a9f51 100644 --- a/userland/libc/src/syscall/mod.rs +++ b/userland/libc/src/syscall/mod.rs @@ -36,6 +36,7 @@ pub(crate) use numbers::{ N_MK_IRQ_WAIT, N_MK_MMAP, N_MK_MMIO_MAP, N_MK_MMIO_UNMAP, N_MK_PCI_CONFIG_READ, N_MK_PCI_CONFIG_WRITE, N_MK_PID_ALIVE, N_MK_PIO_GRANT, N_MK_PIO_READ, N_MK_PIO_RELEASE, N_MK_PIO_WRITE, N_MK_PROC_OUTPUT, N_MK_PROC_STAT, N_MK_SERVICE_LOOKUP, N_MK_SERVICE_REGISTER, + N_MK_SLEEP_MS, N_MK_SURFACE_ATTACH, N_MK_SURFACE_PRESENT, N_MK_SURFACE_REGISTER, N_MK_SURFACE_RELEASE, N_MK_SURFACE_SHARE, N_MK_TIME_MILLIS, N_MK_TIME_RTC, N_MK_YIELD, }; diff --git a/userland/libc/src/syscall/numbers/core.rs b/userland/libc/src/syscall/numbers/core.rs index 55bbbbb049..3a69433274 100644 --- a/userland/libc/src/syscall/numbers/core.rs +++ b/userland/libc/src/syscall/numbers/core.rs @@ -22,6 +22,7 @@ pub(crate) const N_MK_PID_ALIVE: i64 = tag4(b"MPAL"); pub(crate) const N_MK_GETPID: i64 = tag4(b"MGPD"); pub(crate) const N_MK_ARGS: i64 = tag4(b"MKAR"); pub(crate) const N_MK_YIELD: i64 = tag4(b"MYLD"); +pub(crate) const N_MK_SLEEP_MS: i64 = tag4(b"MSLP"); pub(crate) const N_MK_TIME_MILLIS: i64 = tag4(b"MTMS"); pub(crate) const N_MK_TIME_RTC: i64 = tag4(b"MTRT"); pub(crate) const N_MK_BATTERY_STATUS: i64 = tag4(b"MBAT"); diff --git a/userland/libc/src/unistd/mod.rs b/userland/libc/src/unistd/mod.rs index 173e8f8fe8..0fe9856525 100644 --- a/userland/libc/src/unistd/mod.rs +++ b/userland/libc/src/unistd/mod.rs @@ -18,4 +18,4 @@ mod exit; mod sched; pub use exit::mk_exit; -pub use sched::mk_yield; +pub use sched::{mk_sleep_ms, mk_yield}; diff --git a/userland/libc/src/unistd/sched.rs b/userland/libc/src/unistd/sched.rs index fcfc68fb24..823727b6f2 100644 --- a/userland/libc/src/unistd/sched.rs +++ b/userland/libc/src/unistd/sched.rs @@ -14,9 +14,17 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use crate::syscall::{call_raw, N_MK_YIELD}; +use crate::syscall::{call_raw, N_MK_SLEEP_MS, N_MK_YIELD}; #[no_mangle] pub extern "C" fn mk_yield() -> i64 { call_raw(N_MK_YIELD, [0; 6]) } + +// Park the caller for `ms` milliseconds. Use this instead of a tight +// `mk_yield` backoff loop when waiting for a dependency: yield keeps the task +// runnable and pins the CPU, this releases the core until the wake deadline. +#[no_mangle] +pub extern "C" fn mk_sleep_ms(ms: u64) -> i64 { + call_raw(N_MK_SLEEP_MS, [ms, 0, 0, 0, 0, 0]) +}