Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid windows crate types in public API #4

Merged
merged 5 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ jobs:
name: create-release
runs-on: windows-2019
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- uses: actions/checkout@v3

- name: Check semver
uses: obi1kenobi/cargo-semver-checks-action@v2

- uses: actions-rs/toolchain@v1
with:
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "win32job"
version = "1.0.3"
version = "2.0.0"
authors = ["Ohad Ravid <[email protected]>"]
edition = "2021"
license = "MIT OR Apache-2.0"
Expand Down
24 changes: 10 additions & 14 deletions src/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ use crate::error::JobError;
use crate::limits::ExtendedLimitInfo;
use std::{ffi::c_void, mem};

pub use crate::utils::{get_current_process, get_process_memory_info};
pub use crate::utils::get_current_process;

#[derive(Debug)]
pub struct Job {
handle: HANDLE,
pub(crate) handle: HANDLE,
}

unsafe impl Send for Job {}
Expand All @@ -32,9 +32,7 @@ impl Job {
}

/// Create an anonymous job object and sets it's limit according to `info`.
/// Note: This method shouldn't change the provided `info`, but the internal Windows API
/// require a mutable pointer, which means this function requires &mut as well.
pub fn create_with_limit_info(info: &mut ExtendedLimitInfo) -> Result<Self, JobError> {
pub fn create_with_limit_info(info: &ExtendedLimitInfo) -> Result<Self, JobError> {
let job = Self::create()?;
job.set_extended_limit_info(info)?;

Expand All @@ -43,16 +41,16 @@ impl Job {

/// Return the underlying handle to the job.
/// Note that this handle will be closed once the `Job` object is dropped.
pub fn handle(&self) -> HANDLE {
self.handle
pub fn handle(&self) -> isize {
self.handle.0
}

/// Return the underlying handle to the job, consuming the job.
/// Note that the handle will NOT be closed, so it is the caller's responsibly to close it.
pub fn into_handle(self) -> HANDLE {
pub fn into_handle(self) -> isize {
let job = mem::ManuallyDrop::new(self);

job.handle
job.handle.0
}

/// Return basic and extended limit information for a job object.
Expand All @@ -74,9 +72,7 @@ impl Job {
}

/// Set the basic and extended limit information for a job object.
/// Note: This method shouldn't change the provided `info`, but the internal Windows API
/// require a mutable pointer, which means this function requires &mut as well.
pub fn set_extended_limit_info(&self, info: &mut ExtendedLimitInfo) -> Result<(), JobError> {
pub fn set_extended_limit_info(&self, info: &ExtendedLimitInfo) -> Result<(), JobError> {
unsafe {
SetInformationJobObject(
self.handle,
Expand All @@ -90,8 +86,8 @@ impl Job {

/// Assigns a process to the job object.
/// See also [Microsoft Docs](https://docs.microsoft.com/en-us/windows/win32/api/jobapi2/nf-jobapi2-assignprocesstojobobject).
pub fn assign_process(&self, proc_handle: HANDLE) -> Result<(), JobError> {
unsafe { AssignProcessToJobObject(self.handle, proc_handle) }
pub fn assign_process(&self, proc_handle: isize) -> Result<(), JobError> {
unsafe { AssignProcessToJobObject(self.handle, HANDLE(proc_handle)) }
.map_err(|e| JobError::AssignFailed(e.into()))
}

Expand Down
31 changes: 2 additions & 29 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//! or by creating an empty one using `new()`, use helper methods to configure
//! the required limits, and finally set the info to the job.
//!
//! ```edition2018
//! ```edition2021
//! use win32job::*;
//! # fn main() -> Result<(), JobError> {
//!
Expand All @@ -28,7 +28,7 @@
//! ```
//!
//! Which is equivalnent to:
//! ```edition2018
//! ```edition2021
//! use win32job::*;
//! # fn main() -> Result<(), JobError> {
//!
Expand All @@ -45,33 +45,6 @@
//! # Ok(())
//! # }
//! ```
//!
//! # Using the low level API
//!
//! The most basic API is getting an `ExtendedLimitInfo` object and
//! manipulating the raw `JOBOBJECT_BASIC_LIMIT_INFORMATION`, and then set it back to the job.
//!
//! It's important to remeber to set the needed `LimitFlags` for each limit used.
//!
//! ```edition2018
//! use win32job::*;
//! # fn main() -> Result<(), JobError> {
//! use windows::Win32::System::JobObjects::JOB_OBJECT_LIMIT_WORKINGSET;
//!
//! let job = Job::create()?;
//! let mut info = job.query_extended_limit_info()?;
//!
//! info.0.BasicLimitInformation.MinimumWorkingSetSize = 1 * 1024 * 1024;
//! info.0.BasicLimitInformation.MaximumWorkingSetSize = 4 * 1024 * 1024;
//! info.0.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_WORKINGSET;
//!
//! job.set_extended_limit_info(&mut info)?;
//! job.assign_current_process()?;
//! # info.clear_limits();
//! # job.set_extended_limit_info(&mut info)?;
//! # Ok(())
//! # }
//! ```
mod error;
mod job;
mod limits;
Expand Down
10 changes: 5 additions & 5 deletions src/limits.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::mem;

use windows::Win32::System::{
JobObjects::{
JOBOBJECT_EXTENDED_LIMIT_INFORMATION, JOB_OBJECT_LIMIT_AFFINITY,
Expand All @@ -12,8 +10,10 @@ use windows::Win32::System::{
},
};

pub struct ExtendedLimitInfo(pub JOBOBJECT_EXTENDED_LIMIT_INFORMATION);
#[derive(Debug)]
pub struct ExtendedLimitInfo(pub(crate) JOBOBJECT_EXTENDED_LIMIT_INFORMATION);

#[derive(Debug, Clone, Copy)]
#[repr(u32)]
pub enum PriorityClass {
Normal = NORMAL_PRIORITY_CLASS.0,
Expand All @@ -36,7 +36,7 @@ impl Default for ExtendedLimitInfo {
impl ExtendedLimitInfo {
/// Return an empty extended info objects, without any limits.
pub fn new() -> Self {
let inner: JOBOBJECT_EXTENDED_LIMIT_INFORMATION = unsafe { mem::zeroed() };
let inner = Default::default();
ExtendedLimitInfo(inner)
}

Expand Down Expand Up @@ -126,7 +126,7 @@ mod tests {

let memory_info = get_process_memory_info(get_current_process()).unwrap();

assert!(memory_info.WorkingSetSize <= max * 2);
assert!(memory_info.working_set_size <= max * 2);

info.clear_limits();

Expand Down
19 changes: 15 additions & 4 deletions src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use windows::Win32::System::JobObjects::{
use crate::{Job, JobError};

#[repr(C)]
#[derive(Debug)]
struct ProcessIdList {
header: JOBOBJECT_BASIC_PROCESS_ID_LIST,
list: [usize; 1024],
Expand All @@ -20,13 +21,13 @@ impl Job {
// This can be fixed by calling `QueryInformationJobObject` a second time,
// with a bigger list with the correct size (as returned from the first call).
let mut proc_id_list = ProcessIdList {
header: unsafe { mem::zeroed() },
header: Default::default(),
list: [0usize; 1024],
};

unsafe {
QueryInformationJobObject(
self.handle(),
self.handle,
JobObjectBasicProcessIdList,
&mut proc_id_list as *mut _ as *mut c_void,
mem::size_of_val(&proc_id_list) as u32,
Expand All @@ -35,9 +36,15 @@ impl Job {
}
.map_err(|e| JobError::GetInfoFailed(e.into()))?;

let list = &proc_id_list.list[..proc_id_list.header.NumberOfProcessIdsInList as usize];
let list = proc_id_list
.header
.ProcessIdList
.into_iter()
.chain(proc_id_list.list)
.take(proc_id_list.header.NumberOfProcessIdsInList as usize)
.collect();

Ok(list.to_vec())
Ok(list)
}
}

Expand All @@ -56,7 +63,11 @@ mod tests {

let pids = job.query_process_id_list().unwrap();

let current_process_id = std::process::id() as usize;

// It's not equal to 1 because sometime we "catch" `rusty_fork_test` sub procs.
assert!(pids.len() >= 1);

assert!(pids.contains(&current_process_id));
}
}
53 changes: 38 additions & 15 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,66 @@ use std::{io, mem};
use windows::Win32::{
Foundation::HANDLE,
System::{
ProcessStatus::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS},
ProcessStatus::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS_EX},
Threading::{GetCurrentProcess, GetProcessAffinityMask},
},
};

/// Return a pseudo handle to the current process.
/// See also [Microsoft Docs](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess) for this function.
pub fn get_current_process() -> HANDLE {
unsafe { GetCurrentProcess() }
pub fn get_current_process() -> isize {
unsafe { GetCurrentProcess() }.0
}

#[derive(Debug, Clone)]
pub struct ProcessMemoryCounters {
pub page_fault_count: u32,
pub peak_working_set_size: usize,
pub working_set_size: usize,
pub quota_peak_paged_pool_usage: usize,
pub quota_paged_pool_usage: usize,
pub quota_peak_non_paged_pool_usage: usize,
pub quota_non_paged_pool_usage: usize,
pub pagefile_usage: usize,
pub peak_pagefile_usage: usize,
pub private_usage: usize,
}

/// Retrieves information about the memory usage of the specified process.
/// See also [Microsoft Docs](https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getprocessmemoryinfo) for this function.
pub fn get_process_memory_info(
process_handle: HANDLE,
) -> Result<PROCESS_MEMORY_COUNTERS, io::Error> {
let mut counters: PROCESS_MEMORY_COUNTERS = PROCESS_MEMORY_COUNTERS::default();
pub fn get_process_memory_info(process_handle: isize) -> Result<ProcessMemoryCounters, io::Error> {
let mut counters = PROCESS_MEMORY_COUNTERS_EX::default();
unsafe {
GetProcessMemoryInfo(
process_handle,
&mut counters as *mut _,
mem::size_of::<PROCESS_MEMORY_COUNTERS>() as u32,
HANDLE(process_handle),
&mut counters as *mut _ as *mut _,
mem::size_of_val(&counters) as u32,
)
}
.map_err(|e| e.into())
.map(|_| counters)
}?;

Ok(ProcessMemoryCounters {
page_fault_count: counters.PageFaultCount,
peak_working_set_size: counters.PeakWorkingSetSize,
working_set_size: counters.WorkingSetSize,
quota_peak_paged_pool_usage: counters.QuotaPeakPagedPoolUsage,
quota_paged_pool_usage: counters.QuotaPagedPoolUsage,
quota_peak_non_paged_pool_usage: counters.QuotaPeakNonPagedPoolUsage,
quota_non_paged_pool_usage: counters.QuotaNonPagedPoolUsage,
pagefile_usage: counters.PagefileUsage,
peak_pagefile_usage: counters.PeakPagefileUsage,
private_usage: counters.PrivateUsage,
})
}

/// Retrieves the process affinity mask for the specified process and the system affinity mask for the system.
/// See also [Microsoft Docs](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getprocessaffinitymask) for this function.
pub fn get_process_affinity_mask(process_handle: HANDLE) -> Result<(usize, usize), io::Error> {
pub fn get_process_affinity_mask(process_handle: isize) -> Result<(usize, usize), io::Error> {
let mut process_affinity_mask = 0usize;
let mut system_affinity_mask = 0usize;

unsafe {
GetProcessAffinityMask(
process_handle,
HANDLE(process_handle),
&mut process_affinity_mask as *mut _,
&mut system_affinity_mask as *mut _,
)
Expand Down
Loading