-
Notifications
You must be signed in to change notification settings - Fork 13.8k
std: Add Motor OS std library port #147000
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
These commits modify the If this was unintentional then you should revert the changes before this PR is merged. The list of allowed third-party dependencies may have been modified! You must ensure that any new dependencies have compatible licenses before merging. |
Is there any notable std functionality that isn't supported on this platform? Just skimming it, it seems like things are pretty complete (threads, systemtime, process, etc) Nominating for libs as this adds a new std target. @rustbot label +I-libs-nominated |
I believe all major pieces are supported/implemented, including networking. Some specific things are not (yet) fully implemented, like FS links, or DNS lookup (at the moment, only "localhost" resolves to an IP address). On the other hand, tokio is ported via a mio port, which was not completely trivial... |
#[unstable(feature = "motor_ext", issue = "none")] | ||
pub fn map_motor_error(err: moto_rt::ErrorCode) -> crate::io::Error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably doesn't need to be crate public?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a Rust program calls into moto-sys (the Motor OS kernel API) or moto-rt (the Motor OS runtime API), they get moto_rt::ErrorCode
. To convert it into io::Error (e.g. for Tokio) they need access to a similar function. So either the function should be exported here as pub
, or duplicated elsewhere, from where std can't import (due to io::Error being in std). If io::Error is moved to core (which I've seen being discussed), I'll move this function to moto-rt.
I prefer to avoid code duplication and just export it here. If it is better to duplicate it elsewhere, I can do that also, let me know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what you could do here is define the RawOsError
type as moto_rt::ErrorCode
(copy how we do this for UEFI) and override fn decode_error_kind
. That way io::Error
is actually just a a moto_rt::ErrorCode
, and io::Error::from_raw_os_error
can be used rather than needing this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what you could do here is define the
RawOsError
type asmoto_rt::ErrorCode
(copy how we do this for UEFI) and overridefn decode_error_kind
. That wayio::Error
is actually just a amoto_rt::ErrorCode
, andio::Error::from_raw_os_error
can be used rather than needing this function.
Oh, that's a nice trick! I've had a vague desire to use a proper Error enum in public Motor OS API (which is in Rust), and to use a plain ErrorCode/u16 only in internal ABI (which uses C/Linux calling conventions, as Rust doesn't define an ABI).
So I'm going to spend the next several days refactoring the whole Motor OS codebase around a new enum Error (repr u16, most likely).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what you could do here is define the
RawOsError
type asmoto_rt::ErrorCode
(copy how we do this for UEFI) and overridefn decode_error_kind
. That wayio::Error
is actually just a amoto_rt::ErrorCode
, andio::Error::from_raw_os_error
can be used rather than needing this function.Oh, that's a nice trick! I've had a vague desire to use a proper Error enum in public Motor OS API (which is in Rust), and to use a plain ErrorCode/u16 only in internal ABI (which uses C/Linux calling conventions, as Rust doesn't define an ABI).
So I'm going to spend the next several days refactoring the whole Motor OS codebase around a new enum Error (repr u16, most likely).
Bummer... Spent the weekend to make Motor OS API (moto-rt, moto-sys) return an enum Error instead of a u16, only to find out that Rust library assumes it is an integer of no more than 32 bits. Will just use u16 then - this is a fight for another day...
} | ||
|
||
pub fn current_exe() -> io::Result<PathBuf> { | ||
Ok(crate::sys::args::args().next().unwrap().into()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you run say ls foo
on Motor OS, is the first argument ls
(like on Unix and Windows) or /path/to/ls
? If the former, this is not a correct implementation. std::env::current_exe()
is supposed to return an absolute path to the executable file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In many modern systems, even unices, there is often no global "absolute path", as programs run in their own jails/containers/whatever. Also just by looking at how other platforms deal with it, it is all over the place:
- aix just "infers" the location if args[0] is not an absolute path (which is buggy and thus worse, I'd say);
- openbsd does the same thing as Motor OS, only additionally calls
canonicalize()
if args[0] starts with a dot or contains a slash; if not, args[0] is returned unmodified; - same for vxworks.
So I'd say Motor OS is not unique here. I can add a call to canonicalize()
, if you insist, but I don't think it will make things better: I'd rather have an unmodified args[0] rather than have it massaged in some cases and not in others.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the loose expectation here is that you could pass the result of std::env::current_exe()
to another process, which may possibly be launched in another directory, and launch the same binary. If there is a best effort change to make this work then I think it's worthwhile (unless I'm misunderstanding things here)
☔ The latest upstream changes (presumably #147019) made this pull request unmergeable. Please resolve the merge conflicts. |
As part of work to add stdlib support for Motor OS.
e2e23a1
to
f3884e2
Compare
This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
Motor OS was added as a no-std Tier-3 target in rust-lang#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.
f3884e2
to
d8da6c0
Compare
We discussed this in the @rust-lang/libs meeting and are happy to add std support for this target because it supports all major functionality of std. |
Thanks, Amanieu! @tgross35 Trevor, how can I improve this PR to make it mergeable? |
It's on my list, I just haven't had a chance to do a thorough review yet (probably later this week) |
#[unstable(feature = "motor_ext", issue = "none")] | ||
pub fn map_motor_error(err: moto_rt::ErrorCode) -> crate::io::Error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what you could do here is define the RawOsError
type as moto_rt::ErrorCode
(copy how we do this for UEFI) and override fn decode_error_kind
. That way io::Error
is actually just a a moto_rt::ErrorCode
, and io::Error::from_raw_os_error
can be used rather than needing this function.
#[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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following up from #147000 (comment): just make a library tracking issue (there's a library tracking template) and paste these API in them. We can then go through the stabilization process to make them usable on MotorOS with stable rustc, once we eventually have build-std usable on stable.
It's an imperfect system for the tier 3 targets currently given the build-std situation, but at least this will point interested parties somewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The stable
attributes here should technically be unstable(feature = "motor_ext")
like the others. Doesn't matter too much for T3 targets though so maybe this is fine (asked on Zulip)
target_os = "motor" => { | ||
mod motor; | ||
pub use motor::*; | ||
} | ||
target_os = "wasi" => { | ||
mod wasi; | ||
pub use wasi::*; | ||
} | ||
target_os = "uefi" => { | ||
mod uefi; | ||
pub use uefi::*; | ||
} | ||
_ => { | ||
mod unsupported; | ||
pub use unsupported::*; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can Motor just use the mod unsupported;
fallback here? io_slice/motor.rs
looks the same.
pub fn error_string(errno: i32) -> String { | ||
format!("errno: {errno}") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you do the RawOsError
bit I mentioned, then s/i32/RawOsError
.
Is there a way to go from moto_rt::ErrorCode
to a name like E_ALREADY_IN_USE
or a descriptive string? If so, that could be returned here.
} | ||
|
||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { | ||
let mut temp_vec = alloc::vec::Vec::new(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Already in scope
let mut temp_vec = alloc::vec::Vec::new(); | |
let mut temp_vec = Vec::new(); |
pub fn read2(_p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> { | ||
todo!() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably either unsupported()
or a panic!()
rather than an empty todo!()
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); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Save a clone & collect
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); | |
} | |
for (k, v) in env.capture() { | |
if k == moto_rt::process::STDIO_IS_TERMINAL_ENV_KEY { | |
continue; | |
} | |
env.set(k, v); | |
} |
impl From<File> for Stdio { | ||
fn from(_file: File) -> Stdio { | ||
todo!() | ||
} | ||
} | ||
|
||
impl From<io::Stdout> for Stdio { | ||
fn from(_: io::Stdout) -> Stdio { | ||
todo!() | ||
} | ||
} | ||
|
||
impl From<io::Stderr> for Stdio { | ||
fn from(_: io::Stderr) -> Stdio { | ||
todo!() | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use panic!(...)
or unsupported!(...)
rather than todo!(...)
(TODO is usually for things to do before merge by tidy's convention)
let val = if let Some(v) = v { v.to_str().unwrap() } else { "" }; | ||
env.push((k.to_str().unwrap().to_owned(), val.to_owned())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can use as_str()
rather than to_str().unwrap()
Motor OS was added as a no-std Tier-3 target in
PR 146848 as x86_64-unknown-motor.
This PR adds the std library for Motor OS.
While the PR may seem large, all it does is proxy
std pal calls to moto-rt. Where there is some non-trivial
code (e.g. thread::spawn), it is quite similar, often
identical, to what other platforms do.