_core_rustc_static/
lib.rsuse lazy_static::lazy_static;
use std::cell::RefCell;
use std::ffi::c_char;
use zx::sys::zx_handle_t;
use zx::{self as zx, AsHandleRef};
mod allocations_table;
mod profiler;
mod recursion_guard;
mod resources_table;
mod waiter_list;
#[cfg(not(test))]
mod hooks;
use crate::profiler::{PerThreadData, Profiler};
use crate::recursion_guard::with_recursion_guard;
lazy_static! {
static ref PROFILER: Profiler = with_recursion_guard(Default::default);
}
thread_local! {
static THREAD_DATA: RefCell<PerThreadData> = with_recursion_guard(Default::default);
}
#[derive(Clone, Copy, Default)]
#[repr(C)]
pub struct heapdump_global_stats {
pub total_allocated_bytes: u64,
pub total_deallocated_bytes: u64,
}
#[derive(Clone, Copy, Default)]
#[repr(C)]
pub struct heapdump_thread_local_stats {
pub total_allocated_bytes: u64,
pub total_deallocated_bytes: u64,
}
pub fn with_profiler(f: impl FnOnce(&Profiler, &mut PerThreadData)) {
let profiler = &*PROFILER;
THREAD_DATA.with(|thread_data| {
with_recursion_guard(|| {
f(profiler, &mut thread_data.borrow_mut());
})
})
}
#[no_mangle]
pub unsafe extern "C" fn heapdump_bind_with_channel(registry_channel: zx_handle_t) {
let handle = zx::Handle::from_raw(registry_channel);
if !handle.is_invalid() {
assert_eq!(handle.basic_info().unwrap().object_type, zx::ObjectType::CHANNEL);
}
PROFILER.bind(handle.into());
}
#[no_mangle]
pub unsafe extern "C" fn heapdump_get_stats(
global: *mut heapdump_global_stats,
local: *mut heapdump_thread_local_stats,
) {
with_profiler(|profiler, thread_data| {
if global != std::ptr::null_mut() {
*global = profiler.get_global_stats();
}
if local != std::ptr::null_mut() {
*local = thread_data.get_local_stats();
}
});
}
#[no_mangle]
pub unsafe extern "C" fn heapdump_take_named_snapshot(name: *const c_char) {
let name_cstr = std::ffi::CStr::from_ptr(name);
let name_str = name_cstr.to_str().expect("name contains invalid characters");
assert!(name_str.len() <= zx::sys::ZX_MAX_NAME_LEN, "name is too long");
PROFILER.publish_named_snapshot(name_str);
}