forked from M-Labs/artiq
subkernel: pass exceptions to kernel
This commit is contained in:
parent
e12bc586a5
commit
fb8dd01e8d
@ -494,7 +494,8 @@ extern "C-unwind" fn subkernel_await_finish(id: u32, timeout: i64) {
|
||||
SubkernelStatus::CommLost => raise!("SubkernelError",
|
||||
"Lost communication with satellite"),
|
||||
SubkernelStatus::OtherError => raise!("SubkernelError",
|
||||
"An error occurred during subkernel operation")
|
||||
"An error occurred during subkernel operation"),
|
||||
SubkernelStatus::Exception(e) => unsafe { crate::eh_artiq::raise(e) },
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -528,7 +529,8 @@ extern "C-unwind" fn subkernel_await_message(id: i32, timeout: i64, tags: &CSlic
|
||||
SubkernelStatus::CommLost => raise!("SubkernelError",
|
||||
"Lost communication with satellite"),
|
||||
SubkernelStatus::OtherError => raise!("SubkernelError",
|
||||
"An error occurred during subkernel operation")
|
||||
"An error occurred during subkernel operation"),
|
||||
SubkernelStatus::Exception(e) => unsafe { crate::eh_artiq::raise(e) },
|
||||
}
|
||||
})
|
||||
// RpcRecvRequest should be called `count` times after this to receive message data
|
||||
|
@ -11,12 +11,13 @@ pub const KERNELCPU_LAST_ADDRESS: usize = 0x4fffffff;
|
||||
pub const KSUPPORT_HEADER_SIZE: usize = 0x74;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SubkernelStatus {
|
||||
pub enum SubkernelStatus<'a> {
|
||||
NoError,
|
||||
Timeout,
|
||||
IncorrectState,
|
||||
CommLost,
|
||||
OtherError
|
||||
OtherError,
|
||||
Exception(eh::eh_artiq::Exception<'a>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -106,10 +107,10 @@ pub enum Message<'a> {
|
||||
SubkernelLoadRunRequest { id: u32, destination: u8, run: bool },
|
||||
SubkernelLoadRunReply { succeeded: bool },
|
||||
SubkernelAwaitFinishRequest { id: u32, timeout: i64 },
|
||||
SubkernelAwaitFinishReply { status: SubkernelStatus },
|
||||
SubkernelAwaitFinishReply { status: SubkernelStatus<'a> },
|
||||
SubkernelMsgSend { id: u32, destination: Option<u8>, count: u8, tag: &'a [u8], data: *const *const () },
|
||||
SubkernelMsgRecvRequest { id: i32, timeout: i64, tags: &'a [u8] },
|
||||
SubkernelMsgRecvReply { status: SubkernelStatus, count: u8 },
|
||||
SubkernelMsgRecvReply { status: SubkernelStatus<'a>, count: u8 },
|
||||
|
||||
Log(fmt::Arguments<'a>),
|
||||
LogSlice(&'a str)
|
||||
|
@ -95,7 +95,9 @@ pub mod subkernel {
|
||||
use board_artiq::drtio_routing::RoutingTable;
|
||||
use board_misoc::clock;
|
||||
use proto_artiq::{drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE}, rpc_proto as rpc};
|
||||
use io::Cursor;
|
||||
use io::{Cursor, ProtoRead};
|
||||
use eh::eh_artiq::Exception;
|
||||
use cslice::CSlice;
|
||||
use rtio_mgt::drtio;
|
||||
use sched::{Io, Mutex, Error as SchedError};
|
||||
|
||||
@ -226,8 +228,8 @@ pub mod subkernel {
|
||||
if subkernel.state == SubkernelState::Running {
|
||||
subkernel.state = SubkernelState::Finished {
|
||||
status: match with_exception {
|
||||
true => FinishStatus::Exception(exception_src),
|
||||
false => FinishStatus::Ok,
|
||||
true => FinishStatus::Exception(exception_src),
|
||||
false => FinishStatus::Ok,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -256,6 +258,42 @@ pub mod subkernel {
|
||||
}
|
||||
}
|
||||
|
||||
fn read_exception_string<'a>(reader: &mut Cursor<&[u8]>) -> Result<CSlice<'a, u8>, Error> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_exception(buffer: &[u8]) -> Result<Exception, Error>
|
||||
{
|
||||
let mut reader = Cursor::new(buffer);
|
||||
|
||||
let _sync = reader.read_u32()?;
|
||||
let _9 = 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 retrieve_finish_status(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex,
|
||||
routing_table: &RoutingTable, id: u32) -> Result<SubkernelFinished, Error> {
|
||||
let _lock = subkernel_mutex.lock(io)?;
|
||||
|
@ -126,19 +126,6 @@ macro_rules! unexpected {
|
||||
($($arg:tt)*) => (return Err(Error::Unexpected(format!($($arg)*))));
|
||||
}
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
macro_rules! propagate_subkernel_exception {
|
||||
( $exception:ident, $stream:ident ) => {
|
||||
error!("Exception in subkernel");
|
||||
match $stream {
|
||||
None => return Ok(true),
|
||||
Some(ref mut $stream) => {
|
||||
$stream.write_all($exception)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Persistent state
|
||||
#[derive(Debug)]
|
||||
struct Congress {
|
||||
@ -690,10 +677,13 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex,
|
||||
Ok(ref res) => {
|
||||
if res.comm_lost {
|
||||
kern::SubkernelStatus::CommLost
|
||||
} else if let Some(exception) = &res.exception {
|
||||
propagate_subkernel_exception!(exception, stream);
|
||||
// will not be called after exception is served
|
||||
kern::SubkernelStatus::OtherError
|
||||
} else if let Some(raw_exception) = &res.exception {
|
||||
let exception = subkernel::read_exception(raw_exception);
|
||||
if let Ok(exception) = exception {
|
||||
kern::SubkernelStatus::Exception(exception)
|
||||
} else {
|
||||
kern::SubkernelStatus::OtherError
|
||||
}
|
||||
} else {
|
||||
kern::SubkernelStatus::NoError
|
||||
}
|
||||
@ -712,72 +702,92 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex,
|
||||
#[cfg(has_drtio)]
|
||||
&kern::SubkernelMsgRecvRequest { id, timeout, tags } => {
|
||||
let message_received = subkernel::message_await(io, subkernel_mutex, id as u32, timeout);
|
||||
let (status, count) = match message_received {
|
||||
Ok(ref message) => (kern::SubkernelStatus::NoError, message.count),
|
||||
Err(SubkernelError::Timeout) => (kern::SubkernelStatus::Timeout, 0),
|
||||
Err(SubkernelError::IncorrectState) => (kern::SubkernelStatus::IncorrectState, 0),
|
||||
Err(SubkernelError::SubkernelFinished) => {
|
||||
let res = subkernel::retrieve_finish_status(io, aux_mutex, ddma_mutex, subkernel_mutex,
|
||||
routing_table, id as u32)?;
|
||||
if res.comm_lost {
|
||||
(kern::SubkernelStatus::CommLost, 0)
|
||||
} else if let Some(exception) = &res.exception {
|
||||
propagate_subkernel_exception!(exception, stream);
|
||||
(kern::SubkernelStatus::OtherError, 0)
|
||||
} else {
|
||||
(kern::SubkernelStatus::OtherError, 0)
|
||||
}
|
||||
}
|
||||
Err(_) => (kern::SubkernelStatus::OtherError, 0)
|
||||
};
|
||||
kern_send(io, &kern::SubkernelMsgRecvReply { status: status, count: count})?;
|
||||
if let Ok(message) = message_received {
|
||||
// receive code almost identical to RPC recv, except we are not reading from a stream
|
||||
let mut reader = Cursor::new(message.data);
|
||||
let mut current_tags = tags;
|
||||
let mut i = 0;
|
||||
loop {
|
||||
// kernel has to consume all arguments in the whole message
|
||||
let slot = kern_recv(io, |reply| {
|
||||
match reply {
|
||||
&kern::RpcRecvRequest(slot) => Ok(slot),
|
||||
other => unexpected!(
|
||||
"expected root value slot from kernel CPU, not {:?}", other)
|
||||
}
|
||||
if let Err(SubkernelError::SubkernelFinished) = message_received {
|
||||
let res = subkernel::retrieve_finish_status(io, aux_mutex, ddma_mutex, subkernel_mutex,
|
||||
routing_table, id as u32)?;
|
||||
if res.comm_lost {
|
||||
kern_send(io,
|
||||
&kern::SubkernelMsgRecvReply {
|
||||
status: kern::SubkernelStatus::CommLost,
|
||||
count: 0
|
||||
})?;
|
||||
let res = rpc::recv_return(&mut reader, current_tags, slot, &|size| -> Result<_, Error<SchedError>> {
|
||||
if size == 0 {
|
||||
return Ok(0 as *mut ())
|
||||
}
|
||||
kern_send(io, &kern::RpcRecvReply(Ok(size)))?;
|
||||
Ok(kern_recv(io, |reply| {
|
||||
} else if let Some(raw_exception) = &res.exception {
|
||||
let exception = subkernel::read_exception(raw_exception);
|
||||
if let Ok(exception) = exception {
|
||||
kern_send(io,
|
||||
&kern::SubkernelMsgRecvReply {
|
||||
status: kern::SubkernelStatus::Exception(exception),
|
||||
count: 0
|
||||
})?;
|
||||
} else {
|
||||
kern_send(io,
|
||||
&kern::SubkernelMsgRecvReply {
|
||||
status: kern::SubkernelStatus::OtherError,
|
||||
count: 0
|
||||
})?;
|
||||
}
|
||||
} else {
|
||||
kern_send(io,
|
||||
&kern::SubkernelMsgRecvReply {
|
||||
status: kern::SubkernelStatus::OtherError,
|
||||
count: 0
|
||||
})?;
|
||||
}
|
||||
} else {
|
||||
let (status, count) = match message_received {
|
||||
Ok(ref message) => (kern::SubkernelStatus::NoError, message.count),
|
||||
Err(SubkernelError::Timeout) => (kern::SubkernelStatus::Timeout, 0),
|
||||
Err(SubkernelError::IncorrectState) => (kern::SubkernelStatus::IncorrectState, 0),
|
||||
Err(SubkernelError::SubkernelFinished) => unreachable!(), // taken care of above
|
||||
Err(_) => (kern::SubkernelStatus::OtherError, 0)
|
||||
};
|
||||
kern_send(io, &kern::SubkernelMsgRecvReply { status: status, count: count})?;
|
||||
if let Ok(message) = message_received {
|
||||
// receive code almost identical to RPC recv, except we are not reading from a stream
|
||||
let mut reader = Cursor::new(message.data);
|
||||
let mut current_tags = tags;
|
||||
let mut i = 0;
|
||||
loop {
|
||||
// kernel has to consume all arguments in the whole message
|
||||
let slot = kern_recv(io, |reply| {
|
||||
match reply {
|
||||
&kern::RpcRecvRequest(slot) => Ok(slot),
|
||||
other => unexpected!(
|
||||
"expected nested value slot from kernel CPU, not {:?}", other)
|
||||
"expected root value slot from kernel CPU, not {:?}", other)
|
||||
}
|
||||
})?)
|
||||
});
|
||||
match res {
|
||||
Ok(new_tags) => {
|
||||
kern_send(io, &kern::RpcRecvReply(Ok(0)))?;
|
||||
i += 1;
|
||||
if i < message.count {
|
||||
// update the tag for next read
|
||||
current_tags = new_tags;
|
||||
} else {
|
||||
// should be done by then
|
||||
break;
|
||||
})?;
|
||||
let res = rpc::recv_return(&mut reader, current_tags, slot, &|size| -> Result<_, Error<SchedError>> {
|
||||
if size == 0 {
|
||||
return Ok(0 as *mut ())
|
||||
}
|
||||
},
|
||||
Err(_) => unexpected!("expected valid subkernel message data")
|
||||
};
|
||||
kern_send(io, &kern::RpcRecvReply(Ok(size)))?;
|
||||
Ok(kern_recv(io, |reply| {
|
||||
match reply {
|
||||
&kern::RpcRecvRequest(slot) => Ok(slot),
|
||||
other => unexpected!(
|
||||
"expected nested value slot from kernel CPU, not {:?}", other)
|
||||
}
|
||||
})?)
|
||||
});
|
||||
match res {
|
||||
Ok(new_tags) => {
|
||||
kern_send(io, &kern::RpcRecvReply(Ok(0)))?;
|
||||
i += 1;
|
||||
if i < message.count {
|
||||
// update the tag for next read
|
||||
current_tags = new_tags;
|
||||
} else {
|
||||
// should be done by then
|
||||
break;
|
||||
}
|
||||
},
|
||||
Err(_) => unexpected!("expected valid subkernel message data")
|
||||
};
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
// if timed out, no data has been received, exception should be raised by kernel
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
|
||||
request => unexpected!("unexpected request {:?} from kernel CPU", request)
|
||||
|
Loading…
Reference in New Issue
Block a user