mirror of
https://github.com/hexagonal-sun/moss-kernel.git
synced 2025-12-23 22:47:55 -05:00
fix futex based thread joining
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::memory::uaccess::copy_to_user;
|
||||||
use crate::{
|
use crate::{
|
||||||
process::{TASK_LIST, Task, TaskState},
|
process::{TASK_LIST, Task, TaskState},
|
||||||
sched::{self, current_task},
|
sched::{self, current_task},
|
||||||
@@ -44,8 +45,8 @@ bitflags! {
|
|||||||
pub async fn sys_clone(
|
pub async fn sys_clone(
|
||||||
flags: u32,
|
flags: u32,
|
||||||
newsp: UA,
|
newsp: UA,
|
||||||
_arent_tidptr: UA,
|
parent_tidptr: UA,
|
||||||
_child_tidptr: UA,
|
child_tidptr: UA,
|
||||||
tls: usize,
|
tls: usize,
|
||||||
) -> Result<usize> {
|
) -> Result<usize> {
|
||||||
let flags = CloneFlags::from_bits_truncate(flags);
|
let flags = CloneFlags::from_bits_truncate(flags);
|
||||||
@@ -146,6 +147,11 @@ pub async fn sys_clone(
|
|||||||
state: Arc::new(SpinLock::new(TaskState::Runnable)),
|
state: Arc::new(SpinLock::new(TaskState::Runnable)),
|
||||||
last_run: SpinLock::new(None),
|
last_run: SpinLock::new(None),
|
||||||
robust_list: SpinLock::new(None),
|
robust_list: SpinLock::new(None),
|
||||||
|
child_tid_ptr: SpinLock::new(if !child_tidptr.is_null() {
|
||||||
|
Some(child_tidptr.cast::<u32>())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -157,5 +163,13 @@ pub async fn sys_clone(
|
|||||||
|
|
||||||
sched::insert_task(Arc::new(new_task));
|
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::<u32>(), tid.value() as u32).await?;
|
||||||
|
}
|
||||||
|
if flags.contains(CloneFlags::CLONE_CHILD_SETTID) && !child_tidptr.is_null() {
|
||||||
|
copy_to_user(child_tidptr.cast::<u32>(), tid.value() as u32).await?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(tid.value() as _)
|
Ok(tid.value() as _)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::process::threading::futex_wake_addr;
|
||||||
use crate::sched::current_task;
|
use crate::sched::current_task;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use libkernel::error::Result;
|
use libkernel::error::Result;
|
||||||
@@ -101,6 +102,17 @@ pub fn sys_exit_group(exit_code: usize) -> Result<usize> {
|
|||||||
|
|
||||||
pub fn sys_exit(exit_code: usize) -> Result<usize> {
|
pub fn sys_exit(exit_code: usize) -> Result<usize> {
|
||||||
let task = current_task();
|
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 process = Arc::clone(&task.process);
|
||||||
let mut thread_lock = process.threads.lock_save_irq();
|
let mut thread_lock = process.threads.lock_save_irq();
|
||||||
|
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ pub struct Task {
|
|||||||
pub last_run: SpinLock<Option<Instant>>,
|
pub last_run: SpinLock<Option<Instant>>,
|
||||||
pub state: Arc<SpinLock<TaskState>>,
|
pub state: Arc<SpinLock<TaskState>>,
|
||||||
pub robust_list: SpinLock<Option<TUA<RobustListHead>>>,
|
pub robust_list: SpinLock<Option<TUA<RobustListHead>>>,
|
||||||
|
pub child_tid_ptr: SpinLock<Option<TUA<u32>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Task {
|
impl Task {
|
||||||
@@ -214,6 +215,7 @@ impl Task {
|
|||||||
fd_table: Arc::new(SpinLock::new(FileDescriptorTable::new())),
|
fd_table: Arc::new(SpinLock::new(FileDescriptorTable::new())),
|
||||||
last_run: SpinLock::new(None),
|
last_run: SpinLock::new(None),
|
||||||
robust_list: 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),
|
last_run: SpinLock::new(None),
|
||||||
robust_list: SpinLock::new(None),
|
robust_list: SpinLock::new(None),
|
||||||
|
child_tid_ptr: SpinLock::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,25 @@ const FUTEX_WAIT_BITSET: i32 = 9;
|
|||||||
const FUTEX_WAKE_BITSET: i32 = 10;
|
const FUTEX_WAKE_BITSET: i32 = 10;
|
||||||
const FUTEX_PRIVATE_FLAG: i32 = 128;
|
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<u32>, 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(
|
pub async fn sys_futex(
|
||||||
uaddr: TUA<u32>,
|
uaddr: TUA<u32>,
|
||||||
op: i32,
|
op: i32,
|
||||||
@@ -132,21 +151,7 @@ pub async fn sys_futex(
|
|||||||
|
|
||||||
FUTEX_WAKE | FUTEX_WAKE_BITSET => {
|
FUTEX_WAKE | FUTEX_WAKE_BITSET => {
|
||||||
let nr_wake = val as usize;
|
let nr_wake = val as usize;
|
||||||
let mut woke = 0;
|
Ok(futex_wake_addr(uaddr, nr_wake))
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => Err(KernelError::NotSupported),
|
_ => Err(KernelError::NotSupported),
|
||||||
|
|||||||
Reference in New Issue
Block a user