-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Update Fuchsia support for std::process. #39277
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,8 +41,6 @@ pub type mx_object_info_topic_t = u32; | |
|
||
pub const MX_INFO_PROCESS : mx_object_info_topic_t = 3; | ||
|
||
pub const MX_HND_TYPE_JOB: u32 = 6; | ||
|
||
pub fn mx_cvt<T>(t: T) -> io::Result<T> where T: TryInto<mx_status_t>+Copy { | ||
if let Ok(status) = TryInto::try_into(t) { | ||
if status < 0 { | ||
|
@@ -104,6 +102,8 @@ pub struct mx_info_process_t { | |
} | ||
|
||
extern { | ||
static __magenta_job_default: mx_handle_t; | ||
|
||
pub fn mx_task_kill(handle: mx_handle_t) -> mx_status_t; | ||
|
||
pub fn mx_handle_close(handle: mx_handle_t) -> mx_status_t; | ||
|
@@ -119,21 +119,14 @@ extern { | |
avail: *mut mx_size_t) -> mx_status_t; | ||
} | ||
|
||
// Handle Info entries associate a type and optional | ||
// argument with each handle included in the process | ||
// arguments message. | ||
pub fn mx_hnd_info(hnd_type: u32, arg: u32) -> u32 { | ||
(hnd_type & 0xFFFF) | ((arg & 0xFFFF) << 16) | ||
} | ||
|
||
extern { | ||
pub fn mxio_get_startup_handle(id: u32) -> mx_handle_t; | ||
pub fn mx_job_default() -> mx_handle_t { | ||
unsafe { return __magenta_job_default; } | ||
} | ||
|
||
// From `enum special_handles` in system/ulib/launchpad/launchpad.c | ||
#[allow(unused)] pub const HND_LOADER_SVC: usize = 0; | ||
// HND_LOADER_SVC = 0 | ||
// HND_EXEC_VMO = 1 | ||
#[allow(unused)] pub const HND_SPECIAL_COUNT: usize = 2; | ||
pub const HND_SPECIAL_COUNT: usize = 2; | ||
|
||
#[repr(C)] | ||
pub struct launchpad_t { | ||
|
@@ -188,3 +181,124 @@ extern { | |
|
||
pub fn launchpad_vmo_from_file(filename: *const c_char) -> mx_handle_t; | ||
} | ||
|
||
// Errors | ||
|
||
#[allow(unused)] pub const ERR_INTERNAL: mx_status_t = -1; | ||
|
||
// ERR_NOT_SUPPORTED: The operation is not implemented, supported, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This and all the following comments that document these constants should use the triple slash |
||
// or enabled. | ||
#[allow(unused)] pub const ERR_NOT_SUPPORTED: mx_status_t = -2; | ||
|
||
// ERR_NO_RESOURCES: The system was not able to allocate some resource | ||
// needed for the operation. | ||
#[allow(unused)] pub const ERR_NO_RESOURCES: mx_status_t = -5; | ||
|
||
// ERR_NO_MEMORY: The system was not able to allocate memory needed | ||
// for the operation. | ||
#[allow(unused)] pub const ERR_NO_MEMORY: mx_status_t = -4; | ||
|
||
// ERR_CALL_FAILED: The second phase of mx_channel_call(; did not complete | ||
// successfully. | ||
#[allow(unused)] pub const ERR_CALL_FAILED: mx_status_t = -53; | ||
|
||
// ======= Parameter errors ======= | ||
// ERR_INVALID_ARGS: an argument is invalid, ex. null pointer | ||
#[allow(unused)] pub const ERR_INVALID_ARGS: mx_status_t = -10; | ||
|
||
// ERR_WRONG_TYPE: The subject of the operation is the wrong type to | ||
// perform the operation. | ||
// Example: Attempting a message_read on a thread handle. | ||
#[allow(unused)] pub const ERR_WRONG_TYPE: mx_status_t = -54; | ||
|
||
// ERR_BAD_SYSCALL: The specified syscall number is invalid. | ||
#[allow(unused)] pub const ERR_BAD_SYSCALL: mx_status_t = -11; | ||
|
||
// ERR_BAD_HANDLE: A specified handle value does not refer to a handle. | ||
#[allow(unused)] pub const ERR_BAD_HANDLE: mx_status_t = -12; | ||
|
||
// ERR_OUT_OF_RANGE: An argument is outside the valid range for this | ||
// operation. | ||
#[allow(unused)] pub const ERR_OUT_OF_RANGE: mx_status_t = -13; | ||
|
||
// ERR_BUFFER_TOO_SMALL: A caller provided buffer is too small for | ||
// this operation. | ||
#[allow(unused)] pub const ERR_BUFFER_TOO_SMALL: mx_status_t = -14; | ||
|
||
// ======= Precondition or state errors ======= | ||
// ERR_BAD_STATE: operation failed because the current state of the | ||
// object does not allow it, or a precondition of the operation is | ||
// not satisfied | ||
#[allow(unused)] pub const ERR_BAD_STATE: mx_status_t = -20; | ||
|
||
// ERR_NOT_FOUND: The requested entity is not found. | ||
#[allow(unused)] pub const ERR_NOT_FOUND: mx_status_t = -3; | ||
|
||
// ERR_ALREADY_EXISTS: An object with the specified identifier | ||
// already exists. | ||
// Example: Attempting to create a file when a file already exists | ||
// with that name. | ||
#[allow(unused)] pub const ERR_ALREADY_EXISTS: mx_status_t = -15; | ||
|
||
// ERR_ALREADY_BOUND: The operation failed because the named entity | ||
// is already owned or controlled by another entity. The operation | ||
// could succeed later if the current owner releases the entity. | ||
#[allow(unused)] pub const ERR_ALREADY_BOUND: mx_status_t = -16; | ||
|
||
// ERR_TIMED_OUT: The time limit for the operation elapsed before | ||
// the operation completed. | ||
#[allow(unused)] pub const ERR_TIMED_OUT: mx_status_t = -23; | ||
|
||
// ERR_HANDLE_CLOSED: a handle being waited on was closed | ||
#[allow(unused)] pub const ERR_HANDLE_CLOSED: mx_status_t = -24; | ||
|
||
// ERR_REMOTE_CLOSED: The operation failed because the remote end | ||
// of the subject of the operation was closed. | ||
#[allow(unused)] pub const ERR_REMOTE_CLOSED: mx_status_t = -25; | ||
|
||
// ERR_UNAVAILABLE: The subject of the operation is currently unable | ||
// to perform the operation. | ||
// Note: This is used when there's no direct way for the caller to | ||
// observe when the subject will be able to perform the operation | ||
// and should thus retry. | ||
#[allow(unused)] pub const ERR_UNAVAILABLE: mx_status_t = -26; | ||
|
||
// ERR_SHOULD_WAIT: The operation cannot be performed currently but | ||
// potentially could succeed if the caller waits for a prerequisite | ||
// to be satisfied, for example waiting for a handle to be readable | ||
// or writable. | ||
// Example: Attempting to read from a message pipe that has no | ||
// messages waiting but has an open remote will return ERR_SHOULD_WAIT. | ||
// Attempting to read from a message pipe that has no messages waiting | ||
// and has a closed remote end will return ERR_REMOTE_CLOSED. | ||
#[allow(unused)] pub const ERR_SHOULD_WAIT: mx_status_t = -27; | ||
|
||
// ======= Permission check errors ======= | ||
// ERR_ACCESS_DENIED: The caller did not have permission to perform | ||
// the specified operation. | ||
#[allow(unused)] pub const ERR_ACCESS_DENIED: mx_status_t = -30; | ||
|
||
// ======= Input-output errors ======= | ||
// ERR_IO: Otherwise unspecified error occurred during I/O. | ||
#[allow(unused)] pub const ERR_IO: mx_status_t = -40; | ||
|
||
// ERR_REFUSED: The entity the I/O operation is being performed on | ||
// rejected the operation. | ||
// Example: an I2C device NAK'ing a transaction or a disk controller | ||
// rejecting an invalid command. | ||
#[allow(unused)] pub const ERR_IO_REFUSED: mx_status_t = -41; | ||
|
||
// ERR_IO_DATA_INTEGRITY: The data in the operation failed an integrity | ||
// check and is possibly corrupted. | ||
// Example: CRC or Parity error. | ||
#[allow(unused)] pub const ERR_IO_DATA_INTEGRITY: mx_status_t = -42; | ||
|
||
// ERR_IO_DATA_LOSS: The data in the operation is currently unavailable | ||
// and may be permanently lost. | ||
// Example: A disk block is irrecoverably damaged. | ||
#[allow(unused)] pub const ERR_IO_DATA_LOSS: mx_status_t = -43; | ||
|
||
// Filesystem specific errors | ||
#[allow(unused)] pub const ERR_BAD_PATH: mx_status_t = -50; | ||
#[allow(unused)] pub const ERR_NOT_DIR: mx_status_t = -51; | ||
#[allow(unused)] pub const ERR_NOT_FILE: mx_status_t = -52; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,7 +54,7 @@ impl Command { | |
-> io::Result<(*mut launchpad_t, mx_handle_t)> { | ||
use sys::process::magenta::*; | ||
|
||
let job_handle = mxio_get_startup_handle(mx_hnd_info(MX_HND_TYPE_JOB, 0)); | ||
let job_handle = mx_job_default(); | ||
let envp = match *self.get_envp() { | ||
Some(ref envp) => envp.as_ptr(), | ||
None => ptr::null(), | ||
|
@@ -66,14 +66,14 @@ impl Command { | |
fn drop(&mut self) { unsafe { launchpad_destroy(self.0); } } | ||
} | ||
|
||
let mut launchpad: *mut launchpad_t = ptr::null_mut(); | ||
let launchpad_destructor = LaunchpadDestructor(launchpad); | ||
|
||
// Duplicate the job handle | ||
let mut job_copy: mx_handle_t = MX_HANDLE_INVALID; | ||
mx_cvt(mx_handle_duplicate(job_handle, MX_RIGHT_SAME_RIGHTS, &mut job_copy))?; | ||
// Create a launchpad | ||
let mut launchpad: *mut launchpad_t = ptr::null_mut(); | ||
mx_cvt(launchpad_create(job_copy, self.get_argv()[0], &mut launchpad))?; | ||
let launchpad_destructor = LaunchpadDestructor(launchpad); | ||
|
||
// Set the process argv | ||
mx_cvt(launchpad_arguments(launchpad, self.get_argv().len() as i32 - 1, | ||
self.get_argv().as_ptr()))?; | ||
|
@@ -88,19 +88,19 @@ impl Command { | |
|
||
// Clone stdin, stdout, and stderr | ||
if let Some(fd) = stdio.stdin.fd() { | ||
launchpad_transfer_fd(launchpad, fd, 0); | ||
mx_cvt(launchpad_transfer_fd(launchpad, fd, 0))?; | ||
} else { | ||
launchpad_clone_fd(launchpad, 0, 0); | ||
mx_cvt(launchpad_clone_fd(launchpad, 0, 0))?; | ||
} | ||
if let Some(fd) = stdio.stdout.fd() { | ||
launchpad_transfer_fd(launchpad, fd, 1); | ||
mx_cvt(launchpad_transfer_fd(launchpad, fd, 1))?; | ||
} else { | ||
launchpad_clone_fd(launchpad, 1, 1); | ||
mx_cvt(launchpad_clone_fd(launchpad, 1, 1))?; | ||
} | ||
if let Some(fd) = stdio.stderr.fd() { | ||
launchpad_transfer_fd(launchpad, fd, 2); | ||
mx_cvt(launchpad_transfer_fd(launchpad, fd, 2))?; | ||
} else { | ||
launchpad_clone_fd(launchpad, 2, 2); | ||
mx_cvt(launchpad_clone_fd(launchpad, 2, 2))?; | ||
} | ||
|
||
// We don't want FileDesc::drop to be called on any stdio. It would close their fds. The | ||
|
@@ -164,6 +164,36 @@ impl Process { | |
} | ||
Ok(ExitStatus::new(proc_info.rec.return_code)) | ||
} | ||
|
||
pub fn try_wait(&mut self) -> io::Result<ExitStatus> { | ||
use default::Default; | ||
use sys::process::magenta::*; | ||
|
||
let mut proc_info: mx_info_process_t = Default::default(); | ||
let mut actual: mx_size_t = 0; | ||
let mut avail: mx_size_t = 0; | ||
|
||
unsafe { | ||
let status = mx_handle_wait_one(self.handle.raw(), MX_TASK_TERMINATED, | ||
0, ptr::null_mut()); | ||
match status { | ||
0 => { }, // Success | ||
x if x == ERR_TIMED_OUT => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe you can use constants directly as patterns, so this arm could be written as just |
||
return Err(io::Error::from(io::ErrorKind::WouldBlock)); | ||
}, | ||
_ => { panic!("Failed to wait on process handle: {}", status); }, | ||
} | ||
mx_cvt(mx_object_get_info(self.handle.raw(), MX_INFO_PROCESS, | ||
&mut proc_info as *mut _ as *mut libc::c_void, | ||
mem::size_of::<mx_info_process_t>(), &mut actual, | ||
&mut avail))?; | ||
} | ||
if actual != 1 { | ||
return Err(io::Error::new(io::ErrorKind::InvalidData, | ||
"Failed to get exit status of process")); | ||
} | ||
Ok(ExitStatus::new(proc_info.rec.return_code)) | ||
} | ||
} | ||
|
||
impl Drop for Process { | ||
|
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.
Nit: Just use
unsafe { __magenta_job_default }
. Idiomatic Rust only usesreturn
for early returns.