about summary refs log tree commit diff
path: root/src/libstd/sys/vxworks/process
diff options
context:
space:
mode:
authorBaoshan Pang <baoshan.pang@windriver.com>2019-07-15 23:57:53 -0700
committerBaoshan Pang <baoshan.pang@windriver.com>2019-07-16 00:13:07 -0700
commit4c0c0f6158b464ee5070b32bb37f2863d0eff012 (patch)
tree3306eadf9f3bb9023cfca1fc16b44e18132916e9 /src/libstd/sys/vxworks/process
parent4a95e9704de0eeaecba55df102c1129e79a3a929 (diff)
downloadrust-4c0c0f6158b464ee5070b32bb37f2863d0eff012.tar.gz
rust-4c0c0f6158b464ee5070b32bb37f2863d0eff012.zip
Add supporting for vxWorks
r? @alexcrichton
Diffstat (limited to 'src/libstd/sys/vxworks/process')
-rw-r--r--src/libstd/sys/vxworks/process/mod.rs7
-rw-r--r--src/libstd/sys/vxworks/process/process_common.rs503
-rw-r--r--src/libstd/sys/vxworks/process/process_vxworks.rs167
-rw-r--r--src/libstd/sys/vxworks/process/rtp.rs298
4 files changed, 975 insertions, 0 deletions
diff --git a/src/libstd/sys/vxworks/process/mod.rs b/src/libstd/sys/vxworks/process/mod.rs
new file mode 100644
index 00000000000..4dc706006f4
--- /dev/null
+++ b/src/libstd/sys/vxworks/process/mod.rs
@@ -0,0 +1,7 @@
+pub use self::process_common::{Command, ExitStatus, ExitCode, Stdio, StdioPipes};
+pub use self::process_inner::Process;
+
+mod process_common;
+#[path = "process_vxworks.rs"]
+mod process_inner;
+mod rtp;
diff --git a/src/libstd/sys/vxworks/process/process_common.rs b/src/libstd/sys/vxworks/process/process_common.rs
new file mode 100644
index 00000000000..db4e80c216c
--- /dev/null
+++ b/src/libstd/sys/vxworks/process/process_common.rs
@@ -0,0 +1,503 @@
+use crate::os::unix::prelude::*;
+
+use crate::ffi::{OsString, OsStr, CString, CStr};
+use crate::fmt;
+use crate::io;
+use crate::ptr;
+use crate::sys::fd::FileDesc;
+use crate::sys::fs::{File, OpenOptions};
+use crate::sys::pipe::{self, AnonPipe};
+use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
+use crate::collections::BTreeMap;
+
+use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+    // Currently we try hard to ensure that the call to `.exec()` doesn't
+    // actually allocate any memory. While many platforms try to ensure that
+    // memory allocation works after a fork in a multithreaded process, it's
+    // been observed to be buggy and somewhat unreliable, so we do our best to
+    // just not do it at all!
+    //
+    // Along those lines, the `argv` and `envp` raw pointers here are exactly
+    // what's gonna get passed to `execvp`. The `argv` array starts with the
+    // `program` and ends with a NULL, and the `envp` pointer, if present, is
+    // also null-terminated.
+    //
+    // Right now we don't support removing arguments, so there's no much fancy
+    // support there, but we support adding and removing environment variables,
+    // so a side table is used to track where in the `envp` array each key is
+    // located. Whenever we add a key we update it in place if it's already
+    // present, and whenever we remove a key we update the locations of all
+    // other keys.
+    program: CString,
+    args: Vec<CString>,
+    argv: Argv,
+    env: CommandEnv<DefaultEnvKey>,
+
+    cwd: Option<CString>,
+    uid: Option<uid_t>,
+    gid: Option<gid_t>,
+    saw_nul: bool,
+    closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
+    stdin: Option<Stdio>,
+    stdout: Option<Stdio>,
+    stderr: Option<Stdio>,
+}
+
+// Create a new type for argv, so that we can make it `Send`
+struct Argv(Vec<*const c_char>);
+
+// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args`
+unsafe impl Send for Argv {}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+    pub stdin: Option<AnonPipe>,
+    pub stdout: Option<AnonPipe>,
+    pub stderr: Option<AnonPipe>,
+}
+
+// passed to do_exec() with configuration of what the child stdio should look
+// like
+pub struct ChildPipes {
+    pub stdin: ChildStdio,
+    pub stdout: ChildStdio,
+    pub stderr: ChildStdio,
+}
+
+pub enum ChildStdio {
+    Inherit,
+    Explicit(c_int),
+    Owned(FileDesc),
+}
+
+pub enum Stdio {
+    Inherit,
+    Null,
+    MakePipe,
+    Fd(FileDesc),
+}
+
+impl Command {
+    pub fn new(program: &OsStr) -> Command {
+        let mut saw_nul = false;
+        let program = os2c(program, &mut saw_nul);
+        Command {
+            argv: Argv(vec![program.as_ptr(), ptr::null()]),
+            program,
+            args: Vec::new(),
+            env: Default::default(),
+            cwd: None,
+            uid: None,
+            gid: None,
+            saw_nul,
+            closures: Vec::new(),
+            stdin: None,
+            stdout: None,
+            stderr: None,
+        }
+    }
+
+    pub fn arg(&mut self, arg: &OsStr) {
+        // Overwrite the trailing NULL pointer in `argv` and then add a new null
+        // pointer.
+        let arg = os2c(arg, &mut self.saw_nul);
+        self.argv.0[self.args.len() + 1] = arg.as_ptr();
+        self.argv.0.push(ptr::null());
+
+        // Also make sure we keep track of the owned value to schedule a
+        // destructor for this memory.
+        self.args.push(arg);
+    }
+
+    pub fn cwd(&mut self, dir: &OsStr) {
+        self.cwd = Some(os2c(dir, &mut self.saw_nul));
+    }
+    pub fn uid(&mut self, id: uid_t) {
+        self.uid = Some(id);
+    }
+    pub fn gid(&mut self, id: gid_t) {
+        self.gid = Some(id);
+    }
+
+    pub fn saw_nul(&self) -> bool {
+        self.saw_nul
+    }
+    pub fn get_argv(&self) -> &Vec<*const c_char> {
+        &self.argv.0
+    }
+
+    #[allow(dead_code)]
+    pub fn get_cwd(&self) -> &Option<CString> {
+        &self.cwd
+    }
+    #[allow(dead_code)]
+    pub fn get_uid(&self) -> Option<uid_t> {
+        self.uid
+    }
+    #[allow(dead_code)]
+    pub fn get_gid(&self) -> Option<gid_t> {
+        self.gid
+    }
+
+    pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
+        &mut self.closures
+    }
+
+    pub unsafe fn pre_exec(
+        &mut self,
+        _f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>,
+    ) {
+        // Fork() is not supported in vxWorks so no way to run the closure in the new procecss.
+        unimplemented!();;
+    }
+
+    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 env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+        &mut self.env
+    }
+
+    pub fn capture_env(&mut self) -> Option<CStringArray> {
+        let maybe_env = self.env.capture_if_changed();
+        maybe_env.map(|env| construct_envp(env, &mut self.saw_nul))
+    }
+    #[allow(dead_code)]
+    pub fn env_saw_path(&self) -> bool {
+        self.env.have_changed_path()
+    }
+
+    pub fn setup_io(&self, default: Stdio, needs_stdin: bool)
+                -> io::Result<(StdioPipes, ChildPipes)> {
+        let null = Stdio::Null;
+        let default_stdin = if needs_stdin {&default} else {&null};
+        let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
+        let stdout = self.stdout.as_ref().unwrap_or(&default);
+        let stderr = self.stderr.as_ref().unwrap_or(&default);
+        let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
+        let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
+        let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
+        let ours = StdioPipes {
+            stdin: our_stdin,
+            stdout: our_stdout,
+            stderr: our_stderr,
+        };
+        let theirs = ChildPipes {
+            stdin: their_stdin,
+            stdout: their_stdout,
+            stderr: their_stderr,
+        };
+        Ok((ours, theirs))
+    }
+}
+
+fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
+    CString::new(s.as_bytes()).unwrap_or_else(|_e| {
+        *saw_nul = true;
+        CString::new("<string-with-nul>").unwrap()
+    })
+}
+
+// Helper type to manage ownership of the strings within a C-style array.
+pub struct CStringArray {
+    items: Vec<CString>,
+    ptrs: Vec<*const c_char>
+}
+
+impl CStringArray {
+    pub fn with_capacity(capacity: usize) -> Self {
+        let mut result = CStringArray {
+            items: Vec::with_capacity(capacity),
+            ptrs: Vec::with_capacity(capacity+1)
+        };
+        result.ptrs.push(ptr::null());
+        result
+    }
+    pub fn push(&mut self, item: CString) {
+        let l = self.ptrs.len();
+        self.ptrs[l-1] = item.as_ptr();
+        self.ptrs.push(ptr::null());
+        self.items.push(item);
+    }
+    pub fn as_ptr(&self) -> *const *const c_char {
+        self.ptrs.as_ptr()
+    }
+}
+
+fn construct_envp(env: BTreeMap<DefaultEnvKey, OsString>, saw_nul: &mut bool) -> CStringArray {
+    let mut result = CStringArray::with_capacity(env.len());
+    for (k, v) in env {
+        let mut k: OsString = k.into();
+
+        // Reserve additional space for '=' and null terminator
+        k.reserve_exact(v.len() + 2);
+        k.push("=");
+        k.push(&v);
+
+        // Add the new entry into the array
+        if let Ok(item) = CString::new(k.into_vec()) {
+            result.push(item);
+        } else {
+            *saw_nul = true;
+        }
+    }
+
+    result
+}
+
+impl Stdio {
+    pub fn to_child_stdio(&self, readable: bool)
+                      -> io::Result<(ChildStdio, Option<AnonPipe>)> {
+        match *self {
+            Stdio::Inherit => {
+                Ok((ChildStdio::Inherit, None))
+            },
+
+            // Make sure that the source descriptors are not an stdio
+            // descriptor, otherwise the order which we set the child's
+            // descriptors may blow away a descriptor which we are hoping to
+            // save. For example, suppose we want the child's stderr to be the
+            // parent's stdout, and the child's stdout to be the parent's
+            // stderr. No matter which we dup first, the second will get
+            // overwritten prematurely.
+            Stdio::Fd(ref fd) => {
+                if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO {
+                    Ok((ChildStdio::Owned(fd.duplicate()?), None))
+                } else {
+                    Ok((ChildStdio::Explicit(fd.raw()), None))
+                }
+            }
+
+            Stdio::MakePipe => {
+                let (reader, writer) = pipe::anon_pipe()?;
+                let (ours, theirs) = if readable {
+                    (writer, reader)
+                } else {
+                    (reader, writer)
+                };
+                Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
+            }
+
+            Stdio::Null => {
+                let mut opts = OpenOptions::new();
+                opts.read(readable);
+                opts.write(!readable);
+                let path = unsafe {
+                    CStr::from_ptr("/null\0".as_ptr() as *const _)
+                };
+                let fd = File::open_c(&path, &opts)?;
+                Ok((ChildStdio::Owned(fd.into_fd()), None))
+            }
+        }
+    }
+}
+
+impl From<AnonPipe> for Stdio {
+    fn from(pipe: AnonPipe) -> Stdio {
+        Stdio::Fd(pipe.into_fd())
+    }
+}
+
+impl From<File> for Stdio {
+    fn from(file: File) -> Stdio {
+        Stdio::Fd(file.into_fd())
+    }
+}
+
+impl ChildStdio {
+    pub fn fd(&self) -> Option<c_int> {
+        match *self {
+            ChildStdio::Inherit => None,
+            ChildStdio::Explicit(fd) => Some(fd),
+            ChildStdio::Owned(ref fd) => Some(fd.raw()),
+        }
+    }
+}
+
+impl fmt::Debug for Command {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:?}", self.program)?;
+        for arg in &self.args {
+            write!(f, " {:?}", arg)?;
+        }
+        Ok(())
+    }
+}
+
+/// Unix exit statuses
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitStatus(c_int);
+
+impl ExitStatus {
+    pub fn new(status: c_int) -> ExitStatus {
+        ExitStatus(status)
+    }
+
+    fn exited(&self) -> bool {
+        /*unsafe*/ { libc::WIFEXITED(self.0) }
+    }
+
+    pub fn success(&self) -> bool {
+        self.code() == Some(0)
+    }
+
+    pub fn code(&self) -> Option<i32> {
+        if self.exited() {
+            Some(/*unsafe*/ { libc::WEXITSTATUS(self.0) })
+        } else {
+            None
+        }
+    }
+
+    pub fn signal(&self) -> Option<i32> {
+        if !self.exited() {
+            Some(/*unsafe*/ { libc::WTERMSIG(self.0) })
+        } else {
+            None
+        }
+    }
+}
+
+impl From<c_int> for ExitStatus {
+    fn from(a: c_int) -> ExitStatus {
+        ExitStatus(a)
+    }
+}
+
+impl fmt::Display for ExitStatus {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(code) = self.code() {
+            write!(f, "exit code: {}", code)
+        } else {
+            let signal = self.signal().unwrap();
+            write!(f, "signal: {}", signal)
+        }
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(u8);
+
+impl ExitCode {
+    pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
+    pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);
+
+    #[inline]
+    pub fn as_i32(&self) -> i32 {
+        self.0 as i32
+    }
+}
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests {
+    use super::*;
+
+    use crate::ffi::OsStr;
+    use crate::mem;
+    use crate::ptr;
+    use crate::sys::cvt;
+
+    macro_rules! t {
+        ($e:expr) => {
+            match $e {
+                Ok(t) => t,
+                Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
+            }
+        }
+    }
+
+    // Android with api less than 21 define sig* functions inline, so it is not
+    // available for dynamic link. Implementing sigemptyset and sigaddset allow us
+    // to support older Android version (independent of libc version).
+    // The following implementations are based on https://git.io/vSkNf
+
+    #[cfg(not(target_os = "android"))]
+    extern {
+        #[cfg_attr(target_os = "netbsd", link_name = "__sigemptyset14")]
+        fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int;
+
+        #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")]
+        fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int;
+    }
+
+    #[cfg(target_os = "android")]
+    unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int {
+        libc::memset(set as *mut _, 0, mem::size_of::<libc::sigset_t>());
+        return 0;
+    }
+
+    #[cfg(target_os = "android")]
+    unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int {
+        use crate::slice;
+
+        let raw = slice::from_raw_parts_mut(set as *mut u8, mem::size_of::<libc::sigset_t>());
+        let bit = (signum - 1) as usize;
+        raw[bit / 8] |= 1 << (bit % 8);
+        return 0;
+    }
+
+    // See #14232 for more information, but it appears that signal delivery to a
+    // newly spawned process may just be raced in the macOS, so to prevent this
+    // test from being flaky we ignore it on macOS.
+    #[test]
+    #[cfg_attr(target_os = "macos", ignore)]
+    // When run under our current QEMU emulation test suite this test fails,
+    // although the reason isn't very clear as to why. For now this test is
+    // ignored there.
+    #[cfg_attr(target_arch = "arm", ignore)]
+    #[cfg_attr(target_arch = "aarch64", ignore)]
+    fn test_process_mask() {
+        unsafe {
+            // Test to make sure that a signal mask does not get inherited.
+            let mut cmd = Command::new(OsStr::new("cat"));
+
+            let mut set: libc::sigset_t = mem::uninitialized();
+            let mut old_set: libc::sigset_t = mem::uninitialized();
+            t!(cvt(sigemptyset(&mut set)));
+            t!(cvt(sigaddset(&mut set, libc::SIGINT)));
+            t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut old_set)));
+
+            cmd.stdin(Stdio::MakePipe);
+            cmd.stdout(Stdio::MakePipe);
+
+            let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true));
+            let stdin_write = pipes.stdin.take().unwrap();
+            let stdout_read = pipes.stdout.take().unwrap();
+
+            t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &old_set,
+                                         ptr::null_mut())));
+
+            t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT)));
+            // We need to wait until SIGINT is definitely delivered. The
+            // easiest way is to write something to cat, and try to read it
+            // back: if SIGINT is unmasked, it'll get delivered when cat is
+            // next scheduled.
+            let _ = stdin_write.write(b"Hello");
+            drop(stdin_write);
+
+            // Either EOF or failure (EPIPE) is okay.
+            let mut buf = [0; 5];
+            if let Ok(ret) = stdout_read.read(&mut buf) {
+                assert_eq!(ret, 0);
+            }
+
+            t!(cat.wait());
+        }
+    }
+}
diff --git a/src/libstd/sys/vxworks/process/process_vxworks.rs b/src/libstd/sys/vxworks/process/process_vxworks.rs
new file mode 100644
index 00000000000..d06d63bb43d
--- /dev/null
+++ b/src/libstd/sys/vxworks/process/process_vxworks.rs
@@ -0,0 +1,167 @@
+use crate::io::{self, Error, ErrorKind};
+use libc::{self, c_int};
+use libc::{RTP_ID};
+
+use crate::sys::cvt;
+use crate::sys::process::rtp;
+use crate::sys::process::process_common::*;
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+impl Command {
+    pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
+                 -> io::Result<(Process, StdioPipes)> {
+        use crate::sys::{cvt_r};
+        const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";
+
+        let envp = self.capture_env();
+
+        if self.saw_nul() {
+            return Err(io::Error::new(ErrorKind::InvalidInput,
+                                      "nul byte found in provided data"));
+        }
+        let (ours, theirs) = self.setup_io(default, needs_stdin)?;
+        let mut p = Process { pid: 0, status: None };
+
+        unsafe {
+            macro_rules! t {
+                ($e:expr) => (match $e {
+                    Ok(e) => e,
+                    Err(e) => return Err(e.into()),
+                })
+            }
+
+            let mut orig_stdin = libc::STDIN_FILENO;
+            let mut orig_stdout = libc::STDOUT_FILENO;
+            let mut orig_stderr = libc::STDERR_FILENO;
+
+            if let Some(fd) = theirs.stdin.fd() {
+                orig_stdin = t!(cvt_r(|| libc::dup(libc::STDIN_FILENO)));
+                t!(cvt_r(|| libc::dup2(fd, libc::STDIN_FILENO)));
+            }
+            if let Some(fd) = theirs.stdout.fd() {
+                orig_stdout = t!(cvt_r(|| libc::dup(libc::STDOUT_FILENO)));
+                t!(cvt_r(|| libc::dup2(fd, libc::STDOUT_FILENO)));
+            }
+            if let Some(fd) = theirs.stderr.fd() {
+                orig_stderr = t!(cvt_r(|| libc::dup(libc::STDERR_FILENO)));
+                t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO)));
+            }
+
+            if let Some(ref cwd) = *self.get_cwd() {
+                t!(cvt(libc::chdir(cwd.as_ptr())));
+            }
+
+            //            let envp = envp.map(|c| c.as_ptr())
+            //                .unwrap_or(*sys::os::environ() as *const _);
+            // FIXME: https://github.com/rust-lang/rust/issues/61993
+            let envp_empty = CStringArray::with_capacity(0);
+            let envp = match envp {
+                Some(x) => x,
+                None => envp_empty,
+            };
+            let envp = envp.as_ptr();
+            let ret = rtp::rtpSpawn(
+                self.get_argv()[0],                   // executing program
+                self.get_argv().as_ptr() as *const _, // argv
+                envp as *const _,                     // environment variable pointers
+                100 as c_int,                         // initial priority
+                0x16000,                                    // initial stack size. 0 defaults
+                                                      // to 0x4000 in 32 bit and 0x8000 in 64 bit
+                0,                                    // options
+                0                                     // task options
+            );
+
+            // Because FileDesc was not used, each duplicated file descriptor
+            // needs to be closed manually
+            if orig_stdin != libc::STDIN_FILENO {
+                t!(cvt_r(|| libc::dup2(orig_stdin, libc::STDIN_FILENO)));
+                libc::close(orig_stdin);
+            }
+            if orig_stdout != libc::STDOUT_FILENO {
+                t!(cvt_r(|| libc::dup2(orig_stdout, libc::STDOUT_FILENO)));
+                libc::close(orig_stdout);
+            }
+            if orig_stderr != libc::STDERR_FILENO {
+                t!(cvt_r(|| libc::dup2(orig_stderr, libc::STDERR_FILENO)));
+                libc::close(orig_stderr);
+            }
+
+            if ret != rtp::RTP_ID_ERROR {
+                p.pid = ret;
+                Ok((p, ours))
+            } else {
+                Err(io::Error::last_os_error())
+            }
+        }
+    }
+
+    pub fn exec(&mut self, default: Stdio) -> io::Error {
+        let ret = Command::spawn(self, default, false);
+        match ret {
+            Ok(t) => unsafe {
+                let mut status = 0 as c_int;
+                libc::waitpid(t.0.pid, &mut status, 0);
+                libc::exit(0);
+            },
+            Err(e) => e,
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Processes
+////////////////////////////////////////////////////////////////////////////////
+
+/// The unique id of the process (this should never be negative).
+pub struct Process {
+    pid: RTP_ID,
+    status: Option<ExitStatus>,
+}
+
+impl Process {
+    pub fn id(&self) -> u32 {
+        self.pid as u32
+    }
+
+    pub fn kill(&mut self) -> io::Result<()> {
+        // If we've already waited on this process then the pid can be recycled
+        // and used for another process, and we probably shouldn't be killing
+        // random processes, so just return an error.
+        if self.status.is_some() {
+            Err(Error::new(ErrorKind::InvalidInput,
+                           "invalid argument: can't kill an exited process"))
+        } else {
+            cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ())
+        }
+    }
+
+    pub fn wait(&mut self) -> io::Result<ExitStatus> {
+        use crate::sys::cvt_r;
+        if let Some(status) = self.status {
+            return Ok(status)
+        }
+        let mut status = 0 as c_int;
+        cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?;
+        self.status = Some(ExitStatus::new(status));
+        Ok(ExitStatus::new(status))
+    }
+
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+        if let Some(status) = self.status {
+            return Ok(Some(status))
+        }
+        let mut status = 0 as c_int;
+        let pid = cvt(unsafe {
+            libc::waitpid(self.pid, &mut status, libc::WNOHANG)
+        })?;
+        if pid == 0 {
+            Ok(None)
+        } else {
+            self.status = Some(ExitStatus::new(status));
+            Ok(Some(ExitStatus::new(status)))
+        }
+    }
+}
diff --git a/src/libstd/sys/vxworks/process/rtp.rs b/src/libstd/sys/vxworks/process/rtp.rs
new file mode 100644
index 00000000000..3e6e0017abc
--- /dev/null
+++ b/src/libstd/sys/vxworks/process/rtp.rs
@@ -0,0 +1,298 @@
+#![allow(non_camel_case_types, unused)]
+
+use libc::{self, c_int, size_t, c_char, BOOL, RTP_DESC, RTP_ID, TASK_ID};
+
+
+// Copied directly from rtpLibCommon.h, rtpLib.h, signal.h and taskLibCommon.h (for task options)
+
+// ****     definitions for rtpLibCommon.h    ****
+
+pub const RTP_GLOBAL_SYMBOLS     : c_int = 0x01; // register global symbols for RTP
+pub const RTP_LOCAL_SYMBOLS      : c_int = 0x02; // idem for local symbols
+pub const RTP_ALL_SYMBOLS        : c_int = (RTP_GLOBAL_SYMBOLS | RTP_LOCAL_SYMBOLS);
+pub const RTP_DEBUG              : c_int = 0x10; // set RTP in debug mode when created
+pub const RTP_BUFFER_VAL_OFF     : c_int = 0x20; // disable buffer validation for all
+                                                 // system calls issued from the RTP
+pub const RTP_LOADED_WAIT        : c_int = 0x40; // Wait until the RTP is loaded
+pub const RTP_CPU_AFFINITY_NONE  : c_int = 0x80; // Remove any CPU affinity (SMP)
+
+// Error Status codes
+
+pub const M_rtpLib : c_int = 178 << 16;
+
+pub const S_rtpLib_INVALID_FILE                   : c_int = (M_rtpLib | 1);
+pub const S_rtpLib_INVALID_OPTION                 : c_int = (M_rtpLib | 2);
+pub const S_rtpLib_ACCESS_DENIED                  : c_int = (M_rtpLib | 3);
+pub const S_rtpLib_INVALID_RTP_ID                 : c_int = (M_rtpLib | 4);
+pub const S_rtpLib_NO_SYMBOL_TABLE                : c_int = (M_rtpLib | 5);
+pub const S_rtpLib_INVALID_SEGMENT_START_ADDRESS  : c_int = (M_rtpLib | 6);
+pub const S_rtpLib_INVALID_SYMBOL_REGISTR_POLICY  : c_int = (M_rtpLib | 7);
+pub const S_rtpLib_INSTANTIATE_FAILED             : c_int = (M_rtpLib | 8);
+pub const S_rtpLib_INVALID_TASK_OPTION            : c_int = (M_rtpLib | 9);
+pub const S_rtpLib_RTP_NAME_LENGTH_EXCEEDED       : c_int = (M_rtpLib | 10);    // rtpInfoGet
+
+pub const VX_RTP_NAME_LENGTH                      : c_int  = 255;    // max name length for diplay
+
+
+// The 'status' field (32 bit integer) of a RTP holds the RTP state and status.
+//
+// NOTE: RTP_STATE_GET()    : read the RTP state(s)
+//       RTP_STATE_PUT()    : write the RTP state(s)
+//       RTP_STATE_SET()    : set a RTP state
+//       RTP_STATE_UNSET()  : unset a RTP state
+//
+//       RTP_STATUS_GET()   : read the RTP status
+//       RTP_STATUS_PUT()   : write the RTP status
+//       RTP_STATUS_SET()   : set a RTP status
+//       RTP_STATUS_UNSET() : unset a RTP status
+//
+// The PUT/SET/UNSET macros are available only in the kernel headers.
+
+
+// RTP states
+
+pub const RTP_STATE_CREATE           : c_int  = 0x0001; // RrtpStructTP is under construction
+pub const RTP_STATE_NORMAL           : c_int  = 0x0002; // RrtpStructTP is ready
+pub const RTP_STATE_DELETE           : c_int  = 0x0004; // RrtpStructTP is being deleted
+
+pub const RTP_STATUS_STOP            : c_int  = 0x0100; // RTP hrtpStructas recieved stopped signal
+pub const RTP_STATUS_ELECTED_DELETER : c_int  = 0x0200; // RTP drtpStructelete has started
+
+pub const RTP_STATE_MASK             : c_int  = (RTP_STATE_CREATE | RTP_STATE_NORMAL |
+                                                 RTP_STATE_DELETE);
+pub const RTP_STATUS_MASK            : c_int  = (RTP_STATUS_STOP | RTP_STATUS_ELECTED_DELETER);
+
+pub fn RTP_STATE_GET  (value : c_int) -> c_int {
+    value & RTP_STATE_MASK
+}
+pub fn RTP_STATUS_GET (value : c_int) -> c_int {
+    value & RTP_STATUS_MASK
+}
+
+// Indicates that the RTP_ID returned is not valid.
+
+// RTP_ID_ERROR is supposed to be set to -1, but you can't set
+// an unsigned value to a negative without casting, and you
+// can't cast unless the size of the integer types are the same,
+// but the size of RTP_ID may differ between kernel and user space.
+// Bitwise or-ing min and max should get the same result.
+pub const RTP_ID_ERROR : RTP_ID = RTP_ID::min_value() | RTP_ID::max_value();
+
+// IS_RTP_ C macros
+
+pub fn IS_RTP_STATE_NORMAL           (value : c_int) -> bool {
+    (RTP_STATE_GET(value)  & RTP_STATE_NORMAL) == RTP_STATE_NORMAL
+}
+pub fn IS_RTP_STATE_CREATE           (value : c_int) -> bool {
+    (RTP_STATE_GET(value)  & RTP_STATE_CREATE) == RTP_STATE_CREATE
+}
+pub fn IS_RTP_STATE_DELETE           (value : c_int) -> bool {
+    (RTP_STATE_GET(value)  & RTP_STATE_DELETE) == RTP_STATE_DELETE
+}
+pub fn IS_RTP_STATUS_STOP            (value : c_int) -> bool {
+    (RTP_STATUS_GET(value) & RTP_STATUS_STOP ) == RTP_STATUS_STOP
+}
+pub fn IS_RTP_STATUS_ELECTED_DELETER (value : c_int) -> bool {
+    (RTP_STATUS_GET(value) &  RTP_STATUS_ELECTED_DELETER) == RTP_STATUS_ELECTED_DELETER
+}
+
+// **** end of definitions for rtpLibCommon.h ****
+
+
+
+
+// ****    definitions for rtpLib.h     ****
+
+pub fn rtpExit(exitCode : c_int) -> ! {
+    unsafe{ libc::exit (exitCode) }
+}
+
+/* rtpLib.h in the kernel
+pub const RTP_DEL_VIA_TASK_DELETE : c_int  = 0x1;          // rtpDelete() via taskDestroy()
+pub const RTP_DEL_FORCE           : c_int  = 0x2;          // Forceful  rtpDelete()
+pub const RTP_ID_ANY              : RTP_ID = 0;            // used for when a kernel task
+                                                           // wants to wait for the next
+                                                           // RTP to finish
+
+
+// Function pointers
+
+pub type RTP_PRE_CREATE_HOOK    = size_t;
+pub type RTP_POST_CREATE_HOOK   = size_t;
+pub type RTP_INIT_COMPLETE_HOOK = size_t;
+pub type RTP_DELETE_HOOK        = size_t;
+*/
+
+// **** end of definitions for rtpLib.h ****
+
+
+
+
+
+// ****     definitions for signal.h    ****
+pub fn rtpKill(rtpId : RTP_ID, signo : c_int) -> c_int {
+    unsafe{ libc::kill(rtpId as c_int, signo) }
+}
+
+pub fn rtpSigqueue(rtpId : RTP_ID, signo : c_int, value : size_t) -> c_int {
+    unsafe{ libc::sigqueue(rtpId as c_int, signo, value) }
+}
+
+pub fn _rtpSigqueue(rtpId : RTP_ID, signo : c_int, value : *mut size_t, code : c_int) -> c_int {
+    unsafe{ libc::_sigqueue(rtpId, signo, value, code) }
+}
+
+pub fn taskRaise(signo : c_int) -> c_int {
+    unsafe{ libc::taskKill(libc::taskIdSelf(), signo) }
+}
+pub fn rtpRaise(signo : c_int) -> c_int {
+    unsafe{ libc::raise(signo) }
+}
+
+// **** end of definitions for signal.h ****
+
+
+
+// ****     definitions for taskLibCommon.h    ****
+pub const VX_PRIVATE_ENV      : c_int = 0x0080;  // 1 = private environment variables
+pub const VX_NO_STACK_FILL    : c_int = 0x0100;  // 1 = avoid stack fill of 0xee
+pub const VX_PRIVATE_UMASK    : c_int = 0x0400;  // 1 = private file creation mode mask
+pub const VX_TASK_NOACTIVATE  : c_int = 0x2000;  // taskOpen() does not taskActivate()
+pub const VX_NO_STACK_PROTECT : c_int = 0x4000;  // no over/underflow stack protection,
+                                                 // stack space remains executable
+
+// define for all valid user task options
+
+pub const VX_USR_TASK_OPTIONS_BASE: c_int = (VX_PRIVATE_ENV      |
+                                             VX_NO_STACK_FILL    |
+                                             VX_TASK_NOACTIVATE  |
+                                             VX_NO_STACK_PROTECT |
+                                             VX_PRIVATE_UMASK);
+
+// **** end of definitions for taskLibCommon.h ****
+
+
+
+extern "C" {
+// functions in rtpLibCommon.h
+
+// forward declarations
+    pub fn rtpSpawn (
+        pubrtpFileName : *const c_char,
+        argv           : *const *const c_char,
+        envp           : *const *const c_char,
+        priority       : c_int,
+        uStackSize     : size_t,
+        options        : c_int,
+        taskOptions    : c_int,
+    ) -> RTP_ID;
+
+    pub fn rtpInfoGet (
+        rtpId     : RTP_ID,
+        rtpStruct : *mut RTP_DESC,
+    ) -> c_int;
+
+/* functions in rtpLib.h for kernel
+
+
+    // function declarations
+
+    pub fn rtpDelete (
+        id      : RTP_ID,
+        options : c_int,
+        status  : c_int,
+    ) -> c_int;
+
+    pub fn rtpDeleteForce (
+        rtpId : RTP_ID
+    ) -> c_int;
+
+    pub fn rtpShow (
+        rtpNameOrId : *mut c_char,
+        level       : c_int,
+    ) -> BOOL;
+
+    // RTP signals are always present when RTPs are included.  The public RTP
+    // signal APIs are declared here.
+
+
+    pub fn rtpKill (
+        rtpId : RTP_ID,
+        signo : c_int,
+    ) -> c_int;
+
+    pub fn rtpSigqueue (
+        rtpId : RTP_ID,
+        signo : c_int,
+        value : size_t, // Actual type is const union sigval value,
+                        // which is a union of int and void *
+    ) -> c_int;
+
+    pub fn rtpTaskKill (
+        tid   : TASK_ID,
+        signo : c_int,
+    ) -> c_int;
+
+    pub fn rtpTaskSigqueue (
+        tid   : TASK_ID,
+        signo : c_int,
+        value : const size_t, // Actual type is const union sigval,
+                        // which is a union of int and void *
+    ) -> c_int;
+
+    pub fn rtpWait (
+        rtpWaitId : RTP_ID,
+        timeout   : libc::alloc_jemalloc_Vx_ticks_t,
+        pRtpId    : *mut RTP_ID,
+        pStatus   : *mut c_int,
+    ) -> c_int;
+
+                             // Other public functions
+
+
+    pub fn rtpPreCreateHookAdd     (
+        hook      : RTP_PRE_CREATE_HOOK,
+        addToHead : BOOL,
+    ) -> c_int;
+
+    pub fn rtpPreCreateHookDelete  (
+        hook      : RTP_POST_CREATE_HOOK,
+    ) -> c_int;
+
+    pub fn rtpPostCreateHookAdd    (
+        hook      : RTP_POST_CREATE_HOOK,
+        addToHead : BOOL,
+    ) -> c_int;
+
+    pub fn rtpPostCreateHookDelete (
+        hook      : RTP_POST_CREATE_HOOK,
+    ) -> c_int;
+
+    pub fn rtpInitCompleteHookAdd  (
+        hook      : RTP_INIT_COMPLETE_HOOK,
+        addToHead : BOOL,
+    ) -> c_int;
+
+    pub fn rtpInitCompleteHookDelete (
+        hook      : RTP_INIT_COMPLETE_HOOK,
+    ) -> c_int;
+
+    pub fn rtpDeleteHookAdd        (
+        hook      : RTP_DELETE_HOOK,
+        addToHead : BOOL,
+    ) -> c_int;
+
+    pub fn rtpDeleteHookDelete     (
+        hook      : RTP_DELETE_HOOK,
+    ) -> c_int;
+
+    pub fn rtpMemShow              (
+        rtpNameOrId : *mut c_char,
+        level       : c_int,
+    ) -> c_int;
+
+    pub fn rtpHookShow             (
+
+    );
+*/
+}