mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 00:43:24 +00:00
Implement futex private flag
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
a754accf6a
commit
46708f84bc
@ -23,7 +23,7 @@ pub fn do_exit(thread: &Thread, posix_thread: &PosixThread, term_status: TermSta
|
|||||||
let mut clear_ctid = posix_thread.clear_child_tid().lock();
|
let mut clear_ctid = posix_thread.clear_child_tid().lock();
|
||||||
// If clear_ctid !=0 ,do a futex wake and write zero to the clear_ctid addr.
|
// If clear_ctid !=0 ,do a futex wake and write zero to the clear_ctid addr.
|
||||||
if *clear_ctid != 0 {
|
if *clear_ctid != 0 {
|
||||||
futex_wake(*clear_ctid, 1)?;
|
futex_wake(*clear_ctid, 1, None)?;
|
||||||
// FIXME: the correct write length?
|
// FIXME: the correct write length?
|
||||||
CurrentUserSpace::get()
|
CurrentUserSpace::get()
|
||||||
.write_val(*clear_ctid, &0u32)
|
.write_val(*clear_ctid, &0u32)
|
||||||
@ -44,7 +44,7 @@ pub fn do_exit(thread: &Thread, posix_thread: &PosixThread, term_status: TermSta
|
|||||||
do_exit_group(term_status);
|
do_exit_group(term_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
futex_wake(Arc::as_ptr(&posix_thread.process()) as Vaddr, 1)?;
|
futex_wake(Arc::as_ptr(&posix_thread.process()) as Vaddr, 1, None)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ use ostd::{
|
|||||||
};
|
};
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
|
|
||||||
use crate::{prelude::*, time::wait::TimerBuilder};
|
use crate::{prelude::*, process::Pid, time::wait::TimerBuilder};
|
||||||
|
|
||||||
type FutexBitSet = u32;
|
type FutexBitSet = u32;
|
||||||
type FutexBucketRef = Arc<Mutex<FutexBucket>>;
|
type FutexBucketRef = Arc<Mutex<FutexBucket>>;
|
||||||
@ -24,6 +24,7 @@ pub fn futex_wait(
|
|||||||
futex_val: i32,
|
futex_val: i32,
|
||||||
timer_builder: Option<TimerBuilder>,
|
timer_builder: Option<TimerBuilder>,
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
|
pid: Option<Pid>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
futex_wait_bitset(
|
futex_wait_bitset(
|
||||||
futex_addr as _,
|
futex_addr as _,
|
||||||
@ -31,6 +32,7 @@ pub fn futex_wait(
|
|||||||
timer_builder,
|
timer_builder,
|
||||||
FUTEX_BITSET_MATCH_ANY,
|
FUTEX_BITSET_MATCH_ANY,
|
||||||
ctx,
|
ctx,
|
||||||
|
pid,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +43,7 @@ pub fn futex_wait_bitset(
|
|||||||
timer_builder: Option<TimerBuilder>,
|
timer_builder: Option<TimerBuilder>,
|
||||||
bitset: FutexBitSet,
|
bitset: FutexBitSet,
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
|
pid: Option<Pid>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
debug!(
|
debug!(
|
||||||
"futex_wait_bitset addr: {:#x}, val: {}, bitset: {:#x}",
|
"futex_wait_bitset addr: {:#x}, val: {}, bitset: {:#x}",
|
||||||
@ -51,7 +54,7 @@ pub fn futex_wait_bitset(
|
|||||||
return_errno_with_message!(Errno::EINVAL, "at least one bit should be set");
|
return_errno_with_message!(Errno::EINVAL, "at least one bit should be set");
|
||||||
}
|
}
|
||||||
|
|
||||||
let futex_key = FutexKey::new(futex_addr, bitset);
|
let futex_key = FutexKey::new(futex_addr, bitset, pid);
|
||||||
let (futex_item, waiter) = FutexItem::create(futex_key);
|
let (futex_item, waiter) = FutexItem::create(futex_key);
|
||||||
|
|
||||||
let (_, futex_bucket_ref) = get_futex_bucket(futex_key);
|
let (_, futex_bucket_ref) = get_futex_bucket(futex_key);
|
||||||
@ -74,8 +77,8 @@ pub fn futex_wait_bitset(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Does futex wake
|
/// Does futex wake
|
||||||
pub fn futex_wake(futex_addr: Vaddr, max_count: usize) -> Result<usize> {
|
pub fn futex_wake(futex_addr: Vaddr, max_count: usize, pid: Option<Pid>) -> Result<usize> {
|
||||||
futex_wake_bitset(futex_addr, max_count, FUTEX_BITSET_MATCH_ANY)
|
futex_wake_bitset(futex_addr, max_count, FUTEX_BITSET_MATCH_ANY, pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Does futex wake with bitset
|
/// Does futex wake with bitset
|
||||||
@ -83,6 +86,7 @@ pub fn futex_wake_bitset(
|
|||||||
futex_addr: Vaddr,
|
futex_addr: Vaddr,
|
||||||
max_count: usize,
|
max_count: usize,
|
||||||
bitset: FutexBitSet,
|
bitset: FutexBitSet,
|
||||||
|
pid: Option<Pid>,
|
||||||
) -> Result<usize> {
|
) -> Result<usize> {
|
||||||
debug!(
|
debug!(
|
||||||
"futex_wake_bitset addr: {:#x}, max_count: {}, bitset: {:#x}",
|
"futex_wake_bitset addr: {:#x}, max_count: {}, bitset: {:#x}",
|
||||||
@ -93,7 +97,7 @@ pub fn futex_wake_bitset(
|
|||||||
return_errno_with_message!(Errno::EINVAL, "at least one bit should be set");
|
return_errno_with_message!(Errno::EINVAL, "at least one bit should be set");
|
||||||
}
|
}
|
||||||
|
|
||||||
let futex_key = FutexKey::new(futex_addr, bitset);
|
let futex_key = FutexKey::new(futex_addr, bitset, pid);
|
||||||
let (_, futex_bucket_ref) = get_futex_bucket(futex_key);
|
let (_, futex_bucket_ref) = get_futex_bucket(futex_key);
|
||||||
let mut futex_bucket = futex_bucket_ref.lock();
|
let mut futex_bucket = futex_bucket_ref.lock();
|
||||||
let res = futex_bucket.remove_and_wake_items(futex_key, max_count);
|
let res = futex_bucket.remove_and_wake_items(futex_key, max_count);
|
||||||
@ -108,13 +112,14 @@ pub fn futex_requeue(
|
|||||||
max_nwakes: usize,
|
max_nwakes: usize,
|
||||||
max_nrequeues: usize,
|
max_nrequeues: usize,
|
||||||
futex_new_addr: Vaddr,
|
futex_new_addr: Vaddr,
|
||||||
|
pid: Option<Pid>,
|
||||||
) -> Result<usize> {
|
) -> Result<usize> {
|
||||||
if futex_new_addr == futex_addr {
|
if futex_new_addr == futex_addr {
|
||||||
return futex_wake(futex_addr, max_nwakes);
|
return futex_wake(futex_addr, max_nwakes, pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
let futex_key = FutexKey::new(futex_addr, FUTEX_BITSET_MATCH_ANY);
|
let futex_key = FutexKey::new(futex_addr, FUTEX_BITSET_MATCH_ANY, pid);
|
||||||
let futex_new_key = FutexKey::new(futex_new_addr, FUTEX_BITSET_MATCH_ANY);
|
let futex_new_key = FutexKey::new(futex_new_addr, FUTEX_BITSET_MATCH_ANY, pid);
|
||||||
let (bucket_idx, futex_bucket_ref) = get_futex_bucket(futex_key);
|
let (bucket_idx, futex_bucket_ref) = get_futex_bucket(futex_key);
|
||||||
let (new_bucket_idx, futex_new_bucket_ref) = get_futex_bucket(futex_new_key);
|
let (new_bucket_idx, futex_new_bucket_ref) = get_futex_bucket(futex_new_key);
|
||||||
|
|
||||||
@ -332,11 +337,14 @@ impl FutexItem {
|
|||||||
struct FutexKey {
|
struct FutexKey {
|
||||||
addr: Vaddr,
|
addr: Vaddr,
|
||||||
bitset: FutexBitSet,
|
bitset: FutexBitSet,
|
||||||
|
/// Specify whether this `FutexKey` is process private or shared. If `pid` is
|
||||||
|
/// None, then this `FutexKey` is shared.
|
||||||
|
pid: Option<Pid>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FutexKey {
|
impl FutexKey {
|
||||||
pub fn new(addr: Vaddr, bitset: FutexBitSet) -> Self {
|
pub fn new(addr: Vaddr, bitset: FutexBitSet, pid: Option<Pid>) -> Self {
|
||||||
Self { addr, bitset }
|
Self { addr, bitset, pid }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_val(&self, ctx: &Context) -> Result<i32> {
|
pub fn load_val(&self, ctx: &Context) -> Result<i32> {
|
||||||
@ -354,7 +362,8 @@ impl FutexKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn match_up(&self, another: &Self) -> bool {
|
pub fn match_up(&self, another: &Self) -> bool {
|
||||||
self.addr == another.addr && (self.bitset & another.bitset) != 0
|
// TODO: Use hash value to do match_up
|
||||||
|
self.addr == another.addr && (self.bitset & another.bitset) != 0 && self.pid == another.pid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,10 +2,7 @@
|
|||||||
|
|
||||||
//! The implementation of robust list is from occlum.
|
//! The implementation of robust list is from occlum.
|
||||||
|
|
||||||
use crate::{
|
use crate::{prelude::*, process::posix_thread::futex::futex_wake, thread::Tid};
|
||||||
prelude::*,
|
|
||||||
process::{posix_thread::futex::futex_wake, Pid},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug, Pod)]
|
#[derive(Clone, Copy, Debug, Pod)]
|
||||||
@ -125,7 +122,7 @@ const FUTEX_TID_MASK: u32 = 0x3FFF_FFFF;
|
|||||||
|
|
||||||
/// Wakeup one robust futex owned by the thread
|
/// Wakeup one robust futex owned by the thread
|
||||||
/// FIXME: requires atomic operations here
|
/// FIXME: requires atomic operations here
|
||||||
pub fn wake_robust_futex(futex_addr: Vaddr, tid: Pid) -> Result<()> {
|
pub fn wake_robust_futex(futex_addr: Vaddr, tid: Tid) -> Result<()> {
|
||||||
let user_space = CurrentUserSpace::get();
|
let user_space = CurrentUserSpace::get();
|
||||||
let futex_val = {
|
let futex_val = {
|
||||||
if futex_addr == 0 {
|
if futex_addr == 0 {
|
||||||
@ -150,7 +147,7 @@ pub fn wake_robust_futex(futex_addr: Vaddr, tid: Pid) -> Result<()> {
|
|||||||
// Wakeup one waiter
|
// Wakeup one waiter
|
||||||
if cur_val & FUTEX_WAITERS != 0 {
|
if cur_val & FUTEX_WAITERS != 0 {
|
||||||
debug!("wake robust futex addr: {:?}", futex_addr);
|
debug!("wake robust futex addr: {:?}", futex_addr);
|
||||||
futex_wake(futex_addr, 1)?;
|
futex_wake(futex_addr, 1, None)?;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ pub fn sys_futex(
|
|||||||
bitset: u64,
|
bitset: u64,
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
) -> Result<SyscallReturn> {
|
) -> Result<SyscallReturn> {
|
||||||
// FIXME: we current ignore futex flags
|
|
||||||
let (futex_op, futex_flags) = futex_op_and_flags_from_u32(futex_op as _)?;
|
let (futex_op, futex_flags) = futex_op_and_flags_from_u32(futex_op as _)?;
|
||||||
debug!(
|
debug!(
|
||||||
"futex_op = {:?}, futex_flags = {:?}, futex_addr = 0x{:x}, futex_val = 0x{:x}",
|
"futex_op = {:?}, futex_flags = {:?}, futex_addr = 0x{:x}, futex_val = 0x{:x}",
|
||||||
@ -84,10 +83,15 @@ pub fn sys_futex(
|
|||||||
)))
|
)))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let pid = if futex_flags.contains(FutexFlags::FUTEX_PRIVATE) {
|
||||||
|
Some(ctx.process.pid())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
let res = match futex_op {
|
let res = match futex_op {
|
||||||
FutexOp::FUTEX_WAIT => {
|
FutexOp::FUTEX_WAIT => {
|
||||||
let timer_builder = get_futex_timer_builder(utime_addr)?;
|
let timer_builder = get_futex_timer_builder(utime_addr)?;
|
||||||
futex_wait(futex_addr as _, futex_val as _, timer_builder, ctx).map(|_| 0)
|
futex_wait(futex_addr as _, futex_val as _, timer_builder, ctx, pid).map(|_| 0)
|
||||||
}
|
}
|
||||||
FutexOp::FUTEX_WAIT_BITSET => {
|
FutexOp::FUTEX_WAIT_BITSET => {
|
||||||
let timer_builder = get_futex_timer_builder(utime_addr)?;
|
let timer_builder = get_futex_timer_builder(utime_addr)?;
|
||||||
@ -97,16 +101,22 @@ pub fn sys_futex(
|
|||||||
timer_builder,
|
timer_builder,
|
||||||
bitset as _,
|
bitset as _,
|
||||||
ctx,
|
ctx,
|
||||||
|
pid,
|
||||||
)
|
)
|
||||||
.map(|_| 0)
|
.map(|_| 0)
|
||||||
}
|
}
|
||||||
FutexOp::FUTEX_WAKE => {
|
FutexOp::FUTEX_WAKE => {
|
||||||
let max_count = get_futex_val(futex_val as i32)?;
|
// From gVisor/test/syscalls/linux/futex.cc:260: "The Linux kernel wakes one waiter even if val is 0 or negative."
|
||||||
futex_wake(futex_addr as _, max_count).map(|count| count as isize)
|
// To be consistent with Linux, we set the max_count to 1 if it is 0 or negative.
|
||||||
|
let max_count = (futex_val as i32).max(1) as usize;
|
||||||
|
futex_wake(futex_addr as _, max_count, pid).map(|count| count as isize)
|
||||||
}
|
}
|
||||||
FutexOp::FUTEX_WAKE_BITSET => {
|
FutexOp::FUTEX_WAKE_BITSET => {
|
||||||
let max_count = get_futex_val(futex_val as i32)?;
|
// From gVisor/test/syscalls/linux/futex.cc:260: "The Linux kernel wakes one waiter even if val is 0 or negative."
|
||||||
futex_wake_bitset(futex_addr as _, max_count, bitset as _).map(|count| count as isize)
|
// To be consistent with Linux, we set the max_count to 1 if it is 0 or negative.
|
||||||
|
let max_count = (futex_val as i32).max(1) as usize;
|
||||||
|
futex_wake_bitset(futex_addr as _, max_count, bitset as _, pid)
|
||||||
|
.map(|count| count as isize)
|
||||||
}
|
}
|
||||||
FutexOp::FUTEX_REQUEUE => {
|
FutexOp::FUTEX_REQUEUE => {
|
||||||
let max_nwakes = get_futex_val(futex_val as i32)?;
|
let max_nwakes = get_futex_val(futex_val as i32)?;
|
||||||
@ -116,6 +126,7 @@ pub fn sys_futex(
|
|||||||
max_nwakes,
|
max_nwakes,
|
||||||
max_nrequeues,
|
max_nrequeues,
|
||||||
futex_new_addr as _,
|
futex_new_addr as _,
|
||||||
|
pid,
|
||||||
)
|
)
|
||||||
.map(|nwakes| nwakes as _)
|
.map(|nwakes| nwakes as _)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user