From d37a6740ea5e15c68f24b766cc45316ca27b17ff Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sun, 12 Sep 2021 21:48:22 +0800 Subject: [PATCH] add ut for sync::semaphore --- include/libipc/semaphore.h | 4 +- src/libipc/platform/condition_linux.h | 4 - src/libipc/platform/condition_win.h | 4 - src/libipc/platform/mutex_linux.h | 4 - src/libipc/platform/mutex_win.h | 4 - src/libipc/platform/semaphore_linux.h | 101 ++++++++++++++++++++++++++ src/libipc/platform/semaphore_win.h | 9 +-- src/semaphore.cpp | 8 +- test/test_sync.cpp | 16 ++++ 9 files changed, 125 insertions(+), 29 deletions(-) diff --git a/include/libipc/semaphore.h b/include/libipc/semaphore.h index ea8ca3d..7f557e2 100644 --- a/include/libipc/semaphore.h +++ b/include/libipc/semaphore.h @@ -14,7 +14,7 @@ class IPC_EXPORT semaphore { public: semaphore(); - explicit semaphore(char const *name, std::uint32_t count = 0, std::uint32_t limit = ipc::invalid_value); + explicit semaphore(char const *name, std::uint32_t count = 0); ~semaphore(); void const *native() const noexcept; @@ -22,7 +22,7 @@ public: bool valid() const noexcept; - bool open(char const *name, std::uint32_t count = 0, std::uint32_t limit = ipc::invalid_value) noexcept; + bool open(char const *name, std::uint32_t count = 0) noexcept; void close() noexcept; bool wait(std::uint64_t tm = ipc::invalid_value) noexcept; diff --git a/src/libipc/platform/condition_linux.h b/src/libipc/platform/condition_linux.h index 745d29c..509c552 100644 --- a/src/libipc/platform/condition_linux.h +++ b/src/libipc/platform/condition_linux.h @@ -26,10 +26,6 @@ class condition { public: condition() = default; - explicit condition(char const *name) noexcept { - open(name); - } - ~condition() = default; pthread_cond_t const *native() const noexcept { diff --git a/src/libipc/platform/condition_win.h b/src/libipc/platform/condition_win.h index 19f3d0c..02a68ea 100644 --- a/src/libipc/platform/condition_win.h +++ b/src/libipc/platform/condition_win.h @@ -16,10 +16,6 @@ class condition { public: condition() noexcept = default; - explicit condition(char const *name) noexcept { - open(name); - } - ~condition() noexcept = default; HANDLE native() const noexcept { diff --git a/src/libipc/platform/mutex_linux.h b/src/libipc/platform/mutex_linux.h index e3b44f1..5c45dfe 100644 --- a/src/libipc/platform/mutex_linux.h +++ b/src/libipc/platform/mutex_linux.h @@ -50,10 +50,6 @@ class mutex { public: mutex() = default; - explicit mutex(char const *name) noexcept { - open(name); - } - ~mutex() = default; pthread_mutex_t const *native() const noexcept { diff --git a/src/libipc/platform/mutex_win.h b/src/libipc/platform/mutex_win.h index cac5d82..b648c3b 100644 --- a/src/libipc/platform/mutex_win.h +++ b/src/libipc/platform/mutex_win.h @@ -19,10 +19,6 @@ class mutex { public: mutex() noexcept = default; - explicit mutex(char const *name) noexcept { - open(name); - } - ~mutex() noexcept = default; HANDLE native() const noexcept { diff --git a/src/libipc/platform/semaphore_linux.h b/src/libipc/platform/semaphore_linux.h index e69de29..b355124 100644 --- a/src/libipc/platform/semaphore_linux.h +++ b/src/libipc/platform/semaphore_linux.h @@ -0,0 +1,101 @@ +#pragma once + +#include + +#include /* For O_* constants */ +#include /* For mode constants */ +#include +#include + +#include "libipc/utility/log.h" +#include "libipc/platform/get_wait_time.h" +#include "libipc/shm.h" + +namespace ipc { +namespace detail { +namespace sync { + +class semaphore { + ipc::shm::handle shm_; + sem_t *h_ = SEM_FAILED; + +public: + semaphore() noexcept = default; + ~semaphore() noexcept = default; + + sem_t *native() const noexcept { + return h_; + } + + bool valid() const noexcept { + return h_ != SEM_FAILED; + } + + bool open(char const *name, std::uint32_t count) noexcept { + close(); + if (!shm_.acquire(name, 0)) { + ipc::error("[open_semaphore] fail shm.acquire: %s\n", name); + return false; + } + h_ = ::sem_open(name, O_CREAT, 0666, static_cast(count)); + if (h_ == SEM_FAILED) { + ipc::error("fail sem_open[%d]: %s\n", errno, name); + return false; + } + return true; + } + + void close() noexcept { + if (!valid()) return; + if (::sem_close(h_) != 0) { + ipc::error("fail sem_close[%d]: %s\n", errno); + } + if (shm_.ref() == 1) { + if (::sem_unlink(shm_.name()) != 0) { + ipc::error("fail sem_unlink[%d]: %s\n", errno); + } + } + shm_.release(); + h_ = SEM_FAILED; + } + + bool wait(std::uint64_t tm) noexcept { + if (h == invalid()) return false; + switch (tm) { + case 0: + return true; + case invalid_value: + if (::sem_wait(h_) != 0) { + ipc::error("fail sem_wait[%d]: %s\n", errno); + return false; + } + return true; + default: { + auto ts = detail::make_timespec(tm); + if (::sem_timedwait(h, &ts) != 0) { + if (errno != ETIMEDOUT) { + ipc::error("fail sem_timedwait[%d]: tm = %zd, tv_sec = %ld, tv_nsec = %ld\n", + errno, tm, ts.tv_sec, ts.tv_nsec); + } + return false; + } + } + return true; + } + } + + bool post(std::uint32_t count) noexcept { + if (h_ == invalid()) return false; + for (std::uint32_t i = 0; i < count; ++i) { + if (::sem_post(h_) != 0) { + ipc::error("fail sem_post[%d]: %s\n", errno); + return false; + } + } + return true; + } +}; + +} // namespace sync +} // namespace detail +} // namespace ipc diff --git a/src/libipc/platform/semaphore_win.h b/src/libipc/platform/semaphore_win.h index ea95ef3..9a91eba 100644 --- a/src/libipc/platform/semaphore_win.h +++ b/src/libipc/platform/semaphore_win.h @@ -18,10 +18,6 @@ class semaphore { public: semaphore() noexcept = default; - explicit semaphore(char const *name, std::uint32_t count, std::uint32_t limit) noexcept { - open(name, count, limit); - } - ~semaphore() noexcept = default; HANDLE native() const noexcept { @@ -32,11 +28,10 @@ public: return h_ != NULL; } - bool open(char const *name, std::uint32_t count, std::uint32_t limit) noexcept { + bool open(char const *name, std::uint32_t count) noexcept { close(); h_ = ::CreateSemaphore(detail::get_sa(), - static_cast(count), - (limit == invalid_value) ? LONG_MAX : static_cast(limit), + static_cast(count), LONG_MAX, ipc::detail::to_tchar(name).c_str()); if (h_ == NULL) { ipc::error("fail CreateSemaphore[%lu]: %s\n", ::GetLastError(), name); diff --git a/src/semaphore.cpp b/src/semaphore.cpp index 274aead..6e86823 100644 --- a/src/semaphore.cpp +++ b/src/semaphore.cpp @@ -24,9 +24,9 @@ semaphore::semaphore() : p_(p_->make()) { } -semaphore::semaphore(char const * name, std::uint32_t count, std::uint32_t limit) +semaphore::semaphore(char const * name, std::uint32_t count) : semaphore() { - open(name, count, limit); + open(name, count); } semaphore::~semaphore() { @@ -46,8 +46,8 @@ bool semaphore::valid() const noexcept { return impl(p_)->sem_.valid(); } -bool semaphore::open(char const *name, std::uint32_t count, std::uint32_t limit) noexcept { - return impl(p_)->sem_.open(name, count, limit); +bool semaphore::open(char const *name, std::uint32_t count) noexcept { + return impl(p_)->sem_.open(name, count); } void semaphore::close() noexcept { diff --git a/test/test_sync.cpp b/test/test_sync.cpp index d854e44..50ad929 100644 --- a/test/test_sync.cpp +++ b/test/test_sync.cpp @@ -80,4 +80,20 @@ TEST(Sync, Mutex) { EXPECT_TRUE(lock.unlock()); t2.join(); EXPECT_EQ(i, 200); +} + +#include "libipc/semaphore.h" + +TEST(Sync, Semaphore) { + ipc::sync::semaphore sem; + EXPECT_TRUE(sem.open("test-sem")); + std::thread{[] { + ipc::sync::semaphore sem{"test-sem"}; + EXPECT_TRUE(sem.post(10)); + }}.join(); + + for (int i = 0; i < 10; ++i) { + EXPECT_TRUE(sem.wait(0)); + } + EXPECT_FALSE(sem.wait(0)); } \ No newline at end of file