Auto merge of #106673 - flba-eb:add_qnx_nto_stdlib, r=workingjubilee
Add support for QNX Neutrino to standard library This change: - adds standard library support for QNX Neutrino (7.1). - upgrades `libc` to version `0.2.139` which supports QNX Neutrino `@gh-tr` ⚠️ Backtraces on QNX require https://github.com/rust-lang/backtrace-rs/pull/507 which is not yet merged! (But everything else works without these changes) ⚠️ Tested mainly with a x86_64 virtual machine (see qnx-nto.md) and partially with an aarch64 hardware (some tests fail due to constrained resources).
This commit is contained in:
commit
864b6258fc
43 changed files with 602 additions and 80 deletions
|
|
@ -69,7 +69,8 @@ impl DoubleEndedIterator for Args {
|
|||
target_os = "fuchsia",
|
||||
target_os = "redox",
|
||||
target_os = "vxworks",
|
||||
target_os = "horizon"
|
||||
target_os = "horizon",
|
||||
target_os = "nto",
|
||||
))]
|
||||
mod imp {
|
||||
use super::Args;
|
||||
|
|
|
|||
|
|
@ -185,6 +185,17 @@ pub mod os {
|
|||
pub const EXE_EXTENSION: &str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "nto")]
|
||||
pub mod os {
|
||||
pub const FAMILY: &str = "unix";
|
||||
pub const OS: &str = "nto";
|
||||
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 = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
pub mod os {
|
||||
pub const FAMILY: &str = "unix";
|
||||
|
|
|
|||
|
|
@ -53,7 +53,12 @@ const fn max_iov() -> usize {
|
|||
libc::IOV_MAX as usize
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "linux",
|
||||
target_os = "nto",
|
||||
))]
|
||||
const fn max_iov() -> usize {
|
||||
libc::UIO_MAXIOV as usize
|
||||
}
|
||||
|
|
@ -67,6 +72,7 @@ const fn max_iov() -> usize {
|
|||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "nto",
|
||||
target_os = "openbsd",
|
||||
target_os = "horizon",
|
||||
target_os = "watchos",
|
||||
|
|
@ -207,7 +213,8 @@ impl FileDesc {
|
|||
target_os = "linux",
|
||||
target_os = "haiku",
|
||||
target_os = "redox",
|
||||
target_os = "vxworks"
|
||||
target_os = "vxworks",
|
||||
target_os = "nto",
|
||||
)))]
|
||||
pub fn set_cloexec(&self) -> io::Result<()> {
|
||||
unsafe {
|
||||
|
|
@ -225,7 +232,8 @@ impl FileDesc {
|
|||
target_os = "linux",
|
||||
target_os = "haiku",
|
||||
target_os = "redox",
|
||||
target_os = "vxworks"
|
||||
target_os = "vxworks",
|
||||
target_os = "nto",
|
||||
))]
|
||||
pub fn set_cloexec(&self) -> io::Result<()> {
|
||||
unsafe {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ use crate::mem;
|
|||
target_os = "solaris",
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox",
|
||||
target_os = "illumos"
|
||||
target_os = "illumos",
|
||||
target_os = "nto",
|
||||
))]
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
|
||||
|
|
@ -54,7 +55,8 @@ use libc::fstatat64;
|
|||
target_os = "solaris",
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox",
|
||||
target_os = "illumos"
|
||||
target_os = "illumos",
|
||||
target_os = "nto",
|
||||
))]
|
||||
use libc::readdir as readdir64;
|
||||
#[cfg(target_os = "linux")]
|
||||
|
|
@ -69,7 +71,8 @@ use libc::readdir64_r;
|
|||
target_os = "illumos",
|
||||
target_os = "l4re",
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox"
|
||||
target_os = "redox",
|
||||
target_os = "nto",
|
||||
)))]
|
||||
use libc::readdir_r as readdir64_r;
|
||||
#[cfg(target_os = "android")]
|
||||
|
|
@ -277,7 +280,8 @@ unsafe impl Sync for Dir {}
|
|||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox"
|
||||
target_os = "redox",
|
||||
target_os = "nto",
|
||||
))]
|
||||
pub struct DirEntry {
|
||||
dir: Arc<InnerReadDir>,
|
||||
|
|
@ -297,11 +301,12 @@ pub struct DirEntry {
|
|||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox"
|
||||
target_os = "redox",
|
||||
target_os = "nto",
|
||||
))]
|
||||
struct dirent64_min {
|
||||
d_ino: u64,
|
||||
#[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
|
||||
#[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "nto")))]
|
||||
d_type: u8,
|
||||
}
|
||||
|
||||
|
|
@ -311,7 +316,8 @@ struct dirent64_min {
|
|||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox"
|
||||
target_os = "redox",
|
||||
target_os = "nto",
|
||||
)))]
|
||||
pub struct DirEntry {
|
||||
dir: Arc<InnerReadDir>,
|
||||
|
|
@ -438,7 +444,7 @@ impl FileAttr {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "netbsd"))]
|
||||
#[cfg(not(any(target_os = "netbsd", target_os = "nto")))]
|
||||
impl FileAttr {
|
||||
#[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))]
|
||||
pub fn modified(&self) -> io::Result<SystemTime> {
|
||||
|
|
@ -524,6 +530,21 @@ impl FileAttr {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "nto")]
|
||||
impl FileAttr {
|
||||
pub fn modified(&self) -> io::Result<SystemTime> {
|
||||
Ok(SystemTime::new(self.stat.st_mtim.tv_sec, self.stat.st_mtim.tv_nsec))
|
||||
}
|
||||
|
||||
pub fn accessed(&self) -> io::Result<SystemTime> {
|
||||
Ok(SystemTime::new(self.stat.st_atim.tv_sec, self.stat.st_atim.tv_nsec))
|
||||
}
|
||||
|
||||
pub fn created(&self) -> io::Result<SystemTime> {
|
||||
Ok(SystemTime::new(self.stat.st_ctim.tv_sec, self.stat.st_ctim.tv_nsec))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<stat64> for FileAttr {
|
||||
fn as_inner(&self) -> &stat64 {
|
||||
&self.stat
|
||||
|
|
@ -603,7 +624,8 @@ impl Iterator for ReadDir {
|
|||
target_os = "solaris",
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox",
|
||||
target_os = "illumos"
|
||||
target_os = "illumos",
|
||||
target_os = "nto",
|
||||
))]
|
||||
fn next(&mut self) -> Option<io::Result<DirEntry>> {
|
||||
if self.end_of_stream {
|
||||
|
|
@ -686,7 +708,11 @@ impl Iterator for ReadDir {
|
|||
|
||||
let entry = dirent64_min {
|
||||
d_ino: *offset_ptr!(entry_ptr, d_ino) as u64,
|
||||
#[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
|
||||
#[cfg(not(any(
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "nto",
|
||||
)))]
|
||||
d_type: *offset_ptr!(entry_ptr, d_type) as u8,
|
||||
};
|
||||
|
||||
|
|
@ -705,7 +731,8 @@ impl Iterator for ReadDir {
|
|||
target_os = "solaris",
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox",
|
||||
target_os = "illumos"
|
||||
target_os = "illumos",
|
||||
target_os = "nto",
|
||||
)))]
|
||||
fn next(&mut self) -> Option<io::Result<DirEntry>> {
|
||||
if self.end_of_stream {
|
||||
|
|
@ -794,7 +821,8 @@ impl DirEntry {
|
|||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "haiku",
|
||||
target_os = "vxworks"
|
||||
target_os = "vxworks",
|
||||
target_os = "nto",
|
||||
))]
|
||||
pub fn file_type(&self) -> io::Result<FileType> {
|
||||
self.metadata().map(|m| m.file_type())
|
||||
|
|
@ -804,7 +832,8 @@ impl DirEntry {
|
|||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "haiku",
|
||||
target_os = "vxworks"
|
||||
target_os = "vxworks",
|
||||
target_os = "nto",
|
||||
)))]
|
||||
pub fn file_type(&self) -> io::Result<FileType> {
|
||||
match self.entry.d_type {
|
||||
|
|
@ -834,7 +863,8 @@ impl DirEntry {
|
|||
target_os = "redox",
|
||||
target_os = "vxworks",
|
||||
target_os = "espidf",
|
||||
target_os = "horizon"
|
||||
target_os = "horizon",
|
||||
target_os = "nto",
|
||||
))]
|
||||
pub fn ino(&self) -> u64 {
|
||||
self.entry.d_ino as u64
|
||||
|
|
@ -887,7 +917,8 @@ impl DirEntry {
|
|||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox"
|
||||
target_os = "redox",
|
||||
target_os = "nto",
|
||||
)))]
|
||||
fn name_cstr(&self) -> &CStr {
|
||||
unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
|
||||
|
|
@ -898,7 +929,8 @@ impl DirEntry {
|
|||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox"
|
||||
target_os = "redox",
|
||||
target_os = "nto",
|
||||
))]
|
||||
fn name_cstr(&self) -> &CStr {
|
||||
&self.name
|
||||
|
|
@ -1051,7 +1083,8 @@ impl File {
|
|||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
target_os = "openbsd",
|
||||
target_os = "nto",
|
||||
))]
|
||||
unsafe fn os_datasync(fd: c_int) -> c_int {
|
||||
libc::fdatasync(fd)
|
||||
|
|
@ -1065,6 +1098,7 @@ impl File {
|
|||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "watchos",
|
||||
target_os = "nto",
|
||||
)))]
|
||||
unsafe fn os_datasync(fd: c_int) -> c_int {
|
||||
libc::fsync(fd)
|
||||
|
|
@ -1750,13 +1784,25 @@ pub fn chroot(dir: &Path) -> io::Result<()> {
|
|||
pub use remove_dir_impl::remove_dir_all;
|
||||
|
||||
// Fallback for REDOX, ESP-ID, Horizon, and Miri
|
||||
#[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", miri))]
|
||||
#[cfg(any(
|
||||
target_os = "redox",
|
||||
target_os = "espidf",
|
||||
target_os = "horizon",
|
||||
target_os = "nto",
|
||||
miri
|
||||
))]
|
||||
mod remove_dir_impl {
|
||||
pub use crate::sys_common::fs::remove_dir_all;
|
||||
}
|
||||
|
||||
// Modern implementation using openat(), unlinkat() and fdopendir()
|
||||
#[cfg(not(any(target_os = "redox", target_os = "espidf", target_os = "horizon", miri)))]
|
||||
#[cfg(not(any(
|
||||
target_os = "redox",
|
||||
target_os = "espidf",
|
||||
target_os = "horizon",
|
||||
target_os = "nto",
|
||||
miri
|
||||
)))]
|
||||
mod remove_dir_impl {
|
||||
use super::{lstat, Dir, DirEntry, InnerReadDir, ReadDir};
|
||||
use crate::ffi::CStr;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@ use crate::cell::UnsafeCell;
|
|||
use crate::ptr;
|
||||
use crate::sync::atomic::{AtomicPtr, Ordering::Relaxed};
|
||||
use crate::sys::locks::{pthread_mutex, Mutex};
|
||||
#[cfg(not(target_os = "nto"))]
|
||||
use crate::sys::time::TIMESPEC_MAX;
|
||||
#[cfg(target_os = "nto")]
|
||||
use crate::sys::time::TIMESPEC_MAX_CAPPED;
|
||||
use crate::sys_common::lazy_box::{LazyBox, LazyInit};
|
||||
use crate::time::Duration;
|
||||
|
||||
|
|
@ -132,10 +135,18 @@ impl Condvar {
|
|||
let mutex = pthread_mutex::raw(mutex);
|
||||
self.verify(mutex);
|
||||
|
||||
#[cfg(not(target_os = "nto"))]
|
||||
let timeout = Timespec::now(libc::CLOCK_MONOTONIC)
|
||||
.checked_add_duration(&dur)
|
||||
.and_then(|t| t.to_timespec())
|
||||
.unwrap_or(TIMESPEC_MAX);
|
||||
|
||||
#[cfg(target_os = "nto")]
|
||||
let timeout = Timespec::now(libc::CLOCK_MONOTONIC)
|
||||
.checked_add_duration(&dur)
|
||||
.and_then(|t| t.to_timespec_capped())
|
||||
.unwrap_or(TIMESPEC_MAX_CAPPED);
|
||||
|
||||
let r = libc::pthread_cond_timedwait(raw(self), mutex, &timeout);
|
||||
assert!(r == libc::ETIMEDOUT || r == 0);
|
||||
r == 0
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ impl Socket {
|
|||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "nto",
|
||||
))] {
|
||||
// On platforms that support it we pass the SOCK_CLOEXEC
|
||||
// flag to atomically create the socket and set it as
|
||||
|
|
@ -115,6 +116,7 @@ impl Socket {
|
|||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "nto",
|
||||
))] {
|
||||
// Like above, set cloexec atomically
|
||||
cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?;
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ extern "C" {
|
|||
link_name = "__errno"
|
||||
)]
|
||||
#[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")]
|
||||
#[cfg_attr(target_os = "nto", link_name = "__get_errno_ptr")]
|
||||
#[cfg_attr(
|
||||
any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "watchos"),
|
||||
link_name = "__error"
|
||||
|
|
@ -361,6 +362,17 @@ pub fn current_exe() -> io::Result<PathBuf> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "nto")]
|
||||
pub fn current_exe() -> io::Result<PathBuf> {
|
||||
let mut e = crate::fs::read("/proc/self/exefile")?;
|
||||
// Current versions of QNX Neutrino provide a null-terminated path.
|
||||
// Ensure the trailing null byte is not returned here.
|
||||
if let Some(0) = e.last() {
|
||||
e.pop();
|
||||
}
|
||||
Ok(PathBuf::from(OsString::from_vec(e)))
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
|
||||
pub fn current_exe() -> io::Result<PathBuf> {
|
||||
unsafe {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use crate::sys::weak::raw_syscall;
|
|||
target_os = "freebsd",
|
||||
all(target_os = "linux", target_env = "gnu"),
|
||||
all(target_os = "linux", target_env = "musl"),
|
||||
target_os = "nto",
|
||||
))]
|
||||
use crate::sys::weak::weak;
|
||||
|
||||
|
|
@ -30,6 +31,15 @@ use libc::{c_int, pid_t};
|
|||
#[cfg(not(any(target_os = "vxworks", target_os = "l4re")))]
|
||||
use libc::{gid_t, uid_t};
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(target_os = "nto", target_env = "nto71"))] {
|
||||
use crate::thread;
|
||||
use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t};
|
||||
// arbitrary number of tries:
|
||||
const MAX_FORKSPAWN_TRIES: u32 = 4;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Command
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -140,11 +150,31 @@ impl Command {
|
|||
|
||||
// Attempts to fork the process. If successful, returns Ok((0, -1))
|
||||
// in the child, and Ok((child_pid, -1)) in the parent.
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
#[cfg(not(any(target_os = "linux", all(target_os = "nto", target_env = "nto71"))))]
|
||||
unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
|
||||
cvt(libc::fork()).map(|res| (res, -1))
|
||||
}
|
||||
|
||||
// On QNX Neutrino, fork can fail with EBADF in case "another thread might have opened
|
||||
// or closed a file descriptor while the fork() was occurring".
|
||||
// Documentation says "... or try calling fork() again". This is what we do here.
|
||||
// See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html
|
||||
#[cfg(all(target_os = "nto", target_env = "nto71"))]
|
||||
unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
|
||||
use crate::sys::os::errno;
|
||||
|
||||
let mut tries_left = MAX_FORKSPAWN_TRIES;
|
||||
loop {
|
||||
let r = libc::fork();
|
||||
if r == -1 as libc::pid_t && tries_left > 0 && errno() as libc::c_int == libc::EBADF {
|
||||
thread::yield_now();
|
||||
tries_left -= 1;
|
||||
} else {
|
||||
return cvt(r).map(|res| (res, -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempts to fork the process. If successful, returns Ok((0, -1))
|
||||
// in the child, and Ok((child_pid, child_pidfd)) in the parent.
|
||||
#[cfg(target_os = "linux")]
|
||||
|
|
@ -389,6 +419,7 @@ impl Command {
|
|||
target_os = "freebsd",
|
||||
all(target_os = "linux", target_env = "gnu"),
|
||||
all(target_os = "linux", target_env = "musl"),
|
||||
target_os = "nto",
|
||||
)))]
|
||||
fn posix_spawn(
|
||||
&mut self,
|
||||
|
|
@ -405,6 +436,7 @@ impl Command {
|
|||
target_os = "freebsd",
|
||||
all(target_os = "linux", target_env = "gnu"),
|
||||
all(target_os = "linux", target_env = "musl"),
|
||||
target_os = "nto",
|
||||
))]
|
||||
fn posix_spawn(
|
||||
&mut self,
|
||||
|
|
@ -436,6 +468,34 @@ impl Command {
|
|||
}
|
||||
}
|
||||
|
||||
// On QNX Neutrino, posix_spawnp can fail with EBADF in case "another thread might have opened
|
||||
// or closed a file descriptor while the posix_spawn() was occurring".
|
||||
// Documentation says "... or try calling posix_spawn() again". This is what we do here.
|
||||
// See also http://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/p/posix_spawn.html
|
||||
#[cfg(all(target_os = "nto", target_env = "nto71"))]
|
||||
unsafe fn retrying_libc_posix_spawnp(
|
||||
pid: *mut pid_t,
|
||||
file: *const c_char,
|
||||
file_actions: *const posix_spawn_file_actions_t,
|
||||
attrp: *const posix_spawnattr_t,
|
||||
argv: *const *mut c_char,
|
||||
envp: *const *mut c_char,
|
||||
) -> i32 {
|
||||
let mut tries_left = MAX_FORKSPAWN_TRIES;
|
||||
loop {
|
||||
match libc::posix_spawnp(pid, file, file_actions, attrp, argv, envp) {
|
||||
libc::EBADF if tries_left > 0 => {
|
||||
thread::yield_now();
|
||||
tries_left -= 1;
|
||||
continue;
|
||||
}
|
||||
r => {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Solaris, glibc 2.29+, and musl 1.24+ can set a new working directory,
|
||||
// and maybe others will gain this non-POSIX function too. We'll check
|
||||
// for this weak symbol as soon as it's needed, so we can return early
|
||||
|
|
@ -555,7 +615,12 @@ impl Command {
|
|||
// Make sure we synchronize access to the global `environ` resource
|
||||
let _env_lock = sys::os::env_read_lock();
|
||||
let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _);
|
||||
cvt_nz(libc::posix_spawnp(
|
||||
|
||||
#[cfg(not(target_os = "nto"))]
|
||||
let spawn_fn = libc::posix_spawnp;
|
||||
#[cfg(target_os = "nto")]
|
||||
let spawn_fn = retrying_libc_posix_spawnp;
|
||||
cvt_nz(spawn_fn(
|
||||
&mut p.pid,
|
||||
self.get_program_cstr().as_ptr(),
|
||||
file_actions.0.as_ptr(),
|
||||
|
|
@ -760,7 +825,7 @@ fn signal_string(signal: i32) -> &'static str {
|
|||
)
|
||||
))]
|
||||
libc::SIGSTKFLT => " (SIGSTKFLT)",
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_os = "linux", target_os = "nto"))]
|
||||
libc::SIGPWR => " (SIGPWR)",
|
||||
#[cfg(any(
|
||||
target_os = "macos",
|
||||
|
|
@ -769,7 +834,8 @@ fn signal_string(signal: i32) -> &'static str {
|
|||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "dragonfly"
|
||||
target_os = "dragonfly",
|
||||
target_os = "nto",
|
||||
))]
|
||||
libc::SIGEMT => " (SIGEMT)",
|
||||
#[cfg(any(
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use crate::time::Duration;
|
|||
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu"))]
|
||||
use crate::sys::weak::dlsym;
|
||||
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
|
||||
#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))]
|
||||
use crate::sys::weak::weak;
|
||||
#[cfg(not(any(target_os = "l4re", target_os = "vxworks", target_os = "espidf")))]
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
|
||||
|
|
@ -173,7 +173,7 @@ impl Thread {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
|
||||
#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))]
|
||||
pub fn set_name(name: &CStr) {
|
||||
weak! {
|
||||
fn pthread_setname_np(
|
||||
|
|
@ -381,6 +381,17 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
|
|||
}
|
||||
|
||||
Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
|
||||
} else if #[cfg(target_os = "nto")] {
|
||||
unsafe {
|
||||
use libc::_syspage_ptr;
|
||||
if _syspage_ptr.is_null() {
|
||||
Err(io::const_io_error!(io::ErrorKind::NotFound, "No syspage available"))
|
||||
} else {
|
||||
let cpus = (*_syspage_ptr).num_cpu;
|
||||
NonZeroUsize::new(cpus as usize)
|
||||
.ok_or(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"))
|
||||
}
|
||||
}
|
||||
} else if #[cfg(target_os = "haiku")] {
|
||||
// system_info cpu_count field gets the static data set at boot time with `smp_set_num_cpus`
|
||||
// `get_system_info` calls then `smp_get_num_cpus`
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ use crate::pin::Pin;
|
|||
use crate::ptr::addr_of_mut;
|
||||
use crate::sync::atomic::AtomicUsize;
|
||||
use crate::sync::atomic::Ordering::SeqCst;
|
||||
#[cfg(not(target_os = "nto"))]
|
||||
use crate::sys::time::TIMESPEC_MAX;
|
||||
#[cfg(target_os = "nto")]
|
||||
use crate::sys::time::TIMESPEC_MAX_CAPPED;
|
||||
use crate::time::Duration;
|
||||
|
||||
const EMPTY: usize = 0;
|
||||
|
|
@ -80,8 +83,14 @@ unsafe fn wait_timeout(
|
|||
(Timespec::now(libc::CLOCK_MONOTONIC), dur)
|
||||
};
|
||||
|
||||
#[cfg(not(target_os = "nto"))]
|
||||
let timeout =
|
||||
now.checked_add_duration(&dur).and_then(|t| t.to_timespec()).unwrap_or(TIMESPEC_MAX);
|
||||
#[cfg(target_os = "nto")]
|
||||
let timeout = now
|
||||
.checked_add_duration(&dur)
|
||||
.and_then(|t| t.to_timespec_capped())
|
||||
.unwrap_or(TIMESPEC_MAX_CAPPED);
|
||||
let r = libc::pthread_cond_timedwait(cond, lock, &timeout);
|
||||
debug_assert!(r == libc::ETIMEDOUT || r == 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,14 @@ pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
|
|||
pub const TIMESPEC_MAX: libc::timespec =
|
||||
libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 };
|
||||
|
||||
// This additional constant is only used when calling
|
||||
// `libc::pthread_cond_timedwait`.
|
||||
#[cfg(target_os = "nto")]
|
||||
pub(super) const TIMESPEC_MAX_CAPPED: libc::timespec = libc::timespec {
|
||||
tv_sec: (u64::MAX / NSEC_PER_SEC) as i64,
|
||||
tv_nsec: (u64::MAX % NSEC_PER_SEC) as i64,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(transparent)]
|
||||
#[rustc_layout_scalar_valid_range_start(0)]
|
||||
|
|
@ -144,6 +152,20 @@ impl Timespec {
|
|||
tv_nsec: self.tv_nsec.0.try_into().ok()?,
|
||||
})
|
||||
}
|
||||
|
||||
// On QNX Neutrino, the maximum timespec for e.g. pthread_cond_timedwait
|
||||
// is 2^64 nanoseconds
|
||||
#[cfg(target_os = "nto")]
|
||||
pub(super) fn to_timespec_capped(&self) -> Option<libc::timespec> {
|
||||
// Check if timeout in nanoseconds would fit into an u64
|
||||
if (self.tv_nsec.0 as u64)
|
||||
.checked_add((self.tv_sec as u64).checked_mul(NSEC_PER_SEC)?)
|
||||
.is_none()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
self.to_timespec()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<libc::timespec> for Timespec {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue