forked from M-Labs/artiq-zynq
runtime/logger: use blocking wait.
Fixes #84 using the first solution. If the performance is considered too slow, we can do the second option later.
This commit is contained in:
parent
4b6c5d5679
commit
c85e85aa6d
|
@ -38,7 +38,8 @@ impl<'a> Drop for LogBufferRef<'a> {
|
||||||
|
|
||||||
pub struct BufferLogger {
|
pub struct BufferLogger {
|
||||||
buffer: Mutex<LogBuffer<&'static mut [u8]>>,
|
buffer: Mutex<LogBuffer<&'static mut [u8]>>,
|
||||||
uart_filter: Cell<LevelFilter>
|
uart_filter: Cell<LevelFilter>,
|
||||||
|
buffer_filter: Cell<LevelFilter>,
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut LOGGER: Option<BufferLogger> = None;
|
static mut LOGGER: Option<BufferLogger> = None;
|
||||||
|
@ -48,6 +49,7 @@ impl BufferLogger {
|
||||||
BufferLogger {
|
BufferLogger {
|
||||||
buffer: Mutex::new(LogBuffer::new(buffer)),
|
buffer: Mutex::new(LogBuffer::new(buffer)),
|
||||||
uart_filter: Cell::new(LevelFilter::Info),
|
uart_filter: Cell::new(LevelFilter::Info),
|
||||||
|
buffer_filter: Cell::new(LevelFilter::Trace),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +78,15 @@ impl BufferLogger {
|
||||||
pub fn set_uart_log_level(&self, max_level: LevelFilter) {
|
pub fn set_uart_log_level(&self, max_level: LevelFilter) {
|
||||||
self.uart_filter.set(max_level)
|
self.uart_filter.set(max_level)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn buffer_log_level(&self) -> LevelFilter {
|
||||||
|
self.buffer_filter.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// this should be reserverd for mgmt module
|
||||||
|
pub fn set_buffer_log_level(&self, max_level: LevelFilter) {
|
||||||
|
self.buffer_filter.set(max_level)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// required for impl Log
|
// required for impl Log
|
||||||
|
@ -94,7 +105,8 @@ impl Log for BufferLogger {
|
||||||
let seconds = timestamp / 1_000_000;
|
let seconds = timestamp / 1_000_000;
|
||||||
let micros = timestamp % 1_000_000;
|
let micros = timestamp % 1_000_000;
|
||||||
|
|
||||||
if let Some(mut buffer) = self.buffer.try_lock() {
|
if record.level() <= self.buffer_log_level() {
|
||||||
|
let mut buffer = self.buffer.lock();
|
||||||
writeln!(buffer, "[{:6}.{:06}s] {:>5}({}): {}", seconds, micros,
|
writeln!(buffer, "[{:6}.{:06}s] {:>5}({}): {}", seconds, micros,
|
||||||
record.level(), record.target(), record.args()).unwrap();
|
record.level(), record.target(), record.args()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,9 +98,9 @@ async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>) ->
|
||||||
let msg: Request = FromPrimitive::from_i8(msg?).ok_or(Error::UnrecognizedPacket)?;
|
let msg: Request = FromPrimitive::from_i8(msg?).ok_or(Error::UnrecognizedPacket)?;
|
||||||
match msg {
|
match msg {
|
||||||
Request::GetLog => {
|
Request::GetLog => {
|
||||||
let mut buffer = get_logger_buffer().await;
|
let buffer = get_logger_buffer().await.extract().as_bytes().to_vec();
|
||||||
write_i8(stream, Reply::LogContent as i8).await?;
|
write_i8(stream, Reply::LogContent as i8).await?;
|
||||||
write_chunk(stream, buffer.extract().as_bytes()).await?;
|
write_chunk(stream, &buffer).await?;
|
||||||
}
|
}
|
||||||
Request::ClearLog => {
|
Request::ClearLog => {
|
||||||
let mut buffer = get_logger_buffer().await;
|
let mut buffer = get_logger_buffer().await;
|
||||||
|
@ -115,24 +115,22 @@ async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>) ->
|
||||||
};
|
};
|
||||||
loop {
|
loop {
|
||||||
let mut buffer = get_logger_buffer_pred(|b| !b.is_empty()).await;
|
let mut buffer = get_logger_buffer_pred(|b| !b.is_empty()).await;
|
||||||
let bytes = buffer.extract().as_bytes();
|
|
||||||
if id != *pull_id.borrow() {
|
if id != *pull_id.borrow() {
|
||||||
// another connection attempts to pull the log...
|
// another connection attempts to pull the log...
|
||||||
// abort this connection...
|
// abort this connection...
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
write_chunk(stream, bytes).await?;
|
let bytes = buffer.extract().as_bytes().to_vec();
|
||||||
if log::max_level() == LevelFilter::Trace {
|
|
||||||
// Hold exclusive access over the logger until we get positive
|
|
||||||
// acknowledgement; otherwise we get an infinite loop of network
|
|
||||||
// trace messages being transmitted and causing more network
|
|
||||||
// trace messages to be emitted.
|
|
||||||
//
|
|
||||||
// Any messages unrelated to this management socket that arrive
|
|
||||||
// while it is flushed are lost, but such is life.
|
|
||||||
stream.flush().await?;
|
|
||||||
}
|
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
|
core::mem::drop(buffer);
|
||||||
|
write_chunk(stream, &bytes).await?;
|
||||||
|
if log::max_level() == LevelFilter::Trace {
|
||||||
|
// temporarily discard all trace level log
|
||||||
|
let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() };
|
||||||
|
logger.set_buffer_log_level(LevelFilter::Debug);
|
||||||
|
stream.flush().await?;
|
||||||
|
logger.set_buffer_log_level(LevelFilter::Trace);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Request::SetLogFilter => {
|
Request::SetLogFilter => {
|
||||||
|
|
Loading…
Reference in New Issue