win32_ecoqos/
thread.rs

1use std::ffi::c_void;
2
3use crate::preset::{THREAD_RESTORE, THREAD_THROTTLE, THREAD_UNTHROTTLE};
4use windows::Win32::{
5    Foundation::{CloseHandle, HANDLE},
6    System::Threading::{
7        GetThreadInformation, OpenThread, SetThreadInformation, SetThreadPriority,
8        ThreadPowerThrottling, THREAD_INFORMATION_CLASS, THREAD_POWER_THROTTLING_CURRENT_VERSION,
9        THREAD_POWER_THROTTLING_EXECUTION_SPEED, THREAD_POWER_THROTTLING_STATE, THREAD_PRIORITY,
10        THREAD_PRIORITY_IDLE, THREAD_PRIORITY_NORMAL, THREAD_SET_INFORMATION,
11    },
12};
13
14unsafe fn toggle_efficiency_mode_impl(
15    hthread: HANDLE,
16    threadinformation: *const c_void,
17    threadinformationclass: THREAD_INFORMATION_CLASS,
18    threadinformationsize: u32,
19    npriority: THREAD_PRIORITY,
20) -> Result<(), windows_result::Error> {
21    unsafe {
22        SetThreadInformation(
23            hthread,
24            threadinformationclass,
25            threadinformation,
26            threadinformationsize,
27        )?;
28        SetThreadPriority(hthread, npriority)?;
29    }
30
31    Ok(())
32}
33
34/// Toggle efficiency mode of a thread, by a thread_id.
35///
36/// WARN: [`Thread::id()`](https://doc.rust-lang.org/std/thread/struct.Thread.html#method.id)
37/// is entirely unrelated to underlying thread ID.
38///
39/// To receive win32 thread id with ease,
40/// see [retrieve_thread.rs](https://github.com/mokurin000/fitgirl-ecoqos/blob/master/win32-ecoqos/examples/retrieve_thread.rs)
41pub fn toggle_efficiency_mode(
42    thread_id: u32,
43    enable: Option<bool>,
44) -> Result<(), windows_result::Error> {
45    let hthread = unsafe { OpenThread(THREAD_SET_INFORMATION, false, thread_id)? };
46    let result = unsafe { toggle_efficiency_mode_handle(hthread, enable) };
47    let _ = unsafe { CloseHandle(hthread) };
48
49    result
50}
51
52/// Toggle efficiency mode of a thread, by a [`HANDLE`](https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Foundation/struct.HANDLE.html).
53///
54/// [`GetCurrentThread`]: https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/Threading/fn.GetCurrentThread.html
55/// The handle returned by [`GetCurrentThread`] have a `THREAD_ALL_ACCESS`.
56///
57/// You must enable [`THREAD_SET_INFORMATION`](https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/Threading/constant.THREAD_SET_INFORMATION.html)
58/// access flag on the handle to apply EcoQoS throttle.
59///
60/// SAFETY: `hthread` must be a valid process handle. DO NOT pass null ptr, e.g.
61pub unsafe fn toggle_efficiency_mode_handle(
62    hthread: HANDLE,
63    enable: Option<bool>,
64) -> Result<(), windows_result::Error> {
65    let new_state = match enable {
66        Some(true) => THREAD_THROTTLE,
67        Some(false) => THREAD_UNTHROTTLE,
68        None => THREAD_RESTORE,
69    };
70
71    let threadinformationclass = ThreadPowerThrottling;
72    let threadinformation = &new_state as *const _ as *const c_void;
73    let threadinformationsize = size_of::<THREAD_POWER_THROTTLING_STATE>() as u32;
74
75    let npriority = if let Some(true) = enable {
76        THREAD_PRIORITY_IDLE
77    } else {
78        THREAD_PRIORITY_NORMAL
79    };
80
81    unsafe {
82        toggle_efficiency_mode_impl(
83            hthread,
84            threadinformation,
85            threadinformationclass,
86            threadinformationsize,
87            npriority,
88        )
89    }
90}
91
92/// check whether EcoQoS is enabled on a thread.
93///
94/// `hprocess` must have `THREAD_QUERY_INFORMATION` access right.
95///
96/// SAFETY: `hthread` must be a valid process handle. DO NOT pass null ptr, e.g.
97pub unsafe fn ecoqos_enabled(hthread: HANDLE) -> Result<bool, windows_result::Error> {
98    let mut thread_info = THREAD_POWER_THROTTLING_STATE {
99        Version: THREAD_POWER_THROTTLING_CURRENT_VERSION,
100        ..Default::default()
101    };
102
103    unsafe {
104        GetThreadInformation(
105            hthread,
106            ThreadPowerThrottling,
107            &mut thread_info as *mut _ as *mut _,
108            size_of::<THREAD_POWER_THROTTLING_STATE>() as u32,
109        )?;
110    }
111
112    Ok(
113        thread_info.StateMask & THREAD_POWER_THROTTLING_EXECUTION_SPEED
114            == THREAD_POWER_THROTTLING_EXECUTION_SPEED,
115    )
116}