Fix pthread_cond & pthread_tsd & ...

This commit is contained in:
Zichun Yu 2022-04-04 19:30:52 +08:00
parent d6687d9a65
commit 767e9dd745
10 changed files with 164 additions and 93 deletions

View File

@ -1,7 +1,7 @@
//! Linux kernel objects
#![no_std]
// #![deny(warnings, unsafe_code, missing_docs)]
#![deny(warnings, unsafe_code, missing_docs)]
#![allow(clippy::upper_case_acronyms)]
#![allow(clippy::uninit_vec)]
#![feature(bool_to_option)]

View File

@ -241,21 +241,16 @@ impl LinuxProcess {
/// Get futex object.
#[allow(unsafe_code)]
pub fn get_futex(&self, uaddr: VirtAddr) -> Option<Arc<Futex>> {
pub fn get_futex(&self, uaddr: VirtAddr) -> Arc<Futex> {
let mut inner = self.inner.lock();
// if uaddr == 683520 {
// return None;
// }
Some(
inner
.futexes
.entry(uaddr)
.or_insert_with(|| {
let value = unsafe { &*(uaddr as *const AtomicI32) };
Futex::new(value)
})
.clone(),
)
inner
.futexes
.entry(uaddr)
.or_insert_with(|| {
let value = unsafe { &*(uaddr as *const AtomicI32) };
Futex::new(value)
})
.clone()
}
/// Get lowest free fd

View File

@ -1,6 +1,5 @@
//! Linux Thread
use crate::error::LxError;
use crate::error::SysResult;
use crate::process::ProcessExt;
use crate::signal::{SignalStack, Sigset};
@ -22,8 +21,8 @@ pub trait ThreadExt {
/// Get robust list.
fn get_robust_list(
&self,
head_ptr: UserOutPtr<UserOutPtr<RobustList>>,
len_ptr: UserOutPtr<usize>,
_head_ptr: UserOutPtr<UserOutPtr<RobustList>>,
_len_ptr: UserOutPtr<usize>,
) -> SysResult;
/// Set robust list.
fn set_robust_list(&self, head: UserInPtr<RobustList>, len: usize);
@ -61,14 +60,11 @@ impl ThreadExt for Thread {
fn get_robust_list(
&self,
mut head_ptr: UserOutPtr<UserOutPtr<RobustList>>,
mut len_ptr: UserOutPtr<usize>,
mut _head_ptr: UserOutPtr<UserOutPtr<RobustList>>,
mut _len_ptr: UserOutPtr<usize>,
) -> SysResult {
// if self.lock_linux().robust_list_len == 0 {
// return Err(LxError::EFAULT);
// }
head_ptr = (self.lock_linux().robust_list.as_ptr() as *mut RobustList as usize).into();
len_ptr = (&self.lock_linux().robust_list_len as *const usize as usize).into();
_head_ptr = (self.lock_linux().robust_list.as_ptr() as *mut RobustList as usize).into();
_len_ptr = (&self.lock_linux().robust_list_len as *const usize as usize).into();
Ok(0)
}
@ -89,7 +85,7 @@ impl CurrentThreadExt for CurrentThread {
info!("exit: do futex {:?} wake 1", clear_child_tid);
clear_child_tid.write(0).unwrap();
let uaddr = clear_child_tid.as_ptr() as VirtAddr;
let futex = self.proc().linux().get_futex(uaddr).unwrap();
let futex = self.proc().linux().get_futex(uaddr);
futex.wake(1);
}
self.exit();
@ -100,11 +96,11 @@ impl CurrentThreadExt for CurrentThread {
#[derive(Default)]
pub struct RobustList {
/// head
head: usize,
pub head: usize,
/// off
pub off: isize,
/// pending
pending: usize,
pub pending: usize,
}
/// Linux specific thread information.

View File

@ -15,7 +15,7 @@
//!
#![no_std]
// #![deny(warnings, unsafe_code, missing_docs)]
#![deny(warnings, unsafe_code, missing_docs)]
#![allow(clippy::upper_case_acronyms)]
#[macro_use]
@ -363,10 +363,6 @@ impl Syscall<'_> {
}
// process
#[cfg(target_arch = "riscv64")]
Sys::CLONE => self.sys_clone(a0, a1, a2.into(), a3, a4.into()),
#[cfg(target_arch = "x86_64")]
Sys::CLONE => self.sys_clone(a0, a1, a2.into(), a4, a3.into()),
Sys::EXECVE => self.sys_execve(
self.into_in_userptr(a0).unwrap(),
self.into_in_userptr(a1).unwrap(),
@ -379,7 +375,10 @@ impl Syscall<'_> {
.await
}
Sys::SET_TID_ADDRESS => self.sys_set_tid_address(self.into_out_userptr(a0).unwrap()),
Sys::FUTEX => self.sys_futex(a0, a1 as _, a2 as _, a3).await,
Sys::FUTEX => {
info!("Futex: {} {} {} {} {} {}", a0, a1, a2, a3, a4, a5);
self.sys_futex(a0, a1 as _, a2 as _, a3, a4, a5 as _).await
}
// Sys::FUTEX => self.unimplemented("futex", Ok(0)),
Sys::TKILL => self.unimplemented("tkill", Ok(0)),
Sys::GET_ROBUST_LIST => {
@ -532,6 +531,7 @@ impl Syscall<'_> {
Sys::CHOWN => self.unimplemented("chown", Ok(0)),
Sys::ARCH_PRCTL => self.sys_arch_prctl(a0 as _, a1),
Sys::TIME => self.sys_time(self.into_out_userptr(a0).unwrap()),
Sys::CLONE => self.sys_clone(a0, a1, a2.into(), a4, a3.into()),
// Sys::EPOLL_CREATE => self.sys_epoll_create(a0),
// Sys::EPOLL_WAIT => self.sys_epoll_wait(a0, a1.into(), a2, a3),
_ => self.unknown_syscall(sys_type),
@ -540,10 +540,10 @@ impl Syscall<'_> {
#[cfg(target_arch = "riscv64")]
async fn riscv64_syscall(&mut self, sys_type: Sys, args: [usize; 6]) -> SysResult {
debug!("riscv64_syscall: {:?}, {:?}", sys_type, args);
//let [a0, a1, a2, a3, a4, _a5] = args;
let [a0, a1, a2, a3, a4, _a5] = args;
match sys_type {
//Sys::OPEN => self.sys_open(a0.into(), a1, a2),
Sys::CLONE => self.sys_clone(a0, a1, a2.into(), a3, a4.into()),
_ => self.unknown_syscall(sys_type),
}
}

View File

@ -4,10 +4,7 @@ use core::time::Duration;
use futures::pin_mut;
use kernel_hal::timer::timer_now;
use linux_object::time::*;
use zircon_object::{
task::{IntoResult, ThreadState},
ZxResult,
};
use zircon_object::task::ThreadState;
impl Syscall<'_> {
#[cfg(target_arch = "x86_64")]
@ -82,6 +79,8 @@ impl Syscall<'_> {
op: u32,
val: u32,
timeout_addr: usize,
uaddr2: usize,
_val3: u32,
) -> SysResult {
if let Err(_) = self.into_inout_userptr::<i32>(uaddr) {
return Err(LxError::EINVAL);
@ -89,9 +88,15 @@ impl Syscall<'_> {
let op = FutexFlags::from_bits_truncate(op);
if !op.contains(FutexFlags::PRIVATE) {
warn!("process-shared futex is unimplemented");
return Err(LxError::ENOPROTOOPT);
// return Err(LxError::ENOPROTOOPT);
}
let mut val2 = 0;
if op.contains(FutexFlags::REQUEUE) {
if let Err(_) = self.into_inout_userptr::<i32>(uaddr2) {
return Err(LxError::EINVAL);
}
val2 = timeout_addr;
}
let op = op - FutexFlags::PRIVATE;
let timeout = if op.contains(FutexFlags::WAKE) {
self.into_inout_userptr::<TimeSpec>(0).unwrap()
} else {
@ -102,55 +107,96 @@ impl Syscall<'_> {
}
};
warn!(
"Futex: uaddr: {:#x}, op: {:x}, val: {}, timeout_ptr: {:x?}",
"Futex: uaddr: {:#x}, op: {:x}, val: {}, timeout_ptr: {:x?}, val2: {}",
uaddr,
op.bits(),
val,
timeout
timeout,
val2,
);
let futex_op = self.linux_process().get_futex(uaddr);
match futex_op {
Some(futex) => match op {
FutexFlags::WAIT => {
let timeout = timeout.read_if_not_null()?;
let duration: Duration = match timeout {
Some(T) => T.into(),
None => Duration::from_secs(0),
};
let into_lxerror = |e: ZxError| match e {
ZxError::BAD_STATE => LxError::EAGAIN,
e => e.into(),
};
let future = futex.wait(val);
let res = if duration.as_millis() == 0 {
future.await
} else {
warn!("duration: {:?}", duration);
pin_mut!(future);
self.thread
.blocking_run(
future,
ThreadState::BlockedFutex,
timer_now() + duration,
None,
)
.await
};
match res {
Ok(_) => return Ok(0),
Err(e) => return Err(into_lxerror(e)),
}
let futex = self.linux_process().get_futex(uaddr);
let op = op - FutexFlags::PRIVATE;
match op {
FutexFlags::WAIT => {
let timeout = timeout.read_if_not_null()?;
let duration: Duration = match timeout {
Some(t) => t.into(),
None => Duration::from_secs(0),
};
let into_lxerror = |e: ZxError| match e {
ZxError::BAD_STATE => LxError::EAGAIN,
e => e.into(),
};
let future = futex.wait(val, false, self.thread.id() as i32);
let res = if duration.as_millis() == 0 {
future.await
} else {
warn!("duration: {:?}", duration);
pin_mut!(future);
self.thread
.blocking_run(
future,
ThreadState::BlockedFutex,
timer_now() + duration,
None,
)
.await
};
match res {
Ok(_) => return Ok(0),
Err(e) => return Err(into_lxerror(e)),
}
FutexFlags::WAKE => {
let woken_up_count = futex.wake(val as usize);
Ok(woken_up_count)
}
FutexFlags::WAKE => {
let woken_up_count = futex.wake(val as usize);
Ok(woken_up_count)
}
FutexFlags::LOCK_PI => {
let timeout = timeout.read_if_not_null()?;
let duration: Duration = match timeout {
Some(t) => t.into(),
None => Duration::from_secs(0),
};
let into_lxerror = |e: ZxError| match e {
ZxError::BAD_STATE => LxError::EAGAIN,
e => e.into(),
};
let future = futex.wait(val, true, self.thread.id() as i32);
let res = if duration.as_millis() == 0 {
future.await
} else {
warn!("duration: {:?}", duration);
pin_mut!(future);
self.thread
.blocking_run(
future,
ThreadState::BlockedFutex,
timer_now() + duration,
None,
)
.await
};
match res {
Ok(_) => return Ok(0),
Err(e) => return Err(into_lxerror(e)),
}
_ => {
warn!("unsupported futex operation: {:?}", op);
Err(LxError::ENOPROTOOPT)
}
FutexFlags::REQUEUE => {
let requeue_futex = self.linux_process().get_futex(uaddr2);
let into_lxerror = |e: ZxError| match e {
ZxError::BAD_STATE => LxError::EAGAIN,
e => e.into(),
};
let res = futex.requeue(0, val as usize, val2, &requeue_futex, None, false);
match res {
Ok(_) => return Ok(0),
Err(e) => return Err(into_lxerror(e)),
}
},
None => Err(LxError::EAGAIN),
}
_ => {
warn!("unsupported futex operation: {:?}", op);
Err(LxError::ENOPROTOOPT)
}
}
}
@ -218,6 +264,8 @@ bitflags! {
/// wakes at most val of the waiters that are waiting on the futex word at the address uaddr.
const WAKE = 1;
///
const REQUEUE = 3;
///
const LOCK_PI = 6;
///
const UNLOCK_PI = 7;

View File

@ -297,6 +297,7 @@ impl Syscall<'_> {
Ok(tid as usize)
}
/// Get robust list.
pub fn sys_get_robust_list(
&self,
pid: i32,
@ -313,6 +314,7 @@ impl Syscall<'_> {
Ok(0)
}
/// Set robust list.
pub fn sys_set_robust_list(&self, head: UserInPtr<RobustList>, len: usize) -> SysResult {
warn!("in sys_set_robust_list");
if len != size_of::<RobustList>().into() {

View File

@ -60,6 +60,7 @@ async fn run_user(thread: CurrentThread) {
}
info!("back to user: thread id = {}", thread.id());
// run
trace!("go to user: {:#x?}", ctx);
ctx.enter_uspace();

View File

@ -62,7 +62,7 @@ pub fn boot_options() -> BootOptions {
#[cfg(feature = "linux")]
root_proc: String::from(*options.get("ROOTPROC").unwrap_or(&"/bin/busybox?sh")),
// root_proc: String::from(*options.get("ROOTPROC")
// .unwrap_or(&"/libc-test/functional/pthread_robust.exe")),
// .unwrap_or(&"/libc-test/functional/pthread_mutex.exe")),
}
}
}

View File

@ -57,8 +57,13 @@ impl Futex {
///
/// [`wait_with_owner`]: Futex::wait_with_owner
/// [`wake`]: Futex::wake
pub fn wait(self: &Arc<Self>, current_value: u32) -> impl Future<Output = ZxResult> {
self.wait_with_owner(current_value, None, None)
pub fn wait(
self: &Arc<Self>,
current_value: u32,
lock_pi: bool,
thread_id: i32,
) -> impl Future<Output = ZxResult> {
self.wait_with_owner(current_value, None, None, lock_pi, thread_id)
}
/// Wake some number of threads waiting on a futex.
@ -117,12 +122,16 @@ impl Futex {
current_value: u32,
thread: Option<Arc<Thread>>,
new_owner: Option<Arc<Thread>>,
lock_pi: bool,
thread_id: i32,
) -> impl Future<Output = ZxResult> {
#[must_use = "wait does nothing unless polled/`await`-ed"]
struct FutexFuture {
waiter: Arc<Waiter>,
current_value: u32,
new_owner: Option<Arc<Thread>>,
lock_pi: bool,
thread_id: i32,
}
impl Future for FutexFuture {
type Output = ZxResult;
@ -133,15 +142,29 @@ impl Futex {
if inner.woken {
// set new owner on success
inner.futex.inner.lock().set_owner(self.new_owner.clone());
warn!("Futex Ready!!!");
return Poll::Ready(Ok(()));
}
// first time?
if inner.waker.is_none() {
// check value
let value = inner.futex.value.load(Ordering::SeqCst);
if value as u32 != self.current_value {
warn!("Futex BAD STATE");
return Poll::Ready(Err(ZxError::BAD_STATE));
if self.lock_pi {
if value as u32 == 0 {
warn!("This is {}", self.thread_id);
inner.futex.value.store(self.thread_id, Ordering::SeqCst);
} else {
inner
.futex
.value
.store((value as u32 | 0x80000000) as i32, Ordering::SeqCst);
}
return Poll::Ready(Ok(()));
} else {
if value as u32 != self.current_value {
warn!("Futex BAD_STATE!!!");
return Poll::Ready(Err(ZxError::BAD_STATE));
}
}
// check new owner
let mut futex = inner.futex.inner.lock();
@ -182,6 +205,8 @@ impl Futex {
}),
current_value,
new_owner,
lock_pi,
thread_id,
}
}
@ -224,11 +249,14 @@ impl Futex {
requeue_count: usize,
requeue_futex: &Arc<Futex>,
new_requeue_owner: Option<Arc<Thread>>,
check_value: bool,
) -> ZxResult {
let mut inner = self.inner.lock();
// check value
if self.value.load(Ordering::SeqCst) != current_value {
return Err(ZxError::BAD_STATE);
if check_value {
// check value
if self.value.load(Ordering::SeqCst) != current_value {
return Err(ZxError::BAD_STATE);
}
}
// wake
for _ in 0..wake_count {

View File

@ -74,6 +74,7 @@ impl Syscall<'_> {
requeue_count as usize,
&requeue_futex,
new_requeue_owner,
true,
)?;
Ok(())
}