...
 
Commits (14)
......@@ -47,3 +47,7 @@
[submodule "src/doc/embedded-book"]
path = src/doc/embedded-book
url = https://github.com/rust-embedded/book.git
[submodule "src/liblibc"]
path = src/liblibc
url = https://gitlab.redox-os.org/redox-os/liblibc.git
branch = redox-unix
This diff is collapsed.
......@@ -28,6 +28,7 @@ exclude = [
"build",
# HACK(eddyb) This hardcodes the fact that our CI uses `/checkout/obj`.
"obj",
"src/liblibc",
]
# Curiously, LLVM 7.0 will segfault if compiled with opt-level=3
......@@ -69,7 +70,7 @@ rustc-workspace-hack = { path = 'src/tools/rustc-workspace-hack' }
rustc-std-workspace-core = { path = 'src/tools/rustc-std-workspace-core' }
# Redox patches
libc = { git = "https://gitlab.redox-os.org/redox-os/liblibc.git", branch = "redox" }
libc = { path = "src/liblibc" }
[patch."https://github.com/rust-lang/rust-clippy"]
clippy_lints = { path = "src/tools/clippy/clippy_lints" }
Subproject commit 74f73b012c5da6ceeaeb046c055c2c5cb6f8fb86
......@@ -12,5 +12,5 @@ doc = false
[dependencies]
core = { path = "../libcore" }
libc = { git = "https://gitlab.redox-os.org/redox-os/liblibc.git", branch = "redox", default-features = false }
libc = { path = "../liblibc", default-features = false }
compiler_builtins = "0.1.0"
......@@ -49,8 +49,7 @@ pub unsafe extern fn __rust_start_panic(_payload: usize) -> u32 {
libc::abort();
}
#[cfg(any(target_os = "redox",
windows,
#[cfg(any(windows,
all(target_arch = "wasm32", not(target_os = "emscripten"))))]
unsafe fn abort() -> ! {
core::intrinsics::abort();
......
......@@ -13,6 +13,6 @@ doc = false
[dependencies]
alloc = { path = "../liballoc" }
core = { path = "../libcore" }
libc = { git = "https://gitlab.redox-os.org/redox-os/liblibc.git", branch = "redox", default-features = false }
libc = { path = "../liblibc", default-features = false }
unwind = { path = "../libunwind" }
compiler_builtins = "0.1.0"
......@@ -20,7 +20,7 @@ pub fn opts() -> TargetOptions {
TargetOptions {
dynamic_linking: true,
executables: true,
target_family: Some("redox".to_string()),
target_family: Some("unix".to_string()),
linker_is_gnu: true,
has_rpath: true,
pre_link_args: args,
......
......@@ -18,7 +18,7 @@ alloc = { path = "../liballoc" }
panic_unwind = { path = "../libpanic_unwind", optional = true }
panic_abort = { path = "../libpanic_abort" }
core = { path = "../libcore" }
libc = { git = "https://gitlab.redox-os.org/redox-os/liblibc.git", branch = "redox", default-features = false, features = ['rustc-dep-of-std'] }
libc = { path = "../liblibc", default-features = false, features = ['rustc-dep-of-std'] }
compiler_builtins = { version = "0.1.9" }
profiler_builtins = { path = "../libprofiler_builtins", optional = true }
unwind = { path = "../libunwind" }
......
......@@ -51,6 +51,7 @@ cfg_if! {
#[cfg(target_os = "emscripten")] pub mod emscripten;
#[cfg(target_os = "fuchsia")] pub mod fuchsia;
#[cfg(target_os = "hermit")] pub mod hermit;
#[cfg(target_os = "redox")] pub mod redox;
#[cfg(target_env = "wasi")] pub mod wasi;
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] pub mod fortanix_sgx;
......
This diff is collapsed.
//! Redox-specific definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
pub mod raw;
pub mod fs;
//! Redox-specific raw type definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
#![rustc_deprecated(since = "1.8.0",
reason = "these type aliases are no longer supported by \
the standard library, the `libc` crate on \
crates.io should be used instead for the correct \
definitions")]
#![allow(deprecated)]
#![allow(missing_debug_implementations)]
use crate::os::raw::{c_char, c_int, c_long, c_ulong, c_void};
#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = c_long;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type gid_t = c_int;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = c_int;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type uid_t = c_int;
#[stable(feature = "pthread_t", since = "1.8.0")]
pub type pthread_t = *mut c_void;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = c_ulong;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = c_ulong;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = c_ulong;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = c_ulong;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = c_long;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = c_long;
#[repr(C)]
#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_dev: dev_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ino: ino_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_nlink: nlink_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mode: mode_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_uid: uid_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_gid: gid_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_rdev: dev_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_size: off_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_blksize: blksize_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_blocks: blkcnt_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_atime: time_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_atime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mtime: time_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mtime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ctime: time_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ctime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub _pad: [c_char; 24],
}
......@@ -32,9 +32,6 @@ cfg_if! {
} else if #[cfg(target_os = "cloudabi")] {
mod cloudabi;
pub use self::cloudabi::*;
} else if #[cfg(target_os = "redox")] {
mod redox;
pub use self::redox::*;
} else if #[cfg(target_env = "wasi")] {
mod wasi;
pub use self::wasi::*;
......@@ -55,7 +52,7 @@ cfg_if! {
#[cfg(rustdoc)]
cfg_if! {
if #[cfg(any(unix, target_os = "redox"))] {
if #[cfg(unix)] {
// On unix we'll document what's already available
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::ext as unix_ext;
......
//! Global initialization and retrieval of command line arguments.
//!
//! On some platforms these are stored during runtime startup,
//! and on some they are retrieved from the system on demand.
#![allow(dead_code)] // runtime init functions not used during testing
use crate::ffi::OsString;
use crate::marker::PhantomData;
use crate::vec;
/// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
/// One-time global cleanup.
pub unsafe fn cleanup() { imp::cleanup() }
/// Returns the command line arguments
pub fn args() -> Args {
imp::args()
}
pub struct Args {
iter: vec::IntoIter<OsString>,
_dont_send_or_sync_me: PhantomData<*mut ()>,
}
impl Args {
pub fn inner_debug(&self) -> &[OsString] {
self.iter.as_slice()
}
}
impl Iterator for Args {
type Item = OsString;
fn next(&mut self) -> Option<OsString> { self.iter.next() }
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}
impl ExactSizeIterator for Args {
fn len(&self) -> usize { self.iter.len() }
}
impl DoubleEndedIterator for Args {
fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
}
mod imp {
use crate::os::unix::prelude::*;
use crate::mem;
use crate::ffi::{CStr, OsString};
use crate::marker::PhantomData;
use super::Args;
use crate::sys_common::mutex::Mutex;
static mut GLOBAL_ARGS_PTR: usize = 0;
static LOCK: Mutex = Mutex::new();
pub unsafe fn init(argc: isize, argv: *const *const u8) {
let args = (0..argc).map(|i| {
CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
}).collect();
let _guard = LOCK.lock();
let ptr = get_global_ptr();
assert!((*ptr).is_none());
(*ptr) = Some(box args);
}
pub unsafe fn cleanup() {
let _guard = LOCK.lock();
*get_global_ptr() = None;
}
pub fn args() -> Args {
let bytes = clone().unwrap_or_default();
let v: Vec<OsString> = bytes.into_iter().map(|v| {
OsStringExt::from_vec(v)
}).collect();
Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
}
fn clone() -> Option<Vec<Vec<u8>>> {
unsafe {
let _guard = LOCK.lock();
let ptr = get_global_ptr();
(*ptr).as_ref().map(|s| (**s).clone())
}
}
unsafe fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
mem::transmute(&GLOBAL_ARGS_PTR)
}
}
/// See sys/unix/backtrace/mod.rs for an explanation of the method used here.
pub use self::tracing::unwind_backtrace;
pub use self::printing::{foreach_symbol_fileline, resolve_symname};
// tracing impls:
mod tracing;
// symbol resolvers:
mod printing;
pub mod gnu {
use crate::io;
use crate::fs;
use crate::vec::Vec;
use crate::ffi::OsStr;
use crate::os::unix::ffi::OsStrExt;
use crate::io::Read;
use libc::c_char;
pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
let mut exefile = fs::File::open("sys:exe")?;
let mut exename = Vec::new();
exefile.read_to_end(&mut exename)?;
if exename.last() == Some(&b'\n') {
exename.pop();
}
let file = fs::File::open(OsStr::from_bytes(&exename))?;
Ok((exename.into_iter().map(|c| c as c_char).collect(), file))
}
}
pub struct BacktraceContext;
pub use crate::sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
use crate::error::Error;
use crate::fmt;
use crate::io;
use crate::sys::backtrace::BacktraceContext;
use crate::sys_common::backtrace::Frame;
use unwind as uw;
struct Context<'a> {
idx: usize,
frames: &'a mut [Frame],
}
#[derive(Debug)]
struct UnwindError(uw::_Unwind_Reason_Code);
impl Error for UnwindError {
fn description(&self) -> &'static str {
"unexpected return value while unwinding"
}
}
impl fmt::Display for UnwindError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}: {:?}", self.description(), self.0)
}
}
#[inline(never)] // if we know this is a function call, we can skip it when
// tracing
pub fn unwind_backtrace(frames: &mut [Frame])
-> io::Result<(usize, BacktraceContext)>
{
let mut cx = Context {
idx: 0,
frames: frames,
};
let result_unwind = unsafe {
uw::_Unwind_Backtrace(trace_fn,
&mut cx as *mut Context<'_>
as *mut libc::c_void)
};
// See libunwind:src/unwind/Backtrace.c for the return values.
// No, there is no doc.
match result_unwind {
// These return codes seem to be benign and need to be ignored for backtraces
// to show up properly on all tested platforms.
uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
Ok((cx.idx, BacktraceContext))
}
_ => {
Err(io::Error::new(io::ErrorKind::Other,
UnwindError(result_unwind)))
}
}
}
extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
let cx = unsafe { &mut *(arg as *mut Context<'_>) };
if cx.idx >= cx.frames.len() {
return uw::_URC_NORMAL_STOP;
}
let mut ip_before_insn = 0;
let mut ip = unsafe {
uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
};
if !ip.is_null() && ip_before_insn == 0 {
// this is a non-signaling frame, so `ip` refers to the address
// after the calling instruction. account for that.
ip = (ip as usize - 1) as *mut _;
}
// dladdr() on osx gets whiny when we use FindEnclosingFunction, and
// it appears to work fine without it, so we only use
// FindEnclosingFunction on non-osx platforms. In doing so, we get a
// slightly more accurate stack trace in the process.
//
// This is often because panic involves the last instruction of a
// function being "call std::rt::begin_unwind", with no ret
// instructions after it. This means that the return instruction
// pointer points *outside* of the calling function, and by
// unwinding it we go back to the original function.
let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
ip
} else {
unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
};
cx.frames[cx.idx] = Frame {
symbol_addr: symaddr as *mut u8,
exact_position: ip as *mut u8,
inline_context: 0,
};
cx.idx += 1;
uw::_URC_NO_REASON
}
#![cfg(not(test))]
use libc::{c_float, c_double};
#[link_name = "m"]
extern {
pub fn acos(n: c_double) -> c_double;
pub fn acosf(n: c_float) -> c_float;
pub fn asin(n: c_double) -> c_double;
pub fn asinf(n: c_float) -> c_float;
pub fn atan(n: c_double) -> c_double;
pub fn atan2(a: c_double, b: c_double) -> c_double;
pub fn atan2f(a: c_float, b: c_float) -> c_float;
pub fn atanf(n: c_float) -> c_float;
pub fn cbrt(n: c_double) -> c_double;
pub fn cbrtf(n: c_float) -> c_float;
pub fn cosh(n: c_double) -> c_double;
pub fn coshf(n: c_float) -> c_float;
pub fn expm1(n: c_double) -> c_double;
pub fn expm1f(n: c_float) -> c_float;
pub fn fdim(a: c_double, b: c_double) -> c_double;
pub fn fdimf(a: c_float, b: c_float) -> c_float;
pub fn hypot(x: c_double, y: c_double) -> c_double;
pub fn hypotf(x: c_float, y: c_float) -> c_float;
pub fn log1p(n: c_double) -> c_double;
pub fn log1pf(n: c_float) -> c_float;
pub fn sinh(n: c_double) -> c_double;
pub fn sinhf(n: c_float) -> c_float;
pub fn tan(n: c_double) -> c_double;
pub fn tanf(n: c_float) -> c_float;
pub fn tanh(n: c_double) -> c_double;
pub fn tanhf(n: c_float) -> c_float;
}
use crate::cell::UnsafeCell;
use crate::intrinsics::{atomic_cxchg, atomic_load, atomic_xadd, atomic_xchg};
use crate::ptr;
use crate::time::Duration;
use crate::sys::mutex::{mutex_unlock, Mutex};
use crate::sys::syscall::{futex, TimeSpec, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE};
pub struct Condvar {
lock: UnsafeCell<*mut i32>,
seq: UnsafeCell<i32>
}
impl Condvar {
pub const fn new() -> Condvar {
Condvar {
lock: UnsafeCell::new(ptr::null_mut()),
seq: UnsafeCell::new(0)
}
}
#[inline]
pub unsafe fn init(&self) {
*self.lock.get() = ptr::null_mut();
*self.seq.get() = 0;
}
#[inline]
pub fn notify_one(&self) {
unsafe {
let seq = self.seq.get();
atomic_xadd(seq, 1);
let _ = futex(seq, FUTEX_WAKE, 1, 0, ptr::null_mut());
}
}
#[inline]
pub fn notify_all(&self) {
unsafe {
let lock = self.lock.get();
let seq = self.seq.get();
if *lock == ptr::null_mut() {
return;
}
atomic_xadd(seq, 1);
let _ = futex(seq, FUTEX_REQUEUE, 1, crate::usize::MAX, *lock);
}
}
#[inline]
unsafe fn wait_inner(&self, mutex: &Mutex, timeout_ptr: *const TimeSpec) -> bool {
let lock = self.lock.get();
let seq = self.seq.get();
if *lock != mutex.lock.get() {
if *lock != ptr::null_mut() {
panic!("Condvar used with more than one Mutex");
}
atomic_cxchg(lock as *mut usize, 0, mutex.lock.get() as usize);
}
mutex_unlock(*lock);
let seq_before = atomic_load(seq);
let _ = futex(seq, FUTEX_WAIT, seq_before, timeout_ptr as usize, ptr::null_mut());
let seq_after = atomic_load(seq);
while atomic_xchg(*lock, 2) != 0 {
let _ = futex(*lock, FUTEX_WAIT, 2, 0, ptr::null_mut());
}
seq_before != seq_after
}
#[inline]
pub fn wait(&self, mutex: &Mutex) {
unsafe {
assert!(self.wait_inner(mutex, ptr::null()));
}
}
#[inline]
pub fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
unsafe {
let timeout = TimeSpec {
tv_sec: dur.as_secs() as i64,
tv_nsec: dur.subsec_nanos() as i32
};
self.wait_inner(mutex, &timeout as *const TimeSpec)
}
}
#[inline]
pub unsafe fn destroy(&self) {
*self.lock.get() = ptr::null_mut();
*self.seq.get() = 0;
}
}
unsafe impl Send for Condvar {}
unsafe impl Sync for Condvar {}
pub mod os {
pub const FAMILY: &str = "redox";
pub const OS: &str = "redox";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
//! Redox-specific extension to the primitives in the `std::ffi` module.
//!
//! # Examples
//!
//! ```
//! use std::ffi::OsString;
//! use std::os::redox::ffi::OsStringExt;
//!
//! let bytes = b"foo".to_vec();
//!
//! // OsStringExt::from_vec
//! let os_string = OsString::from_vec(bytes);
//! assert_eq!(os_string.to_str(), Some("foo"));
//!
//! // OsStringExt::into_vec
//! let bytes = os_string.into_vec();
//! assert_eq!(bytes, b"foo");
//! ```
//!
//! ```
//! use std::ffi::OsStr;
//! use std::os::redox::ffi::OsStrExt;
//!
//! let bytes = b"foo";
//!
//! // OsStrExt::from_bytes
//! let os_str = OsStr::from_bytes(bytes);
//! assert_eq!(os_str.to_str(), Some("foo"));
//!
//! // OsStrExt::as_bytes
//! let bytes = os_str.as_bytes();
//! assert_eq!(bytes, b"foo");
//! ```
#![stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
pub use crate::sys_common::os_str_bytes::*;
This diff is collapsed.
//! Unix-specific extensions to general I/O primitives
#![stable(feature = "rust1", since = "1.0.0")]
use crate::fs;
use crate::net;
use crate::sys;
use crate::io;
use crate::sys_common::{self, AsInner, FromInner, IntoInner};
/// Raw file descriptors.
#[stable(feature = "rust1", since = "1.0.0")]
pub type RawFd = usize;
/// A trait to extract the raw unix file descriptor from an underlying
/// object.
///
/// This is only available on unix platforms and must be imported in order
/// to call the method. Windows platforms have a corresponding `AsRawHandle`
/// and `AsRawSocket` set of traits.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawFd {
/// Extracts the raw file descriptor.
///
/// This method does **not** pass ownership of the raw file descriptor
/// to the caller. The descriptor is only guaranteed to be valid while
/// the original object has not yet been destroyed.
#[stable(feature = "rust1", since = "1.0.0")]
fn as_raw_fd(&self) -> RawFd;
}
/// A trait to express the ability to construct an object from a raw file
/// descriptor.
#[stable(feature = "from_raw_os", since = "1.1.0")]
pub trait FromRawFd {
/// Constructs a new instances of `Self` from the given raw file
/// descriptor.
///
/// This function **consumes ownership** of the specified file
/// descriptor. The returned object will take responsibility for closing
/// it when the object goes out of scope.
///
/// This function is also unsafe as the primitives currently returned
/// have the contract that they are the sole owner of the file
/// descriptor they are wrapping. Usage of this function could
/// accidentally allow violating this contract which can cause memory
/// unsafety in code that relies on it being true.
#[stable(feature = "from_raw_os", since = "1.1.0")]
unsafe fn from_raw_fd(fd: RawFd) -> Self;
}
/// A trait to express the ability to consume an object and acquire ownership of
/// its raw file descriptor.
#[stable(feature = "into_raw_os", since = "1.4.0")]
pub trait IntoRawFd {
/// Consumes this object, returning the raw underlying file descriptor.
///
/// This function **transfers ownership** of the underlying file descriptor
/// to the caller. Callers are then the unique owners of the file descriptor
/// and must close the descriptor once it's no longer needed.
#[stable(feature = "into_raw_os", since = "1.4.0")]
fn into_raw_fd(self) -> RawFd;
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for fs::File {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd().raw()
}
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawFd for fs::File {
unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
fs::File::from_inner(sys::fs::File::from_inner(fd))
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for fs::File {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_fd().into_raw()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::TcpStream {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().as_inner().fd().raw()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::TcpListener {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().as_inner().fd().raw()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::UdpSocket {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().as_inner().fd().raw()
}
}
#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawFd for io::Stdin {
fn as_raw_fd(&self) -> RawFd { 0 }
}
#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawFd for io::Stdout {
fn as_raw_fd(&self) -> RawFd { 1 }
}
#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawFd for io::Stderr {
fn as_raw_fd(&self) -> RawFd { 2 }
}
#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
impl<'a> AsRawFd for io::StdinLock<'a> {
fn as_raw_fd(&self) -> RawFd { 0 }
}
#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
impl<'a> AsRawFd for io::StdoutLock<'a> {
fn as_raw_fd(&self) -> RawFd { 1 }
}
#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
impl<'a> AsRawFd for io::StderrLock<'a> {
fn as_raw_fd(&self) -> RawFd { 2 }
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawFd for net::TcpStream {
unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
let file = sys::fs::File::from_inner(fd);
net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(file))
}
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawFd for net::TcpListener {
unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
let file = sys::fs::File::from_inner(fd);
net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(file))
}
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawFd for net::UdpSocket {
unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
let file = sys::fs::File::from_inner(fd);
net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(file))
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for net::TcpStream {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_inner().into_fd().into_raw()
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for net::TcpListener {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_inner().into_fd().into_raw()
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for net::UdpSocket {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_inner().into_fd().into_raw()
}
}
//! Experimental extensions to `std` for Unix platforms.
//!
//! For now, this module is limited to extracting file descriptors,
//! but its functionality will grow over time.
//!
//! # Examples
//!
//! ```no_run
//! use std::fs::File;
//! use std::os::unix::prelude::*;
//!
//! fn main() {
//! let f = File::create("foo.txt").unwrap();
//! let fd = f.as_raw_fd();
//!
//! // use fd with native unix bindings
//! }
//! ```
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(cfg(target_os = "redox"))]
pub mod ffi;
pub mod fs;
pub mod io;
pub mod net;
pub mod process;
pub mod thread;
/// A prelude for conveniently writing platform-specific code.
///
/// Includes all extension traits, and some important type definitions.
#[stable(feature = "rust1", since = "1.0.0")]
pub mod prelude {
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::ffi::{OsStrExt, OsStringExt};
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::fs::{FileTypeExt, PermissionsExt, OpenOptionsExt, MetadataExt};
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::thread::JoinHandleExt;
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::process::{CommandExt, ExitStatusExt};
}
This diff is collapsed.
//! Redox-specific extensions to primitives in the `std::process` module.
#![stable(feature = "rust1", since = "1.0.0")]
use crate::io;
use crate::os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd};
use crate::process;
use crate::sys;
use crate::sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};
/// Redox-specific extensions to the [`process::Command`] builder,
///
/// [`process::Command`]: ../../../../std/process/struct.Command.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait CommandExt {
/// Sets the child process's user ID. This translates to a
/// `setuid` call in the child process. Failure in the `setuid`
/// call will cause the spawn to fail.
#[stable(feature = "rust1", since = "1.0.0")]
fn uid(&mut self, id: u32) -> &mut process::Command;
/// Similar to `uid`, but sets the group ID of the child process. This has
/// the same semantics as the `uid` field.
#[stable(feature = "rust1", since = "1.0.0")]
fn gid(&mut self, id: u32) -> &mut process::Command;
/// Schedules a closure to be run just before the `exec` function is
/// invoked.
///
/// The closure is allowed to return an I/O error whose OS error code will
/// be communicated back to the parent and returned as an error from when
/// the spawn was requested.
///
/// Multiple closures can be registered and they will be called in order of
/// their registration. If a closure returns `Err` then no further closures
/// will be called and the spawn operation will immediately return with a
/// failure.
///
/// # Notes and Safety
///
/// This closure will be run in the context of the child process after a
/// `fork`. This primarily means that any modifications made to memory on
/// behalf of this closure will **not** be visible to the parent process.
/// This is often a very constrained environment where normal operations
/// like `malloc` or acquiring a mutex are not guaranteed to work (due to
/// other threads perhaps still running when the `fork` was run).
///
/// This also means that all resources such as file descriptors and
/// memory-mapped regions got duplicated. It is your responsibility to make
/// sure that the closure does not violate library invariants by making
/// invalid use of these duplicates.
///
/// When this closure is run, aspects such as the stdio file descriptors and
/// working directory have successfully been changed, so output to these
/// locations may not appear where intended.
#[stable(feature = "process_pre_exec", since = "1.34.0")]
unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
where F: FnMut() -> io::Result<()> + Send + Sync + 'static;
/// Schedules a closure to be run just before the `exec` function is
/// invoked.
///
/// This method is stable and usable, but it should be unsafe. To fix
/// that, it got deprecated in favor of the unsafe [`pre_exec`].
///
/// [`pre_exec`]: #tymethod.pre_exec
#[stable(feature = "process_exec", since = "1.15.0")]
#[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")]
fn before_exec<F>(&mut self, f: F) -> &mut process::Command
where F: FnMut() -> io::Result<()> + Send + Sync + 'static
{
unsafe { self.pre_exec(f) }
}
/// Performs all the required setup by this `Command`, followed by calling
/// the `execvp` syscall.
///
/// On success this function will not return, and otherwise it will return
/// an error indicating why the exec (or another part of the setup of the
/// `Command`) failed.
///
/// This function, unlike `spawn`, will **not** `fork` the process to create
/// a new child. Like spawn, however, the default behavior for the stdio
/// descriptors will be to inherited from the current process.
///
/// # Notes
///
/// The process may be in a "broken state" if this function returns in
/// error. For example the working directory, environment variables, signal
/// handling settings, various user/group information, or aspects of stdio
/// file descriptors may have changed. If a "transactional spawn" is
/// required to gracefully handle errors it is recommended to use the
/// cross-platform `spawn` instead.
#[stable(feature = "process_exec2", since = "1.9.0")]
fn exec(&mut self) -> io::Error;
}
#[stable(feature = "rust1", since = "1.0.0")]
impl CommandExt for process::Command {
fn uid(&mut self, id: u32) -> &mut process::Command {
self.as_inner_mut().uid(id);
self
}
fn gid(&mut self, id: u32) -> &mut process::Command {
self.as_inner_mut().gid(id);
self
}
unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
where F: FnMut() -> io::Result<()> + Send + Sync + 'static
{
self.as_inner_mut().pre_exec(Box::new(f));
self
}
fn exec(&mut self) -> io::Error {
self.as_inner_mut().exec(sys::process::Stdio::Inherit)
}
}
/// Redox-specific extensions to [`process::ExitStatus`].
///
/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ExitStatusExt {
/// Creates a new `ExitStatus` from the raw underlying `i32` return value of
/// a process.
#[stable(feature = "exit_status_from", since = "1.12.0")]
fn from_raw(raw: i32) -> Self;
/// If the process was terminated by a signal, returns that signal.
#[stable(feature = "rust1", since = "1.0.0")]
fn signal(&self) -> Option<i32>;
}
#[stable(feature = "rust1", since = "1.0.0")]
impl ExitStatusExt for process::ExitStatus {
fn from_raw(raw: i32) -> Self {
process::ExitStatus::from_inner(From::from(raw))
}
fn signal(&self) -> Option<i32> {
self.as_inner().signal()
}
}
#[stable(feature = "process_extensions", since = "1.2.0")]
impl FromRawFd for process::Stdio {
unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
let fd = sys::fd::FileDesc::new(fd);
let io = sys::process::Stdio::Fd(fd);
process::Stdio::from_inner(io)
}
}
#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStdin {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd().raw()
}
}
#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStdout {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd().raw()
}
}
#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStderr {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd().raw()
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStdin {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_fd().into_raw()
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStdout {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_fd().into_raw()
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStderr {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_fd().into_raw()
}
}
//! Redox-specific extensions to primitives in the `std::thread` module.
#![stable(feature = "thread_extensions", since = "1.9.0")]
use crate::sys_common::{AsInner, IntoInner};
use crate::thread::JoinHandle;
#[stable(feature = "thread_extensions", since = "1.9.0")]
#[allow(deprecated)]
pub type RawPthread = usize;
/// Redox-specific extensions to [`thread::JoinHandle`].
///
/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html
#[stable(feature = "thread_extensions", since = "1.9.0")]
pub trait JoinHandleExt {
/// Extracts the raw pthread_t without taking ownership
#[stable(feature = "thread_extensions", since = "1.9.0")]
fn as_pthread_t(&self) -> RawPthread;
/// Consumes the thread, returning the raw pthread_t
///
/// This function **transfers ownership** of the underlying pthread_t to
/// the caller. Callers are then the unique owners of the pthread_t and
/// must either detach or join the pthread_t once it's no longer needed.
#[stable(feature = "thread_extensions", since = "1.9.0")]
fn into_pthread_t(self) -> RawPthread;
}
#[stable(feature = "thread_extensions", since = "1.9.0")]
impl<T> JoinHandleExt for JoinHandle<T> {
fn as_pthread_t(&self) -> RawPthread {
self.as_inner().id() as RawPthread
}
fn into_pthread_t(self) -> RawPthread {
self.into_inner().into_id() as RawPthread
}
}
#![cfg(target_thread_local)]
#![unstable(feature = "thread_local_internals", issue = "0")]
use crate::cell::{Cell, UnsafeCell};
use crate::mem;
use crate::ptr;
pub struct Key<T> {
inner: UnsafeCell<Option<T>>,
// Metadata to keep track of the state of the destructor. Remember that
// these variables are thread-local, not global.
dtor_registered: Cell<bool>,
dtor_running: Cell<bool>,
}
unsafe impl<T> Sync for Key<T> { }
impl<T> Key<T> {
pub const fn new() -> Key<T> {
Key {
inner: UnsafeCell::new(None),
dtor_registered: Cell::new(false),
dtor_running: Cell::new(false)
}
}
pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
unsafe {
if mem::needs_drop::<T>() && self.dtor_running.get() {
return None
}
self.register_dtor();
}
Some(&self.inner)
}
unsafe fn register_dtor(&self) {
if !mem::needs_drop::<T>() || self.dtor_registered.get() {
return
}
register_dtor(self as *const _ as *mut u8,
destroy_value::<T>);
self.dtor_registered.set(true);
}
}
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
// The fallback implementation uses a vanilla OS-based TLS key to track
// the list of destructors that need to be run for this thread. The key
// then has its own destructor which runs all the other destructors.
//
// The destructor for DTORS is a little special in that it has a `while`
// loop to continuously drain the list of registered destructors. It
// *should* be the case that this loop always terminates because we
// provide the guarantee that a TLS key cannot be set after it is
// flagged for destruction.
use crate::sys_common::thread_local as os;
static DTORS: os::StaticKey = os::StaticKey::new(Some(run_dtors));
type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
if DTORS.get().is_null() {
let v: Box<List> = box Vec::new();
DTORS.set(Box::into_raw(v) as *mut u8);
}
let list: &mut List = &mut *(DTORS.get() as *mut List);
list.push((t, dtor));
unsafe extern fn run_dtors(mut ptr: *mut u8) {
while !ptr.is_null() {
let list: Box<List> = Box::from_raw(ptr as *mut List);
for (ptr, dtor) in list.into_iter() {
dtor(ptr);
}
ptr = DTORS.get();
DTORS.set(ptr::null_mut());
}
}
}
pub unsafe extern fn destroy_value<T>(ptr: *mut u8) {
let ptr = ptr as *mut Key<T>;
// Right before we run the user destructor be sure to flag the
// destructor as running for this thread so calls to `get` will return
// `None`.
(*ptr).dtor_running.set(true);
// The macOS implementation of TLS apparently had an odd aspect to it
// where the pointer we have may be overwritten while this destructor
// is running. Specifically if a TLS destructor re-accesses TLS it may
// trigger a re-initialization of all TLS variables, paving over at
// least some destroyed ones with initial values.
//
// This means that if we drop a TLS value in place on macOS that we could
// revert the value to its original state halfway through the
// destructor, which would be bad!
//
// Hence, we use `ptr::read` on macOS (to move to a "safe" location)
// instead of drop_in_place.
if cfg!(target_os = "macos") {
ptr::read((*ptr).inner.get());
} else {
ptr::drop_in_place((*ptr).inner.get());
}
}
pub fn requires_move_before_drop() -> bool {
false
}
#![unstable(reason = "not public", issue = "0", feature = "fd")]
use crate::io::{self, Read};
use crate::mem;
use crate::sys::{cvt, syscall};
use crate::sys_common::AsInner;
pub struct FileDesc {
fd: usize,
}
impl FileDesc {
pub fn new(fd: usize) -> FileDesc {
FileDesc { fd }
}
pub fn raw(&self) -> usize { self.fd }
/// Extracts the actual file descriptor without closing it.
pub fn into_raw(self) -> usize {
let fd = self.fd;
mem::forget(self);
fd
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
cvt(syscall::read(self.fd, buf))
}
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
let mut me = self;
(&mut me).read_to_end(buf)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
cvt(syscall::write(self.fd, buf))
}
pub fn duplicate(&self) -> io::Result<FileDesc> {
self.duplicate_path(&[])
}
pub fn duplicate_path(&self, path: &[u8]) -> io::Result<FileDesc> {
let new_fd = cvt(syscall::dup(self.fd, path))?;
Ok(FileDesc::new(new_fd))
}
pub fn nonblocking(&self) -> io::Result<bool> {
let flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFL, 0))?;
Ok(flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK)
}
pub fn set_cloexec(&self) -> io::Result<()> {
let mut flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFD, 0))?;
flags |= syscall::O_CLOEXEC;
cvt(syscall::fcntl(self.fd, syscall::F_SETFD, flags)).and(Ok(()))
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
let mut flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFL, 0))?;
if nonblocking {
flags |= syscall::O_NONBLOCK;
} else {
flags &= !syscall::O_NONBLOCK;
}
cvt(syscall::fcntl(self.fd, syscall::F_SETFL, flags)).and(Ok(()))
}
}
impl<'a> Read for &'a FileDesc {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf)
}
}
impl AsInner<usize> for FileDesc {
fn as_inner(&self) -> &usize { &self.fd }
}
impl Drop for FileDesc {
fn drop(&mut self) {
// Note that errors are ignored when closing a file descriptor. The
// reason for this is that if an error occurs we don't actually know if
// the file descriptor was closed or not, and if we retried (for
// something like EINTR), we might close another valid file descriptor
// (opened after we closed ours.
let _ = syscall::close(self.fd);
}
}
This diff is collapsed.
pub struct IoVec<'a>(&'a [u8]);
impl<'a> IoVec<'a> {
#[inline]
pub fn new(buf: &'a [u8]) -> IoVec<'a> {
IoVec(buf)
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
self.0
}
}
pub struct IoVecMut<'a>(&'a mut [u8]);
impl<'a> IoVecMut<'a> {
#[inline]
pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> {
IoVecMut(buf)
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
self.0
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
self.0
}
}
// Original implementation taken from rust-memchr.
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
pub use core::slice::memchr::{memchr, memrchr};
#![allow(dead_code, missing_docs, nonstandard_style)]
use crate::io::ErrorKind;
pub use libc::strlen;
pub use self::rand::hashmap_random_keys;
#[path = "../unix/alloc.rs"]
pub mod alloc;
pub mod args;
#[cfg(feature = "backtrace")]
pub mod backtrace;
pub mod cmath;
pub mod condvar;
pub mod env;
pub mod ext;
pub mod fast_thread_local;
pub mod fd;
pub mod fs;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod path;
pub mod pipe;
pub mod process;
pub mod rand;
pub mod rwlock;
pub mod stack_overflow;
pub mod stdio;
pub mod syscall;
pub mod thread;
pub mod thread_local;
pub mod time;
pub use crate::sys_common::os_str_bytes as os_str;
#[cfg(not(test))]
pub fn init() {}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
match errno {
syscall::ECONNREFUSED => ErrorKind::ConnectionRefused,
syscall::ECONNRESET => ErrorKind::ConnectionReset,
syscall::EPERM | syscall::EACCES => ErrorKind::PermissionDenied,
syscall::EPIPE => ErrorKind::BrokenPipe,
syscall::ENOTCONN => ErrorKind::NotConnected,
syscall::ECONNABORTED => ErrorKind::ConnectionAborted,
syscall::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
syscall::EADDRINUSE => ErrorKind::AddrInUse,
syscall::ENOENT => ErrorKind::NotFound,
syscall::EINTR => ErrorKind::Interrupted,
syscall::EINVAL => ErrorKind::InvalidInput,
syscall::ETIMEDOUT => ErrorKind::TimedOut,
syscall::EEXIST => ErrorKind::AlreadyExists,
// These two constants can have the same value on some systems,
// but different values on others, so we can't use a match
// clause
x if x == syscall::EAGAIN || x == syscall::EWOULDBLOCK =>
ErrorKind::WouldBlock,
_ => ErrorKind::Other,
}
}
pub fn cvt(result: Result<usize, syscall::Error>) -> crate::io::Result<usize> {
result.map_err(|err| crate::io::Error::from_raw_os_error(err.errno))
}
#[doc(hidden)]
pub trait IsMinusOne {
fn is_minus_one(&self) -> bool;
}
macro_rules! impl_is_minus_one {
($($t:ident)*) => ($(impl IsMinusOne for $t {
fn is_minus_one(&self) -> bool {
*self == -1
}
})*)
}
impl_is_minus_one! { i8 i16 i32 i64 isize }
pub fn cvt_libc<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
if t.is_minus_one() {
Err(crate::io::Error::last_os_error())
} else {
Ok(t)
}
}
/// On Redox, use an illegal instruction to abort
pub unsafe fn abort_internal() -> ! {