14apply_priority(HANDLE handle, native_thread_priority priority) -> expected<void, std::error_code>
17 return unexpected(std::make_error_code(std::errc::no_such_process));
18 if (SetThreadPriority(handle, map_priority_to_win32(priority.value())) != 0)
20 return unexpected(std::error_code(
static_cast<int>(GetLastError()), std::system_category()));
27 return unexpected(std::make_error_code(std::errc::no_such_process));
28 if (SetThreadPriority(handle, priority) != 0)
36 if (nice_value < -20 || nice_value > 19)
37 return unexpected(std::make_error_code(std::errc::invalid_argument));
38 return apply_priority(handle, native_thread_priority{ nice_value });
43 -> expected<void, std::error_code>
46 return unexpected(std::make_error_code(std::errc::no_such_process));
47 auto params_result = scheduler_parameters::create_for_policy(policy, priority);
48 if (!params_result.has_value())
49 return unexpected(params_result.error());
50 if (SetThreadPriority(handle, params_result.value().sched_priority) != 0)
52 return unexpected(std::error_code(
static_cast<int>(GetLastError()), std::system_category()));
56apply_affinity(HANDLE handle, native_thread_affinity
const& affinity) -> expected<void, std::error_code>
59 return unexpected(std::make_error_code(std::errc::no_such_process));
60 if (!affinity.has_any())
61 return unexpected(std::make_error_code(std::errc::invalid_argument));
62 using set_thread_group_affinity_fn = BOOL(WINAPI*)(HANDLE,
const GROUP_AFFINITY*, PGROUP_AFFINITY);
63 HMODULE
module = GetModuleHandleW(L"kernel32.dll");
66 auto set_group_affinity =
reinterpret_cast<set_thread_group_affinity_fn
>(
67 reinterpret_cast<void*
>(GetProcAddress(module,
"SetThreadGroupAffinity")));
68 if (set_group_affinity)
71 ga.Mask =
static_cast<KAFFINITY
>(affinity.get_mask());
72 ga.Group = affinity.get_group();
73 if (set_group_affinity(handle, &ga,
nullptr) != 0)
78 if (affinity.get_group() != 0)
79 return unexpected(std::make_error_code(std::errc::function_not_supported));
80 DWORD_PTR mask =
static_cast<DWORD_PTR
>(affinity.get_mask());
81 if (SetThreadAffinityMask(handle, mask) != 0)
93 name() const noexcept ->
char const*
override
99 message(
int value)
const -> std::string
override
101 std::ostringstream stream;
102 stream <<
"HRESULT 0x" << std::hex << static_cast<std::uint32_t>(value);
117 if (HRESULT_FACILITY(result) == FACILITY_WIN32)
118 return {
static_cast<int>(HRESULT_CODE(result)), std::system_category() };
125 return {
static_cast<int>(GetLastError()), std::system_category() };
144 DWORD last_error = ERROR_SUCCESS;
145 constexpr wchar_t const* modules[] = { L
"kernel32.dll", L
"kernelbase.dll" };
146 for (
auto const* module_name : modules)
148 SetLastError(ERROR_SUCCESS);
149 HMODULE
const module = module_lookup(module_name);
152 DWORD
const error = GetLastError();
153 if (error != ERROR_SUCCESS)
157 result.found_module =
true;
160 reinterpret_cast<void*
>(proc_lookup(module,
"SetThreadDescription")));
163 reinterpret_cast<void*
>(proc_lookup(module,
"GetThreadDescription")));
165 if (!result.found_module)
167 = {
static_cast<int>(last_error == ERROR_SUCCESS ? ERROR_MOD_NOT_FOUND : last_error), std::system_category() };
174 static std::atomic<set_thread_description_fn> cached{
nullptr };
175 if (
auto const function = cached.load(std::memory_order_acquire))
180 std::error_code
const error
181 = resolved.found_module ? std::make_error_code(std::errc::function_not_supported) : resolved.lookup_error;
182 return unexpected(error);
185 cached.compare_exchange_strong(expected_null, resolved.set, std::memory_order_release, std::memory_order_acquire);
186 return expected_null ? expected_null : resolved.set;
192 static std::atomic<get_thread_description_fn> cached{
nullptr };
193 if (
auto const function = cached.load(std::memory_order_acquire))
198 std::error_code
const error
199 = resolved.found_module ? std::make_error_code(std::errc::function_not_supported) : resolved.lookup_error;
200 return unexpected(error);
203 cached.compare_exchange_strong(expected_null, resolved.get, std::memory_order_release, std::memory_order_acquire);
204 return expected_null ? expected_null : resolved.get;
208utf8_to_utf16(std::string
const& value) -> expected<std::wstring, std::error_code>
211 return std::wstring{};
213 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, value.data(),
static_cast<int>(value.size()),
nullptr, 0);
216 std::wstring result(
static_cast<std::size_t
>(size), L
'\0');
217 int const written = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, value.data(),
static_cast<int>(value.size()),
218 result.data(), size);
221 result.resize(
static_cast<std::size_t
>(written));
238 int const size = WideCharToMultiByte(CP_UTF8, 0, value, -1,
nullptr, 0,
nullptr,
nullptr);
241 std::string result(
static_cast<std::size_t
>(size),
'\0');
242 int const written = WideCharToMultiByte(CP_UTF8, 0, value, -1, result.data(), size,
nullptr,
nullptr);
245 result.resize(
static_cast<std::size_t
>(written - 1));
250apply_name(HANDLE handle, std::string
const& name) -> expected<void, std::error_code>
253 return unexpected(std::make_error_code(std::errc::no_such_process));
255 if (!wide.has_value())
256 return unexpected(wide.error());
258 if (!set_description.has_value())
259 return unexpected(set_description.error());
260 HRESULT
const result = set_description.value()(handle, wide.value().c_str());
261 if (SUCCEEDED(result))
267read_name(HANDLE handle) -> expected<std::string, std::error_code>
270 return unexpected(std::make_error_code(std::errc::no_such_process));
272 if (!get_description.has_value())
273 return unexpected(get_description.error());
274 PWSTR raw_name =
nullptr;
275 HRESULT
const result = get_description.value()(handle, &raw_name);
276 std::unique_ptr<wchar_t, local_free_deleter> name(raw_name);
280 return unexpected(std::make_error_code(std::errc::io_error));
285read_affinity(HANDLE handle) -> expected<native_thread_affinity, std::error_code>
288 return unexpected(std::make_error_code(std::errc::no_such_process));
289 using get_thread_group_affinity_fn = BOOL(WINAPI*)(HANDLE, PGROUP_AFFINITY);
290 HMODULE
module = GetModuleHandleW(L"kernel32.dll");
293 auto get_group_affinity =
reinterpret_cast<get_thread_group_affinity_fn
>(
294 reinterpret_cast<void*
>(GetProcAddress(module,
"GetThreadGroupAffinity")));
295 if (!get_group_affinity)
296 return unexpected(std::make_error_code(std::errc::function_not_supported));
298 if (get_group_affinity(handle, &ga) == 0)
301 native_thread_affinity affinity;
302 for (
int i = 0; i < 64; ++i)
304 if ((ga.Mask & (
static_cast<KAFFINITY
>(1) << i)) != 0)
305 affinity.add_cpu(
static_cast<int>(ga.Group) * 64 + i);
315 int const priority = GetThreadPriority(handle);
316 if (priority == THREAD_PRIORITY_ERROR_RETURN)
325 return unexpected(std::make_error_code(std::errc::no_such_process));
326 int const priority = GetThreadPriority(handle);
327 if (priority == THREAD_PRIORITY_ERROR_RETURN)
329 if (priority >= THREAD_PRIORITY_HIGHEST)
331 if (priority == THREAD_PRIORITY_ABOVE_NORMAL)
333 if (priority == THREAD_PRIORITY_NORMAL)
335 if (priority == THREAD_PRIORITY_BELOW_NORMAL)
337 if (priority == THREAD_PRIORITY_LOWEST)
347 return native_scheduling_policy::other;
351apply_priority(native_thread_id tid, native_thread_priority priority) -> expected<void, std::error_code>
353 unique_handle handle(OpenThread(THREAD_SET_INFORMATION, FALSE, tid));
363 unique_handle handle(OpenThread(THREAD_SET_INFORMATION, FALSE, tid));
372 unique_handle handle(OpenThread(THREAD_SET_INFORMATION, FALSE, tid));
380 -> expected<void, std::error_code>
382 unique_handle handle(OpenThread(THREAD_SET_INFORMATION, FALSE, tid));
390apply_affinity(native_thread_id tid, native_thread_affinity
const& affinity) -> expected<void, std::error_code>
392 unique_handle handle(OpenThread(THREAD_SET_INFORMATION, FALSE, tid));
400apply_name(native_thread_id tid, std::string
const& name) -> expected<void, std::error_code>
402 unique_handle handle(OpenThread(THREAD_SET_LIMITED_INFORMATION, FALSE, tid));
404 return unexpected(std::make_error_code(std::errc::no_such_process));
410read_name(native_thread_id tid) -> expected<std::string, std::error_code>
412 unique_handle handle(OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, tid));
420read_affinity(native_thread_id tid) -> expected<native_thread_affinity, std::error_code>
422 unique_handle handle(OpenThread(THREAD_QUERY_INFORMATION, FALSE, tid));
432 unique_handle handle(OpenThread(THREAD_QUERY_INFORMATION, FALSE, tid));
442 unique_handle handle(OpenThread(THREAD_QUERY_INFORMATION, FALSE, tid));
451 unique_handle handle(OpenThread(THREAD_QUERY_INFORMATION, FALSE, tid));
458#if defined(__MINGW32__)
463win32_handle_from_pthread(pthread_t thread) -> expected<HANDLE, std::error_code>
465 HANDLE
const handle = pthread_gethandle(thread);
473 -> expected<void, std::error_code>
475 auto const handle = win32_handle_from_pthread(thread);
476 if (!handle.has_value())
477 return unexpected(handle.error());
482apply_priority(pthread_t thread, native_thread_priority priority) -> expected<void, std::error_code>
484 auto const handle = win32_handle_from_pthread(thread);
485 if (!handle.has_value())
486 return unexpected(handle.error());
493 auto const handle = win32_handle_from_pthread(thread);
494 if (!handle.has_value())
495 return unexpected(handle.error());
500apply_nice_value(pthread_t thread,
int nice_value) -> expected<void, std::error_code>
502 auto const handle = win32_handle_from_pthread(thread);
503 if (!handle.has_value())
504 return unexpected(handle.error());
509apply_affinity(pthread_t thread, native_thread_affinity
const& affinity) -> expected<void, std::error_code>
511 auto const handle = win32_handle_from_pthread(thread);
512 if (!handle.has_value())
513 return unexpected(handle.error());
518apply_name(pthread_t thread, std::string
const& name) -> expected<void, std::error_code>
522 if (!wide.has_value())
523 return unexpected(wide.error());
524 int const result = pthread_setname_np(thread, name.c_str());
527 return unexpected(std::error_code(result, std::generic_category()));
531read_name(pthread_t thread) -> expected<std::string, std::error_code>
533 std::array<char, 256> name{};
534 int const result = pthread_getname_np(thread, name.data(), name.size());
536 return unexpected(std::error_code(result, std::generic_category()));
537 return std::string(name.data());
541read_affinity(pthread_t thread) -> expected<native_thread_affinity, std::error_code>
543 auto const handle = win32_handle_from_pthread(thread);
544 if (!handle.has_value())
545 return unexpected(handle.error());
552 auto const handle = win32_handle_from_pthread(thread);
559 auto const handle = win32_handle_from_pthread(thread);
560 if (!handle.has_value())
561 return unexpected(handle.error());
568 auto const handle = win32_handle_from_pthread(thread);
auto name() const noexcept -> char const *override
auto message(int value) const -> std::string override
expected< T, std::error_code > result
Standard result type used by public APIs.
void operator()(wchar_t *value) const noexcept
set_thread_description_fn set
std::error_code lookup_error
get_thread_description_fn get
HRESULT(WINAPI *)(HANDLE, PCWSTR) set_thread_description_fn
auto read_affinity(HANDLE handle) -> expected< native_thread_affinity, std::error_code >
auto resolve_thread_description_api(module_lookup_fn module_lookup=GetModuleHandleW, proc_lookup_fn proc_lookup=GetProcAddress) -> thread_description_api
auto hresult_category() -> std::error_category const &
auto error_from_hresult(HRESULT result) -> std::error_code
auto apply_nice_value(HANDLE handle, int nice_value) -> expected< void, std::error_code >
HRESULT(WINAPI *)(HANDLE, PWSTR *) get_thread_description_fn
auto read_nice_value(HANDLE handle) -> expected< int, std::error_code >
auto resolved_set_thread_description() -> expected< set_thread_description_fn, std::error_code >
auto apply_affinity(HANDLE handle, native_thread_affinity const &affinity) -> expected< void, std::error_code >
auto apply_windows_thread_priority(HANDLE handle, int priority) -> expected< void, std::error_code >
auto utf8_to_utf16(std::string const &value) -> expected< std::wstring, std::error_code >
auto resolved_get_thread_description() -> expected< get_thread_description_fn, std::error_code >
auto read_priority(HANDLE handle) -> std::optional< int >
auto last_win32_error() -> std::error_code
HMODULE(WINAPI *)(LPCWSTR) module_lookup_fn
auto read_name(HANDLE handle) -> expected< std::string, std::error_code >
FARPROC(WINAPI *)(HMODULE, LPCSTR) proc_lookup_fn
auto apply_priority(HANDLE handle, native_thread_priority priority) -> expected< void, std::error_code >
auto utf16_to_utf8(PCWSTR value) -> expected< std::string, std::error_code >
auto read_scheduling_policy(HANDLE handle) -> std::optional< native_scheduling_policy >
auto apply_scheduling_policy(HANDLE handle, native_scheduling_policy policy, native_thread_priority priority) -> expected< void, std::error_code >
auto apply_name(HANDLE handle, std::string const &name) -> expected< void, std::error_code >