From 8bf0a72bce91081f0f6e7c29ff5584e834487657 Mon Sep 17 00:00:00 2001 From: Ashwin Naren Date: Sun, 21 Dec 2025 17:02:19 -0800 Subject: [PATCH] fix futex based thread joining --- src/process/clone.rs | 18 ++++++++++++++++-- src/process/exit.rs | 12 ++++++++++++ src/process/mod.rs | 3 +++ src/process/threading.rs | 35 ++++++++++++++++++++--------------- 4 files changed, 51 insertions(+), 17 deletions(-) diff --git a/src/process/clone.rs b/src/process/clone.rs index 4d5abc4..681ab56 100644 --- a/src/process/clone.rs +++ b/src/process/clone.rs @@ -1,3 +1,4 @@ +use crate::memory::uaccess::copy_to_user; use crate::{ process::{TASK_LIST, Task, TaskState}, sched::{self, current_task}, @@ -44,8 +45,8 @@ bitflags! { pub async fn sys_clone( flags: u32, newsp: UA, - _arent_tidptr: UA, - _child_tidptr: UA, + parent_tidptr: UA, + child_tidptr: UA, tls: usize, ) -> Result { let flags = CloneFlags::from_bits_truncate(flags); @@ -146,6 +147,11 @@ pub async fn sys_clone( state: Arc::new(SpinLock::new(TaskState::Runnable)), last_run: SpinLock::new(None), robust_list: SpinLock::new(None), + child_tid_ptr: SpinLock::new(if !child_tidptr.is_null() { + Some(child_tidptr.cast::()) + } else { + None + }), } }; @@ -157,5 +163,13 @@ pub async fn sys_clone( sched::insert_task(Arc::new(new_task)); + // Honour CLONE_*SETTID semantics for the parent and (shared-VM) child. + if flags.contains(CloneFlags::CLONE_PARENT_SETTID) && !parent_tidptr.is_null() { + copy_to_user(parent_tidptr.cast::(), tid.value() as u32).await?; + } + if flags.contains(CloneFlags::CLONE_CHILD_SETTID) && !child_tidptr.is_null() { + copy_to_user(child_tidptr.cast::(), tid.value() as u32).await?; + } + Ok(tid.value() as _) } diff --git a/src/process/exit.rs b/src/process/exit.rs index b586313..373181c 100644 --- a/src/process/exit.rs +++ b/src/process/exit.rs @@ -1,3 +1,4 @@ +use crate::process::threading::futex_wake_addr; use crate::sched::current_task; use alloc::vec::Vec; use libkernel::error::Result; @@ -101,6 +102,17 @@ pub fn sys_exit_group(exit_code: usize) -> Result { pub fn sys_exit(exit_code: usize) -> Result { let task = current_task(); + + // Honour CLONE_CHILD_CLEARTID: clear the user TID word and futex-wake any waiters. + if let Some(ptr) = task.child_tid_ptr.lock_save_irq().take() { + unsafe { + (ptr.value() as *mut u32).write_volatile(0); + } + + // Wake any thread waiting on this futex. + futex_wake_addr(ptr, 1); + } + let process = Arc::clone(&task.process); let mut thread_lock = process.threads.lock_save_irq(); diff --git a/src/process/mod.rs b/src/process/mod.rs index ac928dd..f7a5255 100644 --- a/src/process/mod.rs +++ b/src/process/mod.rs @@ -181,6 +181,7 @@ pub struct Task { pub last_run: SpinLock>, pub state: Arc>, pub robust_list: SpinLock>>, + pub child_tid_ptr: SpinLock>>, } impl Task { @@ -214,6 +215,7 @@ impl Task { fd_table: Arc::new(SpinLock::new(FileDescriptorTable::new())), last_run: SpinLock::new(None), robust_list: SpinLock::new(None), + child_tid_ptr: SpinLock::new(None), } } @@ -241,6 +243,7 @@ impl Task { )), last_run: SpinLock::new(None), robust_list: SpinLock::new(None), + child_tid_ptr: SpinLock::new(None), } } diff --git a/src/process/threading.rs b/src/process/threading.rs index fdc881b..3dea397 100644 --- a/src/process/threading.rs +++ b/src/process/threading.rs @@ -74,6 +74,25 @@ const FUTEX_WAIT_BITSET: i32 = 9; const FUTEX_WAKE_BITSET: i32 = 10; const FUTEX_PRIVATE_FLAG: i32 = 128; +/// Wake up to `nr` waiters sleeping on the futex word located at `uaddr`. +/// Returns the number of tasks actually woken. +pub fn futex_wake_addr(uaddr: TUA, nr: usize) -> usize { + let mut woke = 0; + + if let Some(table) = FUTEX_TABLE.get() + && let Some(waitq_arc) = table.lock_save_irq().get(&uaddr).cloned() + { + let mut waitq = waitq_arc.lock_save_irq(); + for _ in 0..nr { + waitq.wakeups = waitq.wakeups.saturating_add(1); + waitq.wakers.wake_one(); + woke += 1; + } + } + + woke +} + pub async fn sys_futex( uaddr: TUA, op: i32, @@ -132,21 +151,7 @@ pub async fn sys_futex( FUTEX_WAKE | FUTEX_WAKE_BITSET => { let nr_wake = val as usize; - let mut woke = 0; - - if let Some(table) = FUTEX_TABLE.get() - && let Some(waitq_arc) = table.lock_save_irq().get(&uaddr).cloned() - { - let mut waitq = waitq_arc.lock_save_irq(); - for _ in 0..nr_wake { - // Record a pending wake-up and attempt to wake a single waiter. - waitq.wakeups = waitq.wakeups.saturating_add(1); - waitq.wakers.wake_one(); - woke += 1; - } - } - - Ok(woke) + Ok(futex_wake_addr(uaddr, nr_wake)) } _ => Err(KernelError::NotSupported),