diff --git a/src/arch/arm64/exceptions/syscall.rs b/src/arch/arm64/exceptions/syscall.rs index 38c5e03..77a314f 100644 --- a/src/arch/arm64/exceptions/syscall.rs +++ b/src/arch/arm64/exceptions/syscall.rs @@ -169,7 +169,7 @@ pub async fn handle_syscall() { } 0x50 => sys_fstat(arg1.into(), TUA::from_value(arg2 as _)).await, 0x51 => sys_sync().await, - 0x5d => sys_exit(arg1 as _), + 0x5d => sys_exit(arg1 as _).await, 0x5e => sys_exit_group(arg1 as _), 0x60 => sys_set_tid_address(VA::from_value(arg1 as _)).await, 0x62 => { @@ -255,8 +255,8 @@ pub async fn handle_syscall() { sys_clone( arg1 as _, UA::from_value(arg2 as _), - UA::from_value(arg3 as _), - UA::from_value(arg5 as _), + TUA::from_value(arg3 as _), + TUA::from_value(arg5 as _), arg4 as _, ) .await diff --git a/src/process/clone.rs b/src/process/clone.rs index 4d5abc4..36398bf 100644 --- a/src/process/clone.rs +++ b/src/process/clone.rs @@ -1,17 +1,18 @@ +use super::{ctx::Context, thread_group::signal::SigSet}; +use crate::memory::uaccess::copy_to_user; use crate::{ process::{TASK_LIST, Task, TaskState}, sched::{self, current_task}, sync::SpinLock, }; use bitflags::bitflags; +use libkernel::memory::address::TUA; use libkernel::{ error::{KernelError, Result}, memory::address::UA, }; use ringbuf::Arc; -use super::{ctx::Context, thread_group::signal::SigSet}; - bitflags! { #[derive(Debug)] pub struct CloneFlags: u32 { @@ -44,8 +45,8 @@ bitflags! { pub async fn sys_clone( flags: u32, newsp: UA, - _arent_tidptr: UA, - _child_tidptr: UA, + parent_tidptr: TUA, + child_tidptr: TUA, 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) + } 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, tid.value()).await?; + } + if flags.contains(CloneFlags::CLONE_CHILD_SETTID) && !child_tidptr.is_null() { + copy_to_user(child_tidptr, tid.value()).await?; + } + Ok(tid.value() as _) } diff --git a/src/process/exit.rs b/src/process/exit.rs index b586313..952ba0c 100644 --- a/src/process/exit.rs +++ b/src/process/exit.rs @@ -1,12 +1,13 @@ -use crate::sched::current_task; -use alloc::vec::Vec; -use libkernel::error::Result; -use ringbuf::Arc; - use super::{ TaskState, thread_group::{ProcessState, Tgid, ThreadGroup, signal::SigId, wait::ChildState}, }; +use crate::memory::uaccess::copy_to_user; +use crate::process::threading::futex_wake_addr; +use crate::sched::current_task; +use alloc::vec::Vec; +use libkernel::error::Result; +use ringbuf::Arc; pub fn do_exit_group(exit_code: ChildState) { let task = current_task(); @@ -99,8 +100,18 @@ pub fn sys_exit_group(exit_code: usize) -> Result { Ok(0) } -pub fn sys_exit(exit_code: usize) -> Result { +pub async 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. + let ptr = task.child_tid_ptr.lock_save_irq().take(); + if let Some(ptr) = ptr { + copy_to_user(ptr, 0u32).await?; + + // 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),