@@ -106,7 +106,67 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
106106 Name.clear ();
107107}
108108
109+ namespace llvm ::sys::windows {
110+ HMODULE loadSystemModuleSecure (LPCWSTR lpModuleName) {
111+ // Ensure we load indeed a module from system32 path.
112+ // As per GetModuleHandle documentation:
113+ // "If lpModuleName does not include a path and there is more than one loaded
114+ // module with the same base name and extension, you cannot predict which
115+ // module handle will be returned.". This mitigates
116+ // https://learn.microsoft.com/en-us/security-updates/securityadvisories/2010/2269637
117+ SmallVector<wchar_t , MAX_PATH> Buf;
118+ size_t Size = MAX_PATH;
119+ do {
120+ Buf.resize_for_overwrite (Size);
121+ SetLastError (NO_ERROR);
122+ Size = ::GetSystemDirectoryW (Buf.data (), Buf.size ());
123+ if (Size == 0 )
124+ return NULL ;
125+
126+ // Try again with larger buffer.
127+ } while (Size > Buf.size ());
128+
129+ Buf.truncate (Size);
130+ Buf.push_back (L' \\ ' );
131+ Buf.append (lpModuleName, lpModuleName + std::wcslen (lpModuleName));
132+ Buf.push_back (0 );
133+
134+ return ::GetModuleHandleW (Buf.data ());
135+ }
136+ } // namespace llvm::sys::windows
137+
109138SetThreadPriorityResult llvm::set_thread_priority (ThreadPriority Priority) {
139+ HMODULE kernelM = llvm::sys::windows::loadSystemModuleSecure (L" kernel32.dll" );
140+ if (kernelM) {
141+ // SetThreadInformation is only available on Windows 8 and later. Since we
142+ // still support compilation on Windows 7, we load the function dynamically.
143+ typedef BOOL (WINAPI * SetThreadInformation_t)(
144+ HANDLE hThread, THREAD_INFORMATION_CLASS ThreadInformationClass,
145+ _In_reads_bytes_ (ThreadInformationSize) PVOID ThreadInformation,
146+ ULONG ThreadInformationSize);
147+ static const auto pfnSetThreadInformation =
148+ (SetThreadInformation_t)::GetProcAddress (kernelM,
149+ " SetThreadInformation" );
150+ if (pfnSetThreadInformation) {
151+ auto setThreadInformation = [](ULONG ControlMaskAndStateMask) {
152+ THREAD_POWER_THROTTLING_STATE state{};
153+ state.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION;
154+ state.ControlMask = ControlMaskAndStateMask;
155+ state.StateMask = ControlMaskAndStateMask;
156+ return pfnSetThreadInformation (
157+ ::GetCurrentThread (), ThreadPowerThrottling, &state, sizeof(state));
158+ };
159+
160+ // Use EcoQoS for ThreadPriority::Background available (running on most
161+ // efficent cores at the most efficient cpu frequency):
162+ // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadinformation
163+ // https://learn.microsoft.com/en-us/windows/win32/procthread/quality-of-service
164+ setThreadInformation (Priority == ThreadPriority::Background
165+ ? THREAD_POWER_THROTTLING_EXECUTION_SPEED
166+ : 0 );
167+ }
168+ }
169+
110170 // https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority
111171 // Begin background processing mode. The system lowers the resource scheduling
112172 // priorities of the thread so that it can perform background work without
0 commit comments