Skip to content

Commit

Permalink
use lazy_static_ptr! to store pointer to lazy_static globals for debu…
Browse files Browse the repository at this point in the history
…gging (openzfs#277)

We would like to be able to print the log messages from a core file.
Unfortunately, lazy_static! makes it hard to get to the global object
from the debugger.  We would like to save the pointer in a global
variable so that we can easily dereference it from rust-gdb.

The way we are saving LOG_MESSAGES_PTR currently is not right; we're
saving the location of the variable on the stack, which will be moved
into the "real" location after it is returned.

This commit solves the problem by allocating the data on the heap
(inside a `Box`), so that we can know its address before the initializer
returns.  Because this is a little tricky, and you have to name the
(potentially complicated) type of the variable 3 times, a new macro is
introduced to do this for us.

Now in the debugger you can do:

```
(gdb) p util::logging::LOG_MESSAGES_PTR.p.value.data
$1 = core::cell::UnsafeCell<alloc::collections::vec_deque::VecDeque<alloc::string::String, alloc::alloc::Global>> {value: VecDeque(size=28) = {
...
    "[2022-03-04 23:01:49.089][zfs_object_agent][ERROR] Starting ZFS Object Agent (zfs-0.7.0-6003-g5b402b78c).  Local timezone is +00:00 (+00:00)",
```
  • Loading branch information
ahrens authored Mar 6, 2022
1 parent 19fbc40 commit a74d974
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 11 deletions.
7 changes: 7 additions & 0 deletions cmd/zfs_object_agent/Cargo.lock

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

1 change: 1 addition & 0 deletions cmd/zfs_object_agent/util/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ log4rs = "1.0.0"
libc = "0.2"
more-asserts = "0.2.1"
num-traits = "0.2.14"
paste = "1.0.6"
rand = "0.8.3"
rusoto_credential = "0.47.0"
safer-ffi = { version = "0.0.6", features = ["proc_macros"] }
Expand Down
63 changes: 63 additions & 0 deletions cmd/zfs_object_agent/util/src/lazy_static_ptr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
pub use lazy_static::lazy_static;
pub use paste::paste;
pub use std::sync::atomic::{AtomicPtr, Ordering};

/// This macro is similar to `lazy_static!`, but for each static created, it creates an
/// additional static variable with the `_PTR` suffix, which is an `AtomicPtr` to the contents of
/// the lazy_static variable. This can be used by the debugger to find the contents of the
/// lazy_static, which are otherwise buried inside a closure, which makes it hard to name from
/// the global context of the debugger.
///
/// For example:
/// ```
/// lazy_static_ptr! {
/// pub static ref STRINGS: Mutex<Vec<String>> = Default::default();
/// }
/// ```
/// This will declare a `pub static` variable named `STRINGS` which will deref to a
/// `Box<Mutex<Vec<String>>>`, similar to lazy_static!. Additionally, it will declare
/// ```
/// static STRINGS_PTR: AtomicPtr<Mutex<Vec<String>>> = ...;
/// ```
/// When `STRINGS` is initialized (on first dereference, or the .initialize() method),
/// `STRINGS_PTR` will be set to the location of the value returned by the initializer.
///
/// This macro uses `lazy_static!` internally. In order to compute the value's location in the
/// lazy_static initializer, it is allocated on the heap (in a `Box`), so `STRINGS` actually
/// dereferences to a `Box<Mutex<Vec<String>>>`, which itself deref's to a `Mutex<Vec<String>>`.
/// So the contents can be referred to by double-dereferenceing the global, `**STRINGS`. This
/// happens automatically for method calls, e.g. `STRINGS.lock()`
#[macro_export]
macro_rules! lazy_static_ptr {
// "pub" declaration
(pub static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
$crate::lazy_static_ptr!{ @IMPL (pub) $N: $T = $e; }
$crate::lazy_static_ptr!($($t)*);
};

// non-"pub" declaration
(static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
$crate::lazy_static_ptr!{ @IMPL () $N: $T = $e; }
$crate::lazy_static_ptr!($($t)*);
};

// internal implementation
(@IMPL ($($vis:tt)*) $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
$crate::lazy_static_ptr::paste! {
static [<$N _PTR>]: $crate::lazy_static_ptr::AtomicPtr<$T> =
$crate::lazy_static_ptr::AtomicPtr::new(::std::ptr::null_mut());
}
$crate::lazy_static_ptr::lazy_static! {
$($vis)* static ref $N: Box<$T> = {
let mut this: Box<$T> = Box::new($e);
$crate::lazy_static_ptr::paste! {
[<$N _PTR>].store(&mut *this, $crate::lazy_static_ptr::Ordering::Relaxed);
}
this
};
}
};

// empty trailing tokens
() => ()
}
1 change: 1 addition & 0 deletions cmd/zfs_object_agent/util/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mod btreemap_ext;
mod credentials;
mod die;
mod from64;
pub mod lazy_static_ptr;
mod lock_set;
mod logging;
pub mod message;
Expand Down
18 changes: 7 additions & 11 deletions cmd/zfs_object_agent/util/src/logging.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::tunable::log_tunable_config;
use crate::{get_tunable, with_alloctag_hf};
use crate::{get_tunable, lazy_static_ptr, with_alloctag_hf};
use backtrace::Backtrace;
use lazy_static::lazy_static;
use log::*;
Expand All @@ -14,21 +14,17 @@ use std::collections::VecDeque;
use std::fs::OpenOptions;
use std::io::Write;
use std::panic::PanicInfo;
use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
use std::{panic, process, ptr, thread};

static LOG_MESSAGES_PTR: AtomicPtr<std::sync::Mutex<VecDeque<String>>> =
AtomicPtr::new(ptr::null_mut());
use std::sync::atomic::{AtomicBool, Ordering};
use std::{panic, process, thread};

type PanicHook = Box<dyn Fn(&panic::PanicInfo) + Sync + Send>;

lazy_static_ptr! {
static ref LOG_MESSAGES: std::sync::Mutex<VecDeque<String>> = Default::default();
}

lazy_static! {
static ref LOG_PATTERN: String = "[{d(%Y-%m-%d %H:%M:%S%.3f)}][{t}][{l}] {m}{n}".to_string();
static ref LOG_MESSAGES: std::sync::Mutex<VecDeque<String>> = {
let mut inner = Default::default();
LOG_MESSAGES_PTR.store(&mut inner, Ordering::Relaxed);
inner
};
static ref MAX_LOG_MESSAGES: usize = get_tunable("max_log_messages", 100_000);
static ref PANIC_LOG_FOLDER: String =
get_tunable("panic_log_folder", "/var/log/zoa".to_string());
Expand Down

0 comments on commit a74d974

Please sign in to comment.