Skip to content

Commit

Permalink
Rust: add support for artiq_corelog.
Browse files Browse the repository at this point in the history
whitequark committed Sep 28, 2016
1 parent b14c19a commit fdcb27c
Showing 7 changed files with 138 additions and 25 deletions.
14 changes: 14 additions & 0 deletions artiq/runtime.rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions artiq/runtime.rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -12,6 +12,8 @@ path = "src/lib.rs"
std_artiq = { path = "libstd_artiq" }
lwip = { path = "liblwip" }
fringe = { version = "= 1.1.0", default-features = false, features = ["alloc"] }
log = { version = "0.3", default-features = false }
log_buffer = { version = "1.0" }
byteorder = { version = "0.5", default-features = false }

[profile.dev]
57 changes: 57 additions & 0 deletions artiq/runtime.rs/src/buffer_logger.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use core::mem;
use core::cell::RefCell;
use log::{self, Log, LogMetadata, LogRecord, LogLevelFilter};
use log_buffer::LogBuffer;

pub struct BufferLogger {
buffer: RefCell<LogBuffer<&'static mut [u8]>>
}

// We can never preempt from within the logger, so there can be no data races.
unsafe impl Sync for BufferLogger {}

impl BufferLogger {
pub fn new(buffer: &'static mut [u8]) -> BufferLogger {
BufferLogger {
buffer: RefCell::new(LogBuffer::new(buffer))
}
}

pub fn register<F: FnOnce(&BufferLogger)>(&self, f: F) {
// log::set_logger_raw captures a pointer to ourselves, so we must prevent
// ourselves from being moved or dropped after that function is called (and
// before log::shutdown_logger_raw is called).
unsafe {
log::set_logger_raw(|max_log_level| {
max_log_level.set(LogLevelFilter::Trace);
self as *const Log
}).expect("global logger can only be initialized once");
}
f(self);
log::shutdown_logger_raw().unwrap();
}

pub fn clear(&self) {
self.buffer.borrow_mut().clear()
}

pub fn extract<R, F: FnOnce(&str) -> R>(&self, f: F) -> R {
f(self.buffer.borrow_mut().extract())
}
}

impl Log for BufferLogger {
fn enabled(&self, _metadata: &log::LogMetadata) -> bool {
true
}

fn log(&self, record: &LogRecord) {
if self.enabled(record.metadata()) {
use core::fmt::Write;
writeln!(self.buffer.borrow_mut(), "{}({}): {}",
record.level(), record.location().module_path(), record.args()).unwrap();
println!("{}({}): {}",
record.level(), record.location().module_path(), record.args());
}
}
}
10 changes: 7 additions & 3 deletions artiq/runtime.rs/src/io.rs
Original file line number Diff line number Diff line change
@@ -39,7 +39,7 @@ impl Scheduler {
Scheduler { threads: Vec::new(), index: 0 }
}

