forked from rcore-os/zCore
split Thread to CurrentThread, refactor exception
This commit is contained in:
parent
33d4836912
commit
abe4792691
|
@ -53,7 +53,7 @@ pub fn run(args: Vec<String>, envs: Vec<String>, rootfs: Arc<dyn FileSystem>) ->
|
||||||
/// - enter user mode
|
/// - enter user mode
|
||||||
/// - handle trap/interrupt/syscall according to the return value
|
/// - handle trap/interrupt/syscall according to the return value
|
||||||
/// - return the context to the user thread
|
/// - return the context to the user thread
|
||||||
fn spawn(thread: Arc<Thread>) {
|
fn spawn(thread: CurrentThread) {
|
||||||
let vmtoken = thread.proc().vmar().table_phys();
|
let vmtoken = thread.proc().vmar().table_phys();
|
||||||
let future = async move {
|
let future = async move {
|
||||||
loop {
|
loop {
|
||||||
|
@ -102,7 +102,7 @@ fn spawn(thread: Arc<Thread>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// syscall handler entry: create a struct `syscall: Syscall`, and call `syscall.syscall()`
|
/// syscall handler entry: create a struct `syscall: Syscall`, and call `syscall.syscall()`
|
||||||
async fn handle_syscall(thread: &Arc<Thread>, regs: &mut GeneralRegs) -> bool {
|
async fn handle_syscall(thread: &CurrentThread, regs: &mut GeneralRegs) -> bool {
|
||||||
trace!("syscall: {:#x?}", regs);
|
trace!("syscall: {:#x?}", regs);
|
||||||
let num = regs.rax as u32;
|
let num = regs.rax as u32;
|
||||||
let args = [regs.rdi, regs.rsi, regs.rdx, regs.r10, regs.r8, regs.r9];
|
let args = [regs.rdi, regs.rsi, regs.rdx, regs.r10, regs.r8, regs.r9];
|
||||||
|
|
|
@ -5,7 +5,7 @@ use alloc::sync::Arc;
|
||||||
use kernel_hal::user::{Out, UserOutPtr, UserPtr};
|
use kernel_hal::user::{Out, UserOutPtr, UserPtr};
|
||||||
use kernel_hal::VirtAddr;
|
use kernel_hal::VirtAddr;
|
||||||
use spin::{Mutex, MutexGuard};
|
use spin::{Mutex, MutexGuard};
|
||||||
use zircon_object::task::{Process, Thread};
|
use zircon_object::task::{CurrentThread, Process, Thread};
|
||||||
use zircon_object::ZxResult;
|
use zircon_object::ZxResult;
|
||||||
|
|
||||||
/// Thread extension for linux
|
/// Thread extension for linux
|
||||||
|
@ -16,6 +16,10 @@ pub trait ThreadExt {
|
||||||
fn lock_linux(&self) -> MutexGuard<'_, LinuxThread>;
|
fn lock_linux(&self) -> MutexGuard<'_, LinuxThread>;
|
||||||
/// Set pointer to thread ID.
|
/// Set pointer to thread ID.
|
||||||
fn set_tid_address(&self, tidptr: UserOutPtr<i32>);
|
fn set_tid_address(&self, tidptr: UserOutPtr<i32>);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// CurrentThread extension for linux
|
||||||
|
pub trait CurrentThreadExt {
|
||||||
/// exit linux thread
|
/// exit linux thread
|
||||||
fn exit_linux(&self, exit_code: i32);
|
fn exit_linux(&self, exit_code: i32);
|
||||||
}
|
}
|
||||||
|
@ -39,7 +43,9 @@ impl ThreadExt for Thread {
|
||||||
fn set_tid_address(&self, tidptr: UserPtr<i32, Out>) {
|
fn set_tid_address(&self, tidptr: UserPtr<i32, Out>) {
|
||||||
self.lock_linux().clear_child_tid = tidptr;
|
self.lock_linux().clear_child_tid = tidptr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CurrentThreadExt for CurrentThread {
|
||||||
/// Exit current thread for Linux.
|
/// Exit current thread for Linux.
|
||||||
fn exit_linux(&self, _exit_code: i32) {
|
fn exit_linux(&self, _exit_code: i32) {
|
||||||
let mut linux_thread = self.lock_linux();
|
let mut linux_thread = self.lock_linux();
|
||||||
|
|
|
@ -54,13 +54,13 @@ mod vm;
|
||||||
/// The struct of Syscall which stores the information about making a syscall
|
/// The struct of Syscall which stores the information about making a syscall
|
||||||
pub struct Syscall<'a> {
|
pub struct Syscall<'a> {
|
||||||
/// the thread making a syscall
|
/// the thread making a syscall
|
||||||
pub thread: &'a Arc<Thread>,
|
pub thread: &'a CurrentThread,
|
||||||
/// the entry of current syscall
|
/// the entry of current syscall
|
||||||
pub syscall_entry: VirtAddr,
|
pub syscall_entry: VirtAddr,
|
||||||
/// store the regs statues
|
/// store the regs statues
|
||||||
pub regs: &'a mut GeneralRegs,
|
pub regs: &'a mut GeneralRegs,
|
||||||
/// the spawn function in linux-loader
|
/// the spawn function in linux-loader
|
||||||
pub spawn_fn: fn(thread: Arc<Thread>),
|
pub spawn_fn: fn(thread: CurrentThread),
|
||||||
/// Set `true` to exit current task.
|
/// Set `true` to exit current task.
|
||||||
pub exit: bool,
|
pub exit: bool,
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ use bitflags::bitflags;
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use linux_object::fs::INodeExt;
|
use linux_object::fs::INodeExt;
|
||||||
use linux_object::loader::LinuxElfLoader;
|
use linux_object::loader::LinuxElfLoader;
|
||||||
use linux_object::thread::ThreadExt;
|
use linux_object::thread::{CurrentThreadExt, ThreadExt};
|
||||||
|
|
||||||
impl Syscall<'_> {
|
impl Syscall<'_> {
|
||||||
/// Fork the current process. Return the child's PID.
|
/// Fork the current process. Return the child's PID.
|
||||||
|
|
|
@ -172,22 +172,17 @@ kcounter!(EXCEPTIONS_USER, "exceptions.user");
|
||||||
kcounter!(EXCEPTIONS_TIMER, "exceptions.timer");
|
kcounter!(EXCEPTIONS_TIMER, "exceptions.timer");
|
||||||
kcounter!(EXCEPTIONS_PGFAULT, "exceptions.pgfault");
|
kcounter!(EXCEPTIONS_PGFAULT, "exceptions.pgfault");
|
||||||
|
|
||||||
fn spawn(thread: Arc<Thread>) {
|
fn spawn(thread: CurrentThread) {
|
||||||
let vmtoken = thread.proc().vmar().table_phys();
|
let vmtoken = thread.proc().vmar().table_phys();
|
||||||
let future = async move {
|
let future = async move {
|
||||||
kernel_hal::Thread::set_tid(thread.id(), thread.proc().id());
|
kernel_hal::Thread::set_tid(thread.id(), thread.proc().id());
|
||||||
if thread.is_first_thread() {
|
if thread.is_first_thread() {
|
||||||
Exception::create(&thread, ExceptionType::ProcessStarting, None)
|
let exception = Exception::create(&thread, ExceptionType::ProcessStarting, None);
|
||||||
.handle_with_exceptionates(
|
thread.wait_for_exception_handling(exception).await;
|
||||||
false,
|
|
||||||
JobDebuggerIterator::new(thread.proc().job()),
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
};
|
};
|
||||||
Exception::create(&thread, ExceptionType::ThreadStarting, None)
|
let exception = Exception::create(&thread, ExceptionType::ThreadStarting, None);
|
||||||
.handle_with_exceptionates(false, Some(thread.proc().debug_exceptionate()), false)
|
thread.wait_for_exception_handling(exception).await;
|
||||||
.await;
|
|
||||||
loop {
|
loop {
|
||||||
let mut cx = thread.wait_for_run().await;
|
let mut cx = thread.wait_for_run().await;
|
||||||
if thread.state() == ThreadState::Dying {
|
if thread.state() == ThreadState::Dying {
|
||||||
|
@ -243,7 +238,7 @@ fn spawn(thread: Arc<Thread>) {
|
||||||
error!("Page Fault from user mode: {:#x?}", cx);
|
error!("Page Fault from user mode: {:#x?}", cx);
|
||||||
let exception =
|
let exception =
|
||||||
Exception::create(&thread, ExceptionType::FatalPageFault, Some(&cx));
|
Exception::create(&thread, ExceptionType::FatalPageFault, Some(&cx));
|
||||||
exception.handle(true).await;
|
thread.wait_for_exception_handling(exception).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0x8 => {
|
0x8 => {
|
||||||
|
@ -259,7 +254,7 @@ fn spawn(thread: Arc<Thread>) {
|
||||||
};
|
};
|
||||||
error!("User mode exception: {:?} {:#x?}", type_, cx);
|
error!("User mode exception: {:?} {:#x?}", type_, cx);
|
||||||
let exception = Exception::create(&thread, type_, Some(&cx));
|
let exception = Exception::create(&thread, type_, Some(&cx));
|
||||||
exception.handle(true).await;
|
thread.wait_for_exception_handling(exception).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thread.end_running(cx);
|
thread.end_running(cx);
|
||||||
|
@ -277,7 +272,7 @@ fn spawn(thread: Arc<Thread>) {
|
||||||
kernel_hal::Thread::spawn(Box::pin(future), vmtoken);
|
kernel_hal::Thread::spawn(Box::pin(future), vmtoken);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_syscall(thread: &Arc<Thread>, regs: &mut GeneralRegs) {
|
async fn handle_syscall(thread: &CurrentThread, regs: &mut GeneralRegs) {
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
let num = regs.rax as u32;
|
let num = regs.rax as u32;
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
@ -305,7 +300,7 @@ async fn handle_syscall(thread: &Arc<Thread>, regs: &mut GeneralRegs) {
|
||||||
];
|
];
|
||||||
let mut syscall = Syscall {
|
let mut syscall = Syscall {
|
||||||
regs,
|
regs,
|
||||||
thread: thread.clone(),
|
thread,
|
||||||
spawn_fn: spawn,
|
spawn_fn: spawn,
|
||||||
};
|
};
|
||||||
let ret = syscall.syscall(num, args).await as usize;
|
let ret = syscall.syscall(num, args).await as usize;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use {
|
use {
|
||||||
super::*, crate::ipc::*, crate::object::*, alloc::sync::Arc, alloc::vec, alloc::vec::Vec,
|
super::*, crate::ipc::*, crate::object::*, alloc::sync::Arc, alloc::vec, alloc::vec::Vec,
|
||||||
core::mem::size_of, futures::channel::oneshot, futures::pin_mut, kernel_hal::UserContext,
|
core::mem::size_of, futures::channel::oneshot, kernel_hal::UserContext, spin::Mutex,
|
||||||
spin::Mutex,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Kernel-owned exception channel endpoint.
|
/// Kernel-owned exception channel endpoint.
|
||||||
|
@ -197,6 +196,12 @@ pub enum ExceptionType {
|
||||||
ProcessStarting = 0x8308,
|
ProcessStarting = 0x8308,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ExceptionType {
|
||||||
|
fn is_fatal(self) -> bool {
|
||||||
|
(self as u32) < 0x1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Type of the exception channel
|
/// Type of the exception channel
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
@ -341,31 +346,32 @@ impl Exception {
|
||||||
///
|
///
|
||||||
/// Note that it's possible that this may returns before exception was send to any exception channel.
|
/// Note that it's possible that this may returns before exception was send to any exception channel.
|
||||||
/// This happens only when the thread is killed before we send the exception.
|
/// This happens only when the thread is killed before we send the exception.
|
||||||
pub async fn handle(self: &Arc<Self>, fatal: bool) {
|
pub(super) async fn handle(self: &Arc<Self>) {
|
||||||
self.handle_with_exceptionates(fatal, ExceptionateIterator::new(self), false)
|
let result = match self.type_ {
|
||||||
.await
|
ExceptionType::ProcessStarting => {
|
||||||
}
|
self.handle_with(JobDebuggerIterator::new(self.thread.proc().job()), true)
|
||||||
|
.await
|
||||||
/// Same as `handle`, but use a customized iterator.
|
}
|
||||||
///
|
ExceptionType::ThreadStarting | ExceptionType::ThreadExiting => {
|
||||||
/// If `first_only` is true, this will only send exception to the first one that received the exception
|
self.handle_with(Some(self.thread.proc().debug_exceptionate()), false)
|
||||||
/// even when the exception is not handled.
|
.await
|
||||||
pub async fn handle_with_exceptionates(
|
}
|
||||||
self: &Arc<Self>,
|
_ => {
|
||||||
fatal: bool,
|
self.handle_with(ExceptionateIterator::new(self), false)
|
||||||
exceptionates: impl IntoIterator<Item = Arc<Exceptionate>>,
|
.await
|
||||||
first_only: bool,
|
}
|
||||||
) {
|
};
|
||||||
let future = self.handle_internal(exceptionates, first_only);
|
if result == Err(ZxError::NEXT) && self.type_.is_fatal() {
|
||||||
pin_mut!(future);
|
|
||||||
let result = self.thread.wait_for_exception(future, self.clone()).await;
|
|
||||||
if result == Err(ZxError::NEXT) && fatal {
|
|
||||||
// Nobody handled the exception, kill myself
|
// Nobody handled the exception, kill myself
|
||||||
self.thread.proc().exit(TASK_RETCODE_SYSCALL_KILL);
|
self.thread.proc().exit(TASK_RETCODE_SYSCALL_KILL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_internal(
|
/// Handle the exception with a customized iterator.
|
||||||
|
///
|
||||||
|
/// If `first_only` is true, this will only send exception to the first one that received the exception
|
||||||
|
/// even when the exception is not handled.
|
||||||
|
async fn handle_with(
|
||||||
self: &Arc<Self>,
|
self: &Arc<Self>,
|
||||||
exceptionates: impl IntoIterator<Item = Arc<Exceptionate>>,
|
exceptionates: impl IntoIterator<Item = Arc<Exceptionate>>,
|
||||||
first_only: bool,
|
first_only: bool,
|
||||||
|
@ -479,13 +485,13 @@ impl<'a> Iterator for ExceptionateIterator<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is only used by ProcessStarting exceptions
|
/// This is only used by ProcessStarting exceptions
|
||||||
pub struct JobDebuggerIterator {
|
struct JobDebuggerIterator {
|
||||||
job: Option<Arc<Job>>,
|
job: Option<Arc<Job>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JobDebuggerIterator {
|
impl JobDebuggerIterator {
|
||||||
/// Create a new JobDebuggerIterator
|
/// Create a new JobDebuggerIterator
|
||||||
pub fn new(job: Arc<Job>) -> Self {
|
fn new(job: Arc<Job>) -> Self {
|
||||||
JobDebuggerIterator { job: Some(job) }
|
JobDebuggerIterator { job: Some(job) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,6 @@ impl Process {
|
||||||
name: &str,
|
name: &str,
|
||||||
ext: impl Any + Send + Sync,
|
ext: impl Any + Send + Sync,
|
||||||
) -> ZxResult<Arc<Self>> {
|
) -> ZxResult<Arc<Self>> {
|
||||||
// TODO: _options -> options
|
|
||||||
let proc = Arc::new(Process {
|
let proc = Arc::new(Process {
|
||||||
base: KObjectBase::with_name(name),
|
base: KObjectBase::with_name(name),
|
||||||
_counter: CountHelper::new(),
|
_counter: CountHelper::new(),
|
||||||
|
@ -145,7 +144,7 @@ impl Process {
|
||||||
stack: usize,
|
stack: usize,
|
||||||
arg1: Option<Handle>,
|
arg1: Option<Handle>,
|
||||||
arg2: usize,
|
arg2: usize,
|
||||||
spawn_fn: fn(thread: Arc<Thread>),
|
spawn_fn: fn(thread: CurrentThread),
|
||||||
) -> ZxResult {
|
) -> ZxResult {
|
||||||
let handle_value;
|
let handle_value;
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,11 +8,12 @@ use {
|
||||||
core::{
|
core::{
|
||||||
any::Any,
|
any::Any,
|
||||||
future::Future,
|
future::Future,
|
||||||
|
ops::Deref,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
task::{Context, Poll, Waker},
|
task::{Context, Poll, Waker},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
},
|
},
|
||||||
futures::{channel::oneshot::*, future::FutureExt, select_biased},
|
futures::{channel::oneshot::*, future::FutureExt, pin_mut, select_biased},
|
||||||
kernel_hal::{sleep_until, GeneralRegs, UserContext},
|
kernel_hal::{sleep_until, GeneralRegs, UserContext},
|
||||||
spin::Mutex,
|
spin::Mutex,
|
||||||
};
|
};
|
||||||
|
@ -216,7 +217,7 @@ impl Thread {
|
||||||
stack: usize,
|
stack: usize,
|
||||||
arg1: usize,
|
arg1: usize,
|
||||||
arg2: usize,
|
arg2: usize,
|
||||||
spawn_fn: fn(thread: Arc<Thread>),
|
spawn_fn: fn(thread: CurrentThread),
|
||||||
) -> ZxResult {
|
) -> ZxResult {
|
||||||
{
|
{
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
|
@ -239,7 +240,7 @@ impl Thread {
|
||||||
inner.state = ThreadState::Running;
|
inner.state = ThreadState::Running;
|
||||||
inner.update_signal(&self.base);
|
inner.update_signal(&self.base);
|
||||||
}
|
}
|
||||||
spawn_fn(self.clone());
|
spawn_fn(CurrentThread(self.clone()));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +248,7 @@ impl Thread {
|
||||||
pub fn start_with_regs(
|
pub fn start_with_regs(
|
||||||
self: &Arc<Self>,
|
self: &Arc<Self>,
|
||||||
regs: GeneralRegs,
|
regs: GeneralRegs,
|
||||||
spawn_fn: fn(thread: Arc<Thread>),
|
spawn_fn: fn(thread: CurrentThread),
|
||||||
) -> ZxResult {
|
) -> ZxResult {
|
||||||
{
|
{
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
|
@ -261,7 +262,7 @@ impl Thread {
|
||||||
inner.update_signal(&self.base);
|
inner.update_signal(&self.base);
|
||||||
self.base.signal_set(Signal::THREAD_RUNNING);
|
self.base.signal_set(Signal::THREAD_RUNNING);
|
||||||
}
|
}
|
||||||
spawn_fn(self.clone());
|
spawn_fn(CurrentThread(self.clone()));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,23 +301,6 @@ impl Thread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Exit the thread.
|
|
||||||
/// The thread do not terminate immediately when exited. It is just made dying.
|
|
||||||
/// It will terminate after some cleanups (when `terminate` are called **explicitly** by upper layer).
|
|
||||||
pub fn exit(&self) {
|
|
||||||
self.stop(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Terminate the current running thread. This function should be called **explicitly**
|
|
||||||
/// by upper layer after cleanups are finished.
|
|
||||||
pub fn terminate(&self) {
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
self.exceptionate.shutdown();
|
|
||||||
inner.state = ThreadState::Dead;
|
|
||||||
inner.update_signal(&self.base);
|
|
||||||
self.proc().remove_thread(self.base.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read one aspect of thread state.
|
/// Read one aspect of thread state.
|
||||||
pub fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult<usize> {
|
pub fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult<usize> {
|
||||||
let inner = self.inner.lock();
|
let inner = self.inner.lock();
|
||||||
|
@ -331,38 +315,6 @@ impl Thread {
|
||||||
context.write_state(kind, buf)
|
context.write_state(kind, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wait until the thread is ready to run (not suspended),
|
|
||||||
/// and then take away its context to run the thread.
|
|
||||||
pub fn wait_for_run(self: &Arc<Thread>) -> impl Future<Output = Box<UserContext>> {
|
|
||||||
#[must_use = "wait_for_run does nothing unless polled/`await`-ed"]
|
|
||||||
struct RunnableChecker {
|
|
||||||
thread: Arc<Thread>,
|
|
||||||
}
|
|
||||||
impl Future for RunnableChecker {
|
|
||||||
type Output = Box<UserContext>;
|
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
|
||||||
let mut inner = self.thread.inner.lock();
|
|
||||||
if inner.suspend_count == 0 {
|
|
||||||
// resume: return the context token from thread object
|
|
||||||
Poll::Ready(inner.context.take().unwrap())
|
|
||||||
} else {
|
|
||||||
// suspend: put waker into the thread object
|
|
||||||
inner.waker = Some(cx.waker().clone());
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RunnableChecker {
|
|
||||||
thread: self.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The thread ends running and takes back the context.
|
|
||||||
pub fn end_running(&self, context: Box<UserContext>) {
|
|
||||||
self.inner.lock().context = Some(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the thread's information.
|
/// Get the thread's information.
|
||||||
pub fn get_thread_info(&self) -> ThreadInfo {
|
pub fn get_thread_info(&self) -> ThreadInfo {
|
||||||
let inner = self.inner.lock();
|
let inner = self.inner.lock();
|
||||||
|
@ -386,95 +338,6 @@ impl Thread {
|
||||||
Ok(report)
|
Ok(report)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run async future and change state while blocking.
|
|
||||||
pub async fn blocking_run<F, T, FT>(
|
|
||||||
&self,
|
|
||||||
future: F,
|
|
||||||
state: ThreadState,
|
|
||||||
deadline: Duration,
|
|
||||||
cancel_token: Option<Receiver<()>>,
|
|
||||||
) -> ZxResult<T>
|
|
||||||
where
|
|
||||||
F: Future<Output = FT> + Unpin,
|
|
||||||
FT: IntoResult<T>,
|
|
||||||
{
|
|
||||||
let (old_state, killed) = {
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
if inner.get_state() == ThreadState::Dying {
|
|
||||||
return Err(ZxError::STOP);
|
|
||||||
}
|
|
||||||
let (sender, receiver) = channel();
|
|
||||||
inner.killer = Some(sender);
|
|
||||||
let old_state = core::mem::replace(&mut inner.state, state);
|
|
||||||
inner.update_signal(&self.base);
|
|
||||||
(old_state, receiver)
|
|
||||||
};
|
|
||||||
let ret = if let Some(cancel_token) = cancel_token {
|
|
||||||
select_biased! {
|
|
||||||
ret = future.fuse() => ret.into_result(),
|
|
||||||
_ = killed.fuse() => Err(ZxError::STOP),
|
|
||||||
_ = sleep_until(deadline).fuse() => Err(ZxError::TIMED_OUT),
|
|
||||||
_ = cancel_token.fuse() => Err(ZxError::CANCELED),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
select_biased! {
|
|
||||||
ret = future.fuse() => ret.into_result(),
|
|
||||||
_ = killed.fuse() => Err(ZxError::STOP),
|
|
||||||
_ = sleep_until(deadline).fuse() => Err(ZxError::TIMED_OUT),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
inner.killer = None;
|
|
||||||
if inner.state == ThreadState::Dying {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
assert_eq!(inner.state, state);
|
|
||||||
inner.state = old_state;
|
|
||||||
inner.update_signal(&self.base);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run a blocking task when the thread is exited itself and dying.
|
|
||||||
///
|
|
||||||
/// The task will stop running if and once the thread is killed.
|
|
||||||
pub async fn dying_run<F, T, FT>(&self, future: F) -> ZxResult<T>
|
|
||||||
where
|
|
||||||
F: Future<Output = FT> + Unpin,
|
|
||||||
FT: IntoResult<T>,
|
|
||||||
{
|
|
||||||
let killed = {
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
if inner.get_state() == ThreadState::Dead || inner.killed {
|
|
||||||
return Err(ZxError::STOP);
|
|
||||||
}
|
|
||||||
let (sender, receiver) = channel::<()>();
|
|
||||||
inner.killer = Some(sender);
|
|
||||||
receiver
|
|
||||||
};
|
|
||||||
select_biased! {
|
|
||||||
ret = future.fuse() => ret.into_result(),
|
|
||||||
_ = killed.fuse() => Err(ZxError::STOP),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) async fn wait_for_exception<T>(
|
|
||||||
&self,
|
|
||||||
future: impl Future<Output = ZxResult<T>> + Unpin,
|
|
||||||
exception: Arc<Exception>,
|
|
||||||
) -> ZxResult<T> {
|
|
||||||
self.inner.lock().exception = Some(exception);
|
|
||||||
let ret = self
|
|
||||||
.blocking_run(
|
|
||||||
future,
|
|
||||||
ThreadState::BlockedException,
|
|
||||||
Duration::from_nanos(u64::max_value()),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
self.inner.lock().exception = None;
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the thread state.
|
/// Get the thread state.
|
||||||
pub fn state(&self) -> ThreadState {
|
pub fn state(&self) -> ThreadState {
|
||||||
self.inner.lock().get_state()
|
self.inner.lock().get_state()
|
||||||
|
@ -551,6 +414,157 @@ impl Task for Thread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Current thread.
|
||||||
|
pub struct CurrentThread(Arc<Thread>);
|
||||||
|
|
||||||
|
impl Deref for CurrentThread {
|
||||||
|
type Target = Arc<Thread>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CurrentThread {
|
||||||
|
/// Exit the current thread.
|
||||||
|
///
|
||||||
|
/// The thread do not terminate immediately when exited. It is just made dying.
|
||||||
|
/// It will terminate after some cleanups (when `terminate` are called **explicitly** by upper layer).
|
||||||
|
pub fn exit(&self) {
|
||||||
|
self.stop(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Terminate the current running thread.
|
||||||
|
///
|
||||||
|
/// This function should be called **explicitly** by upper layer after cleanups are finished.
|
||||||
|
pub fn terminate(&self) {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
self.exceptionate.shutdown();
|
||||||
|
inner.state = ThreadState::Dead;
|
||||||
|
inner.update_signal(&self.base);
|
||||||
|
self.proc().remove_thread(self.base.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wait until the thread is ready to run (not suspended),
|
||||||
|
/// and then take away its context to run the thread.
|
||||||
|
pub fn wait_for_run(&self) -> impl Future<Output = Box<UserContext>> {
|
||||||
|
#[must_use = "wait_for_run does nothing unless polled/`await`-ed"]
|
||||||
|
struct RunnableChecker {
|
||||||
|
thread: Arc<Thread>,
|
||||||
|
}
|
||||||
|
impl Future for RunnableChecker {
|
||||||
|
type Output = Box<UserContext>;
|
||||||
|
|
||||||
|
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||||
|
let mut inner = self.thread.inner.lock();
|
||||||
|
if inner.suspend_count == 0 {
|
||||||
|
// resume: return the context token from thread object
|
||||||
|
Poll::Ready(inner.context.take().unwrap())
|
||||||
|
} else {
|
||||||
|
// suspend: put waker into the thread object
|
||||||
|
inner.waker = Some(cx.waker().clone());
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RunnableChecker {
|
||||||
|
thread: self.0.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The thread ends running and takes back the context.
|
||||||
|
pub fn end_running(&self, context: Box<UserContext>) {
|
||||||
|
self.inner.lock().context = Some(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run async future and change state while blocking.
|
||||||
|
pub async fn blocking_run<F, T, FT>(
|
||||||
|
&self,
|
||||||
|
future: F,
|
||||||
|
state: ThreadState,
|
||||||
|
deadline: Duration,
|
||||||
|
cancel_token: Option<Receiver<()>>,
|
||||||
|
) -> ZxResult<T>
|
||||||
|
where
|
||||||
|
F: Future<Output = FT> + Unpin,
|
||||||
|
FT: IntoResult<T>,
|
||||||
|
{
|
||||||
|
let (old_state, killed) = {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
if inner.get_state() == ThreadState::Dying {
|
||||||
|
return Err(ZxError::STOP);
|
||||||
|
}
|
||||||
|
let (sender, receiver) = channel();
|
||||||
|
inner.killer = Some(sender);
|
||||||
|
let old_state = core::mem::replace(&mut inner.state, state);
|
||||||
|
inner.update_signal(&self.base);
|
||||||
|
(old_state, receiver)
|
||||||
|
};
|
||||||
|
let ret = if let Some(cancel_token) = cancel_token {
|
||||||
|
select_biased! {
|
||||||
|
ret = future.fuse() => ret.into_result(),
|
||||||
|
_ = killed.fuse() => Err(ZxError::STOP),
|
||||||
|
_ = sleep_until(deadline).fuse() => Err(ZxError::TIMED_OUT),
|
||||||
|
_ = cancel_token.fuse() => Err(ZxError::CANCELED),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
select_biased! {
|
||||||
|
ret = future.fuse() => ret.into_result(),
|
||||||
|
_ = killed.fuse() => Err(ZxError::STOP),
|
||||||
|
_ = sleep_until(deadline).fuse() => Err(ZxError::TIMED_OUT),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
inner.killer = None;
|
||||||
|
if inner.state == ThreadState::Dying {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
assert_eq!(inner.state, state);
|
||||||
|
inner.state = old_state;
|
||||||
|
inner.update_signal(&self.base);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Blocked wait for exception handling.
|
||||||
|
pub async fn wait_for_exception_handling(&self, exception: Arc<Exception>) {
|
||||||
|
self.inner.lock().exception = Some(exception.clone());
|
||||||
|
let future = exception.handle();
|
||||||
|
pin_mut!(future);
|
||||||
|
self.blocking_run(
|
||||||
|
future,
|
||||||
|
ThreadState::BlockedException,
|
||||||
|
Duration::from_nanos(u64::max_value()),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
|
self.inner.lock().exception = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run a blocking task when the thread is exited itself and dying.
|
||||||
|
///
|
||||||
|
/// The task will stop running if and once the thread is killed.
|
||||||
|
pub async fn dying_run<F, T, FT>(&self, future: F) -> ZxResult<T>
|
||||||
|
where
|
||||||
|
F: Future<Output = FT> + Unpin,
|
||||||
|
FT: IntoResult<T>,
|
||||||
|
{
|
||||||
|
let killed = {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
if inner.get_state() == ThreadState::Dead || inner.killed {
|
||||||
|
return Err(ZxError::STOP);
|
||||||
|
}
|
||||||
|
let (sender, receiver) = channel::<()>();
|
||||||
|
inner.killer = Some(sender);
|
||||||
|
receiver
|
||||||
|
};
|
||||||
|
select_biased! {
|
||||||
|
ret = future.fuse() => ret.into_result(),
|
||||||
|
_ = killed.fuse() => Err(ZxError::STOP),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// `into_result` returns `Self` if the type parameter is already a `ZxResult`,
|
/// `into_result` returns `Self` if the type parameter is already a `ZxResult`,
|
||||||
/// otherwise wraps the value in an `Ok`.
|
/// otherwise wraps the value in an `Ok`.
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use {super::*, zircon_object::task::ThreadState};
|
use {
|
||||||
|
super::*,
|
||||||
|
zircon_object::task::{Thread, ThreadState},
|
||||||
|
};
|
||||||
|
|
||||||
impl Syscall<'_> {
|
impl Syscall<'_> {
|
||||||
/// Wait on a futex.
|
/// Wait on a futex.
|
||||||
|
@ -27,7 +30,7 @@ impl Syscall<'_> {
|
||||||
} else {
|
} else {
|
||||||
Some(proc.get_object::<Thread>(new_futex_owner)?)
|
Some(proc.get_object::<Thread>(new_futex_owner)?)
|
||||||
};
|
};
|
||||||
let future = futex.wait_with_owner(current_value, Some(self.thread.clone()), new_owner);
|
let future = futex.wait_with_owner(current_value, Some((*self.thread).clone()), new_owner);
|
||||||
self.thread
|
self.thread
|
||||||
.blocking_run(future, ThreadState::BlockedFutex, deadline.into(), None)
|
.blocking_run(future, ThreadState::BlockedFutex, deadline.into(), None)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
|
@ -19,7 +19,7 @@ use {
|
||||||
futures::pin_mut,
|
futures::pin_mut,
|
||||||
kernel_hal::{user::*, GeneralRegs},
|
kernel_hal::{user::*, GeneralRegs},
|
||||||
zircon_object::object::*,
|
zircon_object::object::*,
|
||||||
zircon_object::task::Thread,
|
zircon_object::task::CurrentThread,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod channel;
|
mod channel;
|
||||||
|
@ -51,8 +51,8 @@ use consts::SyscallType as Sys;
|
||||||
|
|
||||||
pub struct Syscall<'a> {
|
pub struct Syscall<'a> {
|
||||||
pub regs: &'a mut GeneralRegs,
|
pub regs: &'a mut GeneralRegs,
|
||||||
pub thread: Arc<Thread>,
|
pub thread: &'a CurrentThread,
|
||||||
pub spawn_fn: fn(thread: Arc<Thread>),
|
pub spawn_fn: fn(thread: CurrentThread),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Syscall<'_> {
|
impl Syscall<'_> {
|
||||||
|
|
Loading…
Reference in New Issue