diff --git a/src/libipc/platform/win/api.h b/src/libipc/platform/win/api.h index 455df0d..67162bc 100644 --- a/src/libipc/platform/win/api.h +++ b/src/libipc/platform/win/api.h @@ -15,6 +15,7 @@ #include "libimp/system.h" #include "libimp/codecvt.h" #include "libimp/span.h" +#include "libimp/detect_plat.h" #include "libipc/def.h" @@ -33,10 +34,10 @@ inline tstring to_tstring(std::string const &str) { } /** - * \brief Create a SECURITY_ATTRIBUTES structure singleton + * \brief Creates or opens a SECURITY_ATTRIBUTES structure singleton * \see https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa379560(v=vs.85) */ -inline LPSECURITY_ATTRIBUTES get_sa() { +inline LPSECURITY_ATTRIBUTES get_security_descriptor() { static struct initiator { SECURITY_DESCRIPTOR sd_; @@ -46,7 +47,7 @@ inline LPSECURITY_ATTRIBUTES get_sa() { initiator() { using namespace ::LIBIMP; - LIBIMP_LOG_("get_sa"); + LIBIMP_LOG_("get_security_descriptor"); if (!::InitializeSecurityDescriptor(&sd_, SECURITY_DESCRIPTOR_REVISION)) { log.error("failed: InitializeSecurityDescriptor(SECURITY_DESCRIPTOR_REVISION). " "error = ", sys::error()); @@ -96,7 +97,7 @@ inline result close_handle(HANDLE h) noexcept { * * \return File mapping object HANDLE, NULL on error. */ -inline result mmap_open(std::string const &file, std::size_t size, mode::type type) noexcept { +inline result open_file_mapping(std::string const &file, std::size_t size, mode::type type) noexcept { LIBIMP_LOG_(); if (file.empty()) { log.error("file name is empty."); @@ -121,7 +122,7 @@ inline result mmap_open(std::string const &file, std::size_t size, mode: // Creates or opens a named or unnamed file mapping object for a specified file. auto try_create = [&]() -> result { - HANDLE h = ::CreateFileMapping(INVALID_HANDLE_VALUE, winapi::get_sa(), PAGE_READWRITE | SEC_COMMIT, + HANDLE h = ::CreateFileMapping(INVALID_HANDLE_VALUE, winapi::get_security_descriptor(), PAGE_READWRITE | SEC_COMMIT, /// \remark dwMaximumSizeHigh always 0 here. 0, static_cast(size), t_name.c_str()); if (h == NULL) { @@ -159,7 +160,7 @@ inline result mmap_open(std::string const &file, std::size_t size, mode: * \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 */ -inline result mmap_memof(HANDLE h) { +inline result address_of_file_mapping(HANDLE h) { LIBIMP_LOG_(); if (h == NULL) { log.error("handle is null."); @@ -178,7 +179,7 @@ inline 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 */ -inline result mmap_sizeof(LPCVOID mem) { +inline result region_size_of_address(LPCVOID mem) { LIBIMP_LOG_(); if (mem == NULL) { log.error("memory pointer is null."); @@ -197,7 +198,7 @@ inline 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 */ -inline result mmap_release(HANDLE h, LPCVOID mem) { +inline result close_file_mapping(HANDLE h, LPCVOID mem) { LIBIMP_LOG_(); if (h == NULL) { log.error("handle is null."); @@ -219,6 +220,8 @@ enum class wait_result { timeout }; +LIBIMP_INLINE_CONSTEXPR std::int64_t const infinite_time = -1; + /** * \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 @@ -263,5 +266,79 @@ inline result wait_for_multiple_objects(span handles, return wait_result::timeout; } +/** + * \brief Retrieves the current value of the performance counter, + * which is a high resolution (<1us) time stamp that can be used for time-interval measurements. + * \see https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter + */ +inline result query_performance_counter() noexcept { + LIBIMP_LOG_(); + std::int64_t pc; + BOOL r = ::QueryPerformanceCounter(reinterpret_cast(&pc)); + if (!r) { + auto err = sys::error(); + log.error("failed: QueryPerformanceCounter(). error = ", err); + return err; + } + return pc; +} + +/** + * \brief Creates or opens a named or unnamed mutex object. + * \see https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createmutexa + * \return Mutex object HANDLE, NULL on error. + */ +inline result open_mutex(char const *name, bool initial_owner) noexcept { + LIBIMP_LOG_(); + HANDLE h = ::CreateMutexA(winapi::get_security_descriptor(), initial_owner, name); + if (h == NULL) { + auto err = sys::error(); + log.error("failed: CreateMutexA(", initial_owner, ", ", name, "). error = ", err); + return err; + } + return h; +} + +/** + * \brief Releases ownership of the specified mutex object. + * \see https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-releasemutex +*/ +inline result release_mutex(HANDLE h) noexcept { + LIBIMP_LOG_(); + if (::ReleaseMutex(h)) { + return true; + } + auto err = sys::error(); + log.error("failed: ReleaseMutex. error = ", err); + return err; +} + +/** + * \brief Locks the mutex, blocks if the mutex is not available. + * \see https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject +*/ +inline result wait_mutex(HANDLE h, std::int64_t ms) noexcept { + LIBIMP_LOG_(); + // If the mutex is abandoned, we need to release it and try again. + for (;;) { + auto r = winapi::wait_for_single_object(h, ms); + if (!r) { + return r.error(); + } + if (*r == winapi::wait_result::object_0) { + return true; + } + if (*r == winapi::wait_result::abandoned) { + log.info("failed: WaitForSingleObject(", ms, "). The mutex is abandoned, try again."); + auto rr = release_mutex(h); + if (rr) { + continue; + } + return rr.error(); + } + return false; + } +} + } // namespace winapi LIBIPC_NAMESPACE_END_ diff --git a/src/libipc/platform/win/event_impl.h b/src/libipc/platform/win/event_impl.h index 54038e8..4265f1b 100644 --- a/src/libipc/platform/win/event_impl.h +++ b/src/libipc/platform/win/event_impl.h @@ -42,7 +42,7 @@ bool is_valid(evt_t evt) noexcept { result evt_open(std::string name) noexcept { LIBIMP_LOG_(); auto t_name = winapi::to_tstring(name); - auto h = ::CreateEvent(winapi::get_sa(), + auto h = ::CreateEvent(winapi::get_security_descriptor(), /*bManualReset*/ FALSE, /*bInitialState*/FALSE, /*lpName*/ t_name.c_str()); diff --git a/src/libipc/platform/win/mutex_impl.h b/src/libipc/platform/win/mutex_impl.h index a61cfc4..5fd6df8 100644 --- a/src/libipc/platform/win/mutex_impl.h +++ b/src/libipc/platform/win/mutex_impl.h @@ -6,78 +6,21 @@ #include "libimp/log.h" #include "libimp/system.h" +#include "libpmr/new.h" #include "libipc/mutex.h" #include "api.h" +#include "sync_id.h" LIBIPC_NAMESPACE_BEG_ using namespace ::LIBIMP; +using namespace ::LIBPMR; struct mutex_handle { }; -namespace winapi { - -/** - * \brief Creates or opens a named or unnamed mutex object. - * \see https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createmutexa - * \return Mutex object HANDLE, NULL on error. - */ -result mutex_open_or_create(char const *name, bool initial_owner) noexcept { - LIBIMP_LOG_(); - HANDLE h = ::CreateMutexA(winapi::get_sa(), initial_owner, name); - if (h == NULL) { - auto err = sys::error(); - log.error("failed: CreateMutexA(", initial_owner, ", ", name, "). error = ", err); - return err; - } - return h; -} - -/** - * \brief Releases ownership of the specified mutex object. - * \see https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-releasemutex -*/ -result mutex_release(HANDLE h) noexcept { - LIBIMP_LOG_(); - if (::ReleaseMutex(h)) { - return true; - } - auto err = sys::error(); - log.error("failed: ReleaseMutex. error = ", err); - return err; -} - -/** - * \brief Locks the mutex, blocks if the mutex is not available. - * \see https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject -*/ -result mutex_wait(HANDLE h, std::int64_t ms) noexcept { - LIBIMP_LOG_(); - for (;;) { - auto r = winapi::wait_for_single_object(h, ms); - if (!r) { - return r.error(); - } - if (*r == winapi::wait_result::object_0) { - return true; - } - if (*r == winapi::wait_result::abandoned) { - log.info("failed: WaitForSingleObject(", ms, "). The mutex is abandoned, try again."); - auto rr = mutex_release(h); - if (rr) { - continue; - } - return rr.error(); - } - return false; - } -} - -} // namespace winapi - result mutex_open(span<::LIBIMP::byte> mem) noexcept { return {}; } diff --git a/src/libipc/platform/win/shm_impl.h b/src/libipc/platform/win/shm_impl.h index 1dde5ef..9b56134 100644 --- a/src/libipc/platform/win/shm_impl.h +++ b/src/libipc/platform/win/shm_impl.h @@ -28,20 +28,20 @@ struct shm_handle { result shm_open(std::string name, std::size_t size, mode::type type) noexcept { LIBIMP_LOG_(); - auto h = winapi::mmap_open(name, size, type); + auto h = winapi::open_file_mapping(name, size, type); if (*h == NULL) { - log.error("failed: mmap_open(name = ", name, ", size = ", size, ", type = ", type, ")."); + log.error("failed: OpenFileMapping(name = ", name, ", size = ", size, ", type = ", type, ")."); return h.error(); } - auto mem = winapi::mmap_memof(*h); + auto mem = winapi::address_of_file_mapping(*h); if (*mem == NULL) { - log.error("failed: mmap_memof(", *h, ")."); + log.error("failed: MapViewOfFile(", *h, ")."); winapi::close_handle(*h); return mem.error(); } - auto sz = winapi::mmap_sizeof(*mem); + auto sz = winapi::region_size_of_address(*mem); if (!sz) { - log.error("failed: mmap_sizeof(", *mem, ")."); + log.error("failed: RegionSizeOfMemory(", *mem, ")."); winapi::close_handle(*h); return sz.error(); } @@ -55,7 +55,7 @@ result shm_close(shm_t h) noexcept { return std::make_error_code(std::errc::invalid_argument); } auto shm = static_cast(h); - auto ret = winapi::mmap_release(shm->h_fmap, shm->memp); + auto ret = winapi::close_file_mapping(shm->h_fmap, shm->memp); $delete(shm); return ret; }