[llvm] Windows: use EcoQoS for ThreadPriority::Background (PR #148797)
Alexandre Ganea via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 29 07:57:26 PDT 2025
https://github.com/aganea updated https://github.com/llvm/llvm-project/pull/148797
>From 5c586bf7478b7041dda53bfb921f4bdd514f1cf5 Mon Sep 17 00:00:00 2001
From: Tim Blechmann <tim at klingt.org>
Date: Tue, 15 Jul 2025 15:32:15 +0800
Subject: [PATCH 1/5] Windows: use EcoQoS for ThreadPriority::Background
The SetThreadInformation API allows threads to be scheduled on the most
efficient cores on the most efficient frequency.
Using this API for ThreadPriority::Background should make clangd-based
IDEs a little less CPU hungry.
---
llvm/lib/Support/Windows/Threading.inc | 29 ++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/llvm/lib/Support/Windows/Threading.inc b/llvm/lib/Support/Windows/Threading.inc
index d862dbd7f71c9..571e0960a6888 100644
--- a/llvm/lib/Support/Windows/Threading.inc
+++ b/llvm/lib/Support/Windows/Threading.inc
@@ -107,6 +107,35 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
}
SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) {
+
+ // SetThreadInformation is only available on Windows 8 and later. Since we still
+ // support compilation on Windows 7, we load the function dynamically.
+ typedef BOOL(WINAPI * SetThreadInformation_t)(
+ HANDLE hThread, THREAD_INFORMATION_CLASS ThreadInformationClass,
+ _In_reads_bytes_(ThreadInformationSize) PVOID ThreadInformation,
+ ULONG ThreadInformationSize);
+ static const auto pfnSetThreadInformation =
+ (SetThreadInformation_t)GetProcAddress(
+ GetModuleHandle(TEXT("kernel32.dll")), "SetThreadInformation");
+
+ if (pfnSetThreadInformation) {
+ auto setThreadInformation = [](ULONG ControlMaskAndStateMask) {
+ THREAD_POWER_THROTTLING_STATE state{};
+ state.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION;
+ state.ControlMask = ControlMaskAndStateMask;
+ state.StateMask = ControlMaskAndStateMask;
+ return pfnSetThreadInformation(GetCurrentThread(), ThreadPowerThrottling,
+ &state, sizeof(state));
+ };
+
+ // Use EcoQoS for ThreadPriority::Background available (running on most
+ // efficent cores at the most efficient cpu frequency):
+ // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadinformation
+ // https://learn.microsoft.com/en-us/windows/win32/procthread/quality-of-service
+ setThreadInformation(Priority == ThreadPriority::Background ? THREAD_POWER_THROTTLING_EXECUTION_SPEED
+ : 0);
+ }
+
// https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority
// Begin background processing mode. The system lowers the resource scheduling
// priorities of the thread so that it can perform background work without
>From 00e16ce021e2297e1bc3b417ead2e0e0fdc42139 Mon Sep 17 00:00:00 2001
From: Alexandre Ganea <aganea at havenstudios.com>
Date: Wed, 23 Jul 2025 16:36:04 -0400
Subject: [PATCH 2/5] clang-format
---
llvm/lib/Support/Windows/Threading.inc | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Support/Windows/Threading.inc b/llvm/lib/Support/Windows/Threading.inc
index 571e0960a6888..49a7974d312af 100644
--- a/llvm/lib/Support/Windows/Threading.inc
+++ b/llvm/lib/Support/Windows/Threading.inc
@@ -107,9 +107,8 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
}
SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) {
-
- // SetThreadInformation is only available on Windows 8 and later. Since we still
- // support compilation on Windows 7, we load the function dynamically.
+ // SetThreadInformation is only available on Windows 8 and later. Since we
+ // still support compilation on Windows 7, we load the function dynamically.
typedef BOOL(WINAPI * SetThreadInformation_t)(
HANDLE hThread, THREAD_INFORMATION_CLASS ThreadInformationClass,
_In_reads_bytes_(ThreadInformationSize) PVOID ThreadInformation,
@@ -132,8 +131,9 @@ SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) {
// efficent cores at the most efficient cpu frequency):
// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadinformation
// https://learn.microsoft.com/en-us/windows/win32/procthread/quality-of-service
- setThreadInformation(Priority == ThreadPriority::Background ? THREAD_POWER_THROTTLING_EXECUTION_SPEED
- : 0);
+ setThreadInformation(Priority == ThreadPriority::Background
+ ? THREAD_POWER_THROTTLING_EXECUTION_SPEED
+ : 0);
}
// https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority
>From 8130f416a1135ff905c9f210197cd6c844f676c0 Mon Sep 17 00:00:00 2001
From: Alexandre Ganea <aganea at havenstudios.com>
Date: Wed, 23 Jul 2025 17:37:31 -0400
Subject: [PATCH 3/5] Ensure we load the system kernel32.dll and not another
injected lib bearing the same name
---
llvm/lib/Support/Windows/Threading.inc | 84 +++++++++++++++++---------
1 file changed, 57 insertions(+), 27 deletions(-)
diff --git a/llvm/lib/Support/Windows/Threading.inc b/llvm/lib/Support/Windows/Threading.inc
index 49a7974d312af..2d295d1c07ee8 100644
--- a/llvm/lib/Support/Windows/Threading.inc
+++ b/llvm/lib/Support/Windows/Threading.inc
@@ -106,34 +106,64 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
Name.clear();
}
-SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) {
- // SetThreadInformation is only available on Windows 8 and later. Since we
- // still support compilation on Windows 7, we load the function dynamically.
- typedef BOOL(WINAPI * SetThreadInformation_t)(
- HANDLE hThread, THREAD_INFORMATION_CLASS ThreadInformationClass,
- _In_reads_bytes_(ThreadInformationSize) PVOID ThreadInformation,
- ULONG ThreadInformationSize);
- static const auto pfnSetThreadInformation =
- (SetThreadInformation_t)GetProcAddress(
- GetModuleHandle(TEXT("kernel32.dll")), "SetThreadInformation");
-
- if (pfnSetThreadInformation) {
- auto setThreadInformation = [](ULONG ControlMaskAndStateMask) {
- THREAD_POWER_THROTTLING_STATE state{};
- state.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION;
- state.ControlMask = ControlMaskAndStateMask;
- state.StateMask = ControlMaskAndStateMask;
- return pfnSetThreadInformation(GetCurrentThread(), ThreadPowerThrottling,
- &state, sizeof(state));
- };
+static HMODULE LoadSystemModuleSecure(LPCWSTR lpModuleName) {
+ // Ensure we load indeed a module from system32 path.
+ // As per GetModuleHandle documentation:
+ // "If lpModuleName does not include a path and there is more than one loaded
+ // module with the same base name and extension, you cannot predict which
+ // module handle will be returned.". This mitigates
+ // https://learn.microsoft.com/en-us/security-updates/securityadvisories/2010/2269637
+ SmallVector<wchar_t, MAX_PATH> Buf;
+ size_t Size = MAX_PATH;
+ do {
+ Buf.resize_for_overwrite(Size);
+ SetLastError(NO_ERROR);
+ Size = ::GetSystemDirectoryW(Buf.data(), Buf.size());
+ if (Size == 0)
+ return NULL;
+
+ // Try again with larger buffer.
+ } while (Size > Buf.size());
+
+ Buf.truncate(Size);
+ Buf.push_back(TEXT('\\'));
+ Buf.append(lpModuleName, lpModuleName + std::wcslen(lpModuleName));
+ Buf.push_back(0);
+
+ return GetModuleHandleW(Buf.data());
+}
- // Use EcoQoS for ThreadPriority::Background available (running on most
- // efficent cores at the most efficient cpu frequency):
- // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadinformation
- // https://learn.microsoft.com/en-us/windows/win32/procthread/quality-of-service
- setThreadInformation(Priority == ThreadPriority::Background
- ? THREAD_POWER_THROTTLING_EXECUTION_SPEED
- : 0);
+SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) {
+ HMODULE kernelMod = LoadSystemModuleSecure(TEXT("kernel32.dll"));
+ if (kernelMod) {
+ // SetThreadInformation is only available on Windows 8 and later. Since we
+ // still support compilation on Windows 7, we load the function dynamically.
+ typedef BOOL(WINAPI * SetThreadInformation_t)(
+ HANDLE hThread, THREAD_INFORMATION_CLASS ThreadInformationClass,
+ _In_reads_bytes_(ThreadInformationSize) PVOID ThreadInformation,
+ ULONG ThreadInformationSize);
+ static const auto pfnSetThreadInformation =
+ (SetThreadInformation_t)GetProcAddress(kernelMod,
+ "SetThreadInformation");
+
+ if (pfnSetThreadInformation) {
+ auto setThreadInformation = [](ULONG ControlMaskAndStateMask) {
+ THREAD_POWER_THROTTLING_STATE state{};
+ state.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION;
+ state.ControlMask = ControlMaskAndStateMask;
+ state.StateMask = ControlMaskAndStateMask;
+ return pfnSetThreadInformation(
+ GetCurrentThread(), ThreadPowerThrottling, &state, sizeof(state));
+ };
+
+ // Use EcoQoS for ThreadPriority::Background available (running on most
+ // efficent cores at the most efficient cpu frequency):
+ // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadinformation
+ // https://learn.microsoft.com/en-us/windows/win32/procthread/quality-of-service
+ setThreadInformation(Priority == ThreadPriority::Background
+ ? THREAD_POWER_THROTTLING_EXECUTION_SPEED
+ : 0);
+ }
}
// https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority
>From 670a81a8220b5d37d5ed083a5d868683b1657fed Mon Sep 17 00:00:00 2001
From: Alexandre Ganea <aganea at havenstudios.com>
Date: Wed, 23 Jul 2025 17:44:25 -0400
Subject: [PATCH 4/5] Use global functions
---
llvm/lib/Support/Windows/Threading.inc | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Support/Windows/Threading.inc b/llvm/lib/Support/Windows/Threading.inc
index 2d295d1c07ee8..5ef79b340caf1 100644
--- a/llvm/lib/Support/Windows/Threading.inc
+++ b/llvm/lib/Support/Windows/Threading.inc
@@ -130,7 +130,7 @@ static HMODULE LoadSystemModuleSecure(LPCWSTR lpModuleName) {
Buf.append(lpModuleName, lpModuleName + std::wcslen(lpModuleName));
Buf.push_back(0);
- return GetModuleHandleW(Buf.data());
+ return ::GetModuleHandleW(Buf.data());
}
SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) {
@@ -143,8 +143,8 @@ SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) {
_In_reads_bytes_(ThreadInformationSize) PVOID ThreadInformation,
ULONG ThreadInformationSize);
static const auto pfnSetThreadInformation =
- (SetThreadInformation_t)GetProcAddress(kernelMod,
- "SetThreadInformation");
+ (SetThreadInformation_t)::GetProcAddress(kernelMod,
+ "SetThreadInformation");
if (pfnSetThreadInformation) {
auto setThreadInformation = [](ULONG ControlMaskAndStateMask) {
@@ -153,7 +153,7 @@ SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) {
state.ControlMask = ControlMaskAndStateMask;
state.StateMask = ControlMaskAndStateMask;
return pfnSetThreadInformation(
- GetCurrentThread(), ThreadPowerThrottling, &state, sizeof(state));
+ ::GetCurrentThread(), ThreadPowerThrottling, &state, sizeof(state));
};
// Use EcoQoS for ThreadPriority::Background available (running on most
>From c37d94c94323a419123fae5521c2c87994117e7e Mon Sep 17 00:00:00 2001
From: Alexandre Ganea <alex_toresh at yahoo.fr>
Date: Sun, 27 Jul 2025 13:59:42 -0400
Subject: [PATCH 5/5] Force wchar_t string; move function to WindowsSupport.h
---
llvm/include/llvm/Support/Windows/WindowsSupport.h | 4 ++++
llvm/lib/Support/Windows/Threading.inc | 13 +++++++------
2 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/llvm/include/llvm/Support/Windows/WindowsSupport.h b/llvm/include/llvm/Support/Windows/WindowsSupport.h
index ffc6fdf5b983c..f35e7b55cb8d3 100644
--- a/llvm/include/llvm/Support/Windows/WindowsSupport.h
+++ b/llvm/include/llvm/Support/Windows/WindowsSupport.h
@@ -245,6 +245,10 @@ LLVM_ABI std::error_code widenPath(const Twine &Path8,
SmallVectorImpl<wchar_t> &Path16,
size_t MaxPathLen = MAX_PATH);
+/// Retrieves the handle to a in-memory system module such as ntdll.dll, while
+/// ensuring we're not retrieving a malicious injected module but a module
+/// loaded from the system path.
+LLVM_ABI HMODULE loadSystemModuleSecure(LPCWSTR lpModuleName);
} // end namespace windows
} // end namespace sys
} // end namespace llvm.
diff --git a/llvm/lib/Support/Windows/Threading.inc b/llvm/lib/Support/Windows/Threading.inc
index 5ef79b340caf1..8dd7c88fad34a 100644
--- a/llvm/lib/Support/Windows/Threading.inc
+++ b/llvm/lib/Support/Windows/Threading.inc
@@ -106,7 +106,8 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
Name.clear();
}
-static HMODULE LoadSystemModuleSecure(LPCWSTR lpModuleName) {
+namespace llvm::sys::windows {
+HMODULE loadSystemModuleSecure(LPCWSTR lpModuleName) {
// Ensure we load indeed a module from system32 path.
// As per GetModuleHandle documentation:
// "If lpModuleName does not include a path and there is more than one loaded
@@ -126,16 +127,17 @@ static HMODULE LoadSystemModuleSecure(LPCWSTR lpModuleName) {
} while (Size > Buf.size());
Buf.truncate(Size);
- Buf.push_back(TEXT('\\'));
+ Buf.push_back(L'\\');
Buf.append(lpModuleName, lpModuleName + std::wcslen(lpModuleName));
Buf.push_back(0);
return ::GetModuleHandleW(Buf.data());
}
+} // namespace llvm::sys::windows
SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) {
- HMODULE kernelMod = LoadSystemModuleSecure(TEXT("kernel32.dll"));
- if (kernelMod) {
+ HMODULE kernelM = llvm::sys::windows::loadSystemModuleSecure(L"kernel32.dll");
+ if (kernelM) {
// SetThreadInformation is only available on Windows 8 and later. Since we
// still support compilation on Windows 7, we load the function dynamically.
typedef BOOL(WINAPI * SetThreadInformation_t)(
@@ -143,9 +145,8 @@ SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) {
_In_reads_bytes_(ThreadInformationSize) PVOID ThreadInformation,
ULONG ThreadInformationSize);
static const auto pfnSetThreadInformation =
- (SetThreadInformation_t)::GetProcAddress(kernelMod,
+ (SetThreadInformation_t)::GetProcAddress(kernelM,
"SetThreadInformation");
-
if (pfnSetThreadInformation) {
auto setThreadInformation = [](ULONG ControlMaskAndStateMask) {
THREAD_POWER_THROTTLING_STATE state{};
More information about the llvm-commits
mailing list