diff options
| author | Baoshan Pang <baoshan.pang@windriver.com> | 2019-07-15 23:57:53 -0700 |
|---|---|---|
| committer | Baoshan Pang <baoshan.pang@windriver.com> | 2019-07-16 00:13:07 -0700 |
| commit | 4c0c0f6158b464ee5070b32bb37f2863d0eff012 (patch) | |
| tree | 3306eadf9f3bb9023cfca1fc16b44e18132916e9 /src/libstd/sys/vxworks/process | |
| parent | 4a95e9704de0eeaecba55df102c1129e79a3a929 (diff) | |
| download | rust-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.rs | 7 | ||||
| -rw-r--r-- | src/libstd/sys/vxworks/process/process_common.rs | 503 | ||||
| -rw-r--r-- | src/libstd/sys/vxworks/process/process_vxworks.rs | 167 | ||||
| -rw-r--r-- | src/libstd/sys/vxworks/process/rtp.rs | 298 |
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 ( + + ); +*/ +} |
