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",
|
SubkernelStatus::CommLost => raise!("SubkernelError",
|
||||||
"Lost communication with satellite"),
|
"Lost communication with satellite"),
|
||||||
SubkernelStatus::OtherError => raise!("SubkernelError",
|
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",
|
SubkernelStatus::CommLost => raise!("SubkernelError",
|
||||||
"Lost communication with satellite"),
|
"Lost communication with satellite"),
|
||||||
SubkernelStatus::OtherError => raise!("SubkernelError",
|
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
|
// 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;
|
pub const KSUPPORT_HEADER_SIZE: usize = 0x74;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SubkernelStatus {
|
pub enum SubkernelStatus<'a> {
|
||||||
NoError,
|
NoError,
|
||||||
Timeout,
|
Timeout,
|
||||||
IncorrectState,
|
IncorrectState,
|
||||||
CommLost,
|
CommLost,
|
||||||
OtherError
|
OtherError,
|
||||||
|
Exception(eh::eh_artiq::Exception<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -106,10 +107,10 @@ pub enum Message<'a> {
|
||||||
SubkernelLoadRunRequest { id: u32, destination: u8, run: bool },
|
SubkernelLoadRunRequest { id: u32, destination: u8, run: bool },
|
||||||
SubkernelLoadRunReply { succeeded: bool },
|
SubkernelLoadRunReply { succeeded: bool },
|
||||||
SubkernelAwaitFinishRequest { id: u32, timeout: i64 },
|
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 () },
|
SubkernelMsgSend { id: u32, destination: Option<u8>, count: u8, tag: &'a [u8], data: *const *const () },
|
||||||
SubkernelMsgRecvRequest { id: i32, timeout: i64, tags: &'a [u8] },
|
SubkernelMsgRecvRequest { id: i32, timeout: i64, tags: &'a [u8] },
|
||||||
SubkernelMsgRecvReply { status: SubkernelStatus, count: u8 },
|
SubkernelMsgRecvReply { status: SubkernelStatus<'a>, count: u8 },
|
||||||
|
|
||||||
Log(fmt::Arguments<'a>),
|
Log(fmt::Arguments<'a>),
|
||||||
LogSlice(&'a str)
|
LogSlice(&'a str)
|
||||||
|
|
|
@ -95,7 +95,9 @@ pub mod subkernel {
|
||||||
use board_artiq::drtio_routing::RoutingTable;
|
use board_artiq::drtio_routing::RoutingTable;
|
||||||
use board_misoc::clock;
|
use board_misoc::clock;
|
||||||
use proto_artiq::{drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE}, rpc_proto as rpc};
|
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 rtio_mgt::drtio;
|
||||||
use sched::{Io, Mutex, Error as SchedError};
|
use sched::{Io, Mutex, Error as SchedError};
|
||||||
|
|
||||||
|
@ -226,8 +228,8 @@ pub mod subkernel {
|
||||||
if subkernel.state == SubkernelState::Running {
|
if subkernel.state == SubkernelState::Running {
|
||||||
subkernel.state = SubkernelState::Finished {
|
subkernel.state = SubkernelState::Finished {
|
||||||
status: match with_exception {
|
status: match with_exception {
|
||||||
true => FinishStatus::Exception(exception_src),
|
true => FinishStatus::Exception(exception_src),
|
||||||
false => FinishStatus::Ok,
|
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,
|
pub fn retrieve_finish_status(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex,
|
||||||
routing_table: &RoutingTable, id: u32) -> Result<SubkernelFinished, Error> {
|
routing_table: &RoutingTable, id: u32) -> Result<SubkernelFinished, Error> {
|
||||||
let _lock = subkernel_mutex.lock(io)?;
|
let _lock = subkernel_mutex.lock(io)?;
|
||||||
|
|
|
@ -126,19 +126,6 @@ macro_rules! unexpected {
|
||||||
($($arg:tt)*) => (return Err(Error::Unexpected(format!($($arg)*))));
|
($($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
|
// Persistent state
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Congress {
|
struct Congress {
|
||||||
|
@ -690,10 +677,13 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex,
|
||||||
Ok(ref res) => {
|
Ok(ref res) => {
|
||||||
if res.comm_lost {
|
if res.comm_lost {
|
||||||
kern::SubkernelStatus::CommLost
|
kern::SubkernelStatus::CommLost
|
||||||
} else if let Some(exception) = &res.exception {
|
} else if let Some(raw_exception) = &res.exception {
|
||||||
propagate_subkernel_exception!(exception, stream);
|
let exception = subkernel::read_exception(raw_exception);
|
||||||
// will not be called after exception is served
|
if let Ok(exception) = exception {
|
||||||
kern::SubkernelStatus::OtherError
|
kern::SubkernelStatus::Exception(exception)
|
||||||
|
} else {
|
||||||
|
kern::SubkernelStatus::OtherError
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
kern::SubkernelStatus::NoError
|
kern::SubkernelStatus::NoError
|
||||||
}
|
}
|
||||||
|
@ -712,72 +702,92 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex,
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
&kern::SubkernelMsgRecvRequest { id, timeout, tags } => {
|
&kern::SubkernelMsgRecvRequest { id, timeout, tags } => {
|
||||||
let message_received = subkernel::message_await(io, subkernel_mutex, id as u32, timeout);
|
let message_received = subkernel::message_await(io, subkernel_mutex, id as u32, timeout);
|
||||||
let (status, count) = match message_received {
|
if let Err(SubkernelError::SubkernelFinished) = message_received {
|
||||||
Ok(ref message) => (kern::SubkernelStatus::NoError, message.count),
|
let res = subkernel::retrieve_finish_status(io, aux_mutex, ddma_mutex, subkernel_mutex,
|
||||||
Err(SubkernelError::Timeout) => (kern::SubkernelStatus::Timeout, 0),
|
routing_table, id as u32)?;
|
||||||
Err(SubkernelError::IncorrectState) => (kern::SubkernelStatus::IncorrectState, 0),
|
if res.comm_lost {
|
||||||
Err(SubkernelError::SubkernelFinished) => {
|
kern_send(io,
|
||||||
let res = subkernel::retrieve_finish_status(io, aux_mutex, ddma_mutex, subkernel_mutex,
|
&kern::SubkernelMsgRecvReply {
|
||||||
routing_table, id as u32)?;
|
status: kern::SubkernelStatus::CommLost,
|
||||||
if res.comm_lost {
|
count: 0
|
||||||
(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)
|
|
||||||
}
|
|
||||||
})?;
|
})?;
|
||||||
let res = rpc::recv_return(&mut reader, current_tags, slot, &|size| -> Result<_, Error<SchedError>> {
|
} else if let Some(raw_exception) = &res.exception {
|
||||||
if size == 0 {
|
let exception = subkernel::read_exception(raw_exception);
|
||||||
return Ok(0 as *mut ())
|
if let Ok(exception) = exception {
|
||||||
}
|
kern_send(io,
|
||||||
kern_send(io, &kern::RpcRecvReply(Ok(size)))?;
|
&kern::SubkernelMsgRecvReply {
|
||||||
Ok(kern_recv(io, |reply| {
|
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 {
|
match reply {
|
||||||
&kern::RpcRecvRequest(slot) => Ok(slot),
|
&kern::RpcRecvRequest(slot) => Ok(slot),
|
||||||
other => unexpected!(
|
other => unexpected!(
|
||||||
"expected nested value slot from kernel CPU, not {:?}", other)
|
"expected root value slot from kernel CPU, not {:?}", other)
|
||||||
}
|
}
|
||||||
})?)
|
})?;
|
||||||
});
|
let res = rpc::recv_return(&mut reader, current_tags, slot, &|size| -> Result<_, Error<SchedError>> {
|
||||||
match res {
|
if size == 0 {
|
||||||
Ok(new_tags) => {
|
return Ok(0 as *mut ())
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
},
|
kern_send(io, &kern::RpcRecvReply(Ok(size)))?;
|
||||||
Err(_) => unexpected!("expected valid subkernel message data")
|
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
|
// if timed out, no data has been received, exception should be raised by kernel
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
},
|
},
|
||||||
|
|
||||||
request => unexpected!("unexpected request {:?} from kernel CPU", request)
|
request => unexpected!("unexpected request {:?} from kernel CPU", request)
|
||||||
|
|
Loading…
Reference in New Issue