forked from M-Labs/artiq
1
0
Fork 0

Rust: implement idle kernels.

This commit is contained in:
whitequark 2016-10-04 05:20:56 +00:00
parent 398b709e25
commit 6bbaff81bf
5 changed files with 69 additions and 47 deletions

View File

@ -1,5 +1,5 @@
#![no_std] #![no_std]
#![feature(libc, borrow_state, const_fn, try_borrow)] #![feature(libc, const_fn, try_borrow)]
#[macro_use] #[macro_use]
extern crate std_artiq as std; extern crate std_artiq as std;

View File

@ -1,8 +1,7 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::cell::{RefCell, BorrowState}; use std::cell::RefCell;
use std::vec::Vec; use std::vec::Vec;
use std::rc::Rc;
use std::time::{Instant, Duration}; use std::time::{Instant, Duration};
use std::io::{Read, Write, Result, Error, ErrorKind}; use std::io::{Read, Write, Result, Error, ErrorKind};
use fringe::OwnedStack; use fringe::OwnedStack;

View File

@ -95,7 +95,7 @@ fn check_magic(stream: &mut TcpStream) -> io::Result<()> {
fn host_read(stream: &mut TcpStream) -> io::Result<host::Request> { fn host_read(stream: &mut TcpStream) -> io::Result<host::Request> {
let request = try!(host::Request::read_from(stream)); let request = try!(host::Request::read_from(stream));
match &request { match &request {
&host::Request::LoadLibrary(_) => trace!("comm<-host LoadLibrary(...)"), &host::Request::LoadKernel(_) => trace!("comm<-host LoadLibrary(...)"),
_ => trace!("comm<-host {:?}", request) _ => trace!("comm<-host {:?}", request)
} }
Ok(request) Ok(request)
@ -127,6 +127,38 @@ fn kern_acknowledge() -> io::Result<()> {
Ok(()) Ok(())
} }
unsafe fn kern_load(waiter: Waiter, session: &mut Session, library: &[u8]) -> io::Result<()> {
if session.running() {
unexpected!("attempted to load a new kernel while a kernel was running")
}
kernel::start();
try!(kern_send(waiter, kern::LoadRequest(&library)));
kern_recv(waiter, |reply| {
match reply {
kern::LoadReply { error: None } => {
session.kernel_state = KernelState::Loaded;
Ok(())
}
kern::LoadReply { error: Some(cause) } =>
unexpected!("cannot load kernel: {}", cause),
other =>
unexpected!("unexpected reply from kernel CPU: {:?}", other)
}
})
}
fn kern_run(session: &mut Session) -> io::Result<()> {
if session.kernel_state != KernelState::Loaded {
unexpected!("attempted to run a kernel while not in Loaded state")
}
session.kernel_state = KernelState::Running;
// TODO: make this a separate request
kern_acknowledge()
}
fn process_host_message(waiter: Waiter, fn process_host_message(waiter: Waiter,
stream: &mut TcpStream, stream: &mut TcpStream,
session: &mut Session) -> io::Result<()> { session: &mut Session) -> io::Result<()> {
@ -187,40 +219,17 @@ fn process_host_message(waiter: Waiter,
} }
} }
host::Request::LoadLibrary(library) => { host::Request::LoadKernel(kernel) =>
if session.running() { match unsafe { kern_load(waiter, session, &kernel) } {
error!("attempted to load a new kernel while a kernel was running"); Ok(()) => host_write(stream, host::Reply::LoadCompleted),
return host_write(stream, host::Reply::LoadFailed) Err(_) => host_write(stream, host::Reply::LoadFailed)
} },
unsafe { kernel::start() } host::Request::RunKernel =>
match kern_run(session) {
try!(kern_send(waiter, kern::LoadRequest(&library))); Ok(()) => Ok(()),
kern_recv(waiter, |reply| { Err(_) => host_write(stream, host::Reply::KernelStartupFailed)
match reply { },
kern::LoadReply { error: None } => {
session.kernel_state = KernelState::Loaded;
host_write(stream, host::Reply::LoadCompleted)
}
kern::LoadReply { error: Some(cause) } => {
error!("cannot load kernel: {}", cause);
host_write(stream, host::Reply::LoadFailed)
}
other => unexpected!("unexpected reply from kernel CPU: {:?}", other)
}
})
}
host::Request::RunKernel => {
if session.kernel_state != KernelState::Loaded {
error!("attempted to run a kernel while not in Loaded state");
return host_write(stream, host::Reply::KernelStartupFailed)
}
session.kernel_state = KernelState::Running;
// TODO: make this a separate request
kern_acknowledge()
}
request => unexpected!("unexpected request {:?} from host machine", request) request => unexpected!("unexpected request {:?} from host machine", request)
} }
@ -289,6 +298,7 @@ fn host_kernel_worker(waiter: Waiter,
stream: &mut TcpStream, stream: &mut TcpStream,
congress: &mut Congress) -> io::Result<()> { congress: &mut Congress) -> io::Result<()> {
let mut session = Session::new(congress); let mut session = Session::new(congress);
loop { loop {
if stream.readable() { if stream.readable() {
try!(process_host_message(waiter, stream, &mut session)); try!(process_host_message(waiter, stream, &mut session));
@ -315,8 +325,14 @@ fn host_kernel_worker(waiter: Waiter,
} }
fn flash_kernel_worker(waiter: Waiter, fn flash_kernel_worker(waiter: Waiter,
congress: &mut Congress) -> io::Result<()> { congress: &mut Congress,
config_key: &str) -> io::Result<()> {
let mut session = Session::new(congress); let mut session = Session::new(congress);
let kernel = config::read_to_end(config_key);
try!(unsafe { kern_load(waiter, &mut session, &kernel) });
try!(kern_run(&mut session));
loop { loop {
try!(process_kern_message(waiter, &mut session)) try!(process_kern_message(waiter, &mut session))
} }
@ -328,11 +344,13 @@ fn respawn<F>(spawner: Spawner, waiter: Waiter,
match handle.take() { match handle.take() {
None => (), None => (),
Some(handle) => { Some(handle) => {
if !handle.terminated() {
info!("terminating running kernel"); info!("terminating running kernel");
handle.interrupt(); handle.interrupt();
waiter.join(handle).expect("cannot join interrupt thread") waiter.join(handle).expect("cannot join interrupt thread")
} }
} }
}
*handle = Some(spawner.spawn(8192, f)) *handle = Some(spawner.spawn(8192, f))
} }
@ -372,18 +390,23 @@ pub fn handler(waiter: Waiter, spawner: Spawner) {
}) })
} }
if kernel_thread.is_none() { if kernel_thread.as_ref().map_or(true, |h| h.terminated()) {
info!("no connection, starting idle kernel"); info!("no connection, starting idle kernel");
let congress = congress.clone(); let congress = congress.clone();
respawn(spawner.clone(), waiter, &mut kernel_thread, move |waiter, _spawner| { respawn(spawner.clone(), waiter, &mut kernel_thread, move |waiter, _spawner| {
let mut congress = congress.borrow_mut(); let mut congress = congress.borrow_mut();
match flash_kernel_worker(waiter, &mut congress) { match flash_kernel_worker(waiter, &mut congress, "idle_kernel") {
Ok(()) => Ok(()) =>
info!("idle kernel finished, standing by"), info!("idle kernel finished, standing by"),
Err(err) => { Err(err) => {
if err.kind() == io::ErrorKind::Interrupted {
info!("idle kernel interrupted");
} else {
error!("idle kernel aborted: {:?}", err); error!("idle kernel aborted: {:?}", err);
} }
} }
}
}) })
} }

View File

@ -122,7 +122,7 @@ pub enum Request {
Ident, Ident,
SwitchClock(u8), SwitchClock(u8),
LoadLibrary(Vec<u8>), LoadKernel(Vec<u8>),
RunKernel, RunKernel,
RpcReply { tag: String }, // FIXME RpcReply { tag: String }, // FIXME
@ -150,7 +150,7 @@ impl Request {
5 => { 5 => {
let mut code = vec![0; length - HEADER_SIZE]; let mut code = vec![0; length - HEADER_SIZE];
try!(reader.read_exact(&mut code)); try!(reader.read_exact(&mut code));
Request::LoadLibrary(code) Request::LoadKernel(code)
}, },
6 => Request::RunKernel, 6 => Request::RunKernel,
7 => Request::RpcReply { 7 => Request::RpcReply {

View File

@ -1,5 +1,5 @@
use std::rc::Rc; use std::rc::Rc;
use std::ops::{Deref, DerefMut}; use std::ops::Deref;
use std::fmt; use std::fmt;
pub struct Urc<T: ?Sized>(Rc<T>); pub struct Urc<T: ?Sized>(Rc<T>);