mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
add sync::mutex for windows/linux
This commit is contained in:
parent
12944502a1
commit
455c0b479d
1
.gitignore
vendored
1
.gitignore
vendored
@ -44,3 +44,4 @@ CMakeLists.txt.user*
|
|||||||
|
|
||||||
# My output files
|
# My output files
|
||||||
build
|
build
|
||||||
|
.vscode
|
||||||
@ -25,13 +25,16 @@ using uint_t = typename uint<N>::type;
|
|||||||
|
|
||||||
// constants
|
// constants
|
||||||
|
|
||||||
|
enum : std::uint32_t {
|
||||||
|
invalid_value = (std::numeric_limits<std::uint32_t>::max)(),
|
||||||
|
default_timeout = 100, // ms
|
||||||
|
};
|
||||||
|
|
||||||
enum : std::size_t {
|
enum : std::size_t {
|
||||||
invalid_value = (std::numeric_limits<std::size_t>::max)(),
|
|
||||||
data_length = 64,
|
data_length = 64,
|
||||||
large_msg_limit = data_length,
|
large_msg_limit = data_length,
|
||||||
large_msg_align = 512,
|
large_msg_align = 512,
|
||||||
large_msg_cache = 32,
|
large_msg_cache = 32,
|
||||||
default_timeout = 100 // ms
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class relat { // multiplicity of the relationship
|
enum class relat { // multiplicity of the relationship
|
||||||
|
|||||||
@ -27,12 +27,12 @@ struct IPC_EXPORT chan_impl {
|
|||||||
static char const * name(ipc::handle_t h);
|
static char const * name(ipc::handle_t h);
|
||||||
|
|
||||||
static std::size_t recv_count(ipc::handle_t h);
|
static std::size_t recv_count(ipc::handle_t h);
|
||||||
static bool wait_for_recv(ipc::handle_t h, std::size_t r_count, std::size_t tm);
|
static bool wait_for_recv(ipc::handle_t h, std::size_t r_count, std::uint64_t tm);
|
||||||
|
|
||||||
static bool send(ipc::handle_t h, void const * data, std::size_t size, std::size_t tm);
|
static bool send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm);
|
||||||
static buff_t recv(ipc::handle_t h, std::size_t tm);
|
static buff_t recv(ipc::handle_t h, std::uint64_t tm);
|
||||||
|
|
||||||
static bool try_send(ipc::handle_t h, void const * data, std::size_t size, std::size_t tm);
|
static bool try_send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm);
|
||||||
static buff_t try_recv(ipc::handle_t h);
|
static buff_t try_recv(ipc::handle_t h);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -120,41 +120,41 @@ public:
|
|||||||
return detail_t::recv_count(h_);
|
return detail_t::recv_count(h_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wait_for_recv(std::size_t r_count, std::size_t tm = invalid_value) const {
|
bool wait_for_recv(std::size_t r_count, std::uint64_t tm = invalid_value) const {
|
||||||
return detail_t::wait_for_recv(h_, r_count, tm);
|
return detail_t::wait_for_recv(h_, r_count, tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool wait_for_recv(char const * name, std::size_t r_count, std::size_t tm = invalid_value) {
|
static bool wait_for_recv(char const * name, std::size_t r_count, std::uint64_t tm = invalid_value) {
|
||||||
return chan_wrapper(name).wait_for_recv(r_count, tm);
|
return chan_wrapper(name).wait_for_recv(r_count, tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If timeout, this function would call 'force_push' to send the data forcibly.
|
* If timeout, this function would call 'force_push' to send the data forcibly.
|
||||||
*/
|
*/
|
||||||
bool send(void const * data, std::size_t size, std::size_t tm = default_timeout) {
|
bool send(void const * data, std::size_t size, std::uint64_t tm = default_timeout) {
|
||||||
return detail_t::send(h_, data, size, tm);
|
return detail_t::send(h_, data, size, tm);
|
||||||
}
|
}
|
||||||
bool send(buff_t const & buff, std::size_t tm = default_timeout) {
|
bool send(buff_t const & buff, std::uint64_t tm = default_timeout) {
|
||||||
return this->send(buff.data(), buff.size(), tm);
|
return this->send(buff.data(), buff.size(), tm);
|
||||||
}
|
}
|
||||||
bool send(std::string const & str, std::size_t tm = default_timeout) {
|
bool send(std::string const & str, std::uint64_t tm = default_timeout) {
|
||||||
return this->send(str.c_str(), str.size() + 1, tm);
|
return this->send(str.c_str(), str.size() + 1, tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If timeout, this function would just return false.
|
* If timeout, this function would just return false.
|
||||||
*/
|
*/
|
||||||
bool try_send(void const * data, std::size_t size, std::size_t tm = default_timeout) {
|
bool try_send(void const * data, std::size_t size, std::uint64_t tm = default_timeout) {
|
||||||
return detail_t::try_send(h_, data, size, tm);
|
return detail_t::try_send(h_, data, size, tm);
|
||||||
}
|
}
|
||||||
bool try_send(buff_t const & buff, std::size_t tm = default_timeout) {
|
bool try_send(buff_t const & buff, std::uint64_t tm = default_timeout) {
|
||||||
return this->try_send(buff.data(), buff.size(), tm);
|
return this->try_send(buff.data(), buff.size(), tm);
|
||||||
}
|
}
|
||||||
bool try_send(std::string const & str, std::size_t tm = default_timeout) {
|
bool try_send(std::string const & str, std::uint64_t tm = default_timeout) {
|
||||||
return this->try_send(str.c_str(), str.size() + 1, tm);
|
return this->try_send(str.c_str(), str.size() + 1, tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
buff_t recv(std::size_t tm = invalid_value) {
|
buff_t recv(std::uint64_t tm = invalid_value) {
|
||||||
return detail_t::recv(h_, tm);
|
return detail_t::recv(h_, tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
38
include/libipc/mutex.h
Normal file
38
include/libipc/mutex.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint> // std::uint64_t
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
|
#include "libipc/export.h"
|
||||||
|
#include "libipc/def.h"
|
||||||
|
|
||||||
|
namespace ipc {
|
||||||
|
namespace sync {
|
||||||
|
|
||||||
|
class IPC_EXPORT mutex {
|
||||||
|
mutex(mutex const &) = delete;
|
||||||
|
mutex &operator=(mutex const &) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
mutex();
|
||||||
|
explicit mutex(char const *name);
|
||||||
|
~mutex();
|
||||||
|
|
||||||
|
void const *native() const noexcept;
|
||||||
|
void *native() noexcept;
|
||||||
|
|
||||||
|
bool valid() const noexcept;
|
||||||
|
|
||||||
|
bool open(char const *name) noexcept;
|
||||||
|
void close() noexcept;
|
||||||
|
bool lock(std::uint64_t tm = ipc::invalid_value) noexcept;
|
||||||
|
bool try_lock() noexcept(false); // std::system_error
|
||||||
|
bool unlock() noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class mutex_;
|
||||||
|
mutex_* p_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sync
|
||||||
|
} // namespace ipc
|
||||||
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
#include "libipc/export.h"
|
#include "libipc/export.h"
|
||||||
|
|
||||||
@ -20,6 +21,9 @@ IPC_EXPORT void release(id_t id);
|
|||||||
IPC_EXPORT void remove (id_t id);
|
IPC_EXPORT void remove (id_t id);
|
||||||
IPC_EXPORT void remove (char const * name);
|
IPC_EXPORT void remove (char const * name);
|
||||||
|
|
||||||
|
IPC_EXPORT std::uint32_t get_ref(id_t id);
|
||||||
|
IPC_EXPORT void sub_ref(id_t id);
|
||||||
|
|
||||||
class IPC_EXPORT handle {
|
class IPC_EXPORT handle {
|
||||||
public:
|
public:
|
||||||
handle();
|
handle();
|
||||||
@ -31,9 +35,12 @@ public:
|
|||||||
void swap(handle& rhs);
|
void swap(handle& rhs);
|
||||||
handle& operator=(handle rhs);
|
handle& operator=(handle rhs);
|
||||||
|
|
||||||
bool valid() const;
|
bool valid() const noexcept;
|
||||||
std::size_t size () const;
|
std::size_t size () const noexcept;
|
||||||
char const * name () const;
|
char const * name () const noexcept;
|
||||||
|
|
||||||
|
std::uint32_t ref() const noexcept;
|
||||||
|
void sub_ref() noexcept;
|
||||||
|
|
||||||
bool acquire(char const * name, std::size_t size, unsigned mode = create | open);
|
bool acquire(char const * name, std::size_t size, unsigned mode = create | open);
|
||||||
void release();
|
void release();
|
||||||
|
|||||||
@ -54,7 +54,7 @@ public:
|
|||||||
bool open (char const * name, long count = 0);
|
bool open (char const * name, long count = 0);
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
bool wait(std::size_t tm = invalid_value);
|
bool wait(std::uint64_t tm = invalid_value);
|
||||||
bool post(long count = 1);
|
bool post(long count = 1);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -81,7 +81,7 @@ public:
|
|||||||
bool open (char const * name);
|
bool open (char const * name);
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
bool wait(mutex&, std::size_t tm = invalid_value);
|
bool wait(mutex&, std::uint64_t tm = invalid_value);
|
||||||
bool notify();
|
bool notify();
|
||||||
bool broadcast();
|
bool broadcast();
|
||||||
|
|
||||||
|
|||||||
18
src/ipc.cpp
18
src/ipc.cpp
@ -291,7 +291,7 @@ struct conn_info_head {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename W, typename F>
|
template <typename W, typename F>
|
||||||
bool wait_for(W& waiter, F&& pred, std::size_t tm) {
|
bool wait_for(W& waiter, F&& pred, std::uint64_t tm) {
|
||||||
if (tm == 0) return !pred();
|
if (tm == 0) return !pred();
|
||||||
for (unsigned k = 0; pred();) {
|
for (unsigned k = 0; pred();) {
|
||||||
bool loop = true, ret = true;
|
bool loop = true, ret = true;
|
||||||
@ -403,7 +403,7 @@ static std::size_t recv_count(ipc::handle_t h) noexcept {
|
|||||||
return que->conn_count();
|
return que->conn_count();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool wait_for_recv(ipc::handle_t h, std::size_t r_count, std::size_t tm) {
|
static bool wait_for_recv(ipc::handle_t h, std::size_t r_count, std::uint64_t tm) {
|
||||||
auto que = queue_of(h);
|
auto que = queue_of(h);
|
||||||
if (que == nullptr) {
|
if (que == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
@ -475,7 +475,7 @@ static bool send(F&& gen_push, ipc::handle_t h, void const * data, std::size_t s
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool send(ipc::handle_t h, void const * data, std::size_t size, std::size_t tm) {
|
static bool send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
|
||||||
return send([tm](auto info, auto que, auto msg_id) {
|
return send([tm](auto info, auto que, auto msg_id) {
|
||||||
return [tm, info, que, msg_id](std::int32_t remain, void const * data, std::size_t size) {
|
return [tm, info, que, msg_id](std::int32_t remain, void const * data, std::size_t size) {
|
||||||
if (!wait_for(info->wt_waiter_, [&] {
|
if (!wait_for(info->wt_waiter_, [&] {
|
||||||
@ -500,7 +500,7 @@ static bool send(ipc::handle_t h, void const * data, std::size_t size, std::size
|
|||||||
}, h, data, size);
|
}, h, data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool try_send(ipc::handle_t h, void const * data, std::size_t size, std::size_t tm) {
|
static bool try_send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
|
||||||
return send([tm](auto info, auto que, auto msg_id) {
|
return send([tm](auto info, auto que, auto msg_id) {
|
||||||
return [tm, info, que, msg_id](std::int32_t remain, void const * data, std::size_t size) {
|
return [tm, info, que, msg_id](std::int32_t remain, void const * data, std::size_t size) {
|
||||||
if (!wait_for(info->wt_waiter_, [&] {
|
if (!wait_for(info->wt_waiter_, [&] {
|
||||||
@ -514,7 +514,7 @@ static bool try_send(ipc::handle_t h, void const * data, std::size_t size, std::
|
|||||||
}, h, data, size);
|
}, h, data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ipc::buff_t recv(ipc::handle_t h, std::size_t tm) {
|
static ipc::buff_t recv(ipc::handle_t h, std::uint64_t tm) {
|
||||||
auto que = queue_of(h);
|
auto que = queue_of(h);
|
||||||
if (que == nullptr) {
|
if (que == nullptr) {
|
||||||
ipc::error("fail: recv, queue_of(h) == nullptr\n");
|
ipc::error("fail: recv, queue_of(h) == nullptr\n");
|
||||||
@ -630,22 +630,22 @@ std::size_t chan_impl<Flag>::recv_count(ipc::handle_t h) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Flag>
|
template <typename Flag>
|
||||||
bool chan_impl<Flag>::wait_for_recv(ipc::handle_t h, std::size_t r_count, std::size_t tm) {
|
bool chan_impl<Flag>::wait_for_recv(ipc::handle_t h, std::size_t r_count, std::uint64_t tm) {
|
||||||
return detail_impl<policy_t<Flag>>::wait_for_recv(h, r_count, tm);
|
return detail_impl<policy_t<Flag>>::wait_for_recv(h, r_count, tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Flag>
|
template <typename Flag>
|
||||||
bool chan_impl<Flag>::send(ipc::handle_t h, void const * data, std::size_t size, std::size_t tm) {
|
bool chan_impl<Flag>::send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
|
||||||
return detail_impl<policy_t<Flag>>::send(h, data, size, tm);
|
return detail_impl<policy_t<Flag>>::send(h, data, size, tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Flag>
|
template <typename Flag>
|
||||||
buff_t chan_impl<Flag>::recv(ipc::handle_t h, std::size_t tm) {
|
buff_t chan_impl<Flag>::recv(ipc::handle_t h, std::uint64_t tm) {
|
||||||
return detail_impl<policy_t<Flag>>::recv(h, tm);
|
return detail_impl<policy_t<Flag>>::recv(h, tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Flag>
|
template <typename Flag>
|
||||||
bool chan_impl<Flag>::try_send(ipc::handle_t h, void const * data, std::size_t size, std::size_t tm) {
|
bool chan_impl<Flag>::try_send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
|
||||||
return detail_impl<policy_t<Flag>>::try_send(h, data, size, tm);
|
return detail_impl<policy_t<Flag>>::try_send(h, data, size, tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,18 @@
|
|||||||
# error "IPC_CONSTEXPR_ has been defined."
|
# error "IPC_CONSTEXPR_ has been defined."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// detect platform
|
||||||
|
|
||||||
|
#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || \
|
||||||
|
defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || \
|
||||||
|
defined(WINCE) || defined(_WIN32_WCE)
|
||||||
|
# define IPC_OS_WINDOWS_
|
||||||
|
#endif/*WIN*/
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__linux)
|
||||||
|
# define IPC_OS_LINUX_
|
||||||
|
#endif/*linux*/
|
||||||
|
|
||||||
#if __cplusplus >= 201703L
|
#if __cplusplus >= 201703L
|
||||||
|
|
||||||
#define IPC_UNUSED_ [[maybe_unused]]
|
#define IPC_UNUSED_ [[maybe_unused]]
|
||||||
|
|||||||
39
src/libipc/platform/get_wait_time.h
Normal file
39
src/libipc/platform/get_wait_time.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "libipc/utility/log.h"
|
||||||
|
|
||||||
|
namespace ipc {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
inline bool calc_wait_time(timespec &ts, std::uint64_t tm /*ms*/) noexcept {
|
||||||
|
timeval now;
|
||||||
|
int eno = ::gettimeofday(&now, NULL);
|
||||||
|
if (eno != 0) {
|
||||||
|
ipc::error("fail gettimeofday [%d]\n", eno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ts.tv_nsec = (now.tv_usec + (tm % 1000) * 1000) * 1000;
|
||||||
|
ts.tv_sec = now.tv_sec + (tm / 1000) + (ts.tv_nsec / 1000000000l);
|
||||||
|
ts.tv_nsec %= 1000000000l;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline timespec make_timespec(std::uint64_t tm /*ms*/) noexcept(false) {
|
||||||
|
timespec ts {};
|
||||||
|
if (!calc_wait_time(ts, tm)) {
|
||||||
|
ipc::error("fail calc_wait_time: tm = %zd, tv_sec = %ld, tv_nsec = %ld\n",
|
||||||
|
tm, ts.tv_sec, ts.tv_nsec);
|
||||||
|
throw std::system_error{static_cast<int>(errno), std::system_category()};
|
||||||
|
}
|
||||||
|
return ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace ipc
|
||||||
167
src/libipc/platform/mutex_linux.h
Normal file
167
src/libipc/platform/mutex_linux.h
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "libipc/platform/get_wait_time.h"
|
||||||
|
#include "libipc/platform/detail.h"
|
||||||
|
#include "libipc/utility/log.h"
|
||||||
|
#include "libipc/utility/scope_guard.h"
|
||||||
|
#include "libipc/shm.h"
|
||||||
|
|
||||||
|
namespace ipc {
|
||||||
|
namespace detail {
|
||||||
|
namespace sync {
|
||||||
|
|
||||||
|
class mutex {
|
||||||
|
ipc::shm::handle shm_;
|
||||||
|
pthread_mutex_t *mutex_ = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
mutex() noexcept = default;
|
||||||
|
explicit mutex(char const *name) noexcept {
|
||||||
|
open(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
~mutex() noexcept = default;
|
||||||
|
|
||||||
|
pthread_mutex_t const *native() const noexcept {
|
||||||
|
return mutex_;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_t *native() noexcept {
|
||||||
|
return mutex_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool valid() const noexcept {
|
||||||
|
static const tmp[sizeof pthread_mutex_t] {};
|
||||||
|
return shm_.valid()
|
||||||
|
&& (mutex_ != nullptr)
|
||||||
|
&& (std::memcmp(tmp, mutex_, sizeof pthread_mutex_t) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool open(char const *name) noexcept {
|
||||||
|
close();
|
||||||
|
if (!shm_.acquire(name, sizeof pthread_mutex_t)) {
|
||||||
|
ipc::error("fail shm.acquire: %s\n", name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mutex_ = static_cast<pthread_mutex_t *>(shm_.get());
|
||||||
|
assert(mutex_ != nullptr);
|
||||||
|
if ((shm_.ref() == 1) && valid()/*it means mutex has been inited*/) {
|
||||||
|
::pthread_mutex_destroy(mutex_);
|
||||||
|
}
|
||||||
|
auto finally = ipc::guard([this] { close(); }); // close when failed
|
||||||
|
// init mutex
|
||||||
|
int eno;
|
||||||
|
pthread_mutexattr_t mutex_attr;
|
||||||
|
if ((eno = ::pthread_mutexattr_init(&mutex_attr)) != 0) {
|
||||||
|
ipc::error("fail pthread_mutexattr_init[%d]\n", eno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
IPC_UNUSED_ auto guard_mutex_attr = unique_ptr(&mutex_attr, ::pthread_mutexattr_destroy);
|
||||||
|
if ((eno = ::pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED)) != 0) {
|
||||||
|
ipc::error("fail pthread_mutexattr_setpshared[%d]\n", eno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((eno = ::pthread_mutexattr_setrobust(&mutex_attr, PTHREAD_MUTEX_ROBUST)) != 0) {
|
||||||
|
ipc::error("fail pthread_mutexattr_setrobust[%d]\n", eno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*mutex_ = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
if ((eno = ::pthread_mutex_init(mutex_, &mutex_attr)) != 0) {
|
||||||
|
ipc::error("fail pthread_mutex_init[%d]\n", eno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally.dismiss();
|
||||||
|
return valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
void close() noexcept {
|
||||||
|
if (shm_.ref() == 1) {
|
||||||
|
int eno;
|
||||||
|
if ((eno = ::pthread_mutex_destroy(mutex_)) != 0) {
|
||||||
|
ipc::error("fail pthread_mutex_destroy[%d]\n", eno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shm_.release();
|
||||||
|
mutex_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lock(std::uint64_t tm) noexcept {
|
||||||
|
for (;;) {
|
||||||
|
int eno = (tm == invalid_value)
|
||||||
|
? ::pthread_mutex_lock(mutex_)
|
||||||
|
: ::pthread_mutex_timedlock(mutex_, detail::make_timespec(tm));
|
||||||
|
switch (eno) {
|
||||||
|
case 0:
|
||||||
|
return true;
|
||||||
|
case ETIMEDOUT:
|
||||||
|
return false;
|
||||||
|
case EOWNERDEAD:
|
||||||
|
if (shm_.ref() > 1) {
|
||||||
|
shm_.sub_ref();
|
||||||
|
}
|
||||||
|
int eno2 = ::pthread_mutex_consistent(mutex_);
|
||||||
|
if (eno2 != 0) {
|
||||||
|
ipc::error("fail pthread_mutex_lock[%d], pthread_mutex_consistent[%d]\n", eno, eno2);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int eno3 = ::pthread_mutex_unlock(mutex_);
|
||||||
|
if (eno3 != 0) {
|
||||||
|
ipc::error("fail pthread_mutex_lock[%d], pthread_mutex_unlock[%d]\n", eno, eno3);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break; // loop again
|
||||||
|
default:
|
||||||
|
ipc::error("fail pthread_mutex_lock[%d]\n", eno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_lock() noexcept(false) {
|
||||||
|
int eno = ::pthread_mutex_timedlock(mutex_, detail::make_timespec(0));
|
||||||
|
switch (eno) {
|
||||||
|
case 0:
|
||||||
|
return true;
|
||||||
|
case ETIMEDOUT:
|
||||||
|
return false;
|
||||||
|
case EOWNERDEAD:
|
||||||
|
if (shm_.ref() > 1) {
|
||||||
|
shm_.sub_ref();
|
||||||
|
}
|
||||||
|
int eno2 = ::pthread_mutex_consistent(mutex_);
|
||||||
|
if (eno2 != 0) {
|
||||||
|
ipc::error("fail pthread_mutex_timedlock[%d], pthread_mutex_consistent[%d]\n", eno, eno2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int eno3 = ::pthread_mutex_unlock(mutex_);
|
||||||
|
if (eno3 != 0) {
|
||||||
|
ipc::error("fail pthread_mutex_timedlock[%d], pthread_mutex_unlock[%d]\n", eno, eno3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ipc::error("fail pthread_mutex_timedlock[%d]\n", eno);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
throw std::system_error{eno, std::system_category()};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unlock() noexcept {
|
||||||
|
int eno;
|
||||||
|
if ((eno = ::pthread_mutex_unlock(mutex_)) != 0) {
|
||||||
|
ipc::error("fail pthread_mutex_unlock[%d]\n", eno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sync
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace ipc
|
||||||
100
src/libipc/platform/mutex_win.h
Normal file
100
src/libipc/platform/mutex_win.h
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#include "libipc/utility/log.h"
|
||||||
|
|
||||||
|
#include "libipc/platform/to_tchar.h"
|
||||||
|
#include "libipc/platform/get_sa.h"
|
||||||
|
|
||||||
|
namespace ipc {
|
||||||
|
namespace detail {
|
||||||
|
namespace sync {
|
||||||
|
|
||||||
|
class mutex {
|
||||||
|
HANDLE h_ = NULL;
|
||||||
|
|
||||||
|
public:
|
||||||
|
mutex() noexcept = default;
|
||||||
|
explicit mutex(char const *name) noexcept {
|
||||||
|
open(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
~mutex() noexcept = default;
|
||||||
|
|
||||||
|
HANDLE native() const noexcept {
|
||||||
|
return h_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool valid() const noexcept {
|
||||||
|
return h_ != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool open(char const *name) noexcept {
|
||||||
|
close();
|
||||||
|
h_ = ::CreateMutex(detail::get_sa(), FALSE, ipc::detail::to_tchar(name).c_str());
|
||||||
|
if (h_ == NULL) {
|
||||||
|
ipc::error("fail CreateMutex[%lu]: %s\n", ::GetLastError(), name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close() noexcept {
|
||||||
|
if (!valid()) return;
|
||||||
|
::CloseHandle(h_);
|
||||||
|
h_ = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lock(std::uint64_t tm) noexcept {
|
||||||
|
DWORD ret, ms = (tm == invalid_value) ? INFINITE : static_cast<DWORD>(tm);
|
||||||
|
for(;;) {
|
||||||
|
switch ((ret = ::WaitForSingleObject(h_, ms))) {
|
||||||
|
case WAIT_OBJECT_0:
|
||||||
|
return true;
|
||||||
|
case WAIT_TIMEOUT:
|
||||||
|
return false;
|
||||||
|
case WAIT_ABANDONED:
|
||||||
|
ipc::log("fail WaitForSingleObject[%lu]: WAIT_ABANDONED, try again.\n", ::GetLastError());
|
||||||
|
if (!unlock()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break; // loop again
|
||||||
|
default:
|
||||||
|
ipc::error("fail WaitForSingleObject[%lu]: 0x%08X\n", ::GetLastError(), ret);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_lock() noexcept(false) {
|
||||||
|
DWORD ret = ::WaitForSingleObject(h_, 0);
|
||||||
|
switch (ret) {
|
||||||
|
case WAIT_OBJECT_0:
|
||||||
|
return true;
|
||||||
|
case WAIT_TIMEOUT:
|
||||||
|
return false;
|
||||||
|
case WAIT_ABANDONED:
|
||||||
|
unlock();
|
||||||
|
IPC_FALLTHROUGH_;
|
||||||
|
default:
|
||||||
|
ipc::error("fail WaitForSingleObject[%lu]: 0x%08X\n", ::GetLastError(), ret);
|
||||||
|
throw std::system_error{static_cast<int>(ret), std::system_category()};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unlock() noexcept {
|
||||||
|
if (!::ReleaseMutex(h_)) {
|
||||||
|
ipc::error("fail ReleaseMutex[%lu]\n", ::GetLastError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sync
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace ipc
|
||||||
@ -22,7 +22,7 @@
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct info_t {
|
struct info_t {
|
||||||
std::atomic_size_t acc_;
|
std::atomic<std::uint32_t> acc_;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct id_info_t {
|
struct id_info_t {
|
||||||
@ -81,6 +81,31 @@ id_t acquire(char const * name, std::size_t size, unsigned mode) {
|
|||||||
return ii;
|
return ii;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::uint32_t get_ref(id_t id) {
|
||||||
|
if (id == nullptr) {
|
||||||
|
ipc::error("fail get_ref: invalid id (null)\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auto ii = static_cast<id_info_t*>(id);
|
||||||
|
if (ii->mem_ == nullptr || ii->size_ == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return acc_of(mem, ii->size_).load(std::memory_order_acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sub_ref(id_t id) {
|
||||||
|
if (id == nullptr) {
|
||||||
|
ipc::error("fail sub_ref: invalid id (null)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto ii = static_cast<id_info_t*>(id);
|
||||||
|
if (ii->mem_ == nullptr || ii->size_ == 0) {
|
||||||
|
ipc::error("fail sub_ref: invalid id (mem = %p, size = %zd)\n", ii->mem_, ii->size_);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
acc_of(ii->mem_, ii->size_).fetch_sub(1, std::memory_order_acq_rel);
|
||||||
|
}
|
||||||
|
|
||||||
void * get_mem(id_t id, std::size_t * size) {
|
void * get_mem(id_t id, std::size_t * size) {
|
||||||
if (id == nullptr) {
|
if (id == nullptr) {
|
||||||
ipc::error("fail get_mem: invalid id (null)\n");
|
ipc::error("fail get_mem: invalid id (null)\n");
|
||||||
@ -137,7 +162,7 @@ void release(id_t id) {
|
|||||||
if (ii->mem_ == nullptr || ii->size_ == 0) {
|
if (ii->mem_ == nullptr || ii->size_ == 0) {
|
||||||
ipc::error("fail release: invalid id (mem = %p, size = %zd)\n", ii->mem_, ii->size_);
|
ipc::error("fail release: invalid id (mem = %p, size = %zd)\n", ii->mem_, ii->size_);
|
||||||
}
|
}
|
||||||
else if (acc_of(ii->mem_, ii->size_).fetch_sub(1, std::memory_order_acquire) == 1) {
|
else if (acc_of(ii->mem_, ii->size_).fetch_sub(1, std::memory_order_acq_rel) == 1) {
|
||||||
::munmap(ii->mem_, ii->size_);
|
::munmap(ii->mem_, ii->size_);
|
||||||
if (!ii->name_.empty()) {
|
if (!ii->name_.empty()) {
|
||||||
::shm_unlink(ii->name_.c_str());
|
::shm_unlink(ii->name_.c_str());
|
||||||
|
|||||||
@ -58,6 +58,14 @@ id_t acquire(char const * name, std::size_t size, unsigned mode) {
|
|||||||
return ii;
|
return ii;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::uint32_t get_ref(id_t) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sub_ref(id_t) {
|
||||||
|
// Do Nothing.
|
||||||
|
}
|
||||||
|
|
||||||
void * get_mem(id_t id, std::size_t * size) {
|
void * get_mem(id_t id, std::size_t * size) {
|
||||||
if (id == nullptr) {
|
if (id == nullptr) {
|
||||||
ipc::error("fail get_mem: invalid id (null)\n");
|
ipc::error("fail get_mem: invalid id (null)\n");
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
namespace ipc {
|
namespace ipc {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
inline static bool calc_wait_time(timespec& ts, std::size_t tm /*ms*/) {
|
inline static bool calc_wait_time(timespec& ts, std::uint64_t tm /*ms*/) {
|
||||||
timeval now;
|
timeval now;
|
||||||
int eno = ::gettimeofday(&now, NULL);
|
int eno = ::gettimeofday(&now, NULL);
|
||||||
if (eno != 0) {
|
if (eno != 0) {
|
||||||
@ -89,8 +89,7 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
case EOWNERDEAD:
|
case EOWNERDEAD:
|
||||||
if (::pthread_mutex_consistent(&mutex_) == 0) {
|
if (::pthread_mutex_consistent(&mutex_) == 0) {
|
||||||
::pthread_mutex_unlock(&mutex_);
|
return true;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
IPC_FALLTHROUGH_;
|
IPC_FALLTHROUGH_;
|
||||||
case ENOTRECOVERABLE:
|
case ENOTRECOVERABLE:
|
||||||
@ -138,7 +137,7 @@ public:
|
|||||||
IPC_PTHREAD_FUNC_(pthread_cond_destroy, &cond_);
|
IPC_PTHREAD_FUNC_(pthread_cond_destroy, &cond_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wait(mutex& mtx, std::size_t tm = invalid_value) {
|
bool wait(mutex& mtx, std::uint64_t tm = invalid_value) {
|
||||||
switch (tm) {
|
switch (tm) {
|
||||||
case 0:
|
case 0:
|
||||||
return true;
|
return true;
|
||||||
@ -221,7 +220,7 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool wait(handle_t h, std::size_t tm = invalid_value) {
|
static bool wait(handle_t h, std::uint64_t tm = invalid_value) {
|
||||||
if (h == invalid()) return false;
|
if (h == invalid()) return false;
|
||||||
switch (tm) {
|
switch (tm) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -289,7 +288,7 @@ private:
|
|||||||
return ipc::detail::unique_lock(me_->lock_);
|
return ipc::detail::unique_lock(me_->lock_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sema_wait(std::size_t tm) {
|
bool sema_wait(std::uint64_t tm) {
|
||||||
return sem_helper::wait(std::get<1>(h_), tm);
|
return sem_helper::wait(std::get<1>(h_), tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,7 +296,7 @@ private:
|
|||||||
return sem_helper::post(std::get<1>(h_), count);
|
return sem_helper::post(std::get<1>(h_), count);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handshake_wait(std::size_t tm) {
|
bool handshake_wait(std::uint64_t tm) {
|
||||||
return sem_helper::wait(std::get<2>(h_), tm);
|
return sem_helper::wait(std::get<2>(h_), tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,7 +338,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
bool wait_if(handle_t const & h, wait_flags * flags, F&& pred, std::size_t tm = invalid_value) {
|
bool wait_if(handle_t const & h, wait_flags * flags, F&& pred, std::uint64_t tm = invalid_value) {
|
||||||
assert(flags != nullptr);
|
assert(flags != nullptr);
|
||||||
contrl ctrl { this, flags, h };
|
contrl ctrl { this, flags, h };
|
||||||
|
|
||||||
@ -400,7 +399,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
bool wait_if(handle_t h, waiter_helper::wait_flags * flags, F && pred, std::size_t tm = invalid_value) {
|
bool wait_if(handle_t h, waiter_helper::wait_flags * flags, F && pred, std::uint64_t tm = invalid_value) {
|
||||||
if (h == invalid()) return false;
|
if (h == invalid()) return false;
|
||||||
return helper_.wait_if(h, flags, std::forward<F>(pred), tm);
|
return helper_.wait_if(h, flags, std::forward<F>(pred), tm);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,7 +40,7 @@ public:
|
|||||||
::CloseHandle(h_);
|
::CloseHandle(h_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wait(std::size_t tm = invalid_value) {
|
bool wait(std::uint64_t tm = invalid_value) {
|
||||||
DWORD ret, ms = (tm == invalid_value) ? INFINITE : static_cast<DWORD>(tm);
|
DWORD ret, ms = (tm == invalid_value) ? INFINITE : static_cast<DWORD>(tm);
|
||||||
switch ((ret = ::WaitForSingleObject(h_, ms))) {
|
switch ((ret = ::WaitForSingleObject(h_, ms))) {
|
||||||
case WAIT_OBJECT_0:
|
case WAIT_OBJECT_0:
|
||||||
@ -102,7 +102,7 @@ class condition {
|
|||||||
return ipc::detail::unique_lock(me_->lock_);
|
return ipc::detail::unique_lock(me_->lock_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sema_wait(std::size_t tm) {
|
bool sema_wait(std::uint64_t tm) {
|
||||||
return me_->sema_.wait(tm);
|
return me_->sema_.wait(tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ class condition {
|
|||||||
return me_->sema_.post(count);
|
return me_->sema_.post(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handshake_wait(std::size_t tm) {
|
bool handshake_wait(std::uint64_t tm) {
|
||||||
return me_->handshake_.wait(tm);
|
return me_->handshake_.wait(tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +151,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Mutex, typename F>
|
template <typename Mutex, typename F>
|
||||||
bool wait_if(Mutex & mtx, wait_flags * flags, F && pred, std::size_t tm = invalid_value) {
|
bool wait_if(Mutex & mtx, wait_flags * flags, F && pred, std::uint64_t tm = invalid_value) {
|
||||||
assert(flags != nullptr);
|
assert(flags != nullptr);
|
||||||
contrl ctrl { this, flags };
|
contrl ctrl { this, flags };
|
||||||
return waiter_helper::wait_if(ctrl, mtx, std::forward<F>(pred), tm);
|
return waiter_helper::wait_if(ctrl, mtx, std::forward<F>(pred), tm);
|
||||||
@ -201,7 +201,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
bool wait_if(handle_t& h, waiter_helper::wait_flags * flags, F&& pred, std::size_t tm = invalid_value) {
|
bool wait_if(handle_t& h, waiter_helper::wait_flags * flags, F&& pred, std::uint64_t tm = invalid_value) {
|
||||||
if (h == invalid()) return false;
|
if (h == invalid()) return false;
|
||||||
|
|
||||||
class non_mutex {
|
class non_mutex {
|
||||||
|
|||||||
@ -8,9 +8,7 @@
|
|||||||
|
|
||||||
#include "libipc/memory/resource.h"
|
#include "libipc/memory/resource.h"
|
||||||
#include "libipc/platform/detail.h"
|
#include "libipc/platform/detail.h"
|
||||||
#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || \
|
#if defined(IPC_OS_WINDOWS_)
|
||||||
defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || \
|
|
||||||
defined(WINCE) || defined(_WIN32_WCE)
|
|
||||||
|
|
||||||
#include "libipc/platform/waiter_win.h"
|
#include "libipc/platform/waiter_win.h"
|
||||||
|
|
||||||
@ -52,7 +50,7 @@ public:
|
|||||||
cnt_h_.release();
|
cnt_h_.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wait(mutex_impl& mtx, std::size_t tm = invalid_value) {
|
bool wait(mutex_impl& mtx, std::uint64_t tm = invalid_value) {
|
||||||
return base_t::wait_if(mtx, &flags_, [] { return true; }, tm);
|
return base_t::wait_if(mtx, &flags_, [] { return true; }, tm);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -60,7 +58,7 @@ public:
|
|||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
|
|
||||||
#else /*!WIN*/
|
#elif defined(IPC_OS_LINUX_)
|
||||||
|
|
||||||
#include "libipc/platform/waiter_linux.h"
|
#include "libipc/platform/waiter_linux.h"
|
||||||
|
|
||||||
@ -123,7 +121,7 @@ public:
|
|||||||
|
|
||||||
class condition_impl : public object_impl<ipc::detail::condition> {
|
class condition_impl : public object_impl<ipc::detail::condition> {
|
||||||
public:
|
public:
|
||||||
bool wait(mutex_impl& mtx, std::size_t tm = invalid_value) {
|
bool wait(mutex_impl& mtx, std::uint64_t tm = invalid_value) {
|
||||||
return object().wait(mtx.object(), tm);
|
return object().wait(mtx.object(), tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +166,7 @@ public:
|
|||||||
opened_.release();
|
opened_.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wait(std::size_t tm = invalid_value) {
|
bool wait(std::uint64_t tm = invalid_value) {
|
||||||
return sem_helper::wait(h_, tm);
|
return sem_helper::wait(h_, tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,8 +177,9 @@ public:
|
|||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
|
#else/*linux*/
|
||||||
#endif/*!WIN*/
|
# error "Unsupported platform."
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -235,7 +234,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
bool wait_if(F && pred, std::size_t tm = invalid_value) {
|
bool wait_if(F && pred, std::uint64_t tm = invalid_value) {
|
||||||
if (!valid()) return false;
|
if (!valid()) return false;
|
||||||
return w_->wait_if(h_, &flags_, std::forward<F>(pred), tm);
|
return w_->wait_if(h_, &flags_, std::forward<F>(pred), tm);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@ struct waiter_helper {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename Mutex, typename Ctrl, typename F>
|
template <typename Mutex, typename Ctrl, typename F>
|
||||||
static bool wait_if(Ctrl & ctrl, Mutex & mtx, F && pred, std::size_t tm) {
|
static bool wait_if(Ctrl & ctrl, Mutex & mtx, F && pred, std::uint64_t tm) {
|
||||||
auto & flags = ctrl.flags();
|
auto & flags = ctrl.flags();
|
||||||
if (flags.is_closed_.load(std::memory_order_acquire)) {
|
if (flags.is_closed_.load(std::memory_order_acquire)) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
70
src/mutex.cpp
Normal file
70
src/mutex.cpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
|
||||||
|
#include "libipc/mutex.h"
|
||||||
|
|
||||||
|
#include "libipc/utility/pimpl.h"
|
||||||
|
#include "libipc/memory/resource.h"
|
||||||
|
#include "libipc/platform/detail.h"
|
||||||
|
#if defined(IPC_OS_WINDOWS_)
|
||||||
|
#include "libipc/platform/mutex_win.h"
|
||||||
|
#elif defined(IPC_OS_LINUX_)
|
||||||
|
#include "libipc/platform/mutex_linux.h"
|
||||||
|
#else/*linux*/
|
||||||
|
# error "Unsupported platform."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ipc {
|
||||||
|
namespace sync {
|
||||||
|
|
||||||
|
class mutex::mutex_ : public ipc::pimpl<mutex_> {
|
||||||
|
public:
|
||||||
|
ipc::detail::sync::mutex lock_;
|
||||||
|
};
|
||||||
|
|
||||||
|
mutex::mutex()
|
||||||
|
: p_(p_->make()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex::mutex(char const * name)
|
||||||
|
: mutex() {
|
||||||
|
open(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex::~mutex() {
|
||||||
|
close();
|
||||||
|
p_->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void const *mutex::native() const noexcept {
|
||||||
|
return impl(p_)->lock_.native();
|
||||||
|
}
|
||||||
|
|
||||||
|
void *mutex::native() noexcept {
|
||||||
|
return impl(p_)->lock_.native();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mutex::valid() const noexcept {
|
||||||
|
return impl(p_)->lock_.valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mutex::open(char const *name) noexcept {
|
||||||
|
return impl(p_)->lock_.open(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutex::close() noexcept {
|
||||||
|
impl(p_)->lock_.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mutex::lock(std::uint64_t tm) noexcept {
|
||||||
|
return impl(p_)->lock_.lock(tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mutex::try_lock() noexcept(false) {
|
||||||
|
return impl(p_)->lock_.try_lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mutex::unlock() noexcept {
|
||||||
|
return impl(p_)->lock_.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sync
|
||||||
|
} // namespace ipc
|
||||||
14
src/shm.cpp
14
src/shm.cpp
@ -47,18 +47,26 @@ handle& handle::operator=(handle rhs) {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handle::valid() const {
|
bool handle::valid() const noexcept {
|
||||||
return impl(p_)->m_ != nullptr;
|
return impl(p_)->m_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t handle::size() const {
|
std::size_t handle::size() const noexcept {
|
||||||
return impl(p_)->s_;
|
return impl(p_)->s_;
|
||||||
}
|
}
|
||||||
|
|
||||||
char const * handle::name() const {
|
char const * handle::name() const noexcept {
|
||||||
return impl(p_)->n_.c_str();
|
return impl(p_)->n_.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::uint32_t handle::ref() const noexcept {
|
||||||
|
return shm::get_ref(impl(p_)->id_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle::sub_ref() noexcept {
|
||||||
|
shm::sub_ref(impl(p_)->id_);
|
||||||
|
}
|
||||||
|
|
||||||
bool handle::acquire(char const * name, std::size_t size, unsigned mode) {
|
bool handle::acquire(char const * name, std::size_t size, unsigned mode) {
|
||||||
release();
|
release();
|
||||||
impl(p_)->id_ = shm::acquire((impl(p_)->n_ = name).c_str(), size, mode);
|
impl(p_)->id_ = shm::acquire((impl(p_)->n_ = name).c_str(), size, mode);
|
||||||
|
|||||||
@ -44,7 +44,7 @@ bool mutex::unlock() {
|
|||||||
|
|
||||||
#include "libipc/waiter_template.inc"
|
#include "libipc/waiter_template.inc"
|
||||||
|
|
||||||
bool semaphore::wait(std::size_t tm) {
|
bool semaphore::wait(std::uint64_t tm) {
|
||||||
return impl(p_)->h_.wait(tm);
|
return impl(p_)->h_.wait(tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ bool semaphore::post(long count) {
|
|||||||
|
|
||||||
#include "libipc/waiter_template.inc"
|
#include "libipc/waiter_template.inc"
|
||||||
|
|
||||||
bool condition::wait(mutex& mtx, std::size_t tm) {
|
bool condition::wait(mutex& mtx, std::uint64_t tm) {
|
||||||
return impl(p_)->h_.wait(impl(mtx.p_)->h_, tm);
|
return impl(p_)->h_.wait(impl(mtx.p_)->h_, tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,8 @@ include_directories(
|
|||||||
|
|
||||||
file(GLOB SRC_FILES
|
file(GLOB SRC_FILES
|
||||||
${LIBIPC_PROJECT_DIR}/test/*.cpp
|
${LIBIPC_PROJECT_DIR}/test/*.cpp
|
||||||
${LIBIPC_PROJECT_DIR}/test/profiler/*.cpp)
|
# ${LIBIPC_PROJECT_DIR}/test/profiler/*.cpp
|
||||||
|
)
|
||||||
file(GLOB HEAD_FILES ${LIBIPC_PROJECT_DIR}/test/*.h)
|
file(GLOB HEAD_FILES ${LIBIPC_PROJECT_DIR}/test/*.h)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} ${SRC_FILES} ${HEAD_FILES})
|
add_executable(${PROJECT_NAME} ${SRC_FILES} ${HEAD_FILES})
|
||||||
|
|||||||
34
test/test_pthread.cpp → test/test_sync.cpp
Executable file → Normal file
34
test/test_pthread.cpp → test/test_sync.cpp
Executable file → Normal file
@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <mutex>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
|
||||||
@ -47,3 +49,35 @@ TEST(PThread, Robust) {
|
|||||||
CloseHandle(lock);
|
CloseHandle(lock);
|
||||||
}
|
}
|
||||||
#endif // !__linux__
|
#endif // !__linux__
|
||||||
|
|
||||||
|
#include "libipc/mutex.h"
|
||||||
|
|
||||||
|
TEST(Sync, Mutex) {
|
||||||
|
ipc::sync::mutex lock;
|
||||||
|
EXPECT_TRUE(lock.open("test-mutex-robust"));
|
||||||
|
|
||||||
|
std::thread{[] {
|
||||||
|
ipc::sync::mutex lock{"test-mutex-robust"};
|
||||||
|
EXPECT_TRUE(lock.valid());
|
||||||
|
EXPECT_TRUE(lock.lock());
|
||||||
|
}}.join();
|
||||||
|
|
||||||
|
EXPECT_THROW(lock.try_lock(), std::system_error);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
EXPECT_TRUE(lock.lock());
|
||||||
|
i = 100;
|
||||||
|
auto t2 = std::thread{[&i] {
|
||||||
|
ipc::sync::mutex lock{"test-mutex-robust"};
|
||||||
|
EXPECT_TRUE(lock.valid());
|
||||||
|
EXPECT_FALSE(lock.try_lock());
|
||||||
|
EXPECT_TRUE(lock.lock());
|
||||||
|
i += i;
|
||||||
|
EXPECT_TRUE(lock.unlock());
|
||||||
|
}};
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
EXPECT_EQ(i, 100);
|
||||||
|
EXPECT_TRUE(lock.unlock());
|
||||||
|
t2.join();
|
||||||
|
EXPECT_EQ(i, 200);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user