Skip to content

Commit

Permalink
Refactor mutex implementation for Windows platform
Browse files Browse the repository at this point in the history
  • Loading branch information
mutouyun committed Sep 22, 2024
1 parent f38d77b commit 65cb048
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 0 deletions.
46 changes: 46 additions & 0 deletions include/libipc/mutex.h
Original file line number Diff line number Diff line change
@@ -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 <string>
#include <cstddef>
#include <cstdint>

#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_t> 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<void> mutex_close(mutex_t) noexcept;

/// \brief Gets the memory size of the specified mutex.
LIBIMP_EXPORT ::LIBIMP::result<std::size_t> mutex_size(mutex_t) noexcept;

/// \brief Locks the mutex, blocks if the mutex is not available.
LIBIMP_EXPORT ::LIBIMP::result<bool> 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<bool> mutex_try_lock(mutex_t) noexcept;

/// \brief Unlocks the mutex.
LIBIMP_EXPORT ::LIBIMP::result<bool> mutex_unlock(mutex_t) noexcept;

LIBIPC_NAMESPACE_END_
18 changes: 18 additions & 0 deletions src/libipc/mutex.cpp
Original file line number Diff line number Diff line change
@@ -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
85 changes: 85 additions & 0 deletions src/libipc/platform/win/mutex_impl.h
Original file line number Diff line number Diff line change
@@ -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<HANDLE> 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<bool> 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<bool> 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_t> mutex_open(span<::LIBIMP::byte> mem) noexcept {
return {};
}

LIBIPC_NAMESPACE_END_

0 comments on commit 65cb048

Please sign in to comment.