pub unsafe fn spawn<F: FnOnce(Waiter) + Send + 'static>(&mut self, stack_size: usize, f: F) {
pub unsafe fn spawn<F: FnOnce(Waiter) + Send>(&mut self, stack_size: usize, f: F) {
let stack = OwnedStack::new(stack_size);
let thread = Thread {
generator: Generator::unsafe_new(stack, move |yielder, _| {
@@ -286,8 +286,12 @@ impl<'a> Read for TcpStream<'a> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if self.buffer.is_none() {
try!(self.waiter.tcp_readable(&self.lower));
let pbuf = try!(self.lower.try_read()).unwrap();
self.buffer = Some((pbuf, 0))
match self.lower.try_read() {
Ok(Some(pbuf)) => self.buffer = Some((pbuf, 0)),
Ok(None) => unreachable!(),
Err(lwip::Error::ConnectionClosed) => return Ok(0),
Err(err) => return Err(Error::from(err))
}
}

let (pbuf, pos) = self.buffer.take().unwrap();
28 changes: 20 additions & 8 deletions artiq/runtime.rs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
#![no_std]
#![feature(const_fn)]

#[macro_use]
extern crate std_artiq as std;
#[macro_use]
extern crate log;
extern crate log_buffer;
extern crate byteorder;

use std::prelude::v1::*;
use buffer_logger::BufferLogger;

pub mod io;
pub mod buffer_logger;
pub mod session;

extern {
@@ -16,13 +22,19 @@ extern {

#[no_mangle]
pub unsafe extern fn rust_main() {
println!("Accepting network sessions in Rust.");
network_init();
static mut log_buffer: [u8; 4096] = [0; 4096];
BufferLogger::new(&mut log_buffer[..])
.register(move |logger| {
info!("Accepting network sessions in Rust.");
network_init();

let mut scheduler = io::Scheduler::new();
scheduler.spawn(4096, session::handler);
loop {
lwip_service();
scheduler.run()
}
let mut scheduler = io::Scheduler::new();
scheduler.spawn(4096, move |waiter| {
session::handler(waiter, logger)
});
loop {
lwip_service();
scheduler.run()
}
})
}
48 changes: 36 additions & 12 deletions artiq/runtime.rs/src/session/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::prelude::v1::*;
use std::io::{self, Read};
use std::str;
use std::io::{self, Read, ErrorKind};
use self::protocol::*;

mod protocol;
@@ -52,15 +53,16 @@ fn check_magic(stream: &mut ::io::TcpStream) -> io::Result<()> {
}
}

fn handle_request(stream: &mut ::io::TcpStream) -> io::Result<()> {
fn handle_request(stream: &mut ::io::TcpStream,
logger: &::buffer_logger::BufferLogger) -> io::Result<()> {
fn read_request(stream: &mut ::io::TcpStream) -> io::Result<Request> {
let request = try!(Request::read_from(stream));
println!("comm<-host {:?}", request);
trace!("comm<-host {:?}", request);
Ok(request)
}

fn write_reply(stream: &mut ::io::TcpStream, reply: Reply) -> io::Result<()> {
println!("comm->host {:?}", reply);
trace!("comm->host {:?}", reply);
reply.write_to(stream)
}

@@ -75,28 +77,50 @@ fn handle_request(stream: &mut ::io::TcpStream) -> io::Result<()> {
&ident[..ident.iter().position(|&c| c == 0).unwrap()]
};

write_reply(stream, Reply::Ident(ident))
},
write_reply(stream, Reply::Ident(str::from_utf8(ident).unwrap()))
}

Request::Log => {
// Logging the packet with the log is inadvisable
trace!("comm->host Log(...)");
logger.extract(move |log| {
Reply::Log(log).write_to(stream)
})
}

Request::LogClear => {
logger.clear();
write_reply(stream, Reply::Log(""))
}

_ => unreachable!()
}
}

fn handle_requests(stream: &mut ::io::TcpStream) -> io::Result<()> {
fn handle_requests(stream: &mut ::io::TcpStream,
logger: &::buffer_logger::BufferLogger) -> io::Result<()> {
try!(check_magic(stream));
loop {
try!(handle_request(stream))
try!(handle_request(stream, logger))
}
}

pub fn handler(waiter: ::io::Waiter) {
pub fn handler(waiter: ::io::Waiter,
logger: &::buffer_logger::BufferLogger) {
let addr = ::io::SocketAddr::new(::io::IP_ANY, 1381);
let listener = ::io::TcpListener::bind(waiter, addr).unwrap();
loop {
let (mut stream, _addr) = listener.accept().unwrap();
match handle_requests(&mut stream) {
let (mut stream, addr) = listener.accept().unwrap();
info!("new connection from {:?}", addr);

match handle_requests(&mut stream, logger) {
Ok(()) => (),
Err(err) => {
println!("cannot handle network request: {:?}", err);
if err.kind() == ErrorKind::UnexpectedEof {
info!("connection closed");
} else {
error!("cannot handle network request: {:?}", err);
}
}
}
}
4 changes: 2 additions & 2 deletions artiq/runtime.rs/src/session/protocol.rs
Original file line number Diff line number Diff line change
@@ -177,7 +177,7 @@ impl Request {
pub enum Reply<'a> {
Log(&'a str),

Ident(&'a [u8]),
Ident(&'a str),
ClockSwitchCompleted,
ClockSwitchFailed,

@@ -213,7 +213,7 @@ impl<'a> Reply<'a> {
Reply::Ident(ident) => {
try!(write_u8(&mut buf, 2));
try!(buf.write(b"AROR"));
try!(buf.write(ident));
try!(buf.write(ident.as_bytes()));
},
Reply::ClockSwitchCompleted => {
try!(write_u8(&mut buf, 3));

0 comments on commit fdcb27c

Please sign in to comment.