use std::ffi::CString;
use std::os::raw::{c_char, c_int};
use std::sync::Mutex;
use error::{Error, ErrorKind};
use state::ProfilerState;
use util::check_file_path;
lazy_static! {
#[derive(Debug)]
pub static ref HEAP_PROFILER: Mutex<HeapProfiler> = Mutex::new(HeapProfiler {
state: ProfilerState::NotActive,
});
}
#[allow(non_snake_case)]
extern "C" {
fn HeapProfilerStart(fname: *const c_char);
fn HeapProfilerStop();
fn HeapProfilerDump(resaon: *const c_char);
fn IsHeapProfilerRunning() -> c_int;
}
#[derive(Debug)]
pub struct HeapProfiler {
state: ProfilerState,
}
impl HeapProfiler {
pub fn state(&self) -> ProfilerState {
self.state
}
pub fn is_running(&self) -> bool {
let state = unsafe { IsHeapProfilerRunning() };
state == 1
}
pub fn start<T: Into<Vec<u8>>>(&mut self, fname: T) -> Result<(), Error> {
if self.state == ProfilerState::NotActive {
let c_fname = try!(CString::new(fname));
check_file_path(c_fname.clone().into_string().unwrap())?;
unsafe {
HeapProfilerStart(c_fname.as_ptr());
}
self.state = ProfilerState::Active;
Ok(())
} else {
Err(ErrorKind::InvalidState(self.state).into())
}
}
pub fn stop(&mut self) -> Result<(), Error> {
if self.state == ProfilerState::Active {
unsafe {
HeapProfilerStop();
}
self.state = ProfilerState::NotActive;
Ok(())
} else {
Err(ErrorKind::InvalidState(self.state).into())
}
}
pub fn dump<T: Into<Vec<u8>>>(&mut self, reason: T) -> Result<(), Error> {
let c_reason = try!(CString::new(reason));
check_file_path(c_reason.clone().into_string().unwrap())?;
unsafe {
HeapProfilerDump(c_reason.as_ptr());
}
Ok(())
}
}