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:
@@ -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
@@ -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
@@ -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
@@ -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:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user