Skip to content

Commit

Permalink
refactor exception handling
Browse files Browse the repository at this point in the history
- remove exit field from Syscall
- rustify method names
  • Loading branch information
wangrunji0408 committed Aug 13, 2020
1 parent 4c7a3b8 commit a66c9f3
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 168 deletions.
91 changes: 22 additions & 69 deletions zircon-loader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,37 +176,21 @@ fn spawn(thread: Arc<Thread>) {
let vmtoken = thread.proc().vmar().table_phys();
let future = async move {
kernel_hal::Thread::set_tid(thread.id(), thread.proc().id());
let mut exit = false;
if thread.get_first_thread() {
let proc_start_exception =
Exception::create(thread.clone(), ExceptionType::ProcessStarting, None);
if !proc_start_exception
if thread.is_first_thread() {
Exception::create(thread.clone(), ExceptionType::ProcessStarting, None)
.handle_with_exceptionates(
false,
JobDebuggerIterator::new(thread.proc().job()),
true,
)
.await
{
exit = true;
}
.await;
};
let start_exception =
Exception::create(thread.clone(), ExceptionType::ThreadStarting, None);
if !start_exception
Exception::create(thread.clone(), ExceptionType::ThreadStarting, None)
.handle_with_exceptionates(false, Some(thread.proc().get_debug_exceptionate()), false)
.await
{
exit = true;
}
while !exit {
.await;
loop {
let mut cx = thread.wait_for_run().await;
if thread.state() == ThreadState::Dying {
info!(
"proc={:?} thread={:?} was killed",
thread.proc().name(),
thread.name()
);
break;
}
trace!("go to user: {:#x?}", cx);
Expand All @@ -228,12 +212,12 @@ fn spawn(thread: Arc<Thread>) {
EXCEPTIONS_USER.add(1);
#[cfg(target_arch = "aarch64")]
match cx.trap_num {
0 => exit = handle_syscall(&thread, &mut cx.general).await,
0 => handle_syscall(&thread, &mut cx.general).await,
_ => unimplemented!(),
}
#[cfg(target_arch = "x86_64")]
match cx.trap_num {
0x100 => exit = handle_syscall(&thread, &mut cx.general).await,
0x100 => handle_syscall(&thread, &mut cx.general).await,
0x20..=0x3f => {
kernel_hal::InterruptManager::handle(cx.trap_num as u8);
if cx.trap_num == 0x20 {
Expand All @@ -252,34 +236,17 @@ fn spawn(thread: Arc<Thread>) {
// FIXME:
#[cfg(target_arch = "aarch64")]
let flags = MMUFlags::WRITE;
error!(
"page fualt from user mode {:#x} {:#x?}",
kernel_hal::fetch_fault_vaddr(),
flags
);
match thread
.proc()
.vmar()
.handle_page_fault(kernel_hal::fetch_fault_vaddr(), flags)
{
Ok(()) => {}
Err(e) => {
error!(
"proc={:?} thread={:?} err={:?}",
thread.proc().name(),
thread.name(),
e
);
error!("Page Fault from user mode {:#x?}", cx);
let exception = Exception::create(
thread.clone(),
ExceptionType::FatalPageFault,
Some(&cx),
);
if !exception.handle(true).await {
exit = true;
}
}
let fault_vaddr = kernel_hal::fetch_fault_vaddr();
error!("page fault from user mode {:#x} {:#x?}", fault_vaddr, flags);
let vmar = thread.proc().vmar();
if vmar.handle_page_fault(fault_vaddr, flags).is_err() {
error!("Page Fault from user mode: {:#x?}", cx);
let exception = Exception::create(
thread.clone(),
ExceptionType::FatalPageFault,
Some(&cx),
);
exception.handle(true).await;
}
}
0x8 => {
Expand All @@ -293,22 +260,12 @@ fn spawn(thread: Arc<Thread>) {
0x17 => ExceptionType::UnalignedAccess,
_ => ExceptionType::General,
};
error!("User mode exception:{:?} {:#x?}", type_, cx);
error!("User mode exception: {:?} {:#x?}", type_, cx);
let exception = Exception::create(thread.clone(), type_, Some(&cx));
if !exception.handle(true).await {
exit = true;
}
exception.handle(true).await;
}
}
thread.end_running(cx);
if exit {
info!(
"proc={:?} thread={:?} exited",
thread.proc().name(),
thread.name()
);
break;
}
}
let end_exception = Exception::create(thread.clone(), ExceptionType::ThreadExiting, None);
let handled = thread
Expand All @@ -317,15 +274,13 @@ fn spawn(thread: Arc<Thread>) {
.send_exception(&end_exception);
if let Ok(future) = handled {
thread.dying_run(future).await.ok();
} else {
handled.ok();
}
thread.terminate();
};
kernel_hal::Thread::spawn(Box::pin(future), vmtoken);
}

async fn handle_syscall(thread: &Arc<Thread>, regs: &mut GeneralRegs) -> bool {
async fn handle_syscall(thread: &Arc<Thread>, regs: &mut GeneralRegs) {
#[cfg(target_arch = "x86_64")]
let num = regs.rax as u32;
#[cfg(target_arch = "aarch64")]
Expand Down Expand Up @@ -355,7 +310,6 @@ async fn handle_syscall(thread: &Arc<Thread>, regs: &mut GeneralRegs) -> bool {
regs,
thread: thread.clone(),
spawn_fn: spawn,
exit: false,
};
let ret = syscall.syscall(num, args).await as usize;
#[cfg(target_arch = "x86_64")]
Expand All @@ -366,5 +320,4 @@ async fn handle_syscall(thread: &Arc<Thread>, regs: &mut GeneralRegs) -> bool {
{
syscall.regs.x0 = ret;
}
syscall.exit
}
85 changes: 38 additions & 47 deletions zircon-object/src/task/exception.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
super::*, crate::ipc::*, crate::object::*, alloc::sync::Arc, alloc::vec, alloc::vec::Vec,
core::mem::size_of, core::time::Duration, futures::channel::oneshot, futures::pin_mut,
core::mem::size_of, core::ops::Deref, futures::channel::oneshot, futures::pin_mut,
kernel_hal::UserContext, spin::Mutex,
};

Expand Down Expand Up @@ -87,8 +87,7 @@ impl Exceptionate {
type_: exception.type_,
padding: Default::default(),
};
let (sender, receiver) = oneshot::channel::<()>();
let object = ExceptionObject::create(exception.clone(), sender);
let (object, closed) = ExceptionObject::create(exception.clone());
let handle = Handle::new(object, Rights::DEFAULT_EXCEPTION);
let msg = MessagePacket {
data: info.pack(),
Expand All @@ -102,7 +101,7 @@ impl Exceptionate {
}
err
})?;
Ok(receiver)
Ok(closed)
}
}

Expand Down Expand Up @@ -241,25 +240,31 @@ pub struct ExceptionObject {
impl_kobject!(ExceptionObject);

impl ExceptionObject {
/// Create an `ExceptionObject`.
fn create(exception: Arc<Exception>, close_signal: oneshot::Sender<()>) -> Arc<Self> {
Arc::new(ExceptionObject {
/// Create an kernel object of `Exception`.
///
/// Return the object and a `Receiver` of the object dropped event.
fn create(exception: Arc<Exception>) -> (Arc<Self>, oneshot::Receiver<()>) {
let (sender, receiver) = oneshot::channel();
let object = Arc::new(ExceptionObject {
base: KObjectBase::new(),
exception,
close_signal: Some(close_signal),
})
close_signal: Some(sender),
});
(object, receiver)
}
/// Get the exception.
pub fn get_exception(&self) -> &Arc<Exception> {
}

impl Deref for ExceptionObject {
type Target = Arc<Exception>;

fn deref(&self) -> &Self::Target {
&self.exception
}
}

impl Drop for ExceptionObject {
fn drop(&mut self) {
self.close_signal
.take()
.and_then(|signal| signal.send(()).ok());
self.close_signal.take().unwrap().send(()).ok();
}
}

Expand Down Expand Up @@ -300,46 +305,33 @@ impl Exception {
}),
})
}
/// Handle the exception. The return value indicate if the thread is exited after this.
/// 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
pub async fn handle(self: &Arc<Self>, fatal: bool) -> bool {

/// Handle the exception.
///
/// 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.
pub async fn handle(self: &Arc<Self>, fatal: bool) {
self.handle_with_exceptionates(fatal, ExceptionateIterator::new(self), false)
.await
}

/// Same as handle, but use a customed iterator
/// Same as handle, but use a customed 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
pub async fn handle_with_exceptionates(
self: &Arc<Self>,
fatal: bool,
exceptionates: impl IntoIterator<Item = Arc<Exceptionate>>,
first_only: bool,
) -> bool {
self.thread.set_exception(Some(self.clone()));
) {
let future = self.handle_internal(exceptionates, first_only);
pin_mut!(future);
let result: ZxResult = self
.thread
.blocking_run(
future,
ThreadState::BlockedException,
Duration::from_nanos(u64::max_value()),
)
.await;
self.thread.set_exception(None);
if let Err(err) = result {
if err == ZxError::STOP {
// We are killed
return false;
} else if err == ZxError::NEXT && fatal {
// Nobody handled the exception, kill myself
self.thread.proc().exit(TASK_RETCODE_SYSCALL_KILL);
return false;
}
let result = self.thread.wait_for_exception(future, self.clone()).await;
if result == Err(ZxError::NEXT) && fatal {
// Nobody handled the exception, kill myself
self.thread.proc().exit(TASK_RETCODE_SYSCALL_KILL);
}
true
}

async fn handle_internal(
Expand All @@ -349,10 +341,9 @@ impl Exception {
) -> ZxResult {
for exceptionate in exceptionates.into_iter() {
let closed = match exceptionate.send_exception(self) {
Ok(receiver) => receiver,
// This channel is not available now!
Err(ZxError::NEXT) => continue,
Err(err) => return Err(err),
res => res?,
};
self.inner.lock().current_channel_type = exceptionate.type_;
// If this error, the sender is dropped, and the handle should also be closed.
Expand Down Expand Up @@ -380,18 +371,18 @@ impl Exception {
}

/// Get the exception's channel type.
pub fn get_current_channel_type(&self) -> ExceptionChannelType {
pub fn current_channel_type(&self) -> ExceptionChannelType {
self.inner.lock().current_channel_type
}

/// Get a report of the exception.
pub fn get_report(&self) -> ExceptionReport {
pub fn report(&self) -> ExceptionReport {
self.report.clone()
}

/// Get whether closing the exception handle will
/// finish exception processing and resume the underlying thread.
pub fn get_state(&self) -> u32 {
pub fn state(&self) -> u32 {
self.inner.lock().handled as u32
}

Expand All @@ -407,7 +398,7 @@ impl Exception {

/// Get whether the debugger gets a 'second chance' at handling the exception
/// if the process-level handler fails to do so.
pub fn get_strategy(&self) -> u32 {
pub fn strategy(&self) -> u32 {
self.inner.lock().second_chance as u32
}

Expand Down Expand Up @@ -640,7 +631,7 @@ mod tests {
.downcast_arc::<ExceptionObject>()
.unwrap();
if should_handle {
exception.get_exception().set_state(1).unwrap();
exception.set_state(1).unwrap();
}
// record the order of the handler used
handled_order.lock().push(order);
Expand Down
2 changes: 1 addition & 1 deletion zircon-object/src/task/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ impl Process {
inner.status = Status::Running;
handle_value = arg1.map_or(INVALID_HANDLE, |handle| inner.add_handle(handle));
}
thread.set_first_thread(true);
thread.set_first_thread();
match thread.start(entry, stack, handle_value as usize, arg2, spawn_fn) {
Ok(_) => Ok(()),
Err(err) => {
Expand Down
Loading

0 comments on commit a66c9f3

Please sign in to comment.