From 091d639a0fa185372304362e909a6f88d92c5651 Mon Sep 17 00:00:00 2001 From: "U. Lasiotus" Date: Wed, 24 Sep 2025 12:11:44 -0700 Subject: [PATCH 1/2] tidy: allow stdlib to depend on moto-rt As part of work to add stdlib support for Motor OS. --- src/tools/tidy/src/deps.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index c76b46ec2bf26..b4e30c80b3afd 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -568,6 +568,7 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[ "libc", "memchr", "miniz_oxide", + "moto-rt", "object", "r-efi", "r-efi-alloc", From d8da6c0a6905ad8b3204e8ffe06feb3b6ee54104 Mon Sep 17 00:00:00 2001 From: "U. Lasiotus" Date: Mon, 22 Sep 2025 18:51:59 -0700 Subject: [PATCH 2/2] Add Motor OS std library port Motor OS was added as a no-std Tier-3 target in https://github.com/rust-lang/rust/pull/146848 as x86_64-unknown-motor. This patch/PR adds the std library for Motor OS. While the patch may seem large, all it does is proxy std pal calls to moto-rt. When there is some non-trivial code (e.g. thread::spawn), it is quite similar, often identical, to what other platforms do. --- library/Cargo.lock | 11 + library/std/Cargo.toml | 3 + library/std/build.rs | 1 + library/std/src/os/fd/owned.rs | 23 +- library/std/src/os/fd/raw.rs | 10 +- library/std/src/os/mod.rs | 11 +- library/std/src/os/motor/ffi.rs | 44 ++ library/std/src/os/motor/mod.rs | 27 + library/std/src/os/motor/process.rs | 16 + library/std/src/sys/alloc/mod.rs | 3 + library/std/src/sys/alloc/motor.rs | 28 + library/std/src/sys/anonymous_pipe/mod.rs | 4 + library/std/src/sys/anonymous_pipe/motor.rs | 11 + library/std/src/sys/args/mod.rs | 5 + library/std/src/sys/args/motor.rs | 13 + library/std/src/sys/env/mod.rs | 5 + library/std/src/sys/env/motor.rs | 27 + library/std/src/sys/fd/mod.rs | 4 + library/std/src/sys/fd/motor.rs | 122 ++++ library/std/src/sys/fs/mod.rs | 4 + library/std/src/sys/fs/motor.rs | 478 ++++++++++++++++ library/std/src/sys/io/io_slice/motor.rs | 52 ++ library/std/src/sys/io/is_terminal/motor.rs | 6 + library/std/src/sys/io/mod.rs | 8 + library/std/src/sys/net/connection/mod.rs | 4 + library/std/src/sys/net/connection/motor.rs | 529 ++++++++++++++++++ library/std/src/sys/pal/mod.rs | 4 + library/std/src/sys/pal/motor/mod.rs | 29 + library/std/src/sys/pal/motor/os.rs | 91 +++ library/std/src/sys/pal/motor/pipe.rs | 121 ++++ library/std/src/sys/pal/motor/time.rs | 1 + library/std/src/sys/path/unix.rs | 2 +- library/std/src/sys/personality/mod.rs | 2 +- library/std/src/sys/process/mod.rs | 6 + library/std/src/sys/process/motor.rs | 322 +++++++++++ library/std/src/sys/random/mod.rs | 4 + library/std/src/sys/random/motor.rs | 3 + library/std/src/sys/stdio/mod.rs | 4 + library/std/src/sys/stdio/motor.rs | 232 ++++++++ library/std/src/sys/sync/condvar/mod.rs | 1 + library/std/src/sys/sync/mutex/mod.rs | 1 + library/std/src/sys/sync/once/mod.rs | 1 + library/std/src/sys/sync/rwlock/mod.rs | 1 + .../std/src/sys/sync/thread_parking/mod.rs | 1 + library/std/src/sys/thread/mod.rs | 4 + library/std/src/sys/thread/motor.rs | 63 +++ library/std/src/sys/thread_local/mod.rs | 8 + 47 files changed, 2342 insertions(+), 8 deletions(-) create mode 100644 library/std/src/os/motor/ffi.rs create mode 100644 library/std/src/os/motor/mod.rs create mode 100644 library/std/src/os/motor/process.rs create mode 100644 library/std/src/sys/alloc/motor.rs create mode 100644 library/std/src/sys/anonymous_pipe/motor.rs create mode 100644 library/std/src/sys/args/motor.rs create mode 100644 library/std/src/sys/env/motor.rs create mode 100644 library/std/src/sys/fd/motor.rs create mode 100644 library/std/src/sys/fs/motor.rs create mode 100644 library/std/src/sys/io/io_slice/motor.rs create mode 100644 library/std/src/sys/io/is_terminal/motor.rs create mode 100644 library/std/src/sys/net/connection/motor.rs create mode 100644 library/std/src/sys/pal/motor/mod.rs create mode 100644 library/std/src/sys/pal/motor/os.rs create mode 100644 library/std/src/sys/pal/motor/pipe.rs create mode 100644 library/std/src/sys/pal/motor/time.rs create mode 100644 library/std/src/sys/process/motor.rs create mode 100644 library/std/src/sys/random/motor.rs create mode 100644 library/std/src/sys/stdio/motor.rs create mode 100644 library/std/src/sys/thread/motor.rs diff --git a/library/Cargo.lock b/library/Cargo.lock index 47fbf5169f491..3cd7ce0acc926 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -166,6 +166,16 @@ dependencies = [ "rustc-std-workspace-core", ] +[[package]] +name = "moto-rt" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b06cfad394d58f28e4c69ac064b4d0562b5c187cb982d67b44ec53f2acc64e" +dependencies = [ + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + [[package]] name = "object" version = "0.37.3" @@ -316,6 +326,7 @@ dependencies = [ "hermit-abi", "libc", "miniz_oxide", + "moto-rt", "object", "panic_abort", "panic_unwind", diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 888914a2f772e..06e0beaa39c1a 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -70,6 +70,9 @@ fortanix-sgx-abi = { version = "0.6.1", features = [ 'rustc-dep-of-std', ], public = true } +[target.'cfg(target_os = "motor")'.dependencies] +moto-rt = { version = "0.14", features = ['rustc-dep-of-std'], public = true } + [target.'cfg(target_os = "hermit")'.dependencies] hermit-abi = { version = "0.5.0", features = [ 'rustc-dep-of-std', diff --git a/library/std/build.rs b/library/std/build.rs index 8a5a785060c85..bee28e88491d0 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -30,6 +30,7 @@ fn main() { || target_os == "windows" || target_os == "fuchsia" || (target_vendor == "fortanix" && target_env == "sgx") + || target_os == "motor" || target_os == "hermit" || target_os == "trusty" || target_os == "l4re" diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 10e1e73a115bd..d47c1e172ded1 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -3,6 +3,9 @@ #![stable(feature = "io_safety", since = "1.63.0")] #![deny(unsafe_op_in_unsafe_fn)] +#[cfg(target_os = "motor")] +use moto_rt::libc; + use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; #[cfg(not(target_os = "trusty"))] use crate::fs; @@ -12,7 +15,8 @@ use crate::mem::ManuallyDrop; target_arch = "wasm32", target_env = "sgx", target_os = "hermit", - target_os = "trusty" + target_os = "trusty", + target_os = "motor" )))] use crate::sys::cvt; #[cfg(not(target_os = "trusty"))] @@ -95,7 +99,12 @@ impl OwnedFd { impl BorrowedFd<'_> { /// Creates a new `OwnedFd` instance that shares the same underlying file /// description as the existing `BorrowedFd` instance. - #[cfg(not(any(target_arch = "wasm32", target_os = "hermit", target_os = "trusty")))] + #[cfg(not(any( + target_arch = "wasm32", + target_os = "hermit", + target_os = "trusty", + target_os = "motor" + )))] #[stable(feature = "io_safety", since = "1.63.0")] pub fn try_clone_to_owned(&self) -> crate::io::Result { // We want to atomically duplicate this file descriptor and set the @@ -123,6 +132,16 @@ impl BorrowedFd<'_> { pub fn try_clone_to_owned(&self) -> crate::io::Result { Err(crate::io::Error::UNSUPPORTED_PLATFORM) } + + /// Creates a new `OwnedFd` instance that shares the same underlying file + /// description as the existing `BorrowedFd` instance. + #[cfg(target_os = "motor")] + #[stable(feature = "io_safety", since = "1.63.0")] + pub fn try_clone_to_owned(&self) -> crate::io::Result { + let fd = + moto_rt::fs::duplicate(self.as_raw_fd()).map_err(crate::os::motor::map_motor_error)?; + Ok(unsafe { OwnedFd::from_raw_fd(fd) }) + } } #[stable(feature = "io_safety", since = "1.63.0")] diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 34a6cf1a8b84d..c01e6b83cd366 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -4,13 +4,17 @@ #[cfg(target_os = "hermit")] use hermit_abi as libc; +#[cfg(target_os = "motor")] +use moto_rt::libc; +#[cfg(target_os = "motor")] +use super::owned::OwnedFd; #[cfg(not(target_os = "trusty"))] use crate::fs; use crate::io; #[cfg(target_os = "hermit")] use crate::os::hermit::io::OwnedFd; -#[cfg(not(target_os = "hermit"))] +#[cfg(all(not(target_os = "hermit"), not(target_os = "motor")))] use crate::os::raw; #[cfg(all(doc, not(target_arch = "wasm32")))] use crate::os::unix::io::AsFd; @@ -23,10 +27,10 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// Raw file descriptors. #[stable(feature = "rust1", since = "1.0.0")] -#[cfg(not(target_os = "hermit"))] +#[cfg(all(not(target_os = "hermit"), not(target_os = "motor")))] pub type RawFd = raw::c_int; #[stable(feature = "rust1", since = "1.0.0")] -#[cfg(target_os = "hermit")] +#[cfg(any(target_os = "hermit", target_os = "motor"))] pub type RawFd = i32; /// A trait to extract the raw file descriptor from an underlying object. diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index 96d9bfae8ca32..3464c9415460c 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -155,6 +155,8 @@ pub mod ios; pub mod l4re; #[cfg(target_os = "macos")] pub mod macos; +#[cfg(target_os = "motor")] +pub mod motor; #[cfg(target_os = "netbsd")] pub mod netbsd; #[cfg(target_os = "nto")] @@ -182,7 +184,14 @@ pub mod vxworks; #[cfg(target_os = "xous")] pub mod xous; -#[cfg(any(unix, target_os = "hermit", target_os = "trusty", target_os = "wasi", doc))] +#[cfg(any( + unix, + target_os = "hermit", + target_os = "trusty", + target_os = "wasi", + target_os = "motor", + doc +))] pub mod fd; #[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin", doc))] diff --git a/library/std/src/os/motor/ffi.rs b/library/std/src/os/motor/ffi.rs new file mode 100644 index 0000000000000..ae3e9789c6703 --- /dev/null +++ b/library/std/src/os/motor/ffi.rs @@ -0,0 +1,44 @@ +//! Motor OS-specific extensions to primitives in the [`std::ffi`] module. + +#![stable(feature = "rust1", since = "1.0.0")] + +use crate::ffi::{OsStr, OsString}; +use crate::sealed::Sealed; + +/// Motor OS-specific extensions to [`OsString`]. +/// +/// This trait is sealed: it cannot be implemented outside the standard library. +/// This is so that future additional methods are not breaking changes. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait OsStringExt: Sealed { + /// Motor OS strings are utf-8, and thus just strings. + #[stable(feature = "rust1", since = "1.0.0")] + fn as_str(&self) -> &str; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl OsStringExt for OsString { + #[inline] + fn as_str(&self) -> &str { + self.to_str().unwrap() + } +} + +/// Motor OS-specific extensions to [`OsString`]. +/// +/// This trait is sealed: it cannot be implemented outside the standard library. +/// This is so that future additional methods are not breaking changes. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait OsStrExt: Sealed { + /// Motor OS strings are utf-8, and thus just strings. + #[stable(feature = "rust1", since = "1.0.0")] + fn as_str(&self) -> &str; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl OsStrExt for OsStr { + #[inline] + fn as_str(&self) -> &str { + self.to_str().unwrap() + } +} diff --git a/library/std/src/os/motor/mod.rs b/library/std/src/os/motor/mod.rs new file mode 100644 index 0000000000000..5c744751de881 --- /dev/null +++ b/library/std/src/os/motor/mod.rs @@ -0,0 +1,27 @@ +#![unstable(feature = "motor_ext", issue = "none")] + +#[unstable(feature = "motor_ext", issue = "none")] +pub fn map_motor_error(err: moto_rt::ErrorCode) -> crate::io::Error { + use moto_rt::error::*; + + use crate::io::ErrorKind; + + let kind: ErrorKind = match err { + E_ALREADY_IN_USE => ErrorKind::AlreadyExists, + E_INVALID_FILENAME => ErrorKind::InvalidFilename, + E_NOT_FOUND => ErrorKind::NotFound, + E_TIMED_OUT => ErrorKind::TimedOut, + E_NOT_IMPLEMENTED => ErrorKind::Unsupported, + E_FILE_TOO_LARGE => ErrorKind::FileTooLarge, + E_UNEXPECTED_EOF => ErrorKind::UnexpectedEof, + E_INVALID_ARGUMENT => ErrorKind::InvalidInput, + E_NOT_READY => ErrorKind::WouldBlock, + E_NOT_CONNECTED => ErrorKind::NotConnected, + _ => ErrorKind::Other, + }; + + crate::io::Error::from(kind) +} + +pub mod ffi; +pub mod process; diff --git a/library/std/src/os/motor/process.rs b/library/std/src/os/motor/process.rs new file mode 100644 index 0000000000000..a9f1847a866e9 --- /dev/null +++ b/library/std/src/os/motor/process.rs @@ -0,0 +1,16 @@ +use crate::sealed::Sealed; +use crate::sys_common::AsInner; + +#[unstable(feature = "motor_ext", issue = "none")] +pub trait ChildExt: Sealed { + /// Extracts the main thread raw handle, without taking ownership + #[unstable(feature = "motor_ext", issue = "none")] + fn sys_handle(&self) -> u64; +} + +#[unstable(feature = "motor_ext", issue = "none")] +impl ChildExt for crate::process::Child { + fn sys_handle(&self) -> u64 { + self.as_inner().handle() + } +} diff --git a/library/std/src/sys/alloc/mod.rs b/library/std/src/sys/alloc/mod.rs index 2045b2fecc6ac..f2f1d1c7feceb 100644 --- a/library/std/src/sys/alloc/mod.rs +++ b/library/std/src/sys/alloc/mod.rs @@ -83,6 +83,9 @@ cfg_select! { target_os = "hermit" => { mod hermit; } + target_os = "motor" => { + mod motor; + } all(target_vendor = "fortanix", target_env = "sgx") => { mod sgx; } diff --git a/library/std/src/sys/alloc/motor.rs b/library/std/src/sys/alloc/motor.rs new file mode 100644 index 0000000000000..cbe52b66245d8 --- /dev/null +++ b/library/std/src/sys/alloc/motor.rs @@ -0,0 +1,28 @@ +use crate::alloc::{GlobalAlloc, Layout, System}; + +#[stable(feature = "alloc_system_type", since = "1.28.0")] +unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + // Safety: same requirements as in GlobalAlloc::alloc. + moto_rt::alloc::alloc(layout) + } + + #[inline] + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + // Safety: same requirements as in GlobalAlloc::alloc_zeroed. + moto_rt::alloc::alloc_zeroed(layout) + } + + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + // Safety: same requirements as in GlobalAlloc::dealloc. + unsafe { moto_rt::alloc::dealloc(ptr, layout) } + } + + #[inline] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + // Safety: same requirements as in GlobalAlloc::realloc. + unsafe { moto_rt::alloc::realloc(ptr, layout, new_size) } + } +} diff --git a/library/std/src/sys/anonymous_pipe/mod.rs b/library/std/src/sys/anonymous_pipe/mod.rs index b6f464161ee2b..64b2c014b54fe 100644 --- a/library/std/src/sys/anonymous_pipe/mod.rs +++ b/library/std/src/sys/anonymous_pipe/mod.rs @@ -9,6 +9,10 @@ cfg_select! { mod windows; pub use windows::{AnonPipe, pipe}; } + target_os = "motor" => { + mod motor; + pub use motor::{AnonPipe, pipe}; + } _ => { mod unsupported; pub use unsupported::{AnonPipe, pipe}; diff --git a/library/std/src/sys/anonymous_pipe/motor.rs b/library/std/src/sys/anonymous_pipe/motor.rs new file mode 100644 index 0000000000000..dfe10f7fafe49 --- /dev/null +++ b/library/std/src/sys/anonymous_pipe/motor.rs @@ -0,0 +1,11 @@ +use crate::io; +use crate::sys::fd::FileDesc; +use crate::sys::pipe::anon_pipe; +use crate::sys_common::IntoInner; + +pub type AnonPipe = FileDesc; + +#[inline] +pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { + anon_pipe().map(|(rx, wx)| (rx.into_inner(), wx.into_inner())) +} diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs index e11e8e5430f06..38318facf4530 100644 --- a/library/std/src/sys/args/mod.rs +++ b/library/std/src/sys/args/mod.rs @@ -6,6 +6,7 @@ all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))), target_family = "windows", target_os = "hermit", + target_os = "motor", target_os = "uefi", target_os = "wasi", target_os = "xous", @@ -28,6 +29,10 @@ cfg_select! { mod sgx; pub use sgx::*; } + target_os = "motor" => { + mod motor; + pub use motor::*; + } target_os = "uefi" => { mod uefi; pub use uefi::*; diff --git a/library/std/src/sys/args/motor.rs b/library/std/src/sys/args/motor.rs new file mode 100644 index 0000000000000..76299dc2d1c85 --- /dev/null +++ b/library/std/src/sys/args/motor.rs @@ -0,0 +1,13 @@ +pub use super::common::Args; +use crate::ffi::OsString; + +pub fn args() -> Args { + let motor_args: Vec = moto_rt::process::args(); + let mut rust_args = alloc::vec::Vec::new(); + + for arg in motor_args { + rust_args.push(OsString::from(arg)); + } + + Args::new(rust_args) +} diff --git a/library/std/src/sys/env/mod.rs b/library/std/src/sys/env/mod.rs index f211a9fc86b3b..89856516b6dce 100644 --- a/library/std/src/sys/env/mod.rs +++ b/library/std/src/sys/env/mod.rs @@ -5,6 +5,7 @@ #[cfg(any( target_family = "unix", target_os = "hermit", + target_os = "motor", all(target_vendor = "fortanix", target_env = "sgx"), target_os = "solid_asp3", target_os = "uefi", @@ -26,6 +27,10 @@ cfg_select! { mod hermit; pub use hermit::*; } + target_os = "motor" => { + mod motor; + pub use motor::*; + } all(target_vendor = "fortanix", target_env = "sgx") => { mod sgx; pub use sgx::*; diff --git a/library/std/src/sys/env/motor.rs b/library/std/src/sys/env/motor.rs new file mode 100644 index 0000000000000..1f756ccd3ee85 --- /dev/null +++ b/library/std/src/sys/env/motor.rs @@ -0,0 +1,27 @@ +pub use super::common::Env; +use crate::ffi::{OsStr, OsString}; +use crate::io; +use crate::os::motor::ffi::OsStrExt; + +pub fn env() -> Env { + let motor_env: Vec<(String, String)> = moto_rt::process::env(); + let mut rust_env = vec![]; + + for (k, v) in motor_env { + rust_env.push((OsString::from(k), OsString::from(v))); + } + + Env::new(rust_env) +} + +pub fn getenv(key: &OsStr) -> Option { + moto_rt::process::getenv(key.as_str()).map(|s| OsString::from(s)) +} + +pub unsafe fn setenv(key: &OsStr, val: &OsStr) -> io::Result<()> { + Ok(moto_rt::process::setenv(key.as_str(), val.as_str())) +} + +pub unsafe fn unsetenv(key: &OsStr) -> io::Result<()> { + Ok(moto_rt::process::unsetenv(key.as_str())) +} diff --git a/library/std/src/sys/fd/mod.rs b/library/std/src/sys/fd/mod.rs index 7cb9dd1cba9d3..330499ecc18f6 100644 --- a/library/std/src/sys/fd/mod.rs +++ b/library/std/src/sys/fd/mod.rs @@ -11,6 +11,10 @@ cfg_select! { mod hermit; pub use hermit::*; } + target_os = "motor" => { + mod motor; + pub use motor::*; + } all(target_vendor = "fortanix", target_env = "sgx") => { mod sgx; pub use sgx::*; diff --git a/library/std/src/sys/fd/motor.rs b/library/std/src/sys/fd/motor.rs new file mode 100644 index 0000000000000..bbbb81ac3ec66 --- /dev/null +++ b/library/std/src/sys/fd/motor.rs @@ -0,0 +1,122 @@ +#![unstable(reason = "not public", issue = "none", feature = "fd")] + +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read}; +use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +use crate::sys::map_motor_error; +use crate::sys_common::{AsInner, FromInner, IntoInner}; + +#[derive(Debug)] +pub struct FileDesc(OwnedFd); + +impl FileDesc { + pub fn read(&self, buf: &mut [u8]) -> io::Result { + moto_rt::fs::read(self.as_raw_fd(), buf).map_err(map_motor_error) + } + + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + crate::io::default_read_buf(|buf| self.read(buf), cursor) + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + io::default_read_vectored(|b| self.read(b), bufs) + } + + pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { + let mut me = self; + (&mut me).read_to_end(buf) + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + moto_rt::fs::write(self.as_raw_fd(), buf).map_err(map_motor_error) + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + crate::io::default_write_vectored(|b| self.write(b), bufs) + } + + pub fn is_write_vectored(&self) -> bool { + false + } + + #[inline] + pub fn is_read_vectored(&self) -> bool { + false + } + + pub fn set_nonblocking(&self, _nonblocking: bool) -> io::Result<()> { + todo!() + } + + #[inline] + pub fn duplicate(&self) -> io::Result { + todo!() + } + + #[inline] + pub fn try_clone(&self) -> io::Result { + self.duplicate() + } +} + +impl<'a> Read for &'a FileDesc { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + (**self).read(buf) + } + + fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + (**self).read_buf(cursor) + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + (**self).read_vectored(bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + (**self).is_read_vectored() + } +} + +impl AsInner for FileDesc { + #[inline] + fn as_inner(&self) -> &OwnedFd { + &self.0 + } +} + +impl IntoInner for FileDesc { + fn into_inner(self) -> OwnedFd { + self.0 + } +} + +impl FromInner for FileDesc { + fn from_inner(owned_fd: OwnedFd) -> Self { + Self(owned_fd) + } +} + +impl AsFd for FileDesc { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +impl AsRawFd for FileDesc { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl IntoRawFd for FileDesc { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} + +impl FromRawFd for FileDesc { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) } + } +} diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 64f5a6b36d3db..403bfb2d9b929 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -27,6 +27,10 @@ cfg_select! { mod hermit; use hermit as imp; } + target_os = "motor" => { + mod motor; + use motor as imp; + } target_os = "solid_asp3" => { mod solid; use solid as imp; diff --git a/library/std/src/sys/fs/motor.rs b/library/std/src/sys/fs/motor.rs new file mode 100644 index 0000000000000..656b6e81b9518 --- /dev/null +++ b/library/std/src/sys/fs/motor.rs @@ -0,0 +1,478 @@ +use crate::ffi::OsString; +use crate::hash::Hash; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; +use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; +use crate::path::{Path, PathBuf}; +use crate::sys::fd::FileDesc; +pub use crate::sys::fs::common::exists; +use crate::sys::time::SystemTime; +use crate::sys::{map_motor_error, unsupported}; +use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct FileType { + rt_filetype: u8, +} + +impl FileType { + pub fn is_dir(&self) -> bool { + self.rt_filetype == moto_rt::fs::FILETYPE_DIRECTORY + } + + pub fn is_file(&self) -> bool { + self.rt_filetype == moto_rt::fs::FILETYPE_FILE + } + + pub fn is_symlink(&self) -> bool { + false + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct FilePermissions { + rt_perm: u64, +} + +impl FilePermissions { + pub fn readonly(&self) -> bool { + (self.rt_perm & moto_rt::fs::PERM_WRITE == 0) + && (self.rt_perm & moto_rt::fs::PERM_READ != 0) + } + + pub fn set_readonly(&mut self, readonly: bool) { + if readonly { + self.rt_perm = moto_rt::fs::PERM_READ; + } else { + self.rt_perm = moto_rt::fs::PERM_READ | moto_rt::fs::PERM_WRITE; + } + } +} + +#[derive(Copy, Clone, Debug, Default)] +pub struct FileTimes { + modified: u128, + accessed: u128, +} + +impl FileTimes { + pub fn set_accessed(&mut self, t: SystemTime) { + self.accessed = t.as_u128(); + } + + pub fn set_modified(&mut self, t: SystemTime) { + self.modified = t.as_u128(); + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct FileAttr { + inner: moto_rt::fs::FileAttr, +} + +impl FileAttr { + pub fn size(&self) -> u64 { + self.inner.size + } + + pub fn perm(&self) -> FilePermissions { + FilePermissions { rt_perm: self.inner.perm } + } + + pub fn file_type(&self) -> FileType { + FileType { rt_filetype: self.inner.file_type } + } + + pub fn modified(&self) -> io::Result { + match self.inner.modified { + 0 => Err(crate::io::Error::from(crate::io::ErrorKind::Other)), + x => Ok(SystemTime::from_u128(x)), + } + } + + pub fn accessed(&self) -> io::Result { + match self.inner.accessed { + 0 => Err(crate::io::Error::from(crate::io::ErrorKind::Other)), + x => Ok(SystemTime::from_u128(x)), + } + } + + pub fn created(&self) -> io::Result { + match self.inner.created { + 0 => Err(crate::io::Error::from(crate::io::ErrorKind::Other)), + x => Ok(SystemTime::from_u128(x)), + } + } +} + +#[derive(Clone, Debug)] +pub struct OpenOptions { + rt_open_options: u32, +} + +impl OpenOptions { + pub fn new() -> OpenOptions { + OpenOptions { rt_open_options: 0 } + } + + pub fn read(&mut self, read: bool) { + if read { + self.rt_open_options |= moto_rt::fs::O_READ; + } else { + self.rt_open_options &= !moto_rt::fs::O_READ; + } + } + + pub fn write(&mut self, write: bool) { + if write { + self.rt_open_options |= moto_rt::fs::O_WRITE; + } else { + self.rt_open_options &= !moto_rt::fs::O_WRITE; + } + } + + pub fn append(&mut self, append: bool) { + if append { + self.rt_open_options |= moto_rt::fs::O_APPEND; + } else { + self.rt_open_options &= !moto_rt::fs::O_APPEND; + } + } + + pub fn truncate(&mut self, truncate: bool) { + if truncate { + self.rt_open_options |= moto_rt::fs::O_TRUNCATE; + } else { + self.rt_open_options &= !moto_rt::fs::O_TRUNCATE; + } + } + + pub fn create(&mut self, create: bool) { + if create { + self.rt_open_options |= moto_rt::fs::O_CREATE; + } else { + self.rt_open_options &= !moto_rt::fs::O_CREATE; + } + } + + pub fn create_new(&mut self, create_new: bool) { + if create_new { + self.rt_open_options |= moto_rt::fs::O_CREATE_NEW; + } else { + self.rt_open_options &= !moto_rt::fs::O_CREATE_NEW; + } + } +} + +#[derive(Debug)] +pub struct File(FileDesc); + +impl File { + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { + let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; + moto_rt::fs::open(path, opts.rt_open_options) + .map(|fd| unsafe { Self::from_raw_fd(fd) }) + .map_err(map_motor_error) + } + + pub fn file_attr(&self) -> io::Result { + moto_rt::fs::get_file_attr(self.as_raw_fd()) + .map(|inner| -> FileAttr { FileAttr { inner } }) + .map_err(map_motor_error) + } + + pub fn fsync(&self) -> io::Result<()> { + moto_rt::fs::fsync(self.as_raw_fd()).map_err(map_motor_error) + } + + pub fn datasync(&self) -> io::Result<()> { + moto_rt::fs::datasync(self.as_raw_fd()).map_err(map_motor_error) + } + + pub fn truncate(&self, size: u64) -> io::Result<()> { + moto_rt::fs::truncate(self.as_raw_fd(), size).map_err(map_motor_error) + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + moto_rt::fs::read(self.as_raw_fd(), buf).map_err(map_motor_error) + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + crate::io::default_read_vectored(|b| self.read(b), bufs) + } + + pub fn is_read_vectored(&self) -> bool { + false + } + + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + crate::io::default_read_buf(|buf| self.read(buf), cursor) + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + moto_rt::fs::write(self.as_raw_fd(), buf).map_err(map_motor_error) + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + crate::io::default_write_vectored(|b| self.write(b), bufs) + } + + pub fn is_write_vectored(&self) -> bool { + false + } + + pub fn flush(&self) -> io::Result<()> { + moto_rt::fs::flush(self.as_raw_fd()).map_err(map_motor_error) + } + + pub fn seek(&self, pos: SeekFrom) -> io::Result { + match pos { + SeekFrom::Start(offset) => { + moto_rt::fs::seek(self.as_raw_fd(), offset as i64, moto_rt::fs::SEEK_SET) + .map_err(map_motor_error) + } + SeekFrom::End(offset) => { + moto_rt::fs::seek(self.as_raw_fd(), offset, moto_rt::fs::SEEK_END) + .map_err(map_motor_error) + } + SeekFrom::Current(offset) => { + moto_rt::fs::seek(self.as_raw_fd(), offset, moto_rt::fs::SEEK_CUR) + .map_err(map_motor_error) + } + } + } + + pub fn tell(&self) -> io::Result { + self.seek(SeekFrom::Current(0)) + } + + pub fn duplicate(&self) -> io::Result { + moto_rt::fs::duplicate(self.as_raw_fd()) + .map(|fd| unsafe { Self::from_raw_fd(fd) }) + .map_err(map_motor_error) + } + + pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { + moto_rt::fs::set_file_perm(self.as_raw_fd(), perm.rt_perm).map_err(map_motor_error) + } + + pub fn set_times(&self, _times: FileTimes) -> io::Result<()> { + unsupported() // Let's not do that. + } + + pub fn lock(&self) -> io::Result<()> { + unsupported() + } + + pub fn lock_shared(&self) -> io::Result<()> { + unsupported() + } + + pub fn try_lock(&self) -> Result<(), crate::fs::TryLockError> { + Err(crate::fs::TryLockError::Error(io::Error::from(io::ErrorKind::Unsupported))) + } + + pub fn try_lock_shared(&self) -> Result<(), crate::fs::TryLockError> { + Err(crate::fs::TryLockError::Error(io::Error::from(io::ErrorKind::Unsupported))) + } + + pub fn unlock(&self) -> io::Result<()> { + unsupported() + } + + pub fn size(&self) -> Option> { + None + } +} + +#[derive(Debug)] +pub struct DirBuilder {} + +impl DirBuilder { + pub fn new() -> DirBuilder { + DirBuilder {} + } + + pub fn mkdir(&self, path: &Path) -> io::Result<()> { + let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; + moto_rt::fs::mkdir(path).map_err(map_motor_error) + } +} + +pub fn unlink(path: &Path) -> io::Result<()> { + let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; + moto_rt::fs::unlink(path).map_err(map_motor_error) +} + +pub fn rename(old: &Path, new: &Path) -> io::Result<()> { + let old = old.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; + let new = new.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; + moto_rt::fs::rename(old, new).map_err(map_motor_error) +} + +pub fn rmdir(path: &Path) -> io::Result<()> { + let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; + moto_rt::fs::rmdir(path).map_err(map_motor_error) +} + +pub fn remove_dir_all(path: &Path) -> io::Result<()> { + let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; + moto_rt::fs::rmdir_all(path).map_err(map_motor_error) +} + +pub fn set_perm(path: &Path, perm: FilePermissions) -> io::Result<()> { + let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; + moto_rt::fs::set_perm(path, perm.rt_perm).map_err(map_motor_error) +} + +pub fn readlink(_p: &Path) -> io::Result { + unsupported() +} + +pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> { + unsupported() +} + +pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { + unsupported() +} + +pub fn stat(path: &Path) -> io::Result { + let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; + let inner = moto_rt::fs::stat(path).map_err(map_motor_error)?; + Ok(FileAttr { inner }) +} + +pub fn lstat(path: &Path) -> io::Result { + stat(path) +} + +pub fn canonicalize(path: &Path) -> io::Result { + let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; + let path = moto_rt::fs::canonicalize(path).map_err(map_motor_error)?; + Ok(path.into()) +} + +pub fn copy(from: &Path, to: &Path) -> io::Result { + let from = from.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; + let to = to.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; + moto_rt::fs::copy(from, to).map_err(map_motor_error) +} + +#[derive(Debug)] +pub struct ReadDir { + rt_fd: moto_rt::RtFd, + path: String, +} + +impl Drop for ReadDir { + fn drop(&mut self) { + moto_rt::fs::closedir(self.rt_fd).unwrap(); + } +} + +pub fn readdir(path: &Path) -> io::Result { + let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; + Ok(ReadDir { + rt_fd: moto_rt::fs::opendir(path).map_err(map_motor_error)?, + path: path.to_owned(), + }) +} + +impl Iterator for ReadDir { + type Item = io::Result; + + fn next(&mut self) -> Option> { + match moto_rt::fs::readdir(self.rt_fd).map_err(map_motor_error) { + Ok(maybe_item) => match maybe_item { + Some(inner) => Some(Ok(DirEntry { inner, parent_path: self.path.clone() })), + None => None, + }, + Err(err) => Some(Err(err)), + } + } +} + +pub struct DirEntry { + parent_path: String, + inner: moto_rt::fs::DirEntry, +} + +impl DirEntry { + fn filename(&self) -> &str { + core::str::from_utf8(unsafe { + core::slice::from_raw_parts(self.inner.fname.as_ptr(), self.inner.fname_size as usize) + }) + .unwrap() + } + + pub fn path(&self) -> PathBuf { + let mut path = self.parent_path.clone(); + path.push_str("/"); + path.push_str(self.filename()); + path.into() + } + + pub fn file_name(&self) -> OsString { + self.filename().to_owned().into() + } + + pub fn metadata(&self) -> io::Result { + Ok(FileAttr { inner: self.inner.attr }) + } + + pub fn file_type(&self) -> io::Result { + Ok(FileType { rt_filetype: self.inner.attr.file_type }) + } +} + +impl AsInner for File { + #[inline] + fn as_inner(&self) -> &FileDesc { + &self.0 + } +} + +impl AsInnerMut for File { + #[inline] + fn as_inner_mut(&mut self) -> &mut FileDesc { + &mut self.0 + } +} + +impl IntoInner for File { + fn into_inner(self) -> FileDesc { + self.0 + } +} + +impl FromInner for File { + fn from_inner(file_desc: FileDesc) -> Self { + Self(file_desc) + } +} + +impl AsFd for File { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +impl AsRawFd for File { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl IntoRawFd for File { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} + +impl FromRawFd for File { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) } + } +} diff --git a/library/std/src/sys/io/io_slice/motor.rs b/library/std/src/sys/io/io_slice/motor.rs new file mode 100644 index 0000000000000..aa15332e38f7a --- /dev/null +++ b/library/std/src/sys/io/io_slice/motor.rs @@ -0,0 +1,52 @@ +use crate::mem; + +#[derive(Copy, Clone)] +pub struct IoSlice<'a>(&'a [u8]); + +impl<'a> IoSlice<'a> { + #[inline] + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + IoSlice(buf) + } + + #[inline] + pub fn advance(&mut self, n: usize) { + self.0 = &self.0[n..] + } + + #[inline] + pub const fn as_slice(&self) -> &'a [u8] { + self.0 + } +} + +pub struct IoSliceMut<'a>(&'a mut [u8]); + +impl<'a> IoSliceMut<'a> { + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut(buf) + } + + #[inline] + pub fn advance(&mut self, n: usize) { + let slice = mem::replace(&mut self.0, &mut []); + let (_, remaining) = slice.split_at_mut(n); + self.0 = remaining; + } + + #[inline] + pub const fn into_slice(self) -> &'a mut [u8] { + self.0 + } + + #[inline] + pub const fn as_slice(&self) -> &[u8] { + self.0 + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + self.0 + } +} diff --git a/library/std/src/sys/io/is_terminal/motor.rs b/library/std/src/sys/io/is_terminal/motor.rs new file mode 100644 index 0000000000000..0b70299adaaa2 --- /dev/null +++ b/library/std/src/sys/io/is_terminal/motor.rs @@ -0,0 +1,6 @@ +use crate::os::fd::{AsFd, AsRawFd}; + +pub fn is_terminal(fd: &impl AsFd) -> bool { + let fd = fd.as_fd(); + moto_rt::fs::is_terminal(fd.as_raw_fd()) +} diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs index fe8ec1dbb7325..bc650e0905c9b 100644 --- a/library/std/src/sys/io/mod.rs +++ b/library/std/src/sys/io/mod.rs @@ -10,6 +10,10 @@ mod io_slice { mod windows; pub use windows::*; } + target_os = "motor" => { + mod motor; + pub use motor::*; + } target_os = "wasi" => { mod wasi; pub use wasi::*; @@ -39,6 +43,10 @@ mod is_terminal { mod hermit; pub use hermit::*; } + target_os = "motor" => { + mod motor; + pub use motor::*; + } _ => { mod unsupported; pub use unsupported::*; diff --git a/library/std/src/sys/net/connection/mod.rs b/library/std/src/sys/net/connection/mod.rs index 7f9636a8ccfd6..27049d7f6ed43 100644 --- a/library/std/src/sys/net/connection/mod.rs +++ b/library/std/src/sys/net/connection/mod.rs @@ -17,6 +17,10 @@ cfg_select! { mod wasip1; pub use wasip1::*; } + target_os = "motor" => { + mod motor; + pub use motor::*; + } target_os = "xous" => { mod xous; pub use xous::*; diff --git a/library/std/src/sys/net/connection/motor.rs b/library/std/src/sys/net/connection/motor.rs new file mode 100644 index 0000000000000..73b7a8eb2efe3 --- /dev/null +++ b/library/std/src/sys/net/connection/motor.rs @@ -0,0 +1,529 @@ +pub use moto_rt::netc; + +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; +use crate::net::SocketAddr::{V4, V6}; +use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs}; +use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; +use crate::sys::fd::FileDesc; +use crate::sys::map_motor_error; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::time::Duration; + +// We want to re-use as much of Rust's stdlib code as possible, +// and most of it is unixy, but with a lot of nesting. +#[derive(Debug)] +pub struct Socket(FileDesc); + +#[derive(Debug)] +pub struct TcpStream { + inner: Socket, +} + +impl TcpStream { + pub fn socket(&self) -> &Socket { + &self.inner + } + + pub fn into_socket(self) -> Socket { + self.inner + } + + pub fn connect(addr: A) -> io::Result { + let addr = into_netc(&addr.to_socket_addrs()?.next().unwrap()); + moto_rt::net::tcp_connect(&addr, Duration::MAX, false) + .map(|fd| Self { inner: unsafe { Socket::from_raw_fd(fd) } }) + .map_err(map_motor_error) + } + + pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result { + let addr = into_netc(addr); + moto_rt::net::tcp_connect(&addr, timeout, false) + .map(|fd| Self { inner: unsafe { Socket::from_raw_fd(fd) } }) + .map_err(map_motor_error) + } + + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + moto_rt::net::set_read_timeout(self.inner.as_raw_fd(), timeout).map_err(map_motor_error) + } + + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + moto_rt::net::set_write_timeout(self.inner.as_raw_fd(), timeout).map_err(map_motor_error) + } + + pub fn read_timeout(&self) -> io::Result> { + moto_rt::net::read_timeout(self.inner.as_raw_fd()).map_err(map_motor_error) + } + + pub fn write_timeout(&self) -> io::Result> { + moto_rt::net::write_timeout(self.inner.as_raw_fd()).map_err(map_motor_error) + } + + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + moto_rt::net::peek(self.inner.as_raw_fd(), buf).map_err(map_motor_error) + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + moto_rt::fs::read(self.inner.as_raw_fd(), buf).map_err(map_motor_error) + } + + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + crate::io::default_read_buf(|buf| self.read(buf), cursor) + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + let bufs: &mut [&mut [u8]] = unsafe { core::mem::transmute(bufs) }; + moto_rt::fs::read_vectored(self.inner.as_raw_fd(), bufs).map_err(map_motor_error) + } + + pub fn is_read_vectored(&self) -> bool { + true + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + moto_rt::fs::write(self.inner.as_raw_fd(), buf).map_err(map_motor_error) + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + let bufs: &[&[u8]] = unsafe { core::mem::transmute(bufs) }; + moto_rt::fs::write_vectored(self.inner.as_raw_fd(), bufs).map_err(map_motor_error) + } + + pub fn is_write_vectored(&self) -> bool { + true + } + + pub fn peer_addr(&self) -> io::Result { + moto_rt::net::peer_addr(self.inner.as_raw_fd()) + .map(|addr| from_netc(&addr)) + .map_err(map_motor_error) + } + + pub fn socket_addr(&self) -> io::Result { + moto_rt::net::socket_addr(self.inner.as_raw_fd()) + .map(|addr| from_netc(&addr)) + .map_err(map_motor_error) + } + + pub fn shutdown(&self, shutdown: Shutdown) -> io::Result<()> { + let shutdown = match shutdown { + Shutdown::Read => moto_rt::net::SHUTDOWN_READ, + Shutdown::Write => moto_rt::net::SHUTDOWN_WRITE, + Shutdown::Both => moto_rt::net::SHUTDOWN_READ | moto_rt::net::SHUTDOWN_WRITE, + }; + + moto_rt::net::shutdown(self.inner.as_raw_fd(), shutdown).map_err(map_motor_error) + } + + pub fn duplicate(&self) -> io::Result { + moto_rt::fs::duplicate(self.inner.as_raw_fd()) + .map(|fd| Self { inner: unsafe { Socket::from_raw_fd(fd) } }) + .map_err(map_motor_error) + } + + pub fn set_linger(&self, timeout: Option) -> io::Result<()> { + moto_rt::net::set_linger(self.inner.as_raw_fd(), timeout).map_err(map_motor_error) + } + + pub fn linger(&self) -> io::Result> { + moto_rt::net::linger(self.inner.as_raw_fd()).map_err(map_motor_error) + } + + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { + moto_rt::net::set_nodelay(self.inner.as_raw_fd(), nodelay).map_err(map_motor_error) + } + + pub fn nodelay(&self) -> io::Result { + moto_rt::net::nodelay(self.inner.as_raw_fd()).map_err(map_motor_error) + } + + pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { + moto_rt::net::set_ttl(self.inner.as_raw_fd(), ttl).map_err(map_motor_error) + } + + pub fn ttl(&self) -> io::Result { + moto_rt::net::ttl(self.inner.as_raw_fd()).map_err(map_motor_error) + } + + pub fn take_error(&self) -> io::Result> { + moto_rt::net::take_error(self.inner.as_raw_fd()) + .map(|e| match e { + moto_rt::E_OK => None, + e => Some(map_motor_error(e)), + }) + .map_err(map_motor_error) + } + + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + moto_rt::net::set_nonblocking(self.inner.as_raw_fd(), nonblocking).map_err(map_motor_error) + } +} + +#[derive(Debug)] +pub struct TcpListener { + inner: Socket, +} + +impl TcpListener { + #[inline] + pub fn socket(&self) -> &Socket { + &self.inner + } + + pub fn into_socket(self) -> Socket { + self.inner + } + + pub fn bind(addr: A) -> io::Result { + let addr = into_netc(&addr.to_socket_addrs()?.next().unwrap()); + moto_rt::net::bind(moto_rt::net::PROTO_TCP, &addr) + .map(|fd| Self { inner: unsafe { Socket::from_raw_fd(fd) } }) + .map_err(map_motor_error) + } + + pub fn socket_addr(&self) -> io::Result { + moto_rt::net::socket_addr(self.inner.as_raw_fd()) + .map(|addr| from_netc(&addr)) + .map_err(map_motor_error) + } + + pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { + moto_rt::net::accept(self.inner.as_raw_fd()) + .map(|(fd, addr)| { + (TcpStream { inner: unsafe { Socket::from_raw_fd(fd) } }, from_netc(&addr)) + }) + .map_err(map_motor_error) + } + + pub fn duplicate(&self) -> io::Result { + moto_rt::fs::duplicate(self.inner.as_raw_fd()) + .map(|fd| Self { inner: unsafe { Socket::from_raw_fd(fd) } }) + .map_err(map_motor_error) + } + + pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { + moto_rt::net::set_ttl(self.inner.as_raw_fd(), ttl).map_err(map_motor_error) + } + + pub fn ttl(&self) -> io::Result { + moto_rt::net::ttl(self.inner.as_raw_fd()).map_err(map_motor_error) + } + + pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { + moto_rt::net::set_only_v6(self.inner.as_raw_fd(), only_v6).map_err(map_motor_error) + } + + pub fn only_v6(&self) -> io::Result { + moto_rt::net::only_v6(self.inner.as_raw_fd()).map_err(map_motor_error) + } + + pub fn take_error(&self) -> io::Result> { + moto_rt::net::take_error(self.inner.as_raw_fd()) + .map(|e| match e { + moto_rt::E_OK => None, + e => Some(map_motor_error(e)), + }) + .map_err(map_motor_error) + } + + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + moto_rt::net::set_nonblocking(self.inner.as_raw_fd(), nonblocking).map_err(map_motor_error) + } +} + +#[derive(Debug)] +pub struct UdpSocket { + inner: Socket, +} + +impl UdpSocket { + pub fn socket(&self) -> &Socket { + &self.inner + } + + pub fn into_socket(self) -> Socket { + self.inner + } + + pub fn bind(addr: A) -> io::Result { + let addr = into_netc(&addr.to_socket_addrs()?.next().unwrap()); + moto_rt::net::bind(moto_rt::net::PROTO_UDP, &addr) + .map(|fd| Self { inner: unsafe { Socket::from_raw_fd(fd) } }) + .map_err(map_motor_error) + } + + pub fn peer_addr(&self) -> io::Result { + moto_rt::net::peer_addr(self.inner.as_raw_fd()) + .map(|addr| from_netc(&addr)) + .map_err(map_motor_error) + } + + pub fn socket_addr(&self) -> io::Result { + moto_rt::net::socket_addr(self.inner.as_raw_fd()) + .map(|addr| from_netc(&addr)) + .map_err(map_motor_error) + } + + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + moto_rt::net::udp_recv_from(self.inner.as_raw_fd(), buf) + .map(|(sz, addr)| (sz, from_netc(&addr))) + .map_err(map_motor_error) + } + + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + moto_rt::net::udp_peek_from(self.inner.as_raw_fd(), buf) + .map(|(sz, addr)| (sz, from_netc(&addr))) + .map_err(map_motor_error) + } + + pub fn send_to(&self, buf: &[u8], addr: &SocketAddr) -> io::Result { + let addr = into_netc(addr); + moto_rt::net::udp_send_to(self.inner.as_raw_fd(), buf, &addr).map_err(map_motor_error) + } + + pub fn duplicate(&self) -> io::Result { + moto_rt::fs::duplicate(self.inner.as_raw_fd()) + .map(|fd| Self { inner: unsafe { Socket::from_raw_fd(fd) } }) + .map_err(map_motor_error) + } + + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + moto_rt::net::set_read_timeout(self.inner.as_raw_fd(), timeout).map_err(map_motor_error) + } + + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + moto_rt::net::set_write_timeout(self.inner.as_raw_fd(), timeout).map_err(map_motor_error) + } + + pub fn read_timeout(&self) -> io::Result> { + moto_rt::net::read_timeout(self.inner.as_raw_fd()).map_err(map_motor_error) + } + + pub fn write_timeout(&self) -> io::Result> { + moto_rt::net::write_timeout(self.inner.as_raw_fd()).map_err(map_motor_error) + } + + pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { + moto_rt::net::set_udp_broadcast(self.inner.as_raw_fd(), broadcast).map_err(map_motor_error) + } + + pub fn broadcast(&self) -> io::Result { + moto_rt::net::udp_broadcast(self.inner.as_raw_fd()).map_err(map_motor_error) + } + + pub fn set_multicast_loop_v4(&self, val: bool) -> io::Result<()> { + moto_rt::net::set_udp_multicast_loop_v4(self.inner.as_raw_fd(), val) + .map_err(map_motor_error) + } + + pub fn multicast_loop_v4(&self) -> io::Result { + moto_rt::net::udp_multicast_loop_v4(self.inner.as_raw_fd()).map_err(map_motor_error) + } + + pub fn set_multicast_ttl_v4(&self, val: u32) -> io::Result<()> { + moto_rt::net::set_udp_multicast_ttl_v4(self.inner.as_raw_fd(), val).map_err(map_motor_error) + } + + pub fn multicast_ttl_v4(&self) -> io::Result { + moto_rt::net::udp_multicast_ttl_v4(self.inner.as_raw_fd()).map_err(map_motor_error) + } + + pub fn set_multicast_loop_v6(&self, val: bool) -> io::Result<()> { + moto_rt::net::set_udp_multicast_loop_v6(self.inner.as_raw_fd(), val) + .map_err(map_motor_error) + } + + pub fn multicast_loop_v6(&self) -> io::Result { + moto_rt::net::udp_multicast_loop_v6(self.inner.as_raw_fd()).map_err(map_motor_error) + } + + pub fn join_multicast_v4(&self, addr: &Ipv4Addr, iface: &Ipv4Addr) -> io::Result<()> { + let addr = (*addr).into(); + let iface = (*iface).into(); + moto_rt::net::join_udp_multicast_v4(self.inner.as_raw_fd(), &addr, &iface) + .map_err(map_motor_error) + } + + pub fn join_multicast_v6(&self, addr: &Ipv6Addr, iface: u32) -> io::Result<()> { + let addr = (*addr).into(); + moto_rt::net::join_udp_multicast_v6(self.inner.as_raw_fd(), &addr, iface) + .map_err(map_motor_error) + } + + pub fn leave_multicast_v4(&self, addr: &Ipv4Addr, iface: &Ipv4Addr) -> io::Result<()> { + let addr = (*addr).into(); + let iface = (*iface).into(); + moto_rt::net::leave_udp_multicast_v4(self.inner.as_raw_fd(), &addr, &iface) + .map_err(map_motor_error) + } + + pub fn leave_multicast_v6(&self, addr: &Ipv6Addr, iface: u32) -> io::Result<()> { + let addr = (*addr).into(); + moto_rt::net::leave_udp_multicast_v6(self.inner.as_raw_fd(), &addr, iface) + .map_err(map_motor_error) + } + + pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { + moto_rt::net::set_ttl(self.inner.as_raw_fd(), ttl).map_err(map_motor_error) + } + + pub fn ttl(&self) -> io::Result { + moto_rt::net::ttl(self.inner.as_raw_fd()).map_err(map_motor_error) + } + + pub fn take_error(&self) -> io::Result> { + moto_rt::net::take_error(self.inner.as_raw_fd()) + .map(|e| match e { + moto_rt::E_OK => None, + e => Some(map_motor_error(e)), + }) + .map_err(map_motor_error) + } + + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + moto_rt::net::set_nonblocking(self.inner.as_raw_fd(), nonblocking).map_err(map_motor_error) + } + + pub fn recv(&self, buf: &mut [u8]) -> io::Result { + moto_rt::fs::read(self.inner.as_raw_fd(), buf).map_err(map_motor_error) + } + + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + moto_rt::net::peek(self.inner.as_raw_fd(), buf).map_err(map_motor_error) + } + + pub fn send(&self, buf: &[u8]) -> io::Result { + moto_rt::fs::write(self.inner.as_raw_fd(), buf).map_err(map_motor_error) + } + + pub fn connect(&self, addr: A) -> io::Result<()> { + let addr = into_netc(&addr.to_socket_addrs()?.next().unwrap()); + moto_rt::net::udp_connect(self.inner.as_raw_fd(), &addr).map_err(map_motor_error) + } +} + +pub struct LookupHost { + addresses: alloc::collections::VecDeque, +} + +pub fn lookup_host(host: &str, port: u16) -> io::Result { + let (_port, addresses) = moto_rt::net::lookup_host(host, port).map_err(map_motor_error)?; + Ok(LookupHost { addresses }) +} + +impl Iterator for LookupHost { + type Item = SocketAddr; + fn next(&mut self) -> Option { + self.addresses.pop_front().map(|addr| from_netc(&addr)) + } +} + +impl TryFrom<&str> for LookupHost { + type Error = io::Error; + + fn try_from(host_port: &str) -> io::Result { + let (host, port_str) = host_port + .rsplit_once(':') + .ok_or(moto_rt::E_INVALID_ARGUMENT) + .map_err(map_motor_error)?; + let port: u16 = + port_str.parse().map_err(|_| moto_rt::E_INVALID_ARGUMENT).map_err(map_motor_error)?; + (host, port).try_into() + } +} + +impl<'a> TryFrom<(&'a str, u16)> for LookupHost { + type Error = io::Error; + + fn try_from(host_port: (&'a str, u16)) -> io::Result { + let (host, port) = host_port; + + let (_port, addresses) = moto_rt::net::lookup_host(host, port).map_err(map_motor_error)?; + Ok(LookupHost { addresses }) + } +} + +fn into_netc(addr: &SocketAddr) -> netc::sockaddr { + match addr { + V4(addr4) => netc::sockaddr { v4: (*addr4).into() }, + V6(addr6) => netc::sockaddr { v6: (*addr6).into() }, + } +} + +fn from_netc(addr: &netc::sockaddr) -> SocketAddr { + unsafe { + match addr.v4.sin_family { + netc::AF_INET => SocketAddr::V4(crate::net::SocketAddrV4::from(addr.v4)), + netc::AF_INET6 => SocketAddr::V6(crate::net::SocketAddrV6::from(addr.v6)), + _ => panic!("bad sin_family {}", addr.v4.sin_family), + } + } +} + +impl AsInner for Socket { + #[inline] + fn as_inner(&self) -> &FileDesc { + &self.0 + } +} + +impl IntoInner for Socket { + fn into_inner(self) -> FileDesc { + self.0 + } +} + +impl FromInner for Socket { + fn from_inner(file_desc: FileDesc) -> Self { + Self(file_desc) + } +} + +impl AsFd for Socket { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +impl AsRawFd for Socket { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl IntoRawFd for Socket { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} + +impl FromRawFd for Socket { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + Self(FromRawFd::from_raw_fd(raw_fd)) + } +} + +impl AsInner for TcpStream { + #[inline] + fn as_inner(&self) -> &Socket { + &self.inner + } +} + +impl FromInner for TcpStream { + fn from_inner(socket: Socket) -> TcpStream { + TcpStream { inner: socket } + } +} + +impl FromInner for TcpListener { + fn from_inner(socket: Socket) -> TcpListener { + TcpListener { inner: socket } + } +} + +impl FromInner for UdpSocket { + fn from_inner(socket: Socket) -> UdpSocket { + UdpSocket { inner: socket } + } +} diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index dd5e83ee570b6..7e2271f8de96b 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -41,6 +41,10 @@ cfg_select! { mod hermit; pub use self::hermit::*; } + target_os = "motor" => { + mod motor; + pub use self::motor::*; + } target_os = "trusty" => { mod trusty; pub use self::trusty::*; diff --git a/library/std/src/sys/pal/motor/mod.rs b/library/std/src/sys/pal/motor/mod.rs new file mode 100644 index 0000000000000..bc4da84e2aa84 --- /dev/null +++ b/library/std/src/sys/pal/motor/mod.rs @@ -0,0 +1,29 @@ +#![allow(unsafe_op_in_unsafe_fn)] + +pub mod os; +pub mod pipe; +pub mod time; + +pub use moto_rt::futex; + +#[path = "../unsupported/common.rs"] +mod common; +pub use common::*; + +#[cfg(not(test))] +#[unsafe(no_mangle)] +pub extern "C" fn motor_start() -> ! { + // Initialize the runtime. + moto_rt::start(); + + // Call main. + unsafe extern "C" { + fn main(_: isize, _: *const *const u8, _: u8) -> i32; + } + let result = unsafe { main(0, core::ptr::null(), 0) }; + + // Terminate the process. + moto_rt::process::exit(result) +} + +pub(crate) use crate::os::motor::map_motor_error; diff --git a/library/std/src/sys/pal/motor/os.rs b/library/std/src/sys/pal/motor/os.rs new file mode 100644 index 0000000000000..3946986f74ef1 --- /dev/null +++ b/library/std/src/sys/pal/motor/os.rs @@ -0,0 +1,91 @@ +use super::map_motor_error; +use crate::error::Error as StdError; +use crate::ffi::{OsStr, OsString}; +use crate::marker::PhantomData; +use crate::path::{self, PathBuf}; +use crate::{fmt, io}; + +pub fn errno() -> i32 { + // Not used in Motor OS. + -1 +} + +pub fn error_string(errno: i32) -> String { + format!("errno: {errno}") +} + +pub fn getcwd() -> io::Result { + // The CWD is a bad/outdated/unix design, from a single-threaded era: + // concurrent changes to CWD lead to races. Applications/processes + // should manage their CWD, not the OS. + moto_rt::fs::getcwd().map(|s| -> PathBuf { s.into() }).map_err(map_motor_error) +} + +pub fn chdir(path: &path::Path) -> io::Result<()> { + // The CWD is a bad/outdated/unix design, from a single-threaded era: + // concurrent changes to CWD lead to races. Applications/processes + // should manage their CWD, not the OS. + if let Some(path) = path.to_str() { + moto_rt::fs::chdir(path).map_err(map_motor_error) + } else { + Err(io::Error::new(io::ErrorKind::InvalidFilename, "")) + } +} + +pub struct SplitPaths<'a>(!, PhantomData<&'a ()>); + +pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { + panic!("unsupported") +} + +impl<'a> Iterator for SplitPaths<'a> { + type Item = PathBuf; + fn next(&mut self) -> Option { + self.0 + } +} + +#[derive(Debug)] +pub struct JoinPathsError; + +pub fn join_paths(_paths: I) -> Result +where + I: Iterator, + T: AsRef, +{ + Err(JoinPathsError) +} + +impl fmt::Display for JoinPathsError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "not supported on this platform yet".fmt(f) + } +} + +impl StdError for JoinPathsError { + #[allow(deprecated)] + fn description(&self) -> &str { + "not supported on this platform yet" + } +} + +pub fn current_exe() -> io::Result { + Ok(crate::sys::args::args().next().unwrap().into()) +} + +pub fn temp_dir() -> PathBuf { + PathBuf::from(moto_rt::fs::TEMP_DIR) +} + +pub fn home_dir() -> Option { + None +} + +pub fn exit(code: i32) -> ! { + moto_rt::process::exit(code) +} + +pub fn getpid() -> u32 { + // Our pids are u64. Why does Rust mandate u32??? + panic!("no pids on this platform") +} diff --git a/library/std/src/sys/pal/motor/pipe.rs b/library/std/src/sys/pal/motor/pipe.rs new file mode 100644 index 0000000000000..3236678c74bcb --- /dev/null +++ b/library/std/src/sys/pal/motor/pipe.rs @@ -0,0 +1,121 @@ +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; +use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +use crate::sys::fd::FileDesc; +use crate::sys::map_motor_error; +use crate::sys_common::{FromInner, IntoInner}; + +#[derive(Debug)] +pub struct AnonPipe(FileDesc); + +impl From for AnonPipe { + fn from(rt_fd: moto_rt::RtFd) -> AnonPipe { + unsafe { AnonPipe::from_raw_fd(rt_fd) } + } +} + +impl AnonPipe { + pub fn read(&self, buf: &mut [u8]) -> io::Result { + moto_rt::fs::read(self.as_raw_fd(), buf).map_err(map_motor_error) + } + + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + crate::io::default_read_buf(|buf| self.read(buf), cursor) + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + crate::io::default_read_vectored(|b| self.read(b), bufs) + } + + pub fn is_read_vectored(&self) -> bool { + false + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + moto_rt::fs::write(self.as_raw_fd(), buf).map_err(map_motor_error) + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + crate::io::default_write_vectored(|b| self.write(b), bufs) + } + + pub fn is_write_vectored(&self) -> bool { + false + } + + pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { + let mut temp_vec = alloc::vec::Vec::new(); + let mut size = 0_usize; + loop { + temp_vec.resize(256, 0_u8); + match self.read(&mut temp_vec[..]) { + Ok(sz) => { + if sz == 0 { + return Ok(size); + } + size += sz; + temp_vec.truncate(sz); + buf.append(&mut temp_vec); + } + Err(err) => { + if size != 0 { + return Ok(size); + } else { + return Err(err); + } + } + } + } + } +} + +impl AsRawFd for AnonPipe { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl FromRawFd for AnonPipe { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + let desc = FileDesc::from_raw_fd(fd); + Self(desc) + } +} + +impl IntoRawFd for AnonPipe { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} + +impl AsFd for AnonPipe { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +impl IntoInner for AnonPipe { + fn into_inner(self) -> OwnedFd { + self.0.into_inner() + } +} + +impl IntoInner for AnonPipe { + fn into_inner(self) -> FileDesc { + self.0 + } +} + +impl FromInner for AnonPipe { + fn from_inner(owned_fd: OwnedFd) -> Self { + Self(FileDesc::from_inner(owned_fd)) + } +} + +pub fn read2(_p1: AnonPipe, _v1: &mut Vec, _p2: AnonPipe, _v2: &mut Vec) -> io::Result<()> { + todo!() +} + +#[inline] +pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { + Err(io::Error::UNSUPPORTED_PLATFORM) +} diff --git a/library/std/src/sys/pal/motor/time.rs b/library/std/src/sys/pal/motor/time.rs new file mode 100644 index 0000000000000..e917fd466c2e4 --- /dev/null +++ b/library/std/src/sys/pal/motor/time.rs @@ -0,0 +1 @@ +pub use moto_rt::time::{Instant, SystemTime, UNIX_EPOCH}; diff --git a/library/std/src/sys/path/unix.rs b/library/std/src/sys/path/unix.rs index faa2616a6320d..15530323a198d 100644 --- a/library/std/src/sys/path/unix.rs +++ b/library/std/src/sys/path/unix.rs @@ -62,7 +62,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result { } pub(crate) fn is_absolute(path: &Path) -> bool { - if cfg!(any(unix, target_os = "hermit", target_os = "wasi")) { + if cfg!(any(unix, target_os = "hermit", target_os = "wasi", target_os = "motor")) { path.has_root() } else { path.has_root() && path.prefix().is_some() diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs index 158e44e1764a3..eabef92244d01 100644 --- a/library/std/src/sys/personality/mod.rs +++ b/library/std/src/sys/personality/mod.rs @@ -17,7 +17,7 @@ cfg_select! { target_os = "emscripten" => { mod emcc; } - any(target_env = "msvc", target_family = "wasm") => { + any(target_env = "msvc", target_family = "wasm", target_os = "motor") => { // This is required by the compiler to exist (e.g., it's a lang item), // but it's never actually called by the compiler because // __CxxFrameHandler3 (msvc) / __gxx_wasm_personality_v0 (wasm) is the diff --git a/library/std/src/sys/process/mod.rs b/library/std/src/sys/process/mod.rs index a1ed0cd2cdd2d..92e459298fc4c 100644 --- a/library/std/src/sys/process/mod.rs +++ b/library/std/src/sys/process/mod.rs @@ -11,6 +11,10 @@ cfg_select! { mod uefi; use uefi as imp; } + target_os = "motor" => { + mod motor; + use motor as imp; + } _ => { mod unsupported; use unsupported as imp; @@ -38,6 +42,7 @@ pub use imp::{ )) ), target_os = "windows", + target_os = "motor" ))] pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec, Vec)> { use crate::sys::pipe::read2; @@ -77,5 +82,6 @@ pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec, Vec< )) ), target_os = "windows", + target_os = "motor" )))] pub use imp::output; diff --git a/library/std/src/sys/process/motor.rs b/library/std/src/sys/process/motor.rs new file mode 100644 index 0000000000000..b4a5433a6a3cc --- /dev/null +++ b/library/std/src/sys/process/motor.rs @@ -0,0 +1,322 @@ +use super::CommandEnvs; +use super::env::CommandEnv; +use crate::ffi::OsStr; +pub use crate::ffi::OsString as EnvKey; +use crate::num::NonZeroI32; +use crate::os::fd::{FromRawFd, IntoRawFd}; +use crate::path::Path; +use crate::process::StdioPipes; +use crate::sys::fs::File; +use crate::sys::map_motor_error; +use crate::sys::pipe::AnonPipe; +use crate::sys_common::{AsInner, FromInner}; +use crate::{fmt, io}; + +pub enum Stdio { + Inherit, + Null, + MakePipe, + Fd(crate::sys::fd::FileDesc), +} + +impl Stdio { + fn into_rt(self) -> moto_rt::RtFd { + match self { + Stdio::Inherit => moto_rt::process::STDIO_INHERIT, + Stdio::Null => moto_rt::process::STDIO_NULL, + Stdio::MakePipe => moto_rt::process::STDIO_MAKE_PIPE, + Stdio::Fd(fd) => fd.into_raw_fd(), + } + } + + fn try_clone(&self) -> io::Result { + match self { + Self::Fd(fd) => { + Ok(Self::Fd(crate::sys::fd::FileDesc::from_inner(fd.as_inner().try_clone()?))) + } + Self::Inherit => Ok(Self::Inherit), + Self::Null => Ok(Self::Null), + Self::MakePipe => Ok(Self::MakePipe), + } + } +} + +#[derive(Default)] +pub struct Command { + program: String, + args: Vec, + cwd: Option, + stdin: Option, + stdout: Option, + stderr: Option, + env: CommandEnv, +} + +impl Command { + pub fn new(program: &OsStr) -> Command { + let mut env = CommandEnv::default(); + let mut vars = Vec::<(EnvKey, EnvKey)>::new(); + for (k, v) in env.capture() { + if k.clone().into_string().unwrap() != moto_rt::process::STDIO_IS_TERMINAL_ENV_KEY { + vars.push((k, v)); + } + } + + for (k, v) in vars { + env.set(&k, &v); + } + + Command { program: program.to_str().unwrap().to_owned(), env, ..Default::default() } + } + + pub fn arg(&mut self, arg: &OsStr) { + self.args.push(arg.to_str().unwrap().to_owned()) + } + + pub fn env_mut(&mut self) -> &mut CommandEnv { + &mut self.env + } + + pub fn cwd(&mut self, dir: &OsStr) { + self.cwd = Some(dir.to_str().unwrap().to_owned()) + } + + pub fn stdin(&mut self, stdin: Stdio) { + self.stdin = Some(stdin); + } + + pub fn stdout(&mut self, stdout: Stdio) { + self.stdout = Some(stdout); + } + + pub fn stderr(&mut self, stderr: Stdio) { + self.stderr = Some(stderr); + } + + pub fn get_program(&self) -> &OsStr { + OsStr::new(self.program.as_str()) + } + + pub fn get_args(&self) -> CommandArgs<'_> { + let iter = self.args.iter(); + CommandArgs { iter } + } + + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.env.iter() + } + + pub fn get_current_dir(&self) -> Option<&Path> { + self.cwd.as_ref().map(Path::new) + } + + pub fn spawn( + &mut self, + default: Stdio, + needs_stdin: bool, + ) -> io::Result<(Process, StdioPipes)> { + let stdin = if let Some(stdin) = self.stdin.as_ref() { + stdin.try_clone()?.into_rt() + } else if needs_stdin { + default.try_clone()?.into_rt() + } else { + Stdio::Null.into_rt() + }; + let stdout = if let Some(stdout) = self.stdout.as_ref() { + stdout.try_clone()?.into_rt() + } else { + default.try_clone()?.into_rt() + }; + let stderr = if let Some(stderr) = self.stdout.as_ref() { + stderr.try_clone()?.into_rt() + } else { + default.try_clone()?.into_rt() + }; + + let mut env = Vec::<(String, String)>::new(); + for (k, v) in self.env.iter() { + let val = if let Some(v) = v { v.to_str().unwrap() } else { "" }; + env.push((k.to_str().unwrap().to_owned(), val.to_owned())); + } + + let args = moto_rt::process::SpawnArgs { + program: self.program.clone(), + args: self.args.clone(), + env, + cwd: self.cwd.clone(), + stdin, + stdout, + stderr, + }; + + let (handle, stdin, stdout, stderr) = + moto_rt::process::spawn(args).map_err(map_motor_error)?; + + Ok(( + Process { handle }, + StdioPipes { + stdin: if stdin >= 0 { Some(stdin.into()) } else { None }, + stdout: if stdout >= 0 { Some(stdout.into()) } else { None }, + stderr: if stderr >= 0 { Some(stderr.into()) } else { None }, + }, + )) + } +} + +impl From for Stdio { + fn from(pipe: AnonPipe) -> Stdio { + unsafe { Stdio::Fd(crate::sys::fd::FileDesc::from_raw_fd(pipe.into_raw_fd())) } + } +} + +impl From for Stdio { + fn from(fd: crate::sys::fd::FileDesc) -> Stdio { + Stdio::Fd(fd) + } +} + +impl From for Stdio { + fn from(_file: File) -> Stdio { + todo!() + } +} + +impl From for Stdio { + fn from(_: io::Stdout) -> Stdio { + todo!() + } +} + +impl From for Stdio { + fn from(_: io::Stderr) -> Stdio { + todo!() + } +} + +impl fmt::Debug for Command { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + Ok(()) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)] +pub struct ExitStatus(i32); + +impl ExitStatus { + pub fn exit_ok(&self) -> Result<(), ExitStatusError> { + if self.0 == 0 { Ok(()) } else { Err(ExitStatusError(*self)) } + } + + pub fn code(&self) -> Option { + Some(self.0) + } +} + +impl fmt::Display for ExitStatus { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "exit code: {}", self.0) + } +} +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitStatusError(ExitStatus); + +impl Into for ExitStatusError { + fn into(self) -> ExitStatus { + self.0 + } +} + +impl ExitStatusError { + pub fn code(self) -> Option { + NonZeroI32::new(self.0.0) + } +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitCode(i32); + +impl ExitCode { + pub const SUCCESS: ExitCode = ExitCode(0); + pub const FAILURE: ExitCode = ExitCode(1); + + pub fn as_i32(&self) -> i32 { + self.0 + } +} + +impl From for ExitCode { + fn from(code: u8) -> Self { + Self(code as i32) + } +} + +pub struct Process { + handle: u64, +} + +impl Drop for Process { + fn drop(&mut self) { + moto_rt::alloc::release_handle(self.handle).unwrap(); + } +} + +impl Process { + pub fn id(&self) -> u32 { + 0 + } + + pub fn kill(&mut self) -> io::Result<()> { + match moto_rt::process::kill(self.handle) { + moto_rt::E_OK => Ok(()), + err => Err(map_motor_error(err)), + } + } + + pub fn wait(&mut self) -> io::Result { + moto_rt::process::wait(self.handle).map(|c| ExitStatus(c)).map_err(map_motor_error) + } + + pub fn try_wait(&mut self) -> io::Result> { + match moto_rt::process::try_wait(self.handle) { + Ok(s) => Ok(Some(ExitStatus(s))), + Err(err) => match err { + moto_rt::E_NOT_READY => Ok(None), + err => Err(map_motor_error(err)), + }, + } + } + + #[allow(unused)] + pub fn handle(&self) -> u64 { + self.handle + } +} + +pub struct CommandArgs<'a> { + iter: crate::slice::Iter<'a, String>, +} + +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + self.iter.next().map(|arg| OsStr::new(arg)) + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a> ExactSizeIterator for CommandArgs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +impl<'a> fmt::Debug for CommandArgs<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter.clone()).finish() + } +} diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index 3c5a4c82a9f1e..26395eaca49f4 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -62,6 +62,10 @@ cfg_select! { mod redox; pub use redox::fill_bytes; } + target_os = "motor" => { + mod motor; + pub use motor::fill_bytes; + } all(target_vendor = "fortanix", target_env = "sgx") => { mod sgx; pub use sgx::fill_bytes; diff --git a/library/std/src/sys/random/motor.rs b/library/std/src/sys/random/motor.rs new file mode 100644 index 0000000000000..386b3704a91ea --- /dev/null +++ b/library/std/src/sys/random/motor.rs @@ -0,0 +1,3 @@ +pub fn fill_bytes(bytes: &mut [u8]) { + moto_rt::fill_random_bytes(bytes) +} diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs index 404ac87792696..02c2ab23eae3a 100644 --- a/library/std/src/sys/stdio/mod.rs +++ b/library/std/src/sys/stdio/mod.rs @@ -13,6 +13,10 @@ cfg_select! { mod sgx; pub use sgx::*; } + target_os = "motor" => { + mod motor; + pub use motor::*; + } target_os = "solid_asp3" => { mod solid; pub use solid::*; diff --git a/library/std/src/sys/stdio/motor.rs b/library/std/src/sys/stdio/motor.rs new file mode 100644 index 0000000000000..0a44feab723d0 --- /dev/null +++ b/library/std/src/sys/stdio/motor.rs @@ -0,0 +1,232 @@ +use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +use crate::sys::map_motor_error; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::{io, process, sys}; + +pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; + +pub struct Stdin {} + +impl Stdin { + pub const fn new() -> Self { + Self {} + } +} + +pub struct Stdout {} + +impl Stdout { + pub const fn new() -> Self { + Self {} + } +} + +pub struct Stderr {} + +impl Stderr { + pub const fn new() -> Self { + Self {} + } +} + +impl crate::sealed::Sealed for Stdin {} + +impl crate::io::IsTerminal for Stdin { + fn is_terminal(&self) -> bool { + moto_rt::fs::is_terminal(moto_rt::FD_STDIN) + } +} + +impl io::Read for Stdin { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + moto_rt::fs::read(moto_rt::FD_STDIN, buf).map_err(map_motor_error) + } +} + +impl io::Write for Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result { + moto_rt::fs::write(moto_rt::FD_STDOUT, buf).map_err(map_motor_error) + } + + fn flush(&mut self) -> io::Result<()> { + moto_rt::fs::flush(moto_rt::FD_STDOUT).map_err(map_motor_error) + } +} + +impl io::Write for Stderr { + fn write(&mut self, buf: &[u8]) -> io::Result { + moto_rt::fs::write(moto_rt::FD_STDERR, buf).map_err(map_motor_error) + } + + fn flush(&mut self) -> io::Result<()> { + moto_rt::fs::flush(moto_rt::FD_STDERR).map_err(map_motor_error) + } +} + +pub fn panic_output() -> Option { + Some(Stderr::new()) +} + +pub fn is_ebadf(_err: &io::Error) -> bool { + true +} + +#[stable(feature = "process_extensions", since = "1.2.0")] +impl FromRawFd for process::Stdio { + #[inline] + unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio { + let fd = unsafe { sys::fd::FileDesc::from_raw_fd(fd) }; + let io = sys::process::Stdio::Fd(fd); + process::Stdio::from_inner(io) + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl From for process::Stdio { + /// Takes ownership of a file descriptor and returns a [`Stdio`](process::Stdio) + /// that can attach a stream to it. + #[inline] + fn from(fd: OwnedFd) -> process::Stdio { + let fd = sys::fd::FileDesc::from_inner(fd); + let io = sys::process::Stdio::Fd(fd); + process::Stdio::from_inner(io) + } +} + +#[stable(feature = "process_extensions", since = "1.2.0")] +impl AsRawFd for process::ChildStdin { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.as_inner().as_raw_fd() + } +} + +#[stable(feature = "process_extensions", since = "1.2.0")] +impl AsRawFd for process::ChildStdout { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.as_inner().as_raw_fd() + } +} + +#[stable(feature = "process_extensions", since = "1.2.0")] +impl AsRawFd for process::ChildStderr { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.as_inner().as_raw_fd() + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for process::ChildStdin { + #[inline] + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_raw_fd() + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for process::ChildStdout { + #[inline] + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_raw_fd() + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for process::ChildStderr { + #[inline] + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_raw_fd() + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsFd for crate::process::ChildStdin { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().as_fd() + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl From for OwnedFd { + /// Takes ownership of a [`ChildStdin`](crate::process::ChildStdin)'s file descriptor. + #[inline] + fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd { + child_stdin.into_inner().into_inner() + } +} + +/// Creates a `ChildStdin` from the provided `OwnedFd`. +/// +/// The provided file descriptor must point to a pipe +/// with the `CLOEXEC` flag set. +#[stable(feature = "child_stream_from_fd", since = "1.74.0")] +impl From for process::ChildStdin { + #[inline] + fn from(fd: OwnedFd) -> process::ChildStdin { + let pipe = sys::pipe::AnonPipe::from_inner(fd); + process::ChildStdin::from_inner(pipe) + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsFd for crate::process::ChildStdout { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().as_fd() + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl From for OwnedFd { + /// Takes ownership of a [`ChildStdout`](crate::process::ChildStdout)'s file descriptor. + #[inline] + fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd { + child_stdout.into_inner().into_inner() + } +} + +/// Creates a `ChildStdout` from the provided `OwnedFd`. +/// +/// The provided file descriptor must point to a pipe +/// with the `CLOEXEC` flag set. +#[stable(feature = "child_stream_from_fd", since = "1.74.0")] +impl From for process::ChildStdout { + #[inline] + fn from(fd: OwnedFd) -> process::ChildStdout { + let pipe = sys::pipe::AnonPipe::from_inner(fd); + process::ChildStdout::from_inner(pipe) + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsFd for crate::process::ChildStderr { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().as_fd() + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl From for OwnedFd { + /// Takes ownership of a [`ChildStderr`](crate::process::ChildStderr)'s file descriptor. + #[inline] + fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd { + child_stderr.into_inner().into_inner() + } +} + +/// Creates a `ChildStderr` from the provided `OwnedFd`. +/// +/// The provided file descriptor must point to a pipe +/// with the `CLOEXEC` flag set. +#[stable(feature = "child_stream_from_fd", since = "1.74.0")] +impl From for process::ChildStderr { + #[inline] + fn from(fd: OwnedFd) -> process::ChildStderr { + let pipe = sys::pipe::AnonPipe::from_inner(fd); + process::ChildStderr::from_inner(pipe) + } +} diff --git a/library/std/src/sys/sync/condvar/mod.rs b/library/std/src/sys/sync/condvar/mod.rs index cb67d273759dd..83cf0ae629851 100644 --- a/library/std/src/sys/sync/condvar/mod.rs +++ b/library/std/src/sys/sync/condvar/mod.rs @@ -6,6 +6,7 @@ cfg_select! { target_os = "freebsd", target_os = "openbsd", target_os = "dragonfly", + target_os = "motor", target_os = "fuchsia", all(target_family = "wasm", target_feature = "atomics"), target_os = "hermit", diff --git a/library/std/src/sys/sync/mutex/mod.rs b/library/std/src/sys/sync/mutex/mod.rs index c885b0eabae2d..e3d6ad1129c83 100644 --- a/library/std/src/sys/sync/mutex/mod.rs +++ b/library/std/src/sys/sync/mutex/mod.rs @@ -5,6 +5,7 @@ cfg_select! { target_os = "android", target_os = "freebsd", target_os = "openbsd", + target_os = "motor", target_os = "dragonfly", all(target_family = "wasm", target_feature = "atomics"), target_os = "hermit", diff --git a/library/std/src/sys/sync/once/mod.rs b/library/std/src/sys/sync/once/mod.rs index 8adeb1f259d72..aeea884b9f617 100644 --- a/library/std/src/sys/sync/once/mod.rs +++ b/library/std/src/sys/sync/once/mod.rs @@ -14,6 +14,7 @@ cfg_select! { target_os = "android", all(target_arch = "wasm32", target_feature = "atomics"), target_os = "freebsd", + target_os = "motor", target_os = "openbsd", target_os = "dragonfly", target_os = "fuchsia", diff --git a/library/std/src/sys/sync/rwlock/mod.rs b/library/std/src/sys/sync/rwlock/mod.rs index 82f1dd18dee49..ab5715bf2de33 100644 --- a/library/std/src/sys/sync/rwlock/mod.rs +++ b/library/std/src/sys/sync/rwlock/mod.rs @@ -9,6 +9,7 @@ cfg_select! { target_os = "fuchsia", all(target_family = "wasm", target_feature = "atomics"), target_os = "hermit", + target_os = "motor", ) => { mod futex; pub use futex::RwLock; diff --git a/library/std/src/sys/sync/thread_parking/mod.rs b/library/std/src/sys/sync/thread_parking/mod.rs index b9fb27b4eef2d..e8a9dc884f816 100644 --- a/library/std/src/sys/sync/thread_parking/mod.rs +++ b/library/std/src/sys/sync/thread_parking/mod.rs @@ -8,6 +8,7 @@ cfg_select! { target_os = "openbsd", target_os = "dragonfly", target_os = "fuchsia", + target_os = "motor", target_os = "hermit", ) => { mod futex; diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs index 3bd83dd760ac9..add38a7fcb14d 100644 --- a/library/std/src/sys/thread/mod.rs +++ b/library/std/src/sys/thread/mod.rs @@ -6,6 +6,10 @@ cfg_select! { mod unsupported; pub use unsupported::{current_os_id, set_name}; } + target_os = "motor" => { + mod motor; + pub use motor::*; + } all(target_vendor = "fortanix", target_env = "sgx") => { mod sgx; pub use sgx::{Thread, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; diff --git a/library/std/src/sys/thread/motor.rs b/library/std/src/sys/thread/motor.rs new file mode 100644 index 0000000000000..022f3561bd220 --- /dev/null +++ b/library/std/src/sys/thread/motor.rs @@ -0,0 +1,63 @@ +use crate::ffi::CStr; +use crate::io; +use crate::num::NonZeroUsize; +use crate::sys::map_motor_error; +use crate::time::Duration; + +pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 256; + +pub struct Thread { + sys_thread: moto_rt::thread::ThreadHandle, +} + +unsafe impl Send for Thread {} +unsafe impl Sync for Thread {} + +impl Thread { + pub unsafe fn new( + stack: usize, + _name: Option<&str>, + p: Box, + ) -> io::Result { + extern "C" fn __moto_rt_thread_fn(thread_arg: u64) { + unsafe { + Box::from_raw( + core::ptr::with_exposed_provenance::>(thread_arg as usize) + .cast_mut(), + )(); + } + } + + let thread_arg = Box::into_raw(Box::new(p)) as *mut _ as usize as u64; + let sys_thread = moto_rt::thread::spawn(__moto_rt_thread_fn, stack, thread_arg) + .map_err(map_motor_error)?; + Ok(Self { sys_thread }) + } + + pub fn join(self) { + assert!(moto_rt::thread::join(self.sys_thread) == moto_rt::E_OK) + } +} + +pub fn set_name(name: &CStr) { + let bytes = name.to_bytes(); + if let Ok(s) = core::str::from_utf8(bytes) { + let _ = moto_rt::thread::set_name(s); + } +} + +pub fn current_os_id() -> Option { + None +} + +pub fn available_parallelism() -> io::Result { + Ok(unsafe { NonZeroUsize::new_unchecked(moto_rt::num_cpus()) }) +} + +pub fn yield_now() { + moto_rt::thread::yield_now() +} + +pub fn sleep(dur: Duration) { + moto_rt::thread::sleep_until(moto_rt::time::Instant::now() + dur) +} diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index d5c795093cf04..f172c7a2ecd69 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -187,6 +187,14 @@ pub(crate) mod key { pub(super) use xous::{Key, get, set}; use xous::{create, destroy}; } + target_os = "motor" => { + mod racy; + #[cfg(test)] + mod tests; + pub(super) use racy::LazyKey; + pub(super) use moto_rt::tls::{Key, get, set}; + use moto_rt::tls::{create, destroy}; + } _ => {} } }