subkernels: raise exceptions to kernel

This commit is contained in:
mwojcik 2024-06-27 10:23:40 +08:00
parent d51e5e60c3
commit 6057af56d9
4 changed files with 75 additions and 20 deletions

View File

@ -14,8 +14,10 @@
use core::mem; use core::mem;
use core_io::Error as ReadError;
use cslice::CSlice; use cslice::CSlice;
use dwarf::eh::{self, EHAction, EHContext}; use dwarf::eh::{self, EHAction, EHContext};
use io::{Cursor, ProtoRead};
use libc::{c_int, c_void, uintptr_t}; use libc::{c_int, c_void, uintptr_t};
use log::{error, trace}; use log::{error, trace};
use unwind as uw; use unwind as uw;
@ -295,6 +297,60 @@ pub unsafe extern "C" fn raise(exception: *const Exception) -> ! {
unreachable!(); unreachable!();
} }
fn read_exception_string<'a>(reader: &mut Cursor<&[u8]>) -> Result<CSlice<'a, u8>, ReadError> {
let len = reader.read_u32()? as usize;
if len == usize::MAX {
let data = reader.read_u32()?;
Ok(unsafe { CSlice::new(data as *const u8, len) })
} else {
let pos = reader.position();
let slice = unsafe {
let ptr = reader.get_ref().as_ptr().offset(pos as isize);
CSlice::new(ptr, len)
};
reader.set_position(pos + len);
Ok(slice)
}
}
fn read_exception(raw_exception: &[u8]) -> Result<Exception, ReadError> {
let mut reader = Cursor::new(raw_exception);
let mut byte = reader.read_u8()?;
// to sync
while byte != 0x5a {
byte = reader.read_u8()?;
}
// skip sync bytes, 0x09 indicates exception
while byte != 0x09 {
byte = reader.read_u8()?;
}
let _len = reader.read_u32()?;
// ignore the remaining exceptions, stack traces etc. - unwinding from another device would be unwise anyway
Ok(Exception {
id: reader.read_u32()?,
message: read_exception_string(&mut reader)?,
param: [
reader.read_u64()? as i64,
reader.read_u64()? as i64,
reader.read_u64()? as i64,
],
file: read_exception_string(&mut reader)?,
line: reader.read_u32()?,
column: reader.read_u32()?,
function: read_exception_string(&mut reader)?,
})
}
pub fn raise_raw(raw_exception: &[u8]) -> ! {
use crate::artiq_raise;
if let Ok(exception) = read_exception(raw_exception) {
unsafe { raise(&exception) };
} else {
artiq_raise!("SubkernelError", "Error passing exception");
}
}
pub unsafe extern "C" fn resume() -> ! { pub unsafe extern "C" fn resume() -> ! {
trace!("resume"); trace!("resume");
assert!(EXCEPTION_BUFFER.exception_count != 0); assert!(EXCEPTION_BUFFER.exception_count != 0);

View File

@ -24,6 +24,7 @@ pub enum SubkernelStatus {
IncorrectState, IncorrectState,
CommLost, CommLost,
OtherError, OtherError,
Exception(Vec<u8>),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View File

@ -3,7 +3,7 @@ use alloc::vec::Vec;
use cslice::CSlice; use cslice::CSlice;
use super::{Message, SubkernelStatus, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0}; use super::{Message, SubkernelStatus, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
use crate::{artiq_raise, rpc::send_args}; use crate::{artiq_raise, eh_artiq, rpc::send_args};
pub extern "C" fn load_run(id: u32, destination: u8, run: bool) { pub extern "C" fn load_run(id: u32, destination: u8, run: bool) {
unsafe { unsafe {
@ -51,6 +51,12 @@ pub extern "C" fn await_finish(id: u32, timeout: i64) {
Message::SubkernelAwaitFinishReply { Message::SubkernelAwaitFinishReply {
status: SubkernelStatus::OtherError, status: SubkernelStatus::OtherError,
} => artiq_raise!("SubkernelError", "An error occurred during subkernel operation"), } => artiq_raise!("SubkernelError", "An error occurred during subkernel operation"),
Message::SubkernelAwaitFinishReply {
status: SubkernelStatus::Exception(raw_exception),
} => {
// reconstruct the exception here and raise it
eh_artiq::raise_raw(&raw_exception)
}
_ => panic!("expected SubkernelAwaitFinishReply after SubkernelAwaitFinishRequest"), _ => panic!("expected SubkernelAwaitFinishReply after SubkernelAwaitFinishRequest"),
} }
} }
@ -116,6 +122,13 @@ pub extern "C" fn await_message(id: i32, timeout: i64, tags: &CSlice<u8>, min: u
status: SubkernelStatus::OtherError, status: SubkernelStatus::OtherError,
.. ..
} => artiq_raise!("SubkernelError", "An error occurred during subkernel operation"), } => artiq_raise!("SubkernelError", "An error occurred during subkernel operation"),
Message::SubkernelMsgRecvReply {
status: SubkernelStatus::Exception(raw_exception),
..
} => {
// reconstruct the raw exception here
eh_artiq::raise_raw(&raw_exception);
}
_ => panic!("expected SubkernelMsgRecvReply after SubkernelMsgRecvRequest"), _ => panic!("expected SubkernelMsgRecvReply after SubkernelMsgRecvRequest"),
} }
// RpcRecvRequest should be called after this to receive message data // RpcRecvRequest should be called after this to receive message data

View File

@ -423,19 +423,11 @@ async fn handle_run_kernel(
kernel::Message::SubkernelAwaitFinishRequest { id, timeout } => { kernel::Message::SubkernelAwaitFinishRequest { id, timeout } => {
let res = subkernel::await_finish(aux_mutex, routing_table, timer, id, timeout).await; let res = subkernel::await_finish(aux_mutex, routing_table, timer, id, timeout).await;
let status = match res { let status = match res {
Ok(ref res) => { Ok(res) => {
if res.status == subkernel::FinishStatus::CommLost { if res.status == subkernel::FinishStatus::CommLost {
kernel::SubkernelStatus::CommLost kernel::SubkernelStatus::CommLost
} else if let Some(exception) = &res.exception { } else if let Some(exception) = res.exception {
error!("Exception in subkernel"); kernel::SubkernelStatus::Exception(exception)
match stream {
None => (),
Some(stream) => {
write_chunk(stream, exception).await?;
}
}
// will not be called after exception is served
kernel::SubkernelStatus::OtherError
} else { } else {
kernel::SubkernelStatus::NoError kernel::SubkernelStatus::NoError
} }
@ -475,18 +467,11 @@ async fn handle_run_kernel(
Err(SubkernelError::IncorrectState) => (kernel::SubkernelStatus::IncorrectState, 0), Err(SubkernelError::IncorrectState) => (kernel::SubkernelStatus::IncorrectState, 0),
Err(SubkernelError::CommLost) => (kernel::SubkernelStatus::CommLost, 0), Err(SubkernelError::CommLost) => (kernel::SubkernelStatus::CommLost, 0),
Err(SubkernelError::SubkernelException) => { Err(SubkernelError::SubkernelException) => {
error!("Exception in subkernel");
// just retrieve the exception // just retrieve the exception
let status = subkernel::await_finish(aux_mutex, routing_table, timer, id as u32, timeout) let status = subkernel::await_finish(aux_mutex, routing_table, timer, id as u32, timeout)
.await .await
.unwrap(); .unwrap();
match stream { (kernel::SubkernelStatus::Exception(status.exception.unwrap()), 0)
None => (),
Some(stream) => {
write_chunk(stream, &status.exception.unwrap()).await?;
}
}
(kernel::SubkernelStatus::OtherError, 0)
} }
Err(_) => (kernel::SubkernelStatus::OtherError, 0), Err(_) => (kernel::SubkernelStatus::OtherError, 0),
}; };