Skip to content

Commit af0a071

Browse files
committed
Auto merge of #37936 - tedsta:fuchsia_std_process, r=alexcrichton
Fuchsia support for std::process via liblaunchpad. Now we can launch processes on Fuchsia via the Rust standard library! ... Mostly. Right now, ~5% of the time, reading the stdout/stderr off the pipes will fail. Some Magenta kernel people think it's probably a bug in Magenta's pipes. I wrote a unit test that demonstrates the issue in C, which I was told will expedite a fix. https://fuchsia-review.googlesource.com/#/c/15628/ Hopefully this can get merged once the issue is fixed :) @raphlinus
2 parents 1077149 + e1b752b commit af0a071

File tree

8 files changed

+689
-238
lines changed

8 files changed

+689
-238
lines changed

src/libstd/build.rs

+2
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ fn main() {
6060
println!("cargo:rustc-link-lib=shell32");
6161
} else if target.contains("fuchsia") {
6262
println!("cargo:rustc-link-lib=magenta");
63+
println!("cargo:rustc-link-lib=mxio");
64+
println!("cargo:rustc-link-lib=launchpad"); // for std::process
6365
}
6466
}
6567

src/libstd/sys/unix/fd.rs

+2
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ impl FileDesc {
110110
#[cfg(not(any(target_env = "newlib",
111111
target_os = "solaris",
112112
target_os = "emscripten",
113+
target_os = "fuchsia",
113114
target_os = "haiku")))]
114115
pub fn set_cloexec(&self) -> io::Result<()> {
115116
unsafe {
@@ -120,6 +121,7 @@ impl FileDesc {
120121
#[cfg(any(target_env = "newlib",
121122
target_os = "solaris",
122123
target_os = "emscripten",
124+
target_os = "fuchsia",
123125
target_os = "haiku"))]
124126
pub fn set_cloexec(&self) -> io::Result<()> {
125127
unsafe {

src/libstd/sys/unix/pipe.rs

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ pub fn read2(p1: AnonPipe,
7777
v1: &mut Vec<u8>,
7878
p2: AnonPipe,
7979
v2: &mut Vec<u8>) -> io::Result<()> {
80+
8081
// Set both pipes into nonblocking mode as we're gonna be reading from both
8182
// in the `select` loop below, and we wouldn't want one to block the other!
8283
let p1 = p1.into_fd();
+191
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(non_camel_case_types)]
12+
13+
use convert::TryInto;
14+
use io;
15+
use os::raw::c_char;
16+
use u64;
17+
18+
use libc::{c_int, c_void};
19+
20+
pub type mx_handle_t = i32;
21+
pub type mx_vaddr_t = usize;
22+
pub type mx_rights_t = u32;
23+
pub type mx_status_t = i32;
24+
25+
pub type mx_size_t = usize;
26+
pub type mx_ssize_t = isize;
27+
28+
pub const MX_HANDLE_INVALID: mx_handle_t = 0;
29+
30+
pub type mx_time_t = u64;
31+
pub const MX_TIME_INFINITE : mx_time_t = u64::MAX;
32+
33+
pub type mx_signals_t = u32;
34+
35+
pub const MX_OBJECT_SIGNAL_3 : mx_signals_t = 1 << 3;
36+
37+
pub const MX_TASK_TERMINATED : mx_signals_t = MX_OBJECT_SIGNAL_3;
38+
39+
pub const MX_RIGHT_SAME_RIGHTS : mx_rights_t = 1 << 31;
40+
41+
pub type mx_object_info_topic_t = u32;
42+
43+
pub const MX_INFO_PROCESS : mx_object_info_topic_t = 3;
44+
45+
pub const MX_HND_TYPE_JOB: u32 = 6;
46+
47+
pub fn mx_cvt<T>(t: T) -> io::Result<T> where T: TryInto<mx_status_t>+Copy {
48+
if let Ok(status) = TryInto::try_into(t) {
49+
if status < 0 {
50+
Err(io::Error::from_raw_os_error(status))
51+
} else {
52+
Ok(t)
53+
}
54+
} else {
55+
Err(io::Error::last_os_error())
56+
}
57+
}
58+
59+
// Safe wrapper around mx_handle_t
60+
pub struct Handle {
61+
raw: mx_handle_t,
62+
}
63+
64+
impl Handle {
65+
pub fn new(raw: mx_handle_t) -> Handle {
66+
Handle {
67+
raw: raw,
68+
}
69+
}
70+
71+
pub fn raw(&self) -> mx_handle_t {
72+
self.raw
73+
}
74+
}
75+
76+
impl Drop for Handle {
77+
fn drop(&mut self) {
78+
unsafe { mx_cvt(mx_handle_close(self.raw)).expect("Failed to close mx_handle_t"); }
79+
}
80+
}
81+
82+
// Common MX_INFO header
83+
#[derive(Default)]
84+
#[repr(C)]
85+
pub struct mx_info_header_t {
86+
pub topic: u32, // identifies the info struct
87+
pub avail_topic_size: u16, // “native” size of the struct
88+
pub topic_size: u16, // size of the returned struct (<=topic_size)
89+
pub avail_count: u32, // number of records the kernel has
90+
pub count: u32, // number of records returned (limited by buffer size)
91+
}
92+
93+
#[derive(Default)]
94+
#[repr(C)]
95+
pub struct mx_record_process_t {
96+
pub return_code: c_int,
97+
}
98+
99+
// Returned for topic MX_INFO_PROCESS
100+
#[derive(Default)]
101+
#[repr(C)]
102+
pub struct mx_info_process_t {
103+
pub hdr: mx_info_header_t,
104+
pub rec: mx_record_process_t,
105+
}
106+
107+
extern {
108+
pub fn mx_task_kill(handle: mx_handle_t) -> mx_status_t;
109+
110+
pub fn mx_handle_close(handle: mx_handle_t) -> mx_status_t;
111+
112+
pub fn mx_handle_duplicate(handle: mx_handle_t, rights: mx_rights_t,
113+
out: *const mx_handle_t) -> mx_handle_t;
114+
115+
pub fn mx_handle_wait_one(handle: mx_handle_t, signals: mx_signals_t, timeout: mx_time_t,
116+
pending: *mut mx_signals_t) -> mx_status_t;
117+
118+
pub fn mx_object_get_info(handle: mx_handle_t, topic: u32, buffer: *mut c_void,
119+
buffer_size: mx_size_t, actual_size: *mut mx_size_t,
120+
avail: *mut mx_size_t) -> mx_status_t;
121+
}
122+
123+
// Handle Info entries associate a type and optional
124+
// argument with each handle included in the process
125+
// arguments message.
126+
pub fn mx_hnd_info(hnd_type: u32, arg: u32) -> u32 {
127+
(hnd_type & 0xFFFF) | ((arg & 0xFFFF) << 16)
128+
}
129+
130+
extern {
131+
pub fn mxio_get_startup_handle(id: u32) -> mx_handle_t;
132+
}
133+
134+
// From `enum special_handles` in system/ulib/launchpad/launchpad.c
135+
#[allow(unused)] pub const HND_LOADER_SVC: usize = 0;
136+
// HND_EXEC_VMO = 1
137+
#[allow(unused)] pub const HND_SPECIAL_COUNT: usize = 2;
138+
139+
#[repr(C)]
140+
pub struct launchpad_t {
141+
argc: u32,
142+
envc: u32,
143+
args: *const c_char,
144+
args_len: usize,
145+
env: *const c_char,
146+
env_len: usize,
147+
148+
handles: *mut mx_handle_t,
149+
handles_info: *mut u32,
150+
handle_count: usize,
151+
handle_alloc: usize,
152+
153+
entry: mx_vaddr_t,
154+
base: mx_vaddr_t,
155+
vdso_base: mx_vaddr_t,
156+
157+
stack_size: usize,
158+
159+
special_handles: [mx_handle_t; HND_SPECIAL_COUNT],
160+
loader_message: bool,
161+
}
162+
163+
extern {
164+
pub fn launchpad_create(job: mx_handle_t, name: *const c_char,
165+
lp: *mut *mut launchpad_t) -> mx_status_t;
166+
167+
pub fn launchpad_start(lp: *mut launchpad_t) -> mx_status_t;
168+
169+
pub fn launchpad_destroy(lp: *mut launchpad_t);
170+
171+
pub fn launchpad_arguments(lp: *mut launchpad_t, argc: c_int,
172+
argv: *const *const c_char) -> mx_status_t;
173+
174+
pub fn launchpad_environ(lp: *mut launchpad_t, envp: *const *const c_char) -> mx_status_t;
175+
176+
pub fn launchpad_clone_mxio_root(lp: *mut launchpad_t) -> mx_status_t;
177+
178+
pub fn launchpad_clone_mxio_cwd(lp: *mut launchpad_t) -> mx_status_t;
179+
180+
pub fn launchpad_clone_fd(lp: *mut launchpad_t, fd: c_int, target_fd: c_int) -> mx_status_t;
181+
182+
pub fn launchpad_transfer_fd(lp: *mut launchpad_t, fd: c_int, target_fd: c_int) -> mx_status_t;
183+
184+
pub fn launchpad_elf_load(lp: *mut launchpad_t, vmo: mx_handle_t) -> mx_status_t;
185+
186+
pub fn launchpad_add_vdso_vmo(lp: *mut launchpad_t) -> mx_status_t;
187+
188+
pub fn launchpad_load_vdso(lp: *mut launchpad_t, vmo: mx_handle_t) -> mx_status_t;
189+
190+
pub fn launchpad_vmo_from_file(filename: *const c_char) -> mx_handle_t;
191+
}

src/libstd/sys/unix/process/mod.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
pub use self::process_common::{Command, ExitStatus, Stdio, StdioPipes};
12+
pub use self::process_inner::Process;
13+
14+
mod process_common;
15+
#[cfg(not(target_os = "fuchsia"))]
16+
#[path = "process_unix.rs"]
17+
mod process_inner;
18+
#[cfg(target_os = "fuchsia")]
19+
#[path = "process_fuchsia.rs"]
20+
mod process_inner;
21+
#[cfg(target_os = "fuchsia")]
22+
mod magenta;

0 commit comments

Comments
 (0)