aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2019-03-20 16:40:17 -0400
committerJosh Matthews <josh@joshmatthews.net>2019-05-01 18:57:44 -0400
commitd0e9acf1eb81c2b535a01c42b7541d2b33a0acb2 (patch)
tree32778fc43e85f18c78df44a0e708cb293e9b5ee5
parentdaabda7fe14cb79ddc1b06019bec77f953eb9cf8 (diff)
downloadservo-d0e9acf1eb81c2b535a01c42b7541d2b33a0acb2.tar.gz
servo-d0e9acf1eb81c2b535a01c42b7541d2b33a0acb2.zip
Redirect stdout to ML logging.
-rw-r--r--Cargo.lock1
-rw-r--r--ports/libmlservo/Cargo.toml1
-rw-r--r--ports/libmlservo/src/lib.rs80
3 files changed, 82 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 334d517ae5f..aeb8120e189 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2437,6 +2437,7 @@ dependencies = [
name = "libmlservo"
version = "0.0.1"
dependencies = [
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"libservo 0.0.1",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/ports/libmlservo/Cargo.toml b/ports/libmlservo/Cargo.toml
index b0db3605df2..2534dbe4a9d 100644
--- a/ports/libmlservo/Cargo.toml
+++ b/ports/libmlservo/Cargo.toml
@@ -15,6 +15,7 @@ bench = false
[dependencies]
libservo = { path = "../../components/servo", features = ["no_static_freetype"] }
simpleservo = { path = "../libsimpleservo/api", features = ["no_static_freetype"] }
+libc = "0.2"
log = "0.4"
servo-egl = "0.2"
smallvec = "0.6"
diff --git a/ports/libmlservo/src/lib.rs b/ports/libmlservo/src/lib.rs
index 3af71da4b99..5f27e3f2b58 100644
--- a/ports/libmlservo/src/lib.rs
+++ b/ports/libmlservo/src/lib.rs
@@ -7,6 +7,7 @@ use egl::egl::EGLDisplay;
use egl::egl::EGLSurface;
use egl::egl::MakeCurrent;
use egl::egl::SwapBuffers;
+use libc::{dup2, pipe, read};
use log::info;
use log::warn;
use servo::euclid::TypedScale;
@@ -25,6 +26,7 @@ use std::ffi::CStr;
use std::ffi::CString;
use std::io::Write;
use std::os::raw::c_char;
+use std::os::raw::c_int;
use std::os::raw::c_void;
use std::rc::Rc;
use std::thread;
@@ -67,6 +69,7 @@ pub enum MLKeyType {
}
#[repr(transparent)]
+#[derive(Copy, Clone)]
pub struct MLLogger(extern "C" fn(MLLogLevel, *const c_char));
#[repr(transparent)]
@@ -109,6 +112,7 @@ pub unsafe extern "C" fn init_servo(
height: u32,
hidpi: f32,
) -> *mut ServoInstance {
+ redirect_stdout_to_log(logger);
let _ = log::set_boxed_logger(Box::new(logger));
log::set_max_level(LOG_LEVEL);
@@ -382,3 +386,79 @@ impl log::Log for MLLogger {
fn flush(&self) {}
}
+
+fn redirect_stdout_to_log(logger: MLLogger) {
+ // The first step is to redirect stdout and stderr to the logs.
+ // We redirect stdout and stderr to a custom descriptor.
+ let mut pfd: [c_int; 2] = [0, 0];
+ unsafe {
+ pipe(pfd.as_mut_ptr());
+ dup2(pfd[1], 1);
+ dup2(pfd[1], 2);
+ }
+
+ let descriptor = pfd[0];
+
+ // Then we spawn a thread whose only job is to read from the other side of the
+ // pipe and redirect to the logs.
+ let _detached = thread::spawn(move || {
+ const BUF_LENGTH: usize = 512;
+ let mut buf = vec![b'\0' as c_char; BUF_LENGTH];
+
+ // Always keep at least one null terminator
+ const BUF_AVAILABLE: usize = BUF_LENGTH - 1;
+ let buf = &mut buf[..BUF_AVAILABLE];
+
+ let mut cursor = 0_usize;
+
+ loop {
+ let result = {
+ let read_into = &mut buf[cursor..];
+ unsafe {
+ read(
+ descriptor,
+ read_into.as_mut_ptr() as *mut _,
+ read_into.len(),
+ )
+ }
+ };
+
+ let end = if result == 0 {
+ return;
+ } else if result < 0 {
+ (logger.0)(
+ MLLogLevel::Error,
+ b"error in log thread; closing\0".as_ptr() as *const _,
+ );
+ return;
+ } else {
+ result as usize + cursor
+ };
+
+ // Only modify the portion of the buffer that contains real data.
+ let buf = &mut buf[0..end];
+
+ if let Some(last_newline_pos) = buf.iter().rposition(|&c| c == b'\n' as c_char) {
+ buf[last_newline_pos] = b'\0' as c_char;
+ (logger.0)(MLLogLevel::Info, buf.as_ptr());
+ if last_newline_pos < buf.len() - 1 {
+ let pos_after_newline = last_newline_pos + 1;
+ let len_not_logged_yet = buf[pos_after_newline..].len();
+ for j in 0..len_not_logged_yet as usize {
+ buf[j] = buf[pos_after_newline + j];
+ }
+ cursor = len_not_logged_yet;
+ } else {
+ cursor = 0;
+ }
+ } else if end == BUF_AVAILABLE {
+ // No newline found but the buffer is full, flush it anyway.
+ // `buf.as_ptr()` is null-terminated by BUF_LENGTH being 1 less than BUF_AVAILABLE.
+ (logger.0)(MLLogLevel::Info, buf.as_ptr());
+ cursor = 0;
+ } else {
+ cursor = end;
+ }
+ }
+ });
+}