use winapi::{
shared::ntdef::FALSE,
um::{
handleapi::CloseHandle,
processthreadsapi::{GetCurrentProcess, GetProcessHandleCount, OpenProcess},
winnt::{HANDLE, PROCESS_QUERY_INFORMATION},
},
};
pub type Result<T> = std::io::Result<T>;
#[inline]
fn process_fd_count_inner(handler: ProcessHandler) -> Result<u32> {
let mut count = 0;
let ret = unsafe { GetProcessHandleCount(handler.raw(), &mut count) };
if ret == 0 {
return Err(std::io::Error::last_os_error());
}
Ok(count)
}
pub fn fd_count_pid(pid: u32) -> Result<u32> {
let handler = unsafe { OpenProcess(PROCESS_QUERY_INFORMATION, FALSE as i32, pid) }.into();
process_fd_count_inner(handler)
}
pub fn fd_count_cur() -> Result<u32> {
let handler = unsafe { GetCurrentProcess() }.into();
process_fd_count_inner(handler)
}
pub struct ProcessHandler(HANDLE);
impl ProcessHandler {
pub fn raw(&self) -> HANDLE {
self.0
}
}
impl From<HANDLE> for ProcessHandler {
fn from(h: HANDLE) -> Self {
ProcessHandler(h)
}
}
impl Drop for ProcessHandler {
fn drop(&mut self) {
unsafe {
CloseHandle(self.0);
}
}
}
#[cfg(test)]
mod test {
use super::*;
use winapi::um::processthreadsapi::GetCurrentProcessId;
#[test]
fn test_count_fd() {
const NUM: u32 = 100000;
for _ in 0..NUM {
let pid = unsafe { GetCurrentProcessId() };
let handler = unsafe { OpenProcess(PROCESS_QUERY_INFORMATION, FALSE as i32, pid) };
unsafe { CloseHandle(handler) };
}
let new_count = fd_count_cur().unwrap();
assert!(new_count < NUM);
for _ in 0..NUM {
let pid = unsafe { GetCurrentProcessId() };
unsafe { OpenProcess(PROCESS_QUERY_INFORMATION, FALSE as i32, pid) };
}
let new_count = fd_count_cur().unwrap();
assert!(new_count >= NUM);
}
}