diff --git a/include/libimp/result.h b/include/libimp/result.h index 6b9d374..d9f2a9a 100644 --- a/include/libimp/result.h +++ b/include/libimp/result.h @@ -92,7 +92,8 @@ struct default_traits { }; template -struct default_traits::value>> : generic_traits { +struct default_traits::value || std::is_enum::value>> + : generic_traits { /// \brief Custom initialization. static constexpr void init_code(typename generic_traits::storage_t &code, T value, bool ok) noexcept { @@ -192,7 +193,7 @@ std::string default_traits::format(result const &r) { } template -std::string default_traits::value>> +std::string default_traits::value || std::is_enum::value>> ::format(result const &r) noexcept { return fmt(*r); } diff --git a/src/libipc/platform/win/api.h b/src/libipc/platform/win/api.h index 45f94e3..455df0d 100644 --- a/src/libipc/platform/win/api.h +++ b/src/libipc/platform/win/api.h @@ -14,10 +14,12 @@ #include "libimp/log.h" #include "libimp/system.h" #include "libimp/codecvt.h" +#include "libimp/span.h" #include "libipc/def.h" LIBIPC_NAMESPACE_BEG_ + using namespace ::LIBIMP; namespace winapi { @@ -94,7 +96,7 @@ inline result close_handle(HANDLE h) noexcept { * * \return File mapping object HANDLE, NULL on error. */ -result mmap_open(std::string const &file, std::size_t size, mode::type type) noexcept { +inline result mmap_open(std::string const &file, std::size_t size, mode::type type) noexcept { LIBIMP_LOG_(); if (file.empty()) { log.error("file name is empty."); @@ -157,7 +159,7 @@ result mmap_open(std::string const &file, std::size_t size, mode::type t * \brief Maps a view of a file mapping into the address space of a calling process. * \see https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-mapviewoffile */ -result mmap_memof(HANDLE h) { +inline result mmap_memof(HANDLE h) { LIBIMP_LOG_(); if (h == NULL) { log.error("handle is null."); @@ -176,7 +178,7 @@ result mmap_memof(HANDLE h) { * \brief Retrieves the size about a range of pages in the virtual address space of the calling process. * \see https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualquery */ -result mmap_sizeof(LPCVOID mem) { +inline result mmap_sizeof(LPCVOID mem) { LIBIMP_LOG_(); if (mem == NULL) { log.error("memory pointer is null."); @@ -195,7 +197,7 @@ result mmap_sizeof(LPCVOID mem) { * \brief Unmaps a mapped view of a file from the calling process's address space. * \see https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-unmapviewoffile */ -result mmap_release(HANDLE h, LPCVOID mem) { +inline result mmap_release(HANDLE h, LPCVOID mem) { LIBIMP_LOG_(); if (h == NULL) { log.error("handle is null."); @@ -211,5 +213,55 @@ result mmap_release(HANDLE h, LPCVOID mem) { return winapi::close_handle(h); } +enum class wait_result { + object_0, + abandoned, + timeout +}; + +/** + * \brief Waits until the specified object is in the signaled state or the time-out interval elapses. + * \see https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject + */ +inline result wait_for_single_object(HANDLE h, std::int64_t ms) noexcept { + LIBIMP_LOG_(); + DWORD dwMilliseconds = (ms < 0) ? INFINITE : static_cast(ms); + DWORD r = ::WaitForSingleObject(h, dwMilliseconds); + if (r == WAIT_FAILED) { + auto err = sys::error(); + log.error("failed: WaitForSingleObject(", h, ", ", dwMilliseconds, "). error = ", err); + return err; + } + if (r == WAIT_OBJECT_0) { + return wait_result::object_0; + } + if (r == WAIT_ABANDONED) { + return wait_result::abandoned; + } + return wait_result::timeout; +} + +/** + * \brief Waits until one or all of the specified objects are in the signaled state or the time-out interval elapses. + * \see https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitformultipleobjects + */ +inline result wait_for_multiple_objects(span handles, std::int64_t ms) noexcept { + LIBIMP_LOG_(); + DWORD dwMilliseconds = (ms < 0) ? INFINITE : static_cast(ms); + DWORD r = ::WaitForMultipleObjects(static_cast(handles.size()), handles.data(), FALSE, dwMilliseconds); + if (r == WAIT_FAILED) { + auto err = sys::error(); + log.error("failed: WaitForMultipleObjects(", handles.size(), ", ", dwMilliseconds, "). error = ", err); + return err; + } + if ((r >= WAIT_OBJECT_0) && (r < WAIT_OBJECT_0 + handles.size())) { + return wait_result::object_0; + } + if ((r >= WAIT_ABANDONED_0) && (r < WAIT_ABANDONED_0 + handles.size())) { + return wait_result::abandoned; + } + return wait_result::timeout; +} + } // namespace winapi LIBIPC_NAMESPACE_END_ diff --git a/src/libipc/platform/win/event_impl.h b/src/libipc/platform/win/event_impl.h index ada9d56..54038e8 100644 --- a/src/libipc/platform/win/event_impl.h +++ b/src/libipc/platform/win/event_impl.h @@ -95,21 +95,18 @@ result evt_wait(evt_t evt, std::int64_t ms) noexcept { log.error("handle is null."); return std::make_error_code(std::errc::invalid_argument); } - DWORD dwMilliseconds = (ms < 0) ? INFINITE : static_cast(ms); - auto r = ::WaitForSingleObject(evt->h_event, dwMilliseconds); - if (r == WAIT_TIMEOUT) { - return false; + auto r = winapi::wait_for_single_object(evt->h_event, ms); + if (!r) { + return r.error(); } - if (r == WAIT_ABANDONED_0) { - log.error("failed: WaitForSingleObject(", evt->h_event, ", ", dwMilliseconds, "). error = WAIT_ABANDONED_0"); - return {}; - } - if (r == WAIT_OBJECT_0) { + if (*r == winapi::wait_result::object_0) { return true; } - auto err = sys::error(); - log.error("failed: WaitForSingleObject(", evt->h_event, ", ", dwMilliseconds, "). error = ", err); - return err; + if (*r == winapi::wait_result::abandoned) { + log.error("failed: WaitForSingleObject(", evt->h_event, ", ", ms, "). error = WAIT_ABANDONED"); + return false; + } + return false; } /** @@ -132,21 +129,18 @@ result evt_wait(::LIBIMP::span evts, std::int64_t ms) noexcep handles[i] = evts[i]->h_event; } // Wait for the events. - DWORD dwMilliseconds = (ms < 0) ? INFINITE : static_cast(ms); - auto r = ::WaitForMultipleObjects(static_cast(handles.size()), handles.data(), FALSE, dwMilliseconds); - if (r == WAIT_TIMEOUT) { - return false; + auto r = winapi::wait_for_multiple_objects(handles, ms); + if (!r) { + return r.error(); } - if ((r >= WAIT_ABANDONED_0) && (r < WAIT_ABANDONED_0 + handles.size())) { - log.error("failed: WaitForMultipleObjects(", handles.size(), ", ", dwMilliseconds, "). error = WAIT_ABANDONED_0 + ", r - WAIT_ABANDONED_0); - return {}; - } - if ((r >= WAIT_OBJECT_0) && (r < WAIT_OBJECT_0 + handles.size())) { + if (*r == winapi::wait_result::object_0) { return true; } - auto err = sys::error(); - log.error("failed: WaitForMultipleObjects(", handles.size(), ", ", dwMilliseconds, "). error = ", err); - return err; + if (*r == winapi::wait_result::abandoned) { + log.error("failed: WaitForMultipleObjects(", handles.size(), ", ", ms, "). error = WAIT_ABANDONED"); + return false; + } + return false; } LIBIPC_NAMESPACE_END_