2023-09-06 16:06:38 +08:00
|
|
|
use alloc::{collections::{BTreeMap, VecDeque},
|
|
|
|
format,
|
|
|
|
string::{String, ToString},
|
|
|
|
vec::Vec};
|
2024-01-10 12:13:00 +08:00
|
|
|
use core::{option::NoneError, slice, str};
|
2023-09-06 16:06:38 +08:00
|
|
|
|
|
|
|
use core_io::{Error as IoError, Write};
|
|
|
|
use cslice::AsCSlice;
|
2024-01-10 12:13:00 +08:00
|
|
|
use dma::{Error as DmaError, Manager as DmaManager};
|
2023-10-18 11:56:38 +08:00
|
|
|
use io::{Cursor, ProtoWrite};
|
2023-09-06 16:06:38 +08:00
|
|
|
use ksupport::{eh_artiq, kernel, rpc};
|
2023-12-12 16:51:54 +08:00
|
|
|
use libboard_artiq::{drtio_routing::RoutingTable,
|
|
|
|
drtioaux,
|
|
|
|
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE, SAT_PAYLOAD_MAX_SIZE},
|
2023-09-06 16:06:38 +08:00
|
|
|
pl::csr};
|
|
|
|
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
|
|
|
|
use libcortex_a9::sync_channel::Receiver;
|
|
|
|
use log::warn;
|
2024-01-10 12:13:00 +08:00
|
|
|
use routing::{Router, SliceMeta, Sliceable};
|
2023-09-06 16:06:38 +08:00
|
|
|
|
2023-10-18 11:56:38 +08:00
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
2023-09-06 16:06:38 +08:00
|
|
|
enum KernelState {
|
|
|
|
Absent,
|
|
|
|
Loaded,
|
|
|
|
Running,
|
2023-10-18 11:56:38 +08:00
|
|
|
MsgAwait(Milliseconds, Vec<u8>),
|
2023-09-06 16:06:38 +08:00
|
|
|
MsgSending,
|
2023-12-12 16:51:54 +08:00
|
|
|
SubkernelAwaitLoad,
|
2024-01-10 12:13:00 +08:00
|
|
|
SubkernelAwaitFinish {
|
|
|
|
max_time: Milliseconds,
|
|
|
|
id: u32,
|
|
|
|
},
|
|
|
|
DmaUploading,
|
|
|
|
DmaPendingPlayback {
|
|
|
|
id: u32,
|
|
|
|
timestamp: u64,
|
|
|
|
},
|
|
|
|
DmaPendingAwait {
|
|
|
|
id: u32,
|
|
|
|
timestamp: u64,
|
|
|
|
max_time: Milliseconds,
|
|
|
|
},
|
|
|
|
DmaAwait {
|
|
|
|
max_time: Milliseconds,
|
|
|
|
},
|
2023-09-06 16:06:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Error {
|
|
|
|
Load(String),
|
|
|
|
KernelNotFound,
|
|
|
|
Unexpected(String),
|
|
|
|
NoMessage,
|
|
|
|
AwaitingMessage,
|
|
|
|
SubkernelIoError,
|
2023-12-12 16:51:54 +08:00
|
|
|
DrtioError,
|
2023-09-06 16:06:38 +08:00
|
|
|
KernelException(Sliceable),
|
2024-01-10 12:13:00 +08:00
|
|
|
DmaError(DmaError),
|
2023-09-06 16:06:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<NoneError> for Error {
|
|
|
|
fn from(_: NoneError) -> Error {
|
|
|
|
Error::KernelNotFound
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<IoError> for Error {
|
|
|
|
fn from(_value: IoError) -> Error {
|
|
|
|
Error::SubkernelIoError
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-10 12:13:00 +08:00
|
|
|
impl From<DmaError> for Error {
|
|
|
|
fn from(value: DmaError) -> Error {
|
|
|
|
Error::DmaError(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-06 16:06:38 +08:00
|
|
|
impl From<()> for Error {
|
|
|
|
fn from(_: ()) -> Error {
|
|
|
|
Error::NoMessage
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-12 16:51:54 +08:00
|
|
|
impl From<drtioaux::Error> for Error {
|
|
|
|
fn from(_value: drtioaux::Error) -> Error {
|
|
|
|
Error::DrtioError
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-06 16:06:38 +08:00
|
|
|
macro_rules! unexpected {
|
|
|
|
($($arg:tt)*) => (return Err(Error::Unexpected(format!($($arg)*))));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* represents interkernel messages */
|
|
|
|
struct Message {
|
2023-09-29 12:06:20 +08:00
|
|
|
count: u8,
|
2023-09-06 16:06:38 +08:00
|
|
|
data: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(PartialEq)]
|
|
|
|
enum OutMessageState {
|
|
|
|
NoMessage,
|
|
|
|
MessageBeingSent,
|
|
|
|
MessageSent,
|
|
|
|
MessageAcknowledged,
|
|
|
|
}
|
|
|
|
|
|
|
|
/* for dealing with incoming and outgoing interkernel messages */
|
|
|
|
struct MessageManager {
|
|
|
|
out_message: Option<Sliceable>,
|
|
|
|
out_state: OutMessageState,
|
|
|
|
in_queue: VecDeque<Message>,
|
|
|
|
in_buffer: Option<Message>,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Per-run state
|
|
|
|
struct Session {
|
|
|
|
id: u32,
|
|
|
|
kernel_state: KernelState,
|
|
|
|
last_exception: Option<Sliceable>,
|
|
|
|
messages: MessageManager,
|
2023-12-12 16:51:54 +08:00
|
|
|
source: u8, // which destination requested running the kernel
|
|
|
|
subkernels_finished: Vec<u32>,
|
2023-09-06 16:06:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Session {
|
|
|
|
pub fn new(id: u32) -> Session {
|
|
|
|
Session {
|
|
|
|
id: id,
|
|
|
|
kernel_state: KernelState::Absent,
|
|
|
|
last_exception: None,
|
|
|
|
messages: MessageManager::new(),
|
2023-12-12 16:51:54 +08:00
|
|
|
source: 0,
|
|
|
|
subkernels_finished: Vec::new(),
|
2023-09-06 16:06:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn running(&self) -> bool {
|
|
|
|
match self.kernel_state {
|
|
|
|
KernelState::Absent | KernelState::Loaded => false,
|
2024-01-10 12:13:00 +08:00
|
|
|
_ => true,
|
2023-09-06 16:06:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct KernelLibrary {
|
|
|
|
library: Vec<u8>,
|
|
|
|
complete: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Manager<'a> {
|
|
|
|
kernels: BTreeMap<u32, KernelLibrary>,
|
|
|
|
session: Session,
|
|
|
|
control: &'a mut kernel::Control,
|
|
|
|
cache: BTreeMap<String, Vec<i32>>,
|
2023-09-06 16:44:54 +08:00
|
|
|
last_finished: Option<SubkernelFinished>,
|
2023-09-06 16:06:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct SubkernelFinished {
|
|
|
|
pub id: u32,
|
|
|
|
pub with_exception: bool,
|
2023-12-12 16:51:54 +08:00
|
|
|
pub exception_source: u8,
|
|
|
|
pub source: u8,
|
2023-09-06 16:06:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl MessageManager {
|
|
|
|
pub fn new() -> MessageManager {
|
|
|
|
MessageManager {
|
|
|
|
out_message: None,
|
|
|
|
out_state: OutMessageState::NoMessage,
|
|
|
|
in_queue: VecDeque::new(),
|
|
|
|
in_buffer: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-02 14:49:53 +08:00
|
|
|
pub fn handle_incoming(&mut self, status: PayloadStatus, length: usize, data: &[u8; MASTER_PAYLOAD_MAX_SIZE]) {
|
2023-09-06 16:06:38 +08:00
|
|
|
// called when receiving a message from master
|
2023-11-02 14:49:53 +08:00
|
|
|
if status.is_first() {
|
|
|
|
self.in_buffer = None;
|
|
|
|
}
|
2023-09-06 16:06:38 +08:00
|
|
|
match self.in_buffer.as_mut() {
|
|
|
|
Some(message) => message.data.extend(&data[..length]),
|
|
|
|
None => {
|
|
|
|
self.in_buffer = Some(Message {
|
2023-09-29 12:06:20 +08:00
|
|
|
count: data[0],
|
2023-10-18 11:56:38 +08:00
|
|
|
data: data[1..length].to_vec(),
|
2023-09-06 16:06:38 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
2023-11-02 14:49:53 +08:00
|
|
|
if status.is_last() {
|
2023-09-06 16:06:38 +08:00
|
|
|
// when done, remove from working queue
|
|
|
|
self.in_queue.push_back(self.in_buffer.take().unwrap());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn was_message_acknowledged(&mut self) -> bool {
|
|
|
|
match self.out_state {
|
|
|
|
OutMessageState::MessageAcknowledged => {
|
|
|
|
self.out_state = OutMessageState::NoMessage;
|
|
|
|
true
|
|
|
|
}
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_outgoing_slice(&mut self, data_slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE]) -> Option<SliceMeta> {
|
|
|
|
if self.out_state != OutMessageState::MessageBeingSent {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
let meta = self.out_message.as_mut()?.get_slice_master(data_slice);
|
2023-11-02 14:49:53 +08:00
|
|
|
if meta.status.is_last() {
|
2023-09-06 16:06:38 +08:00
|
|
|
// clear the message slot
|
|
|
|
self.out_message = None;
|
|
|
|
// notify kernel with a flag that message is sent
|
|
|
|
self.out_state = OutMessageState::MessageSent;
|
|
|
|
}
|
|
|
|
Some(meta)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn ack_slice(&mut self) -> bool {
|
|
|
|
// returns whether or not there's more to be sent
|
|
|
|
match self.out_state {
|
|
|
|
OutMessageState::MessageBeingSent => true,
|
|
|
|
OutMessageState::MessageSent => {
|
|
|
|
self.out_state = OutMessageState::MessageAcknowledged;
|
|
|
|
false
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
warn!("received unsolicited SubkernelMessageAck");
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-12 16:51:54 +08:00
|
|
|
pub fn accept_outgoing(
|
|
|
|
&mut self,
|
|
|
|
id: u32,
|
|
|
|
self_destination: u8,
|
|
|
|
destination: u8,
|
|
|
|
message: Vec<u8>,
|
|
|
|
routing_table: &RoutingTable,
|
|
|
|
rank: u8,
|
|
|
|
router: &mut Router,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
self.out_message = Some(Sliceable::new(destination, message));
|
|
|
|
|
|
|
|
let mut data_slice: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
|
|
|
self.out_state = OutMessageState::MessageBeingSent;
|
|
|
|
let meta = self.get_outgoing_slice(&mut data_slice).unwrap();
|
|
|
|
router.route(
|
|
|
|
drtioaux::Packet::SubkernelMessage {
|
|
|
|
source: self_destination,
|
|
|
|
destination: destination,
|
|
|
|
id: id,
|
|
|
|
status: meta.status,
|
|
|
|
length: meta.len as u16,
|
|
|
|
data: data_slice,
|
|
|
|
},
|
|
|
|
routing_table,
|
|
|
|
rank,
|
|
|
|
self_destination,
|
|
|
|
);
|
2023-09-06 16:06:38 +08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_incoming(&mut self) -> Option<Message> {
|
|
|
|
self.in_queue.pop_front()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Manager<'_> {
|
|
|
|
pub fn new(control: &mut kernel::Control) -> Manager {
|
|
|
|
Manager {
|
|
|
|
kernels: BTreeMap::new(),
|
|
|
|
session: Session::new(0),
|
|
|
|
control: control,
|
|
|
|
cache: BTreeMap::new(),
|
2023-09-06 16:44:54 +08:00
|
|
|
last_finished: None,
|
2023-09-06 16:06:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-02 14:49:53 +08:00
|
|
|
pub fn add(&mut self, id: u32, status: PayloadStatus, data: &[u8], data_len: usize) -> Result<(), Error> {
|
2023-09-06 16:06:38 +08:00
|
|
|
let kernel = match self.kernels.get_mut(&id) {
|
|
|
|
Some(kernel) => {
|
2023-11-02 14:49:53 +08:00
|
|
|
if kernel.complete || status.is_first() {
|
2023-09-06 16:06:38 +08:00
|
|
|
// replace entry
|
|
|
|
self.kernels.remove(&id);
|
|
|
|
self.kernels.insert(
|
|
|
|
id,
|
|
|
|
KernelLibrary {
|
|
|
|
library: Vec::new(),
|
|
|
|
complete: false,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
self.kernels.get_mut(&id)?
|
|
|
|
} else {
|
|
|
|
kernel
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
self.kernels.insert(
|
|
|
|
id,
|
|
|
|
KernelLibrary {
|
|
|
|
library: Vec::new(),
|
|
|
|
complete: false,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
self.kernels.get_mut(&id)?
|
|
|
|
}
|
|
|
|
};
|
|
|
|
kernel.library.extend(&data[0..data_len]);
|
|
|
|
|
2023-11-02 14:49:53 +08:00
|
|
|
kernel.complete = status.is_last();
|
2023-09-06 16:06:38 +08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn running(&self) -> bool {
|
|
|
|
self.session.running()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_current_id(&self) -> Option<u32> {
|
|
|
|
match self.running() {
|
|
|
|
true => Some(self.session.id),
|
|
|
|
false => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-12 16:51:54 +08:00
|
|
|
pub fn run(&mut self, source: u8, id: u32) -> Result<(), Error> {
|
2023-09-06 16:06:38 +08:00
|
|
|
if self.session.kernel_state != KernelState::Loaded || self.session.id != id {
|
|
|
|
self.load(id)?;
|
|
|
|
}
|
|
|
|
self.session.kernel_state = KernelState::Running;
|
2023-12-12 16:51:54 +08:00
|
|
|
self.session.source = source;
|
2023-09-06 16:06:38 +08:00
|
|
|
unsafe {
|
|
|
|
csr::cri_con::selected_write(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.control.tx.send(kernel::Message::StartRequest);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-11-02 14:49:53 +08:00
|
|
|
pub fn message_handle_incoming(
|
|
|
|
&mut self,
|
|
|
|
status: PayloadStatus,
|
|
|
|
length: usize,
|
|
|
|
slice: &[u8; MASTER_PAYLOAD_MAX_SIZE],
|
|
|
|
) {
|
2023-09-06 16:06:38 +08:00
|
|
|
if !self.running() {
|
|
|
|
return;
|
|
|
|
}
|
2023-11-02 14:49:53 +08:00
|
|
|
self.session.messages.handle_incoming(status, length, slice);
|
2023-09-06 16:06:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn message_get_slice(&mut self, slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE]) -> Option<SliceMeta> {
|
|
|
|
if !self.running() {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
self.session.messages.get_outgoing_slice(slice)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn message_ack_slice(&mut self) -> bool {
|
|
|
|
if !self.running() {
|
|
|
|
warn!("received unsolicited SubkernelMessageAck");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
self.session.messages.ack_slice()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn load(&mut self, id: u32) -> Result<(), Error> {
|
|
|
|
if self.session.id == id && self.session.kernel_state == KernelState::Loaded {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
if !self.kernels.get(&id)?.complete {
|
|
|
|
return Err(Error::KernelNotFound);
|
|
|
|
}
|
|
|
|
self.session = Session::new(id);
|
|
|
|
self.control.restart();
|
|
|
|
|
|
|
|
self.control
|
|
|
|
.tx
|
|
|
|
.send(kernel::Message::LoadRequest(self.kernels.get(&id)?.library.clone()));
|
|
|
|
let reply = self.control.rx.recv();
|
|
|
|
match reply {
|
|
|
|
kernel::Message::LoadCompleted => Ok(()),
|
|
|
|
kernel::Message::LoadFailed => Err(Error::Load("kernel load failed".to_string())),
|
|
|
|
_ => Err(Error::Load(format!(
|
|
|
|
"unexpected kernel CPU reply to load request: {:?}",
|
|
|
|
reply
|
|
|
|
))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn exception_get_slice(&mut self, data_slice: &mut [u8; SAT_PAYLOAD_MAX_SIZE]) -> SliceMeta {
|
|
|
|
match self.session.last_exception.as_mut() {
|
|
|
|
Some(exception) => exception.get_slice_sat(data_slice),
|
2023-11-02 14:49:53 +08:00
|
|
|
None => SliceMeta {
|
2023-12-12 16:51:54 +08:00
|
|
|
destination: 0,
|
2023-11-02 14:49:53 +08:00
|
|
|
len: 0,
|
|
|
|
status: PayloadStatus::FirstAndLast,
|
|
|
|
},
|
2023-09-06 16:06:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn kernel_stop(&mut self) {
|
|
|
|
self.session.kernel_state = KernelState::Absent;
|
|
|
|
unsafe {
|
|
|
|
csr::cri_con::selected_write(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn runtime_exception(&mut self, cause: Error) {
|
|
|
|
let raw_exception: Vec<u8> = Vec::new();
|
|
|
|
let mut writer = Cursor::new(raw_exception);
|
|
|
|
match write_exception(
|
|
|
|
&mut writer,
|
|
|
|
&[Some(eh_artiq::Exception {
|
|
|
|
id: 11, // SubkernelError, defined in ksupport
|
|
|
|
message: format!("in subkernel id {}: {:?}", self.session.id, cause).as_c_slice(),
|
|
|
|
param: [0, 0, 0],
|
|
|
|
file: file!().as_c_slice(),
|
|
|
|
line: line!(),
|
|
|
|
column: column!(),
|
|
|
|
function: format!("subkernel id {}", self.session.id).as_c_slice(),
|
|
|
|
})],
|
|
|
|
&[eh_artiq::StackPointerBacktrace {
|
|
|
|
stack_pointer: 0,
|
|
|
|
initial_backtrace_size: 0,
|
|
|
|
current_backtrace_size: 0,
|
|
|
|
}],
|
|
|
|
&[],
|
|
|
|
0,
|
|
|
|
) {
|
2023-12-12 16:51:54 +08:00
|
|
|
Ok(_) => self.session.last_exception = Some(Sliceable::new(0, writer.into_inner())),
|
2023-09-06 16:06:38 +08:00
|
|
|
Err(_) => error!("Error writing exception data"),
|
|
|
|
}
|
|
|
|
self.kernel_stop();
|
|
|
|
}
|
|
|
|
|
2024-01-10 12:13:00 +08:00
|
|
|
pub fn ddma_finished(&mut self, error: u8, channel: u32, timestamp: u64) {
|
|
|
|
if let KernelState::DmaAwait { .. } = self.session.kernel_state {
|
|
|
|
self.control.tx.send(kernel::Message::DmaAwaitRemoteReply {
|
|
|
|
timeout: false,
|
|
|
|
error: error,
|
|
|
|
channel: channel,
|
|
|
|
timestamp: timestamp,
|
|
|
|
});
|
|
|
|
self.session.kernel_state = KernelState::Running;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn ddma_nack(&mut self) {
|
|
|
|
// for simplicity treat it as a timeout...
|
|
|
|
if let KernelState::DmaAwait { .. } = self.session.kernel_state {
|
|
|
|
self.control.tx.send(kernel::Message::DmaAwaitRemoteReply {
|
|
|
|
timeout: true,
|
|
|
|
error: 0,
|
|
|
|
channel: 0,
|
|
|
|
timestamp: 0,
|
|
|
|
});
|
|
|
|
self.session.kernel_state = KernelState::Running;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn ddma_remote_uploaded(&mut self, succeeded: bool) -> Option<(u32, u64)> {
|
|
|
|
// returns a tuple of id, timestamp in case a playback needs to be started immediately
|
|
|
|
if !succeeded {
|
|
|
|
self.kernel_stop();
|
|
|
|
self.runtime_exception(Error::DmaError(DmaError::UploadFail));
|
|
|
|
}
|
|
|
|
let res = match self.session.kernel_state {
|
|
|
|
KernelState::DmaPendingPlayback { id, timestamp } => {
|
|
|
|
self.session.kernel_state = KernelState::Running;
|
|
|
|
Some((id, timestamp))
|
|
|
|
}
|
|
|
|
KernelState::DmaPendingAwait {
|
|
|
|
id,
|
|
|
|
timestamp,
|
|
|
|
max_time,
|
|
|
|
} => {
|
|
|
|
self.session.kernel_state = KernelState::DmaAwait { max_time: max_time };
|
|
|
|
Some((id, timestamp))
|
|
|
|
}
|
|
|
|
KernelState::DmaUploading => {
|
|
|
|
self.session.kernel_state = KernelState::Running;
|
|
|
|
None
|
|
|
|
}
|
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
res
|
|
|
|
}
|
|
|
|
|
2023-12-12 16:51:54 +08:00
|
|
|
pub fn process_kern_requests(
|
|
|
|
&mut self,
|
|
|
|
router: &mut Router,
|
|
|
|
routing_table: &RoutingTable,
|
|
|
|
rank: u8,
|
|
|
|
destination: u8,
|
2024-01-10 12:13:00 +08:00
|
|
|
dma_manager: &mut DmaManager,
|
2023-12-12 16:51:54 +08:00
|
|
|
timer: &GlobalTimer,
|
|
|
|
) {
|
|
|
|
if let Some(subkernel_finished) = self.last_finished.take() {
|
|
|
|
info!(
|
|
|
|
"subkernel {} finished, with exception: {}",
|
|
|
|
subkernel_finished.id, subkernel_finished.with_exception
|
|
|
|
);
|
|
|
|
router.route(
|
|
|
|
drtioaux::Packet::SubkernelFinished {
|
|
|
|
destination: subkernel_finished.source,
|
|
|
|
id: subkernel_finished.id,
|
|
|
|
with_exception: subkernel_finished.with_exception,
|
|
|
|
exception_src: subkernel_finished.exception_source,
|
|
|
|
},
|
|
|
|
&routing_table,
|
|
|
|
rank,
|
|
|
|
destination,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-09-06 16:06:38 +08:00
|
|
|
if !self.running() {
|
2023-09-06 16:44:54 +08:00
|
|
|
return;
|
2023-09-06 16:06:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
match self.process_external_messages(timer) {
|
|
|
|
Ok(()) => (),
|
2023-09-06 16:44:54 +08:00
|
|
|
Err(Error::AwaitingMessage) => return, // kernel still waiting, do not process kernel messages
|
2023-09-06 16:06:38 +08:00
|
|
|
Err(Error::KernelException(exception)) => {
|
|
|
|
self.session.last_exception = Some(exception);
|
2023-09-06 16:44:54 +08:00
|
|
|
self.last_finished = Some(SubkernelFinished {
|
2023-09-06 16:06:38 +08:00
|
|
|
id: self.session.id,
|
|
|
|
with_exception: true,
|
2023-12-12 16:51:54 +08:00
|
|
|
exception_source: destination,
|
|
|
|
source: self.session.source,
|
2023-09-06 16:06:38 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
error!("Error while running processing external messages: {:?}", e);
|
|
|
|
self.runtime_exception(e);
|
2023-09-06 16:44:54 +08:00
|
|
|
self.last_finished = Some(SubkernelFinished {
|
2023-09-06 16:06:38 +08:00
|
|
|
id: self.session.id,
|
|
|
|
with_exception: true,
|
2023-12-12 16:51:54 +08:00
|
|
|
exception_source: destination,
|
|
|
|
source: self.session.source,
|
2023-09-06 16:06:38 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-10 12:13:00 +08:00
|
|
|
match self.process_kern_message(router, routing_table, rank, destination, dma_manager, timer) {
|
2023-09-06 16:44:54 +08:00
|
|
|
Ok(true) => {
|
|
|
|
self.last_finished = Some(SubkernelFinished {
|
|
|
|
id: self.session.id,
|
|
|
|
with_exception: false,
|
2023-12-12 16:51:54 +08:00
|
|
|
exception_source: 0,
|
|
|
|
source: self.session.source,
|
2023-09-06 16:44:54 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
Ok(false) | Err(Error::NoMessage) => (),
|
2023-09-06 16:06:38 +08:00
|
|
|
Err(Error::KernelException(exception)) => {
|
|
|
|
self.session.last_exception = Some(exception);
|
2023-09-06 16:44:54 +08:00
|
|
|
self.last_finished = Some(SubkernelFinished {
|
2023-09-06 16:06:38 +08:00
|
|
|
id: self.session.id,
|
|
|
|
with_exception: true,
|
2023-12-12 16:51:54 +08:00
|
|
|
exception_source: destination,
|
|
|
|
source: self.session.source,
|
2023-09-06 16:06:38 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
error!("Error while running kernel: {:?}", e);
|
|
|
|
self.runtime_exception(e);
|
2023-09-06 16:44:54 +08:00
|
|
|
self.last_finished = Some(SubkernelFinished {
|
2023-09-06 16:06:38 +08:00
|
|
|
id: self.session.id,
|
|
|
|
with_exception: true,
|
2023-12-12 16:51:54 +08:00
|
|
|
exception_source: destination,
|
|
|
|
source: self.session.source,
|
2023-09-06 16:44:54 +08:00
|
|
|
});
|
2023-09-06 16:06:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-12 16:51:54 +08:00
|
|
|
pub fn subkernel_load_run_reply(&mut self, succeeded: bool) {
|
|
|
|
if self.session.kernel_state == KernelState::SubkernelAwaitLoad {
|
|
|
|
self.control
|
|
|
|
.tx
|
|
|
|
.send(kernel::Message::SubkernelLoadRunReply { succeeded: succeeded });
|
|
|
|
self.session.kernel_state = KernelState::Running;
|
|
|
|
} else {
|
|
|
|
warn!("received unsolicited SubkernelLoadRunReply");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn remote_subkernel_finished(&mut self, id: u32, with_exception: bool, exception_source: u8) {
|
|
|
|
if with_exception {
|
|
|
|
self.kernel_stop();
|
|
|
|
self.last_finished = Some(SubkernelFinished {
|
|
|
|
source: self.session.source,
|
|
|
|
id: self.session.id,
|
|
|
|
with_exception: true,
|
|
|
|
exception_source: exception_source,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
self.session.subkernels_finished.push(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_kern_message(
|
|
|
|
&mut self,
|
|
|
|
router: &mut Router,
|
|
|
|
routing_table: &RoutingTable,
|
|
|
|
rank: u8,
|
|
|
|
self_destination: u8,
|
2024-01-10 12:13:00 +08:00
|
|
|
dma_manager: &mut DmaManager,
|
2023-12-12 16:51:54 +08:00
|
|
|
timer: &GlobalTimer,
|
|
|
|
) -> Result<bool, Error> {
|
2023-09-06 16:06:38 +08:00
|
|
|
let reply = self.control.rx.try_recv()?;
|
|
|
|
match reply {
|
|
|
|
kernel::Message::KernelFinished(_async_errors) => {
|
|
|
|
self.kernel_stop();
|
2024-01-10 12:13:00 +08:00
|
|
|
dma_manager.cleanup(router, rank, self_destination, routing_table);
|
2023-09-06 16:06:38 +08:00
|
|
|
return Ok(true);
|
|
|
|
}
|
|
|
|
kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors) => {
|
|
|
|
error!("exception in kernel");
|
|
|
|
for exception in exceptions {
|
|
|
|
error!("{:?}", exception.unwrap());
|
|
|
|
}
|
|
|
|
error!("stack pointers: {:?}", stack_pointers);
|
|
|
|
error!("backtrace: {:?}", backtrace);
|
|
|
|
let buf: Vec<u8> = Vec::new();
|
|
|
|
let mut writer = Cursor::new(buf);
|
|
|
|
match write_exception(&mut writer, exceptions, stack_pointers, backtrace, async_errors) {
|
|
|
|
Ok(()) => (),
|
|
|
|
Err(_) => error!("Error writing exception data"),
|
|
|
|
}
|
|
|
|
self.kernel_stop();
|
2023-12-12 16:51:54 +08:00
|
|
|
return Err(Error::KernelException(Sliceable::new(0, writer.into_inner())));
|
2023-09-06 16:06:38 +08:00
|
|
|
}
|
|
|
|
kernel::Message::CachePutRequest(key, value) => {
|
|
|
|
self.cache.insert(key, value);
|
|
|
|
}
|
|
|
|
kernel::Message::CacheGetRequest(key) => {
|
|
|
|
const DEFAULT: Vec<i32> = Vec::new();
|
|
|
|
let value = self.cache.get(&key).unwrap_or(&DEFAULT).clone();
|
|
|
|
self.control.tx.send(kernel::Message::CacheGetReply(value));
|
|
|
|
}
|
2024-01-10 12:13:00 +08:00
|
|
|
|
|
|
|
kernel::Message::DmaPutRequest(recorder) => {
|
|
|
|
// ddma is always used on satellites
|
|
|
|
if let Ok(id) = dma_manager.put_record(recorder, self_destination) {
|
|
|
|
dma_manager.upload_traces(id, router, rank, self_destination, routing_table)?;
|
|
|
|
self.session.kernel_state = KernelState::DmaUploading;
|
|
|
|
} else {
|
|
|
|
unexpected!("DMAError: found an unsupported call to RTIO devices on master")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
kernel::Message::DmaEraseRequest(name) => {
|
|
|
|
dma_manager.erase_name(&name, router, rank, self_destination, routing_table);
|
|
|
|
}
|
|
|
|
kernel::Message::DmaGetRequest(name) => {
|
|
|
|
let dma_meta = dma_manager.retrieve(self_destination, &name);
|
|
|
|
self.control.tx.send(kernel::Message::DmaGetReply(dma_meta));
|
|
|
|
}
|
|
|
|
kernel::Message::DmaStartRemoteRequest { id, timestamp } => {
|
|
|
|
if self.session.kernel_state != KernelState::DmaUploading {
|
|
|
|
dma_manager.playback_remote(
|
|
|
|
id as u32,
|
|
|
|
timestamp as u64,
|
|
|
|
router,
|
|
|
|
rank,
|
|
|
|
self_destination,
|
|
|
|
routing_table,
|
|
|
|
)?;
|
|
|
|
} else {
|
|
|
|
self.session.kernel_state = KernelState::DmaPendingPlayback {
|
|
|
|
id: id as u32,
|
|
|
|
timestamp: timestamp as u64,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
kernel::Message::DmaAwaitRemoteRequest(_id) => {
|
|
|
|
let max_time = timer.get_time() + Milliseconds(10000);
|
|
|
|
self.session.kernel_state = match self.session.kernel_state {
|
|
|
|
// if we are still waiting for the traces to be uploaded, extend the state by timeout
|
|
|
|
KernelState::DmaPendingPlayback { id, timestamp } => KernelState::DmaPendingAwait {
|
|
|
|
id: id,
|
|
|
|
timestamp: timestamp,
|
|
|
|
max_time: max_time,
|
|
|
|
},
|
|
|
|
_ => KernelState::DmaAwait { max_time: max_time },
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-12-12 16:51:54 +08:00
|
|
|
kernel::Message::SubkernelMsgSend {
|
|
|
|
id: _id,
|
|
|
|
destination: msg_dest,
|
|
|
|
data,
|
|
|
|
} => {
|
|
|
|
let msg_dest = msg_dest.or(Some(self.session.source)).unwrap();
|
|
|
|
self.session.messages.accept_outgoing(
|
|
|
|
self.session.id,
|
|
|
|
self_destination,
|
|
|
|
msg_dest,
|
|
|
|
data,
|
|
|
|
routing_table,
|
|
|
|
rank,
|
|
|
|
router,
|
|
|
|
)?;
|
2023-09-06 16:06:38 +08:00
|
|
|
self.session.kernel_state = KernelState::MsgSending;
|
|
|
|
}
|
2023-10-18 11:56:38 +08:00
|
|
|
kernel::Message::SubkernelMsgRecvRequest { id: _, timeout, tags } => {
|
2023-09-06 16:06:38 +08:00
|
|
|
let max_time = timer.get_time() + Milliseconds(timeout);
|
2023-10-18 11:56:38 +08:00
|
|
|
self.session.kernel_state = KernelState::MsgAwait(max_time, tags);
|
2023-09-06 16:06:38 +08:00
|
|
|
}
|
2023-12-12 16:51:54 +08:00
|
|
|
kernel::Message::SubkernelLoadRunRequest {
|
|
|
|
id,
|
|
|
|
destination: sk_destination,
|
|
|
|
run,
|
|
|
|
} => {
|
|
|
|
self.session.kernel_state = KernelState::SubkernelAwaitLoad;
|
|
|
|
router.route(
|
|
|
|
drtioaux::Packet::SubkernelLoadRunRequest {
|
|
|
|
source: self_destination,
|
|
|
|
destination: sk_destination,
|
|
|
|
id: id,
|
|
|
|
run: run,
|
|
|
|
},
|
|
|
|
routing_table,
|
|
|
|
rank,
|
|
|
|
self_destination,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
kernel::Message::SubkernelAwaitFinishRequest { id, timeout } => {
|
|
|
|
let max_time = timer.get_time() + Milliseconds(timeout);
|
|
|
|
self.session.kernel_state = KernelState::SubkernelAwaitFinish {
|
|
|
|
max_time: max_time,
|
|
|
|
id: id,
|
|
|
|
};
|
|
|
|
}
|
2023-09-06 16:06:38 +08:00
|
|
|
kernel::Message::UpDestinationsRequest(destination) => {
|
2023-12-12 16:51:54 +08:00
|
|
|
self.control.tx.send(kernel::Message::UpDestinationsReply(
|
|
|
|
destination == (self_destination as i32),
|
|
|
|
));
|
2023-09-06 16:06:38 +08:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
unexpected!("unexpected message from core1 while kernel was running: {:?}", reply);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
|
2023-12-12 16:51:54 +08:00
|
|
|
fn process_external_messages(&mut self, timer: &GlobalTimer) -> Result<(), Error> {
|
2023-10-18 11:56:38 +08:00
|
|
|
match &self.session.kernel_state {
|
|
|
|
KernelState::MsgAwait(timeout, tags) => {
|
|
|
|
if timer.get_time() > *timeout {
|
2023-09-06 16:06:38 +08:00
|
|
|
self.control.tx.send(kernel::Message::SubkernelMsgRecvReply {
|
|
|
|
status: kernel::SubkernelStatus::Timeout,
|
2023-09-29 12:06:20 +08:00
|
|
|
count: 0,
|
2023-09-06 16:06:38 +08:00
|
|
|
});
|
|
|
|
self.session.kernel_state = KernelState::Running;
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
if let Some(message) = self.session.messages.get_incoming() {
|
|
|
|
self.control.tx.send(kernel::Message::SubkernelMsgRecvReply {
|
|
|
|
status: kernel::SubkernelStatus::NoError,
|
2023-09-29 12:06:20 +08:00
|
|
|
count: message.count,
|
2023-09-06 16:06:38 +08:00
|
|
|
});
|
2023-10-18 11:56:38 +08:00
|
|
|
let tags = tags.clone();
|
2023-09-06 16:06:38 +08:00
|
|
|
self.session.kernel_state = KernelState::Running;
|
2023-10-18 11:56:38 +08:00
|
|
|
self.pass_message_to_kernel(&message, tags, timer)
|
2023-09-06 16:06:38 +08:00
|
|
|
} else {
|
|
|
|
Err(Error::AwaitingMessage)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
KernelState::MsgSending => {
|
|
|
|
if self.session.messages.was_message_acknowledged() {
|
|
|
|
self.session.kernel_state = KernelState::Running;
|
|
|
|
self.control.tx.send(kernel::Message::SubkernelMsgSent);
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(Error::AwaitingMessage)
|
|
|
|
}
|
|
|
|
}
|
2023-12-12 16:51:54 +08:00
|
|
|
KernelState::SubkernelAwaitFinish { max_time, id } => {
|
|
|
|
if timer.get_time() > *max_time {
|
|
|
|
self.control.tx.send(kernel::Message::SubkernelAwaitFinishReply {
|
|
|
|
status: kernel::SubkernelStatus::Timeout,
|
|
|
|
});
|
|
|
|
self.session.kernel_state = KernelState::Running;
|
|
|
|
} else {
|
|
|
|
let mut i = 0;
|
|
|
|
for status in &self.session.subkernels_finished {
|
|
|
|
if *status == *id {
|
|
|
|
self.control.tx.send(kernel::Message::SubkernelAwaitFinishReply {
|
|
|
|
status: kernel::SubkernelStatus::NoError,
|
|
|
|
});
|
|
|
|
self.session.kernel_state = KernelState::Running;
|
|
|
|
self.session.subkernels_finished.swap_remove(i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2024-01-10 12:13:00 +08:00
|
|
|
KernelState::DmaAwait { max_time } | KernelState::DmaPendingAwait { max_time, .. } => {
|
|
|
|
if timer.get_time() > *max_time {
|
|
|
|
self.control.tx.send(kernel::Message::DmaAwaitRemoteReply {
|
|
|
|
timeout: true,
|
|
|
|
error: 0,
|
|
|
|
channel: 0,
|
|
|
|
timestamp: 0,
|
|
|
|
});
|
|
|
|
self.session.kernel_state = KernelState::Running;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2023-09-06 16:06:38 +08:00
|
|
|
_ => Ok(()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-12 16:51:54 +08:00
|
|
|
fn pass_message_to_kernel(&mut self, message: &Message, tags: Vec<u8>, timer: &GlobalTimer) -> Result<(), Error> {
|
2023-09-06 16:06:38 +08:00
|
|
|
let mut reader = Cursor::new(&message.data);
|
2023-10-18 11:56:38 +08:00
|
|
|
let mut current_tags: &[u8] = &tags;
|
2023-09-29 12:06:20 +08:00
|
|
|
let mut i = message.count;
|
2023-09-06 16:06:38 +08:00
|
|
|
loop {
|
|
|
|
let slot = match recv_w_timeout(&mut self.control.rx, timer, 100)? {
|
|
|
|
kernel::Message::RpcRecvRequest(slot) => slot,
|
|
|
|
other => unexpected!("expected root value slot from core1, not {:?}", other),
|
|
|
|
};
|
|
|
|
let mut exception: Option<Sliceable> = None;
|
|
|
|
let mut unexpected: Option<String> = None;
|
2023-10-18 11:56:38 +08:00
|
|
|
let remaining_tags = rpc::recv_return(&mut reader, current_tags, slot, &mut |size| {
|
2023-09-06 16:06:38 +08:00
|
|
|
if size == 0 {
|
|
|
|
0 as *mut ()
|
|
|
|
} else {
|
|
|
|
self.control.tx.send(kernel::Message::RpcRecvReply(Ok(size)));
|
|
|
|
match recv_w_timeout(&mut self.control.rx, timer, 100) {
|
|
|
|
Ok(kernel::Message::RpcRecvRequest(slot)) => slot,
|
|
|
|
Ok(kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors)) => {
|
|
|
|
let buf: Vec<u8> = Vec::new();
|
|
|
|
let mut writer = Cursor::new(buf);
|
|
|
|
match write_exception(&mut writer, exceptions, stack_pointers, backtrace, async_errors) {
|
|
|
|
Ok(()) => {
|
2023-12-12 16:51:54 +08:00
|
|
|
exception = Some(Sliceable::new(0, writer.into_inner()));
|
2023-09-06 16:06:38 +08:00
|
|
|
}
|
|
|
|
Err(_) => {
|
|
|
|
unexpected = Some("Error writing exception data".to_string());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
0 as *mut ()
|
|
|
|
}
|
|
|
|
other => {
|
|
|
|
unexpected = Some(format!("expected nested value slot from kernel CPU, not {:?}", other));
|
|
|
|
0 as *mut ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})?;
|
|
|
|
if let Some(exception) = exception {
|
|
|
|
self.kernel_stop();
|
|
|
|
return Err(Error::KernelException(exception));
|
|
|
|
} else if let Some(unexpected) = unexpected {
|
|
|
|
self.kernel_stop();
|
|
|
|
unexpected!("{}", unexpected);
|
|
|
|
}
|
|
|
|
self.control.tx.send(kernel::Message::RpcRecvReply(Ok(0)));
|
2023-09-29 12:06:20 +08:00
|
|
|
i -= 1;
|
|
|
|
if i == 0 {
|
|
|
|
break;
|
|
|
|
} else {
|
2023-10-18 11:56:38 +08:00
|
|
|
current_tags = remaining_tags;
|
2023-09-06 16:06:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_exception<W>(
|
|
|
|
writer: &mut W,
|
|
|
|
exceptions: &[Option<eh_artiq::Exception>],
|
|
|
|
stack_pointers: &[eh_artiq::StackPointerBacktrace],
|
|
|
|
backtrace: &[(usize, usize)],
|
|
|
|
async_errors: u8,
|
|
|
|
) -> Result<(), Error>
|
|
|
|
where
|
|
|
|
W: Write + ?Sized,
|
|
|
|
{
|
|
|
|
/* header */
|
|
|
|
writer.write_bytes(&[0x5a, 0x5a, 0x5a, 0x5a, /*Reply::KernelException*/ 9])?;
|
|
|
|
writer.write_u32(exceptions.len() as u32)?;
|
|
|
|
for exception in exceptions.iter() {
|
|
|
|
let exception = exception.as_ref().unwrap();
|
|
|
|
writer.write_u32(exception.id)?;
|
|
|
|
|
|
|
|
if exception.message.len() == usize::MAX {
|
|
|
|
// exception with host string
|
|
|
|
writer.write_u32(u32::MAX)?;
|
|
|
|
writer.write_u32(exception.message.as_ptr() as u32)?;
|
|
|
|
} else {
|
|
|
|
let msg =
|
|
|
|
str::from_utf8(unsafe { slice::from_raw_parts(exception.message.as_ptr(), exception.message.len()) })
|
|
|
|
.unwrap()
|
|
|
|
.replace(
|
|
|
|
"{rtio_channel_info:0}",
|
|
|
|
&format!(
|
|
|
|
"0x{:04x}:{}",
|
|
|
|
exception.param[0],
|
|
|
|
ksupport::resolve_channel_name(exception.param[0] as u32)
|
|
|
|
),
|
|
|
|
);
|
|
|
|
writer.write_string(&msg)?;
|
|
|
|
}
|
|
|
|
writer.write_u64(exception.param[0] as u64)?;
|
|
|
|
writer.write_u64(exception.param[1] as u64)?;
|
|
|
|
writer.write_u64(exception.param[2] as u64)?;
|
|
|
|
writer.write_bytes(exception.file.as_ref())?;
|
|
|
|
writer.write_u32(exception.line)?;
|
|
|
|
writer.write_u32(exception.column)?;
|
|
|
|
writer.write_bytes(exception.function.as_ref())?;
|
|
|
|
}
|
|
|
|
|
|
|
|
for sp in stack_pointers.iter() {
|
|
|
|
writer.write_u32(sp.stack_pointer as u32)?;
|
|
|
|
writer.write_u32(sp.initial_backtrace_size as u32)?;
|
|
|
|
writer.write_u32(sp.current_backtrace_size as u32)?;
|
|
|
|
}
|
|
|
|
writer.write_u32(backtrace.len() as u32)?;
|
|
|
|
for &(addr, sp) in backtrace {
|
|
|
|
writer.write_u32(addr as u32)?;
|
|
|
|
writer.write_u32(sp as u32)?;
|
|
|
|
}
|
|
|
|
writer.write_u8(async_errors as u8)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn recv_w_timeout(
|
|
|
|
rx: &mut Receiver<'_, kernel::Message>,
|
2023-12-12 16:51:54 +08:00
|
|
|
timer: &GlobalTimer,
|
2023-09-06 16:06:38 +08:00
|
|
|
timeout: u64,
|
|
|
|
) -> Result<kernel::Message, Error> {
|
|
|
|
let max_time = timer.get_time() + Milliseconds(timeout);
|
|
|
|
while timer.get_time() < max_time {
|
|
|
|
match rx.try_recv() {
|
|
|
|
Err(_) => (),
|
|
|
|
Ok(message) => return Ok(message),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(Error::NoMessage)
|
|
|
|
}
|