Skip to content

Commit

Permalink
Merge pull request #4 from ohadravid/bugfix/semver-and-windows-crate
Browse files Browse the repository at this point in the history
Avoid `windows` crate types in public API
  • Loading branch information
ohadravid authored Jan 26, 2024
2 parents 402433e + 3765887 commit d92b210
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 71 deletions.
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

0 comments on commit d92b210

Please sign in to comment.