forked from M-Labs/artiq
Rust: implement idle kernels.
This commit is contained in:
parent
398b709e25
commit
6bbaff81bf
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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>);
|
||||||
|
|
Loading…
Reference in New Issue