Merge branch 'detach-crash' into 'master'

Fix crash when exiting from detached thread

See merge request redox-os/relibc!1517
This commit is contained in:
Jeremy Soller
2026-07-04 19:19:50 -06:00
4 changed files with 38 additions and 6 deletions
+1
View File
@@ -541,6 +541,7 @@ pub struct TmpDisableSignalsGuard {
active: bool,
}
/// Used to prevent EINTR from appearing across all syscall
pub fn tmp_disable_signals() -> TmpDisableSignalsGuard {
if !crate::TLS_ACTIVATED.load(Ordering::Relaxed) {
return TmpDisableSignalsGuard { active: false };
+2 -1
View File
@@ -527,7 +527,8 @@ pub fn posix_exit(status: i32) -> ! {
&[ProcCall::Exit as u64, (status & 0xFF) as u64],
) {
Ok(_) => break,
// TODO: procmgr can sometimes send EAGAIN, but why EINTR needed?
// procmgr can sometimes send EAGAIN.
// cannot disable signals so kernel might send EINTR.
Err(Error { errno: EINTR } | Error { errno: EAGAIN }) => continue,
Err(e) => panic!("failed to call proc mgr with Exit: {e}"),
}
+12 -4
View File
@@ -2,7 +2,7 @@ use core::mem::size_of;
use syscall::Result;
use crate::{RtTcb, arch::*, proc::*, signal::tmp_disable_signals, static_proc_info};
use crate::{RtTcb, arch::*, proc::*, static_proc_info};
/// Spawns a new context sharing the same address space as the current one (i.e. a new thread).
pub unsafe fn rlct_clone_impl(stack: *mut usize, tcb: &RtTcb) -> Result<usize> {
@@ -52,12 +52,20 @@ pub unsafe fn rlct_clone_impl(stack: *mut usize, tcb: &RtTcb) -> Result<usize> {
}
pub unsafe fn exit_this_thread(stack_base: *mut (), stack_size: usize) -> ! {
let _guard = tmp_disable_signals();
let _guard = crate::signal::tmp_disable_signals();
let thread_fd = RtTcb::current().thread_fd();
let tcb = RtTcb::current();
// TODO: modify interface so it writes directly to the thread fd?
let status_fd = tcb.thread_fd().dup_into_upper(b"status").unwrap();
let status_fd = thread_fd.dup_into_upper(b"status").unwrap();
unsafe { exit_this_thread_inner(stack_base, stack_size, status_fd) }
}
/// exit_this_thread, but current thread_fd might has disappear
pub unsafe fn exit_this_thread_inner(
stack_base: *mut (),
stack_size: usize,
status_fd: FdGuard<true>,
) -> ! {
let mut buf = [0; size_of::<usize>() * 3];
plain::slice_from_mut_bytes(&mut buf)
.unwrap()
+23 -1
View File
@@ -7,6 +7,8 @@ use core::{
};
use alloc::collections::BTreeMap;
#[cfg(target_os = "redox")]
use redox_rt::{RtTcb, proc::FdGuard};
use crate::{
error::Errno,
@@ -307,9 +309,22 @@ pub unsafe fn exit_current_thread(retval: Retval) -> ! {
let stack_size = this.stack_size;
if this.flags.load(Ordering::Acquire) & PthreadFlags::DETACHED.bits() != 0 {
// dealloc_thread() unmaps the tcb so extract the thread_fd now
#[cfg(target_os = "redox")]
let status_fd = {
let _guard = redox_rt::signal::tmp_disable_signals();
let thread_fd = FdGuard::new(RtTcb::current().thread_fd().as_raw_fd());
thread_fd.dup_into_upper(b"status").unwrap()
};
// When detached, the thread state no longer makes any sense, and can immediately be
// deallocated.
unsafe { dealloc_thread(this) };
#[cfg(target_os = "redox")]
unsafe {
redox_rt::thread::exit_this_thread_inner(stack_base.cast(), stack_size, status_fd)
}
} else {
// When joinable, the return value should be made available to other threads.
unsafe { this.waitval.post(retval) };
@@ -327,7 +342,14 @@ unsafe fn dealloc_thread(thread: &Pthread) {
unsafe {
let tcb = thread.tcb_selfref.get().read();
if !tcb.is_null() {
let _ = syscall::funmap(tcb as usize, syscall::PAGE_SIZE);
loop {
match syscall::funmap(tcb as usize, syscall::PAGE_SIZE) {
Ok(_) => break,
// might be not guarded by tmp_disable_signals()
Err(syscall::Error { errno: EINTR }) => continue,
Err(e) => log::warn!("Cannot dealloc_thread: {e:?}"),
}
}
}
}
}