diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index ca942caa5..dd52aabaf 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -29,9 +29,10 @@ extern crate riscv; extern crate tar_no_std; use alloc::collections::BTreeMap; -use core::cell::RefCell; +use core::cell::{RefCell, Cell}; use core::convert::TryFrom; use smoltcp::wire::HardwareAddress; +use urc::Urc; use board_misoc::{csr, ident, clock, spiflash, config, net_settings, pmp, boot}; #[cfg(has_ethmac)] @@ -196,6 +197,7 @@ fn startup() { let ddma_mutex = sched::Mutex::new(); let subkernel_mutex = sched::Mutex::new(); + let restart_idle = Urc::new(Cell::new(false)); let mut scheduler = sched::Scheduler::new(interface); let io = scheduler.io(); @@ -205,15 +207,18 @@ fn startup() { } rtio_mgt::startup(&io, &aux_mutex, &drtio_routing_table, &up_destinations, &ddma_mutex, &subkernel_mutex); - - io.spawn(4096, mgmt::thread); + { + let restart_idle = restart_idle.clone(); + io.spawn(4096, move |io| { mgmt::thread(io, &restart_idle) }); + } { let aux_mutex = aux_mutex.clone(); let drtio_routing_table = drtio_routing_table.clone(); let up_destinations = up_destinations.clone(); let ddma_mutex = ddma_mutex.clone(); let subkernel_mutex = subkernel_mutex.clone(); - io.spawn(32768, move |io| { session::thread(io, &aux_mutex, &drtio_routing_table, &up_destinations, &ddma_mutex, &subkernel_mutex) }); + let restart_idle = restart_idle.clone(); + io.spawn(32768, move |io| { session::thread(io, &aux_mutex, &drtio_routing_table, &up_destinations, &ddma_mutex, &subkernel_mutex, &restart_idle) }); } #[cfg(any(has_rtio_moninj, has_drtio))] { diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 449ed91be..72e335e4e 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -1,10 +1,12 @@ use log::{self, LevelFilter}; +use core::cell::Cell; use io::{Write, ProtoWrite, Error as IoError}; use board_misoc::{config, spiflash}; use logger_artiq::BufferLogger; use mgmt_proto::*; use sched::{Io, TcpListener, TcpStream, Error as SchedError}; +use urc::Urc; impl From for Error { fn from(value: SchedError) -> Error { @@ -12,7 +14,7 @@ impl From for Error { } } -fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), Error> { +fn worker(io: &Io, stream: &mut TcpStream, restart_idle: &Urc>) -> Result<(), Error> { read_magic(stream)?; Write::write_all(stream, "e".as_bytes())?; info!("new connection from {}", stream.remote_endpoint()); @@ -84,7 +86,13 @@ fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), Error> { } Request::ConfigWrite { ref key, ref value } => { match config::write(key, value) { - Ok(_) => Reply::Success.write_to(stream), + Ok(_) => { + if key == "idle_kernel" { + io.until(|| !restart_idle.get())?; + restart_idle.set(true); + } + Reply::Success.write_to(stream) + }, Err(_) => Reply::Error.write_to(stream) }?; } @@ -117,16 +125,17 @@ fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), Error> { } } -pub fn thread(io: Io) { +pub fn thread(io: Io, restart_idle: &Urc>) { let listener = TcpListener::new(&io, 8192); listener.listen(1380).expect("mgmt: cannot listen"); info!("management interface active"); loop { let stream = listener.accept().expect("mgmt: cannot accept").into_handle(); + let restart_idle = restart_idle.clone(); io.spawn(4096, move |io| { let mut stream = TcpStream::from_handle(&io, stream); - match worker(&io, &mut stream) { + match worker(&io, &mut stream, &restart_idle) { Ok(()) => (), Err(Error::Io(IoError::UnexpectedEnd)) => (), Err(err) => error!("aborted: {}", err) diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 71fbb2ce3..01b49900c 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -839,7 +839,7 @@ fn flash_kernel_worker(io: &Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, up_destinations: &Urc>, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, congress: &mut Congress, - config_key: &str) -> Result<(), Error> { + config_key: &str, restart_idle: Option<&Urc>>) -> Result<(), Error> { let mut session = Session::new(congress); config::read(config_key, |result| { @@ -859,11 +859,16 @@ fn flash_kernel_worker(io: &Io, aux_mutex: &Mutex, } })?; kern_run(&mut session)?; - loop { if !rpc_queue::empty() { unexpected!("unexpected background RPC in flash kernel") } + + if let Some(r_idle) = restart_idle { + if r_idle.get() { + return Err(Error::KernelNotFound) + } + } if mailbox::receive() != 0 { if process_kern_message(io, aux_mutex, routing_table, up_destinations, ddma_mutex, subkernel_mutex, None, &mut session)? { @@ -897,7 +902,7 @@ fn respawn(io: &Io, handle: &mut Option, f: F) pub fn thread(io: Io, aux_mutex: &Mutex, routing_table: &Urc>, up_destinations: &Urc>, - ddma_mutex: &Mutex, subkernel_mutex: &Mutex) { + ddma_mutex: &Mutex, subkernel_mutex: &Mutex, restart_idle: &Urc>) { let listener = TcpListener::new(&io, 65535); listener.listen(1381).expect("session: cannot listen"); info!("accepting network sessions"); @@ -910,7 +915,7 @@ pub fn thread(io: Io, aux_mutex: &Mutex, let mut congress = congress.borrow_mut(); info!("running startup kernel"); match flash_kernel_worker(&io, &aux_mutex, &routing_table, &up_destinations, - ddma_mutex, subkernel_mutex, &mut congress, "startup_kernel") { + ddma_mutex, subkernel_mutex, &mut congress, "startup_kernel", None) { Ok(()) => info!("startup kernel finished"), Err(Error::KernelNotFound) => @@ -994,11 +999,13 @@ pub fn thread(io: Io, aux_mutex: &Mutex, let congress = congress.clone(); let ddma_mutex = ddma_mutex.clone(); let subkernel_mutex = subkernel_mutex.clone(); + let restart_idle = restart_idle.clone(); + restart_idle.set(false); respawn(&io, &mut kernel_thread, move |io| { let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); match flash_kernel_worker(&io, &aux_mutex, &routing_table, &up_destinations, - &ddma_mutex, &subkernel_mutex, &mut *congress, "idle_kernel") { + &ddma_mutex, &subkernel_mutex, &mut *congress, "idle_kernel", Some(&restart_idle)) { Ok(()) => info!("idle kernel finished, standing by"), Err(Error::Protocol(host::Error::Io( @@ -1010,7 +1017,9 @@ pub fn thread(io: Io, aux_mutex: &Mutex, } Err(Error::KernelNotFound) => { info!("no idle kernel found"); - while io.relinquish().is_ok() {} + loop { + if !io.relinquish().is_ok() || restart_idle.get() { break; } + } } Err(err) => { error!("idle kernel aborted: {}", err);