diff --git a/include/libipc/mutex.h b/include/libipc/mutex.h new file mode 100644 index 00000000..a6a6c539 --- /dev/null +++ b/include/libipc/mutex.h @@ -0,0 +1,46 @@ +/** + * \file libipc/mutex.h + * \author mutouyun (orz@orzz.org) + * \brief A synchronization primitive that can be used to protect shared data + * from being simultaneously accessed by multiple processes. + */ +#pragma once + +#include +#include +#include + +#include "libimp/export.h" +#include "libimp/result.h" +#include "libimp/span.h" +#include "libimp/byte.h" + +#include "libipc/def.h" + +LIBIPC_NAMESPACE_BEG_ + +struct mutex_handle; +using mutex_t = mutex_handle *; + +/// \brief Create or open a mutex object based on memory. +LIBIMP_EXPORT ::LIBIMP::result mutex_open(::LIBIMP::span<::LIBIMP::byte>) noexcept; + +/// \brief Close the mutex handle. +/// \note The mutex object will be destroyed when the last handle is closed, +/// and the lifetime of a mutex object needs to be shorter than +/// the memory specified when it is created or opened. +LIBIMP_EXPORT ::LIBIMP::result mutex_close(mutex_t) noexcept; + +/// \brief Gets the memory size of the specified mutex. +LIBIMP_EXPORT ::LIBIMP::result mutex_size(mutex_t) noexcept; + +/// \brief Locks the mutex, blocks if the mutex is not available. +LIBIMP_EXPORT ::LIBIMP::result mutex_lock(mutex_t, std::int64_t ms) noexcept; + +/// \brief Tries to lock the mutex, returns if the mutex is not available. +LIBIMP_EXPORT ::LIBIMP::result mutex_try_lock(mutex_t) noexcept; + +/// \brief Unlocks the mutex. +LIBIMP_EXPORT ::LIBIMP::result mutex_unlock(mutex_t) noexcept; + +LIBIPC_NAMESPACE_END_ diff --git a/src/libipc/mutex.cpp b/src/libipc/mutex.cpp new file mode 100644 index 00000000..71ad9f0d --- /dev/null +++ b/src/libipc/mutex.cpp @@ -0,0 +1,18 @@ + +#include "libimp/log.h" + +#include "libimp/detect_plat.h" +#if defined(LIBIMP_OS_WIN) +# include "libipc/platform/win/mutex_impl.h" +#else +#endif + +#if !defined(LIBIMP_OS_LINUX) +LIBIPC_NAMESPACE_BEG_ + +/// \brief C style mutex access interface implementation. + +/// \brief The mutex object. + +LIBIPC_NAMESPACE_END_ +#endif diff --git a/src/libipc/platform/win/mutex_impl.h b/src/libipc/platform/win/mutex_impl.h new file mode 100644 index 00000000..a61cfc4e --- /dev/null +++ b/src/libipc/platform/win/mutex_impl.h @@ -0,0 +1,85 @@ +/** + * \file libipc/platform/win/mutex_impl.h + * \author mutouyun (orz@orzz.org) + */ +#pragma once + +#include "libimp/log.h" +#include "libimp/system.h" +#include "libipc/mutex.h" + +#include "api.h" + +LIBIPC_NAMESPACE_BEG_ + +using namespace ::LIBIMP; + +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 {}; +} + +LIBIPC_NAMESPACE_END_