diff --git a/include/libipc/event.h b/include/libipc/event.h index 005d984..d10e622 100644 --- a/include/libipc/event.h +++ b/include/libipc/event.h @@ -19,7 +19,7 @@ LIBIPC_NAMESPACE_BEG_ struct evt_handle; using evt_t = evt_handle *; -/// \brief Create a new event object with a name. +/// \brief Creates or opens a named event object. LIBIMP_EXPORT ::LIBIMP::result evt_open(std::string name) noexcept; /// \brief Close the event object. @@ -32,8 +32,10 @@ LIBIMP_EXPORT std::string evt_name(evt_t) noexcept; /// \brief Sets the event object to the signaled state. LIBIMP_EXPORT ::LIBIMP::result evt_set(evt_t) noexcept; -/// \brief Waits until one of the specified event objects is in the signaled state. +/// \brief Waits until the specified object is in the signaled state or the time-out interval elapses. LIBIMP_EXPORT ::LIBIMP::result evt_wait(evt_t, std::int64_t ms) noexcept; + +/// \brief Waits until one or all of the specified objects are in the signaled state or the time-out interval elapses. LIBIMP_EXPORT ::LIBIMP::result evt_wait(::LIBIMP::span, std::int64_t ms) noexcept; /** diff --git a/src/libipc/CMakeLists.txt b/src/libipc/CMakeLists.txt index 5ec2563..8ece8b5 100644 --- a/src/libipc/CMakeLists.txt +++ b/src/libipc/CMakeLists.txt @@ -41,9 +41,11 @@ target_include_directories(${PROJECT_NAME} if(NOT MSVC) target_link_libraries(${PROJECT_NAME} PUBLIC $<$>:pthread> - $<$,$>>:rt>) + $<$,$>>:rt> + "-Wl,--whole-archive" imp pmr "-Wl,--no-whole-archive") +else() + target_link_libraries(${PROJECT_NAME} PUBLIC imp pmr) endif() -target_link_libraries(${PROJECT_NAME} PUBLIC imp) install( TARGETS ${PROJECT_NAME} diff --git a/src/libipc/event.cpp b/src/libipc/event.cpp new file mode 100644 index 0000000..3f14aef --- /dev/null +++ b/src/libipc/event.cpp @@ -0,0 +1,27 @@ + +#include "libimp/log.h" + +#include "libimp/detect_plat.h" + +#include "libimp/detect_plat.h" +#if defined(LIBIMP_OS_WIN) +# include "libipc/platform/win/event_impl.h" +#else +#endif + +LIBIPC_NAMESPACE_BEG_ + +/// \brief C style event access interface implementation. + +std::string evt_name(evt_t evt) noexcept { + LIBIMP_LOG_(); + if (!is_valid(evt)) { + log.error("handle is null."); + return {}; + } + return evt->name; +} + +/// \brief The event object. + +LIBIPC_NAMESPACE_END_ diff --git a/src/libipc/platform/win/event_impl.h b/src/libipc/platform/win/event_impl.h new file mode 100644 index 0000000..ca892f6 --- /dev/null +++ b/src/libipc/platform/win/event_impl.h @@ -0,0 +1,155 @@ +/** + * \file libipc/platform/win/event_impl.h + * \author mutouyun (orz@orzz.org) + */ +#pragma once + +#include +#include +#include +#include + +#include + +#include "libimp/log.h" +#include "libipc/event.h" + +#include "get_sa.h" +#include "to_tchar.h" + +LIBIPC_NAMESPACE_BEG_ +using namespace ::LIBIMP; + +struct evt_handle { + std::string name; + HANDLE h_event; +}; + +namespace { + +bool is_valid(evt_t evt) noexcept { + return (evt != nullptr) && (evt->h_event != NULL); +} + +} // namespace + +/** + * \brief Creates or opens a named event object. + * \see https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createeventa + * \param name The name of the event object. The name is limited to MAX_PATH characters. Name comparison is case sensitive. + * \return A handle to the event object, NULL on error. + */ +result evt_open(std::string name) noexcept { + LIBIMP_LOG_(); + auto t_name = detail::to_tstring(name); + auto h = ::CreateEvent(detail::get_sa(), FALSE, FALSE, t_name.c_str()); + if (h == NULL) { + auto err = sys::error(); + log.error("failed: CreateEvent(FALSE, FALSE, ", name, "). error = ", err); + return {nullptr, err}; + } + return new evt_handle{std::move(name), h}; +} + +/** + * \brief Closes an open object handle. + * \see https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle + */ +result evt_close(evt_t evt) noexcept { + LIBIMP_LOG_(); + LIBIMP_UNUSED auto guard = std::unique_ptr(evt); + if (!is_valid(evt)) { + log.error("handle is null."); + return {}; + } + if (!::CloseHandle(evt->h_event)) { + auto err = sys::error(); + log.error("failed: CloseHandle(", evt->h_event, "). error = ", err); + return err; + } + return no_error; +} + +/** + * \brief Sets the specified event object to the signaled state. + * \see https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-setevent + */ +result evt_set(evt_t evt) noexcept { + LIBIMP_LOG_(); + if (!is_valid(evt)) { + log.error("handle is null."); + return {}; + } + if (!::SetEvent(evt->h_event)) { + auto err = sys::error(); + log.error("failed: SetEvent(", evt->h_event, "). error = ", err); + return err; + } + return no_error; +} + +/** + * \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 + */ +result evt_wait(evt_t evt, std::int64_t ms) noexcept { + LIBIMP_LOG_(); + if (!is_valid(evt)) { + log.error("handle is null."); + return {}; + } + DWORD dwMilliseconds = (ms < 0) ? INFINITE : static_cast(ms); + auto r = ::WaitForSingleObject(evt->h_event, dwMilliseconds); + if (r == WAIT_TIMEOUT) { + return false; + } + if (r == WAIT_ABANDONED_0) { + log.error("failed: WaitForSingleObject(", evt->h_event, ", ", dwMilliseconds, "). error = WAIT_ABANDONED_0"); + return {}; + } + if (r == WAIT_OBJECT_0) { + return true; + } + auto err = sys::error(); + log.error("failed: WaitForSingleObject(", evt->h_event, ", ", dwMilliseconds, "). error = ", err); + return {false, err}; +} + +/** + * \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 + */ +result evt_wait(::LIBIMP::span evts, std::int64_t ms) noexcept { + LIBIMP_LOG_(); + if (evts.empty()) { + log.error("evts handle is empty."); + return {}; + } + // Conversion of the event handle array to the windows handle array. + std::vector handles(evts.size()); + for (std::size_t i = 0; i < evts.size(); ++i) { + if (!is_valid(evts[i])) { + log.error("handle is null."); + return {}; + } + 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; + } + 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())) { + return true; + } + auto err = sys::error(); + log.error("failed: WaitForMultipleObjects(", handles.size(), ", ", dwMilliseconds, "). error = ", err); + return {false, err}; +} + +LIBIPC_NAMESPACE_END_ diff --git a/src/libipc/platform/win/mmap_impl.h b/src/libipc/platform/win/mmap_impl.h index 9a5b78d..962dc2f 100644 --- a/src/libipc/platform/win/mmap_impl.h +++ b/src/libipc/platform/win/mmap_impl.h @@ -53,12 +53,12 @@ result mmap_close(HANDLE h) { * \see https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-openfilemappinga * https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createfilemappinga * - * \param file Specifies the name of the file mapping object + * \param file Specifies the name of the file mapping object. * \param size Specifies the size required to create a file mapping object. - * This size is ignored when opening an existing file mapping object - * \param type Combinable open modes, create | open + * This size is ignored when opening an existing file mapping object. + * \param type Combinable open modes, create | open. * - * \return File mapping object HANDLE, NULL on error + * \return File mapping object HANDLE, NULL on error. */ result mmap_open(std::string const &file, std::size_t size, mode::type type) noexcept { LIBIMP_LOG_();