chore: commit durable overlay state (configs, patches, recipe symlinks)
Pre-existing work from other sessions committed as durable state: - local/config/drivers.d/ (8 driver configs) - local/config/firmware-fallbacks.d/ (3 firmware configs) - local/patches/base/, kernel/, relibc/ (new patch carriers) - recipes/system/ symlinks (driver-params, acmd, ecmd, usbaudiod) pkgar build artifacts and cache intentionally excluded.
This commit is contained in:
@@ -0,0 +1,359 @@
|
||||
diff --git a/src/header/pthread/mod.rs b/src/header/pthread/mod.rs
|
||||
index c742a42..03c4043 100644
|
||||
--- a/src/header/pthread/mod.rs
|
||||
+++ b/src/header/pthread/mod.rs
|
||||
@@ -3,15 +3,26 @@
|
||||
//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/pthread.h.html>.
|
||||
|
||||
use alloc::collections::LinkedList;
|
||||
-use core::{cell::Cell, ptr::NonNull};
|
||||
+use core::{cell::Cell, mem::size_of, ptr::NonNull};
|
||||
+
|
||||
+#[cfg(target_os = "redox")]
|
||||
+use redox_rt::proc::FdGuard;
|
||||
+#[cfg(target_os = "linux")]
|
||||
+use sc::syscall;
|
||||
+#[cfg(target_os = "redox")]
|
||||
+use syscall;
|
||||
|
||||
use crate::{
|
||||
error::Errno,
|
||||
- header::{bits_timespec::timespec, sched::*},
|
||||
+ header::{
|
||||
+ bits_timespec::timespec,
|
||||
+ errno::{EINVAL, ERANGE},
|
||||
+ sched::*,
|
||||
+ },
|
||||
platform::{
|
||||
Pal, Sys,
|
||||
types::{
|
||||
- c_int, c_uchar, c_uint, c_void, clockid_t, pthread_attr_t, pthread_barrier_t,
|
||||
+ c_char, c_int, c_uchar, c_uint, c_void, clockid_t, pthread_attr_t, pthread_barrier_t,
|
||||
pthread_barrierattr_t, pthread_cond_t, pthread_condattr_t, pthread_key_t,
|
||||
pthread_mutex_t, pthread_mutexattr_t, pthread_once_t, pthread_rwlock_t,
|
||||
pthread_rwlockattr_t, pthread_spinlock_t, pthread_t, size_t,
|
||||
@@ -20,6 +31,9 @@ use crate::{
|
||||
pthread,
|
||||
};
|
||||
|
||||
+#[cfg(target_os = "linux")]
|
||||
+use crate::platform::sys::e_raw;
|
||||
+
|
||||
pub fn e(result: Result<(), Errno>) -> i32 {
|
||||
match result {
|
||||
Ok(()) => 0,
|
||||
@@ -27,6 +41,96 @@ pub fn e(result: Result<(), Errno>) -> i32 {
|
||||
}
|
||||
}
|
||||
|
||||
+const RLCT_AFFINITY_BYTES: usize = size_of::<u64>();
|
||||
+const RLCT_MAX_AFFINITY_CPUS: usize = u64::BITS as usize;
|
||||
+
|
||||
+fn cpuset_bytes<'a>(cpusetsize: size_t, cpuset: *const cpu_set_t) -> Result<&'a [u8], Errno> {
|
||||
+ if cpuset.is_null() || !(RLCT_AFFINITY_BYTES..=size_of::<cpu_set_t>()).contains(&cpusetsize) {
|
||||
+ return Err(Errno(EINVAL));
|
||||
+ }
|
||||
+
|
||||
+ Ok(unsafe { core::slice::from_raw_parts(cpuset.cast::<u8>(), cpusetsize) })
|
||||
+}
|
||||
+
|
||||
+fn cpuset_bytes_mut<'a>(cpusetsize: size_t, cpuset: *mut cpu_set_t) -> Result<&'a mut [u8], Errno> {
|
||||
+ if cpuset.is_null() || !(RLCT_AFFINITY_BYTES..=size_of::<cpu_set_t>()).contains(&cpusetsize) {
|
||||
+ return Err(Errno(EINVAL));
|
||||
+ }
|
||||
+
|
||||
+ Ok(unsafe { core::slice::from_raw_parts_mut(cpuset.cast::<u8>(), cpusetsize) })
|
||||
+}
|
||||
+
|
||||
+fn cpuset_to_u64(cpusetsize: size_t, cpuset: *const cpu_set_t) -> Result<u64, Errno> {
|
||||
+ let bytes = cpuset_bytes(cpusetsize, cpuset)?;
|
||||
+ let mut mask = 0_u64;
|
||||
+
|
||||
+ for (byte_index, byte) in bytes.iter().copied().enumerate() {
|
||||
+ for bit in 0..u8::BITS as usize {
|
||||
+ if byte & (1 << bit) == 0 {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ let cpu = byte_index * u8::BITS as usize + bit;
|
||||
+ if cpu >= RLCT_MAX_AFFINITY_CPUS {
|
||||
+ return Err(Errno(EINVAL));
|
||||
+ }
|
||||
+
|
||||
+ mask |= 1_u64 << cpu;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ Ok(mask)
|
||||
+}
|
||||
+
|
||||
+fn copy_u64_to_cpuset(mask: u64, cpusetsize: size_t, cpuset: *mut cpu_set_t) -> Result<(), Errno> {
|
||||
+ let bytes = cpuset_bytes_mut(cpusetsize, cpuset)?;
|
||||
+ bytes.fill(0);
|
||||
+
|
||||
+ for (byte_index, dst) in bytes.iter_mut().take(RLCT_AFFINITY_BYTES).enumerate() {
|
||||
+ *dst = (mask >> (byte_index * u8::BITS as usize)) as u8;
|
||||
+ }
|
||||
+
|
||||
+ Ok(())
|
||||
+}
|
||||
+
|
||||
+#[cfg(target_os = "redox")]
|
||||
+fn redox_set_thread_affinity(thread: &pthread::Pthread, mask: u64) -> Result<(), Errno> {
|
||||
+ let mut kernel_cpuset = cpu_set_t::default();
|
||||
+ kernel_cpuset.__bits[0] = mask;
|
||||
+
|
||||
+ let handle = FdGuard::new(unsafe {
|
||||
+ syscall::dup(thread.os_tid.get().read().thread_fd, b"sched-affinity")?
|
||||
+ });
|
||||
+ let _ = handle.write(unsafe {
|
||||
+ core::slice::from_raw_parts(
|
||||
+ core::ptr::from_ref(&kernel_cpuset).cast::<u8>(),
|
||||
+ size_of::<cpu_set_t>(),
|
||||
+ )
|
||||
+ })?;
|
||||
+
|
||||
+ Ok(())
|
||||
+}
|
||||
+
|
||||
+#[cfg(target_os = "redox")]
|
||||
+fn redox_get_thread_affinity(thread: &pthread::Pthread) -> Result<u64, Errno> {
|
||||
+ let handle = FdGuard::new(unsafe {
|
||||
+ syscall::dup(thread.os_tid.get().read().thread_fd, b"sched-affinity")?
|
||||
+ });
|
||||
+ let mut kernel_cpuset = cpu_set_t::default();
|
||||
+ let _ = handle.read(unsafe {
|
||||
+ core::slice::from_raw_parts_mut(
|
||||
+ core::ptr::from_mut(&mut kernel_cpuset).cast::<u8>(),
|
||||
+ size_of::<cpu_set_t>(),
|
||||
+ )
|
||||
+ })?;
|
||||
+
|
||||
+ if kernel_cpuset.__bits[1..].iter().any(|bits| *bits != 0) {
|
||||
+ return Err(Errno(EINVAL));
|
||||
+ }
|
||||
+
|
||||
+ Ok(kernel_cpuset.__bits[0])
|
||||
+}
|
||||
+
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct RlctAttr {
|
||||
pub detachstate: c_uchar,
|
||||
@@ -186,6 +290,43 @@ pub unsafe extern "C" fn pthread_getcpuclockid(
|
||||
}
|
||||
}
|
||||
|
||||
+/// GNU extension. See <https://man7.org/linux/man-pages/man3/pthread_setaffinity_np.3.html>.
|
||||
+#[unsafe(no_mangle)]
|
||||
+pub unsafe extern "C" fn pthread_getaffinity_np(
|
||||
+ thread: pthread_t,
|
||||
+ cpusetsize: size_t,
|
||||
+ cpuset: *mut cpu_set_t,
|
||||
+) -> c_int {
|
||||
+ let thread: &pthread::Pthread = unsafe { &*thread.cast() };
|
||||
+
|
||||
+ let result = {
|
||||
+ #[cfg(target_os = "redox")]
|
||||
+ {
|
||||
+ redox_get_thread_affinity(thread)
|
||||
+ .and_then(|mask| copy_u64_to_cpuset(mask, cpusetsize, cpuset))
|
||||
+ }
|
||||
+
|
||||
+ #[cfg(target_os = "linux")]
|
||||
+ {
|
||||
+ if cpuset.is_null() {
|
||||
+ Err(Errno(EINVAL))
|
||||
+ } else {
|
||||
+ e_raw(unsafe {
|
||||
+ syscall!(
|
||||
+ SCHED_GETAFFINITY,
|
||||
+ thread.os_tid.get().read().thread_id,
|
||||
+ cpusetsize,
|
||||
+ cpuset.cast::<c_void>()
|
||||
+ )
|
||||
+ })
|
||||
+ .map(|_| ())
|
||||
+ }
|
||||
+ }
|
||||
+ };
|
||||
+
|
||||
+ e(result)
|
||||
+}
|
||||
+
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_getschedparam.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn pthread_getschedparam(
|
||||
@@ -235,6 +376,43 @@ pub unsafe extern "C" fn pthread_self() -> pthread_t {
|
||||
core::ptr::from_ref(unsafe { pthread::current_thread().unwrap_unchecked() }) as *mut _
|
||||
}
|
||||
|
||||
+/// GNU extension. See <https://man7.org/linux/man-pages/man3/pthread_setaffinity_np.3.html>.
|
||||
+#[unsafe(no_mangle)]
|
||||
+pub unsafe extern "C" fn pthread_setaffinity_np(
|
||||
+ thread: pthread_t,
|
||||
+ cpusetsize: size_t,
|
||||
+ cpuset: *const cpu_set_t,
|
||||
+) -> c_int {
|
||||
+ let thread: &pthread::Pthread = unsafe { &*thread.cast() };
|
||||
+
|
||||
+ let result = {
|
||||
+ #[cfg(target_os = "redox")]
|
||||
+ {
|
||||
+ cpuset_to_u64(cpusetsize, cpuset)
|
||||
+ .and_then(|mask| redox_set_thread_affinity(thread, mask))
|
||||
+ }
|
||||
+
|
||||
+ #[cfg(target_os = "linux")]
|
||||
+ {
|
||||
+ if cpuset.is_null() {
|
||||
+ Err(Errno(EINVAL))
|
||||
+ } else {
|
||||
+ e_raw(unsafe {
|
||||
+ syscall!(
|
||||
+ SCHED_SETAFFINITY,
|
||||
+ thread.os_tid.get().read().thread_id,
|
||||
+ cpusetsize,
|
||||
+ cpuset.cast::<c_void>()
|
||||
+ )
|
||||
+ })
|
||||
+ .map(|_| ())
|
||||
+ }
|
||||
+ }
|
||||
+ };
|
||||
+
|
||||
+ e(result)
|
||||
+}
|
||||
+
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_setcancelstate.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn pthread_setcancelstate(state: c_int, oldstate: *mut c_int) -> c_int {
|
||||
@@ -307,6 +485,13 @@ pub unsafe extern "C" fn pthread_testcancel() {
|
||||
unsafe { pthread::testcancel() };
|
||||
}
|
||||
|
||||
+/// <https://man7.org/linux/man-pages/man3/pthread_yield.3.html>
|
||||
+///
|
||||
+/// Non-standard GNU extension. Prefer `sched_yield()` instead.
|
||||
+pub extern "C" fn pthread_yield() {
|
||||
+ let _ = Sys::sched_yield();
|
||||
+}
|
||||
+
|
||||
// Must be the same struct as defined in the pthread_cleanup_push macro.
|
||||
#[repr(C)]
|
||||
pub(crate) struct CleanupLinkedListEntry {
|
||||
@@ -350,3 +535,84 @@ pub(crate) unsafe fn run_destructor_stack() {
|
||||
(entry.routine)(entry.arg);
|
||||
}
|
||||
}
|
||||
+
|
||||
+#[unsafe(no_mangle)]
|
||||
+pub unsafe extern "C" fn pthread_setname_np(thread: pthread_t, name: *const c_char) -> c_int {
|
||||
+ if name.is_null() {
|
||||
+ return EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ let cstr = unsafe { core::ffi::CStr::from_ptr(name) };
|
||||
+ let name_bytes = cstr.to_bytes();
|
||||
+ let len = name_bytes.len().min(31);
|
||||
+
|
||||
+ #[cfg(target_os = "redox")]
|
||||
+ {
|
||||
+ let thread = unsafe { &*thread.cast::<crate::pthread::Pthread>() };
|
||||
+ let os_tid = unsafe { thread.os_tid.get().read() };
|
||||
+ let path = alloc::format!("proc:{}/name\0", os_tid.thread_fd);
|
||||
+ let path_cstr = core::ffi::CStr::from_bytes_with_nul(path.as_bytes()).unwrap();
|
||||
+ let fd = match Sys::open(path_cstr.into(), crate::header::fcntl::O_WRONLY, 0) {
|
||||
+ Ok(fd) => fd,
|
||||
+ Err(Errno(code)) => return code,
|
||||
+ };
|
||||
+
|
||||
+ let result = match Sys::write(fd, &name_bytes[..len]) {
|
||||
+ Ok(written) if written == len => 0,
|
||||
+ Ok(_) => crate::header::errno::EIO,
|
||||
+ Err(Errno(code)) => code,
|
||||
+ };
|
||||
+ let _ = Sys::close(fd);
|
||||
+ result
|
||||
+ }
|
||||
+ #[cfg(not(target_os = "redox"))]
|
||||
+ {
|
||||
+ let _ = thread;
|
||||
+ 0
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#[unsafe(no_mangle)]
|
||||
+pub unsafe extern "C" fn pthread_getname_np(
|
||||
+ thread: pthread_t,
|
||||
+ name: *mut c_char,
|
||||
+ len: size_t,
|
||||
+) -> c_int {
|
||||
+ if name.is_null() {
|
||||
+ return EINVAL;
|
||||
+ }
|
||||
+ if len == 0 {
|
||||
+ return ERANGE;
|
||||
+ }
|
||||
+
|
||||
+ #[cfg(target_os = "redox")]
|
||||
+ {
|
||||
+ let thread = unsafe { &*thread.cast::<crate::pthread::Pthread>() };
|
||||
+ let os_tid = unsafe { thread.os_tid.get().read() };
|
||||
+ let path = alloc::format!("proc:{}/name\0", os_tid.thread_fd);
|
||||
+ let path_cstr = core::ffi::CStr::from_bytes_with_nul(path.as_bytes()).unwrap();
|
||||
+ let fd = match Sys::open(path_cstr.into(), crate::header::fcntl::O_RDONLY, 0) {
|
||||
+ Ok(fd) => fd,
|
||||
+ Err(Errno(code)) => return code,
|
||||
+ };
|
||||
+
|
||||
+ let mut buf = [0u8; 31];
|
||||
+ let result = match Sys::read(fd, &mut buf) {
|
||||
+ Ok(read) if read < len => {
|
||||
+ unsafe { core::ptr::copy_nonoverlapping(buf.as_ptr(), name.cast(), read) };
|
||||
+ unsafe { *name.add(read) = 0 };
|
||||
+ 0
|
||||
+ }
|
||||
+ Ok(_) => ERANGE,
|
||||
+ Err(Errno(code)) => code,
|
||||
+ };
|
||||
+ let _ = Sys::close(fd);
|
||||
+ result
|
||||
+ }
|
||||
+ #[cfg(not(target_os = "redox"))]
|
||||
+ {
|
||||
+ let _ = thread;
|
||||
+ unsafe { *name = 0 };
|
||||
+ 0
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/header/sched/cbindgen.toml b/src/header/sched/cbindgen.toml
|
||||
index b361fa4..d6d959d 100644
|
||||
--- a/src/header/sched/cbindgen.toml
|
||||
+++ b/src/header/sched/cbindgen.toml
|
||||
@@ -5,7 +5,7 @@
|
||||
# - "[SS|TSP] The <sched.h> header shall define the time_t type as described in <sys/types.h>."
|
||||
# - "The <sched.h> header shall define the timespec structure as described in <time.h>."
|
||||
# - "Inclusion of the <sched.h> header may make visible all symbols from the <time.h> header."
|
||||
-sys_includes = ["sys/types.h"]
|
||||
+sys_includes = ["sys/types.h", "stdint.h"]
|
||||
include_guard = "_RELIBC_SCHED_H"
|
||||
after_includes = """
|
||||
#include <bits/timespec.h> // for timespec
|
||||
@@ -20,3 +20,17 @@ prefix_with_name = true
|
||||
|
||||
[export.rename]
|
||||
"timespec" = "struct timespec"
|
||||
+
|
||||
+[export]
|
||||
+include = [
|
||||
+ "sched_param",
|
||||
+ "cpu_set_t",
|
||||
+ "sched_get_priority_max",
|
||||
+ "sched_get_priority_min",
|
||||
+ "sched_getparam",
|
||||
+ "sched_getscheduler",
|
||||
+ "sched_rr_get_interval",
|
||||
+ "sched_setparam",
|
||||
+ "sched_setscheduler",
|
||||
+ "sched_yield",
|
||||
+]
|
||||
@@ -0,0 +1,69 @@
|
||||
diff --git a/src/header/spawn/cbindgen.toml b/src/header/spawn/cbindgen.toml
|
||||
new file mode 100644
|
||||
index 0000000..a9f188f
|
||||
--- /dev/null
|
||||
+++ b/src/header/spawn/cbindgen.toml
|
||||
@@ -0,0 +1,63 @@
|
||||
+sys_includes = ["sys/types.h", "signal.h", "sched.h"]
|
||||
+include_guard = "_SPAWN_H"
|
||||
+after_includes = """
|
||||
+typedef struct {
|
||||
+ short __flags;
|
||||
+ pid_t __pgrp;
|
||||
+ sigset_t __sd;
|
||||
+ sigset_t __ss;
|
||||
+ struct sched_param __sp;
|
||||
+ int __policy;
|
||||
+ int __pad[16];
|
||||
+} posix_spawnattr_t;
|
||||
+
|
||||
+typedef struct {
|
||||
+ int __allocated;
|
||||
+ int __used;
|
||||
+ void *__actions;
|
||||
+ int __pad[16];
|
||||
+} posix_spawn_file_actions_t;
|
||||
+"""
|
||||
+trailer = """
|
||||
+#define POSIX_SPAWN_RESETIDS 0x01
|
||||
+#define POSIX_SPAWN_SETPGROUP 0x02
|
||||
+#define POSIX_SPAWN_SETSIGDEF 0x04
|
||||
+#define POSIX_SPAWN_SETSIGMASK 0x08
|
||||
+#define POSIX_SPAWN_SETSCHEDPARAM 0x10
|
||||
+#define POSIX_SPAWN_SETSCHEDULER 0x20
|
||||
+
|
||||
+int posix_spawn(pid_t *__restrict, const char *__restrict,
|
||||
+ const posix_spawn_file_actions_t *,
|
||||
+ const posix_spawnattr_t *__restrict,
|
||||
+ char *const __restrict[], char *const __restrict[]);
|
||||
+int posix_spawnp(pid_t *__restrict, const char *__restrict,
|
||||
+ const posix_spawn_file_actions_t *,
|
||||
+ const posix_spawnattr_t *__restrict,
|
||||
+ char *const __restrict[], char *const __restrict[]);
|
||||
+int posix_spawnattr_init(posix_spawnattr_t *);
|
||||
+int posix_spawnattr_destroy(posix_spawnattr_t *);
|
||||
+int posix_spawnattr_setflags(posix_spawnattr_t *, short);
|
||||
+int posix_spawnattr_getflags(const posix_spawnattr_t *__restrict, short *__restrict);
|
||||
+int posix_spawnattr_setpgroup(posix_spawnattr_t *, pid_t);
|
||||
+int posix_spawnattr_getpgroup(const posix_spawnattr_t *__restrict, pid_t *__restrict);
|
||||
+int posix_spawnattr_setsigdefault(posix_spawnattr_t *__restrict, const sigset_t *__restrict);
|
||||
+int posix_spawnattr_getsigdefault(posix_spawnattr_t *__restrict, sigset_t *__restrict);
|
||||
+int posix_spawnattr_setsigmask(posix_spawnattr_t *__restrict, const sigset_t *__restrict);
|
||||
+int posix_spawnattr_getsigmask(posix_spawnattr_t *__restrict, sigset_t *__restrict);
|
||||
+int posix_spawn_file_actions_init(posix_spawn_file_actions_t *);
|
||||
+int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *);
|
||||
+int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *, int, int);
|
||||
+int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *, int);
|
||||
+int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *__restrict,
|
||||
+ int, const char *__restrict, int, mode_t);
|
||||
+"""
|
||||
+language = "C"
|
||||
+style = "Type"
|
||||
+no_includes = true
|
||||
+cpp_compat = true
|
||||
+
|
||||
+[enum]
|
||||
+prefix_with_name = true
|
||||
+
|
||||
+[export]
|
||||
+include = []
|
||||
@@ -0,0 +1,35 @@
|
||||
Fix sys/timerfd.h cbindgen.toml to generate proper C headers instead of C++.
|
||||
|
||||
The empty cbindgen.toml from P3-timerfd-relative.patch caused cbindgen to
|
||||
generate C++ output (cstdarg, constexpr, etc.) in the installed
|
||||
sys/timerfd.h. C compilers including this header would fail with
|
||||
"cstdarg: No such file or directory". Add language="C", after_includes
|
||||
for bits/timespec.h, and explicit export list for the timerfd constants.
|
||||
|
||||
diff --git a/src/header/sys_timerfd/cbindgen.toml b/src/header/sys_timerfd/cbindgen.toml
|
||||
--- a/src/header/sys_timerfd/cbindgen.toml
|
||||
+++ b/src/header/sys_timerfd/cbindgen.toml
|
||||
@@ -1,12 +1,23 @@
|
||||
sys_includes = ["time.h"]
|
||||
+after_includes = """
|
||||
+#include <bits/timespec.h> // for itimerspec
|
||||
+"""
|
||||
include_guard = "_SYS_TIMERFD_H"
|
||||
language = "C"
|
||||
style = "Tag"
|
||||
no_includes = true
|
||||
cpp_compat = true
|
||||
|
||||
[enum]
|
||||
prefix_with_name = true
|
||||
|
||||
+[export]
|
||||
+include = [
|
||||
+ "TFD_CLOEXEC",
|
||||
+ "TFD_NONBLOCK",
|
||||
+ "TFD_TIMER_ABSTIME",
|
||||
+ "TFD_TIMER_CANCEL_ON_SET",
|
||||
+]
|
||||
+
|
||||
[export.rename]
|
||||
"itimerspec" = "struct itimerspec"
|
||||
@@ -0,0 +1,188 @@
|
||||
diff --git a/src/lib.rs b/src/lib.rs
|
||||
--- a/src/lib.rs
|
||||
+++ b/src/lib.rs
|
||||
@@ -57,61 +57,201 @@ pub mod start;
|
||||
pub mod sync;
|
||||
|
||||
-use crate::platform::{Allocator, NEWALLOCATOR};
|
||||
+use crate::platform::{Allocator, NEWALLOCATOR, Pal, Sys};
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: Allocator = NEWALLOCATOR;
|
||||
+
|
||||
+const MAX_FATAL_BACKTRACE_FRAMES: usize = 16;
|
||||
+const MAX_FATAL_FRAME_STRIDE: usize = 1024 * 1024;
|
||||
+
|
||||
+#[inline(never)]
|
||||
+fn write_process_thread_identity(w: &mut platform::FileWriter) {
|
||||
+ use core::fmt::Write;
|
||||
+
|
||||
+ let pid = Sys::getpid();
|
||||
+ let tid = Sys::gettid();
|
||||
+
|
||||
+ match crate::pthread::current_thread() {
|
||||
+ Some(thread) => {
|
||||
+ let _ = w.write_fmt(format_args!(
|
||||
+ "RELIBC CONTEXT: pid={} tid={} pthread={:#x}\n",
|
||||
+ pid,
|
||||
+ tid,
|
||||
+ thread as *const _ as usize,
|
||||
+ ));
|
||||
+ }
|
||||
+ None => {
|
||||
+ let _ = w.write_fmt(format_args!(
|
||||
+ "RELIBC CONTEXT: pid={} tid={} pthread=<unavailable>\n",
|
||||
+ pid, tid,
|
||||
+ ));
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#[cfg(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))]
|
||||
+#[inline(never)]
|
||||
+fn current_frame_pointer() -> *const usize {
|
||||
+ let frame: *const usize;
|
||||
+
|
||||
+ #[cfg(target_arch = "x86_64")]
|
||||
+ unsafe {
|
||||
+ core::arch::asm!("mov {}, rbp", out(reg) frame, options(nomem, nostack, preserves_flags));
|
||||
+ }
|
||||
+
|
||||
+ #[cfg(target_arch = "x86")]
|
||||
+ unsafe {
|
||||
+ core::arch::asm!("mov {}, ebp", out(reg) frame, options(nomem, nostack, preserves_flags));
|
||||
+ }
|
||||
+
|
||||
+ #[cfg(target_arch = "aarch64")]
|
||||
+ unsafe {
|
||||
+ core::arch::asm!("mov {}, x29", out(reg) frame, options(nomem, nostack, preserves_flags));
|
||||
+ }
|
||||
+
|
||||
+ frame
|
||||
+}
|
||||
+
|
||||
+#[cfg(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))]
|
||||
+fn read_backtrace_frame(frame: *const usize) -> Option<(*const usize, usize)> {
|
||||
+ let align = core::mem::align_of::<usize>();
|
||||
+ let frame_addr = frame as usize;
|
||||
+
|
||||
+ if frame.is_null() || frame_addr % align != 0 {
|
||||
+ return None;
|
||||
+ }
|
||||
+
|
||||
+ let next_frame = unsafe { frame.read() } as *const usize;
|
||||
+ let return_address = unsafe { frame.add(1).read() };
|
||||
+
|
||||
+ if return_address == 0 {
|
||||
+ return None;
|
||||
+ }
|
||||
+
|
||||
+ Some((next_frame, return_address))
|
||||
+}
|
||||
+
|
||||
+#[cfg(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))]
|
||||
+fn is_sane_next_backtrace_frame(current: *const usize, next: *const usize) -> bool {
|
||||
+ let align = core::mem::align_of::<usize>();
|
||||
+ let current_addr = current as usize;
|
||||
+ let next_addr = next as usize;
|
||||
+
|
||||
+ !next.is_null()
|
||||
+ && next_addr % align == 0
|
||||
+ && next_addr > current_addr
|
||||
+ && next_addr - current_addr <= MAX_FATAL_FRAME_STRIDE
|
||||
+}
|
||||
+
|
||||
+#[inline(never)]
|
||||
+fn write_best_effort_backtrace(w: &mut platform::FileWriter) {
|
||||
+ use core::fmt::Write;
|
||||
+
|
||||
+ let _ = w.write_str("RELIBC: attempting best-effort backtrace\n");
|
||||
+
|
||||
+ #[cfg(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))]
|
||||
+ {
|
||||
+ let mut frame = current_frame_pointer();
|
||||
+ let mut wrote_frame = false;
|
||||
+
|
||||
+ for frame_index in 0..MAX_FATAL_BACKTRACE_FRAMES {
|
||||
+ let Some((next_frame, return_address)) = read_backtrace_frame(frame) else {
|
||||
+ break;
|
||||
+ };
|
||||
+
|
||||
+ wrote_frame = true;
|
||||
+ let _ = w.write_fmt(format_args!(
|
||||
+ "RELIBC BACKTRACE[{frame_index:02}]: {:#x}\n",
|
||||
+ return_address,
|
||||
+ ));
|
||||
+
|
||||
+ if !is_sane_next_backtrace_frame(frame, next_frame) {
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ frame = next_frame;
|
||||
+ }
|
||||
+
|
||||
+ if !wrote_frame {
|
||||
+ let _ = w.write_str("RELIBC: backtrace attempt produced no frames\n");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ #[cfg(not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64")))]
|
||||
+ {
|
||||
+ let _ = w.write_str("RELIBC: backtrace unavailable on this architecture\n");
|
||||
+ }
|
||||
+}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn relibc_panic(pi: &::core::panic::PanicInfo) -> ! {
|
||||
use core::fmt::Write;
|
||||
|
||||
let mut w = platform::FileWriter::new(2);
|
||||
- let _ = w.write_fmt(format_args!("RELIBC PANIC: {}\n", pi));
|
||||
+
|
||||
+ if let Some(location) = pi.location() {
|
||||
+ let _ = w.write_fmt(format_args!(
|
||||
+ "RELIBC PANIC LOCATION: {}:{}:{}\n",
|
||||
+ location.file(),
|
||||
+ location.line(),
|
||||
+ location.column(),
|
||||
+ ));
|
||||
+ } else {
|
||||
+ let _ = w.write_str("RELIBC PANIC LOCATION: <unavailable>\n");
|
||||
+ }
|
||||
+
|
||||
+ write_process_thread_identity(&mut w);
|
||||
+ let _ = w.write_fmt(format_args!("RELIBC PANIC: {}\n", pi));
|
||||
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
@@ -95,23 +235,27 @@ pub extern "C" fn rust_oom(layout: ::core::alloc::Layout) -> ! {
|
||||
|
||||
let mut w = platform::FileWriter::new(2);
|
||||
let _ = w.write_fmt(format_args!(
|
||||
- "RELIBC OOM: {} bytes aligned to {} bytes\n",
|
||||
+ "RELIBC OOM: {} bytes aligned to {} bytes - process will abort\n",
|
||||
layout.size(),
|
||||
layout.align()
|
||||
));
|
||||
+ write_process_thread_identity(&mut w);
|
||||
+ write_best_effort_backtrace(&mut w);
|
||||
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[allow(non_snake_case)]
|
||||
#[linkage = "weak"]
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn _Unwind_Resume() -> ! {
|
||||
use core::fmt::Write;
|
||||
|
||||
let mut w = platform::FileWriter::new(2);
|
||||
- let _ = w.write_str("_Unwind_Resume\n");
|
||||
+ let _ = w.write_str(
|
||||
+ "RELIBC: _Unwind_Resume called - exception propagation failed, aborting\n",
|
||||
+ );
|
||||
+ write_process_thread_identity(&mut w);
|
||||
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
Fix ENOTRECOVERABLE returned for non-robust mutexes and register main
|
||||
thread in OS_TID_TO_PTHREAD.
|
||||
|
||||
The robust mutex liveness check (mutex_owner_id_is_live) was returning
|
||||
ENOTRECOVERABLE for non-robust mutexes when the owner appeared dead.
|
||||
Per POSIX, the behaviour of a non-robust mutex whose owner has died is
|
||||
undefined; returning an error crashes every Rust std::sync::Mutex user.
|
||||
For lock_inner, fall through to spin/futex-wait instead. For try_lock,
|
||||
return EBUSY instead.
|
||||
|
||||
Additionally, pthread::init() never registered the main thread in
|
||||
OS_TID_TO_PTHREAD, so any mutex owned by the main thread would always
|
||||
appear to have a dead owner, making the liveness check unreliable.
|
||||
|
||||
diff --git a/src/pthread/mod.rs b/src/pthread/mod.rs
|
||||
index 8243a48..c455a67 100644
|
||||
--- a/src/pthread/mod.rs
|
||||
+++ b/src/pthread/mod.rs
|
||||
@@ -43,9 +43,13 @@ pub unsafe fn init() {
|
||||
thread.stack_size = STACK_SIZE;
|
||||
}
|
||||
|
||||
- unsafe { Tcb::current() }
|
||||
- .expect_notls("no TCB present for main thread")
|
||||
- .pthread = thread;
|
||||
+ let tcb = unsafe { Tcb::current() }
|
||||
+ .expect_notls("no TCB present for main thread");
|
||||
+ tcb.pthread = thread;
|
||||
+
|
||||
+ OS_TID_TO_PTHREAD
|
||||
+ .lock()
|
||||
+ .insert(Sys::current_os_tid(), ForceSendSync(tcb as *const Tcb as *mut Tcb));
|
||||
}
|
||||
|
||||
//static NEXT_INDEX: AtomicU32 = AtomicU32::new(FIRST_THREAD_IDX + 1);
|
||||
diff --git a/src/sync/pthread_mutex.rs b/src/sync/pthread_mutex.rs
|
||||
index af0c429..1b2b3ca 100644
|
||||
--- a/src/sync/pthread_mutex.rs
|
||||
+++ b/src/sync/pthread_mutex.rs
|
||||
@@ -136,14 +136,17 @@ impl RlctMutex {
|
||||
Err(thread) => {
|
||||
let owner = thread & INDEX_MASK;
|
||||
|
||||
- if !crate::pthread::mutex_owner_id_is_live(owner) {
|
||||
- if !self.robust {
|
||||
- return Err(Errno(ENOTRECOVERABLE));
|
||||
- }
|
||||
-
|
||||
+ if !crate::pthread::mutex_owner_id_is_live(owner) && self.robust {
|
||||
let new_value = (thread & WAITING_BIT) | FUTEX_OWNER_DIED | this_thread;
|
||||
match self.inner.compare_exchange(
|
||||
thread,
|
||||
@@ -152,6 +155,12 @@ impl RlctMutex {
|
||||
Ok(_) => return self.finish_lock_acquire(true),
|
||||
Err(_) => continue,
|
||||
}
|
||||
+ } else if !crate::pthread::mutex_owner_id_is_live(owner) {
|
||||
+ // Non-robust mutex with apparently-dead owner: per POSIX the
|
||||
+ // behaviour is undefined. We conservatively keep spinning /
|
||||
+ // futex-waiting rather than returning ENOTRECOVERABLE, which
|
||||
+ // would crash any Rust std::sync::Mutex user.
|
||||
}
|
||||
|
||||
if spins_left > 0 {
|
||||
@@ -241,14 +250,17 @@ impl RlctMutex {
|
||||
|
||||
if current & FUTEX_OWNER_DIED != 0 || (owner != 0 && !crate::pthread::mutex_owner_id_is_live(owner)) {
|
||||
- if !self.robust {
|
||||
- return Err(Errno(ENOTRECOVERABLE));
|
||||
- }
|
||||
-
|
||||
+ if self.robust {
|
||||
let new_value = (current & WAITING_BIT) | FUTEX_OWNER_DIED | this_thread;
|
||||
match self.inner.compare_exchange(
|
||||
current,
|
||||
@@ -257,6 +269,11 @@ impl RlctMutex {
|
||||
Ok(_) => return self.finish_lock_acquire(true),
|
||||
Err(_) => continue,
|
||||
}
|
||||
+ } else {
|
||||
+ // Non-robust mutex: owner appears dead but POSIX behaviour is
|
||||
+ // undefined; report busy rather than ENOTRECOVERABLE.
|
||||
+ return Err(Errno(EBUSY));
|
||||
+ }
|
||||
}
|
||||
|
||||
return Err(Errno(EBUSY));
|
||||
@@ -0,0 +1,112 @@
|
||||
diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs
|
||||
index 022f873..ab96dea 100644
|
||||
--- a/redox-rt/src/signal.rs
|
||||
+++ b/redox-rt/src/signal.rs
|
||||
@@ -1,4 +1,10 @@
|
||||
-use core::{ffi::c_int, ptr::NonNull, sync::atomic::Ordering};
|
||||
+use core::{
|
||||
+ ffi::c_int,
|
||||
+ hint::unreachable_unchecked,
|
||||
+ panic::AssertUnwindSafe,
|
||||
+ ptr::NonNull,
|
||||
+ sync::atomic::Ordering,
|
||||
+};
|
||||
|
||||
use syscall::{
|
||||
CallFlags, EAGAIN, EINTR, EINVAL, ENOMEM, EPERM, Error, RawAction, Result, SenderInfo,
|
||||
@@ -103,6 +109,47 @@ pub struct SiginfoAbi {
|
||||
pub si_value: usize, // sigval
|
||||
}
|
||||
|
||||
+fn invoke_signal_handler<F: FnOnce()>(f: AssertUnwindSafe<F>) -> bool {
|
||||
+ fn do_call<F: FnOnce()>(data: *mut u8) {
|
||||
+ let callback = unsafe { &mut *data.cast::<Option<AssertUnwindSafe<F>>>() };
|
||||
+ if let Some(callback) = callback.take() {
|
||||
+ callback.0();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ fn do_catch<F: FnOnce()>(_data: *mut u8, _payload: *mut u8) {}
|
||||
+
|
||||
+ let mut callback = Some(f);
|
||||
+ unsafe {
|
||||
+ core::intrinsics::catch_unwind(
|
||||
+ do_call::<F>,
|
||||
+ (&mut callback as *mut Option<AssertUnwindSafe<F>>).cast(),
|
||||
+ do_catch::<F>,
|
||||
+ ) != 0
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#[inline(always)]
|
||||
+unsafe fn return_ignored_signal(
|
||||
+ os: &RtTcb,
|
||||
+ stack: &SigStack,
|
||||
+ signals_were_disabled: bool,
|
||||
+) {
|
||||
+ unsafe {
|
||||
+ (*os.arch.get()).last_sig_was_restart = true;
|
||||
+ (*os.arch.get()).last_sigstack = NonNull::new(stack.link);
|
||||
+ }
|
||||
+
|
||||
+ if !signals_were_disabled {
|
||||
+ core::sync::atomic::compiler_fence(Ordering::Release);
|
||||
+ let control_flags = &os.control.control_flags;
|
||||
+ control_flags.store(
|
||||
+ control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(),
|
||||
+ Ordering::Relaxed,
|
||||
+ );
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
#[inline(always)]
|
||||
unsafe fn inner(stack: &mut SigStack) {
|
||||
let os = unsafe { &Tcb::current().unwrap().os_specific };
|
||||
@@ -168,7 +215,10 @@ unsafe fn inner(stack: &mut SigStack) {
|
||||
// and reaching this code. If so, we do already know whether the signal is IGNORED *now*,
|
||||
// and so we should return early ideally without even temporarily touching the signal mask.
|
||||
SigactionKind::Ignore => {
|
||||
- panic!("ctl {:#x?} signal {}", os.control, stack.sig_num)
|
||||
+ unsafe {
|
||||
+ return_ignored_signal(os, stack, signals_were_disabled);
|
||||
+ }
|
||||
+ return;
|
||||
}
|
||||
// this case should be treated equally as the one above
|
||||
//
|
||||
@@ -183,7 +233,9 @@ unsafe fn inner(stack: &mut SigStack) {
|
||||
CallFlags::empty(),
|
||||
&[ProcCall::Exit as u64, u64::from(sig) << 8],
|
||||
);
|
||||
- panic!()
|
||||
+ // SAFETY: ProcCall::Exit terminates the current process when it succeeds, so reaching
|
||||
+ // this point would violate the proc manager exit contract.
|
||||
+ unsafe { unreachable_unchecked() }
|
||||
}
|
||||
SigactionKind::Handled { handler } => handler,
|
||||
};
|
||||
@@ -224,15 +276,21 @@ unsafe fn inner(stack: &mut SigStack) {
|
||||
si_uid: sender_uid as i32,
|
||||
si_value: stack.sival,
|
||||
};
|
||||
- unsafe {
|
||||
+ if invoke_signal_handler(AssertUnwindSafe(|| unsafe {
|
||||
sigaction(
|
||||
stack.sig_num as c_int,
|
||||
core::ptr::addr_of!(info).cast(),
|
||||
stack as *mut SigStack as *mut (),
|
||||
)
|
||||
- };
|
||||
+ })) {
|
||||
+ let _ = syscall::write(2, b"redox-rt: sa_siginfo handler panicked; continuing\n");
|
||||
+ }
|
||||
} else if let Some(handler) = unsafe { handler.handler } {
|
||||
- handler(stack.sig_num as c_int);
|
||||
+ if invoke_signal_handler(AssertUnwindSafe(|| {
|
||||
+ handler(stack.sig_num as c_int);
|
||||
+ })) {
|
||||
+ let _ = syscall::write(2, b"redox-rt: sa_handler panicked; continuing\n");
|
||||
+ }
|
||||
}
|
||||
|
||||
// Disable signals while we modify the sigmask again
|
||||
@@ -0,0 +1,101 @@
|
||||
diff --git a/src/start.rs b/src/start.rs
|
||||
--- a/src/start.rs
|
||||
+++ b/src/start.rs
|
||||
@@ -1,8 +1,6 @@
|
||||
//! Startup code.
|
||||
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
-use core::{intrinsics, ptr};
|
||||
-
|
||||
-#[cfg(target_os = "redox")]
|
||||
-use generic_rt::ExpectTlsFree;
|
||||
+use core::{fmt::Write, intrinsics, panic::AssertUnwindSafe, ptr};
|
||||
|
||||
use crate::{
|
||||
ALLOCATOR,
|
||||
@@ -143,6 +141,28 @@ fn io_init() {
|
||||
stdio::stderr = stdio::default_stderr().get();
|
||||
}
|
||||
}
|
||||
+
|
||||
+fn catch_unwind<F: FnOnce()>(f: AssertUnwindSafe<F>) -> Result<(), ()> {
|
||||
+ fn do_call<F: FnOnce()>(data: *mut u8) {
|
||||
+ let callback = unsafe { &mut *data.cast::<Option<AssertUnwindSafe<F>>>() };
|
||||
+ if let Some(callback) = callback.take() {
|
||||
+ callback.0();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ fn do_catch<F: FnOnce()>(_data: *mut u8, _payload: *mut u8) {}
|
||||
+
|
||||
+ let mut callback = Some(f);
|
||||
+ let panicked = unsafe {
|
||||
+ intrinsics::catch_unwind(
|
||||
+ do_call::<F>,
|
||||
+ (&mut callback as *mut Option<AssertUnwindSafe<F>>).cast(),
|
||||
+ do_catch::<F>,
|
||||
+ ) != 0
|
||||
+ };
|
||||
+
|
||||
+ if panicked { Err(()) } else { Ok(()) }
|
||||
+}
|
||||
+
|
||||
#[cold]
|
||||
fn abort_startup(args: core::fmt::Arguments<'_>) -> ! {
|
||||
let mut w = platform::FileWriter::new(2);
|
||||
@@ -164,15 +184,24 @@ pub unsafe extern "C" fn relibc_start_v1(
|
||||
unsafe { relibc_verify_host() };
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
- let thr_fd = redox_rt::proc::FdGuard::new(
|
||||
- unsafe {
|
||||
- crate::platform::get_auxv_raw(sp.auxv().cast(), redox_rt::auxv_defs::AT_REDOX_THR_FD)
|
||||
- }
|
||||
- .expect_notls("no thread fd present"),
|
||||
- )
|
||||
- .to_upper()
|
||||
- .expect_notls("failed to move thread fd to upper table");
|
||||
+ let thr_fd = {
|
||||
+ let thr_fd = match unsafe {
|
||||
+ crate::platform::get_auxv_raw(sp.auxv().cast(), redox_rt::auxv_defs::AT_REDOX_THR_FD)
|
||||
+ } {
|
||||
+ Some(thr_fd) => thr_fd,
|
||||
+ None => abort_startup(format_args!(
|
||||
+ "relibc_start_v1: missing AT_REDOX_THR_FD auxv entry; no thread fd present\n"
|
||||
+ )),
|
||||
+ };
|
||||
+
|
||||
+ match redox_rt::proc::FdGuard::new(thr_fd).to_upper() {
|
||||
+ Ok(thr_fd) => thr_fd,
|
||||
+ Err(err) => abort_startup(format_args!(
|
||||
+ "relibc_start_v1: failed to move thread fd to upper table: {err:?}\n"
|
||||
+ )),
|
||||
+ }
|
||||
+ };
|
||||
|
||||
// Initialize TLS, if necessary
|
||||
unsafe {
|
||||
@@ -237,7 +266,10 @@ pub unsafe extern "C" fn relibc_start_v1(
|
||||
let mut f = unsafe { &__preinit_array_start } as *const _;
|
||||
#[allow(clippy::op_ref)]
|
||||
while f < &raw const __preinit_array_end {
|
||||
- (unsafe { *f })();
|
||||
+ let func = unsafe { *f };
|
||||
+ if catch_unwind(AssertUnwindSafe(|| unsafe { (*f)() })).is_err() {
|
||||
+ log_initializer_panic(".preinit_array", func);
|
||||
+ }
|
||||
f = unsafe { f.offset(1) };
|
||||
}
|
||||
}
|
||||
@@ -247,7 +279,10 @@ pub unsafe extern "C" fn relibc_start_v1(
|
||||
let mut f = unsafe { &__init_array_start } as *const _;
|
||||
#[allow(clippy::op_ref)]
|
||||
while f < &raw const __init_array_end {
|
||||
- (unsafe { *f })();
|
||||
+ let func = unsafe { *f };
|
||||
+ if catch_unwind(AssertUnwindSafe(|| unsafe { (*f)() })).is_err() {
|
||||
+ log_initializer_panic(".init_array", func);
|
||||
+ }
|
||||
f = unsafe { f.offset(1) };
|
||||
}
|
||||
}
|
||||
@@ -21,3 +21,107 @@ diff --git a/src/header/fcntl/mod.rs b/src/header/fcntl/mod.rs
|
||||
+ }
|
||||
+ return new_fd;
|
||||
+ }
|
||||
|
||||
diff --git a/src/pthread/mod.rs b/src/pthread/mod.rs
|
||||
--- a/src/pthread/mod.rs
|
||||
+++ b/src/pthread/mod.rs
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use core::{
|
||||
cell::UnsafeCell,
|
||||
+ panic::AssertUnwindSafe,
|
||||
ptr,
|
||||
sync::atomic::{AtomicBool, AtomicUsize, Ordering},
|
||||
};
|
||||
@@ -208,13 +209,41 @@ pub(crate) unsafe fn create(
|
||||
}
|
||||
|
||||
/// A shim to wrap thread entry points in logic to set up TLS, for example
|
||||
+fn catch_unwind<F: FnOnce()>(f: AssertUnwindSafe<F>) -> Result<(), ()> {
|
||||
+ fn do_call<F: FnOnce()>(data: *mut u8) {
|
||||
+ let callback = unsafe { &mut *data.cast::<Option<AssertUnwindSafe<F>>>() };
|
||||
+ if let Some(callback) = callback.take() {
|
||||
+ callback.0();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ fn do_catch<F: FnOnce()>(_data: *mut u8, _payload: *mut u8) {}
|
||||
+
|
||||
+ let mut callback = Some(f);
|
||||
+ let panicked = unsafe {
|
||||
+ core::intrinsics::catch_unwind(
|
||||
+ do_call::<F>,
|
||||
+ (&mut callback as *mut Option<AssertUnwindSafe<F>>).cast(),
|
||||
+ do_catch::<F>,
|
||||
+ ) != 0
|
||||
+ };
|
||||
+
|
||||
+ if panicked { Err(()) } else { Ok(()) }
|
||||
+}
|
||||
+
|
||||
unsafe extern "C" fn new_thread_shim(
|
||||
tcb: *mut Tcb,
|
||||
synchronization_mutex: *const Mutex<u64>,
|
||||
) -> ! {
|
||||
- let tcb = unsafe { tcb.as_mut() }.expect_notls("non-null TLS is required");
|
||||
+ let tcb = match unsafe { tcb.as_mut() } {
|
||||
+ Some(tcb) => tcb,
|
||||
+ None => {
|
||||
+ log::error!("pthread: child thread started without a TCB");
|
||||
+ unsafe { exit_current_thread(Retval(ptr::null_mut())) }
|
||||
+ }
|
||||
+ };
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
{
|
||||
@@ -227,12 +256,23 @@ unsafe extern "C" fn new_thread_shim(
|
||||
unsafe {
|
||||
tcb.activate(None);
|
||||
}
|
||||
- redox_rt::signal::setup_sighandler(&tcb.os_specific, false);
|
||||
+ match catch_unwind(AssertUnwindSafe(|| {
|
||||
+ redox_rt::signal::setup_sighandler(&tcb.os_specific, false)
|
||||
+ })) {
|
||||
+ Ok(()) => {}
|
||||
+ Err(()) => {
|
||||
+ log::error!("pthread: failed to set up child thread signal handler");
|
||||
+ unsafe { exit_current_thread(Retval(ptr::null_mut())) }
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
let procmask = unsafe { (&*synchronization_mutex).as_ptr().read() };
|
||||
|
||||
- unsafe { tcb.copy_masters() }.unwrap();
|
||||
+ if let Err(err) = unsafe { tcb.copy_masters() } {
|
||||
+ log::error!("pthread: failed to copy TLS masters for child thread: {err:?}");
|
||||
+ unsafe { exit_current_thread(Retval(ptr::null_mut())) }
|
||||
+ }
|
||||
|
||||
unsafe { (*tcb).pthread.os_tid.get().write(Sys::current_os_tid()) };
|
||||
|
||||
@@ -240,11 +280,21 @@ unsafe extern "C" fn new_thread_shim(
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
{
|
||||
- redox_rt::signal::set_sigmask(Some(procmask), None)
|
||||
- .expect("failed to set procmask in child thread");
|
||||
+ if let Err(err) = redox_rt::signal::set_sigmask(Some(procmask), None) {
|
||||
+ log::error!("pthread: failed to set child thread signal mask: {err:?}");
|
||||
+ }
|
||||
}
|
||||
|
||||
- let retval = unsafe { entry_point(arg) };
|
||||
+ let mut retval = ptr::null_mut();
|
||||
+ match catch_unwind(AssertUnwindSafe(|| {
|
||||
+ retval = unsafe { entry_point(arg) };
|
||||
+ })) {
|
||||
+ Ok(()) => {}
|
||||
+ Err(()) => {
|
||||
+ log::error!("pthread: child thread entry point panicked");
|
||||
+ unsafe { exit_current_thread(Retval(ptr::null_mut())) }
|
||||
+ }
|
||||
+ }
|
||||
|
||||
unsafe { exit_current_thread(Retval(retval)) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user