From 4d3b05af0d2965d2c6ba74bc5a8367cdc05df20e Mon Sep 17 00:00:00 2001 From: Yurii Rashkovskii Date: Thu, 24 Apr 2025 09:20:18 -0700 Subject: [PATCH] Allow use of semaphore posting with noexcept Addresses a concern in #262 --- .../sync/interprocess_semaphore.hpp | 11 +++++++++++ .../interprocess/sync/named_semaphore.hpp | 11 +++++++++++ .../sync/posix/named_semaphore.hpp | 9 +++++++++ .../interprocess/sync/posix/semaphore.hpp | 9 +++++++++ .../interprocess/sync/shm/named_semaphore.hpp | 9 +++++++++ .../interprocess/sync/spin/semaphore.hpp | 9 +++++++++ .../sync/windows/named_semaphore.hpp | 19 ++++++++++++++++++- .../interprocess/sync/windows/semaphore.hpp | 19 ++++++++++++++++++- .../sync/windows/winapi_semaphore_wrapper.hpp | 4 ++-- test/semaphore_test_template.hpp | 8 ++++++++ 10 files changed, 104 insertions(+), 4 deletions(-) diff --git a/include/boost/interprocess/sync/interprocess_semaphore.hpp b/include/boost/interprocess/sync/interprocess_semaphore.hpp index abb74e8a..9e503ac8 100644 --- a/include/boost/interprocess/sync/interprocess_semaphore.hpp +++ b/include/boost/interprocess/sync/interprocess_semaphore.hpp @@ -29,6 +29,8 @@ #include #include +#include + #if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && \ defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && \ defined(BOOST_INTERPROCESS_POSIX_UNNAMED_SEMAPHORES) @@ -74,6 +76,11 @@ class interprocess_semaphore //!its wait function. If there is an error an interprocess_exception exception is thrown. void post(); + //!Increments the interprocess_semaphore count. If there are processes/threads blocked waiting + //!for the interprocess_semaphore, then one of these processes will return successfully from + //!its wait function. If there is an error, it'll return a non-null error code. + std::error_code post(const std::nothrow_t &) noexcept; + //!Decrements the interprocess_semaphore. If the interprocess_semaphore value is not greater than zero, //!then the calling process/thread blocks until it can decrement the counter. //!If there is an error an interprocess_exception exception is thrown. @@ -135,6 +142,10 @@ inline bool interprocess_semaphore::timed_wait(const TimePoint &abs_time) inline void interprocess_semaphore::post() { m_sem.post(); } +std::error_code interprocess_semaphore::post(const std::nothrow_t &) noexcept { + return m_sem.post(std::nothrow) ; +} + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/sync/named_semaphore.hpp b/include/boost/interprocess/sync/named_semaphore.hpp index 74d38ba9..faf5e09a 100644 --- a/include/boost/interprocess/sync/named_semaphore.hpp +++ b/include/boost/interprocess/sync/named_semaphore.hpp @@ -26,6 +26,8 @@ #include #include +#include + #if defined(BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES) #include //Experimental... @@ -116,6 +118,11 @@ class named_semaphore //!its wait function. If there is an error an interprocess_exception exception is thrown. void post(); + //!Increments the interprocess_semaphore count. If there are processes/threads blocked waiting + //!for the interprocess_semaphore, then one of these processes will return successfully from + //!its wait function. If there is an error, it'll return a non-null error code. + std::error_code post(std::nothrow_t &) noexcept; + //!Decrements the semaphore. If the semaphore value is not greater than zero, //!then the calling process/thread blocks until it can decrement the counter. //!If there is an error an interprocess_exception exception is thrown. @@ -211,6 +218,10 @@ inline void named_semaphore::wait() inline void named_semaphore::post() { m_sem.post(); } +inline std::error_code named_semaphore::post(std::nothrow_t &) noexcept +{ return m_sem.post(std::nothrow); } + + inline bool named_semaphore::try_wait() { return m_sem.try_wait(); } diff --git a/include/boost/interprocess/sync/posix/named_semaphore.hpp b/include/boost/interprocess/sync/posix/named_semaphore.hpp index 410e76f9..b003fbd3 100644 --- a/include/boost/interprocess/sync/posix/named_semaphore.hpp +++ b/include/boost/interprocess/sync/posix/named_semaphore.hpp @@ -24,6 +24,8 @@ #include +#include + namespace boost { namespace interprocess { @@ -59,6 +61,13 @@ class posix_named_semaphore void post() { semaphore_post(mp_sem); } + std::error_code post(const std::nothrow_t &) noexcept { + if (sem_post(mp_sem) != 0) { + return {errno, std::system_category()}; + } + return {0, std::system_category()}; + } + void wait() { semaphore_wait(mp_sem); } diff --git a/include/boost/interprocess/sync/posix/semaphore.hpp b/include/boost/interprocess/sync/posix/semaphore.hpp index bf64d430..73e78172 100644 --- a/include/boost/interprocess/sync/posix/semaphore.hpp +++ b/include/boost/interprocess/sync/posix/semaphore.hpp @@ -24,6 +24,8 @@ #include +#include + namespace boost { namespace interprocess { namespace ipcdetail { @@ -44,6 +46,13 @@ class posix_semaphore void post() { semaphore_post(&m_sem); } + std::error_code post(std::nothrow_t &) noexcept { + if (sem_post(&m_sem) != 0) { + return {errno, std::system_category()}; + } + return {0, std::system_category()}; + } + void wait() { semaphore_wait(&m_sem); } diff --git a/include/boost/interprocess/sync/shm/named_semaphore.hpp b/include/boost/interprocess/sync/shm/named_semaphore.hpp index 9977888b..668d4a72 100644 --- a/include/boost/interprocess/sync/shm/named_semaphore.hpp +++ b/include/boost/interprocess/sync/shm/named_semaphore.hpp @@ -30,6 +30,8 @@ #include #include +#include + namespace boost { namespace interprocess { namespace ipcdetail { @@ -64,6 +66,8 @@ class shm_named_semaphore ~shm_named_semaphore(); void post(); + std::error_code post(std::nothrow_t &) noexcept; + void wait(); bool try_wait(); template bool timed_wait(const TimePoint &abs_time); @@ -169,6 +173,11 @@ inline shm_named_semaphore::shm_named_semaphore inline void shm_named_semaphore::post() { semaphore()->post(); } +std::error_code shm_named_semaphore::post(std::nothrow_t &) noexcept { + post(); + return {0, std::generic_category()}; +} + inline void shm_named_semaphore::wait() { semaphore()->wait(); } diff --git a/include/boost/interprocess/sync/spin/semaphore.hpp b/include/boost/interprocess/sync/spin/semaphore.hpp index cd3c8662..367ec1a1 100644 --- a/include/boost/interprocess/sync/spin/semaphore.hpp +++ b/include/boost/interprocess/sync/spin/semaphore.hpp @@ -27,6 +27,8 @@ #include #include +#include + namespace boost { namespace interprocess { namespace ipcdetail { @@ -41,6 +43,8 @@ class spin_semaphore ~spin_semaphore(); void post(); + std::error_code post(const std::nothrow_t &) noexcept; + void wait(); bool try_wait(); template bool timed_wait(const TimePoint &abs_time); @@ -62,6 +66,11 @@ inline void spin_semaphore::post() ipcdetail::atomic_inc32(&m_count); } +inline std::error_code spin_semaphore::post(const std::nothrow_t &) noexcept { + post(); + return {0, std::system_category()}; +} + inline void spin_semaphore::wait() { ipcdetail::lock_to_wait lw(*this); diff --git a/include/boost/interprocess/sync/windows/named_semaphore.hpp b/include/boost/interprocess/sync/windows/named_semaphore.hpp index bd3cff37..b50503fa 100644 --- a/include/boost/interprocess/sync/windows/named_semaphore.hpp +++ b/include/boost/interprocess/sync/windows/named_semaphore.hpp @@ -27,6 +27,12 @@ #include #include +extern "C" { +#include +} + +#include + namespace boost { namespace interprocess { namespace ipcdetail { @@ -59,6 +65,7 @@ class winapi_named_semaphore ~winapi_named_semaphore(); void post(); + std::error_code post(const std::nothrow_t &) noexcept; void wait(); bool try_wait(); template bool timed_wait(const TimePoint &abs_time); @@ -192,9 +199,19 @@ inline winapi_named_semaphore::winapi_named_semaphore(open_only_t, const wchar_t inline void winapi_named_semaphore::post() { - m_sem_wrapper.post(); + if (m_sem_wrapper.post() == 0) { + throw interprocess_exception(GetLastError()); + } } +inline std::error_code winapi_named_semaphore::post(const std::nothrow_t &) noexcept { + if (m_sem_wrapper.post() == 0) { + return {GetLastError(), std::system_category()}; + }; + return {0, std::system_category()}; +} + + inline void winapi_named_semaphore::wait() { m_sem_wrapper.wait(); diff --git a/include/boost/interprocess/sync/windows/semaphore.hpp b/include/boost/interprocess/sync/windows/semaphore.hpp index 888ab71a..42d424d8 100644 --- a/include/boost/interprocess/sync/windows/semaphore.hpp +++ b/include/boost/interprocess/sync/windows/semaphore.hpp @@ -28,6 +28,10 @@ #include #include +extern "C" { +#include +} +#include namespace boost { namespace interprocess { @@ -43,6 +47,7 @@ class winapi_semaphore ~winapi_semaphore(); void post(unsigned int release_count = 1); + std::error_code post(const std::nothrow_t&); void wait(); bool try_wait(); template bool timed_wait(const TimePoint &abs_time); @@ -106,7 +111,19 @@ inline void winapi_semaphore::post(unsigned release_count) sync_handles &handles = windows_intermodule_singleton::get(); winapi_semaphore_functions sem(handles.obtain_semaphore(this->id_, this, initial_count_)); - sem.post(static_cast(release_count)); + if (sem.post(static_cast(release_count)) == 0) { + throw interprocess_exception(GetLastError()); + } +} + +std::error_code post(const std::nothrow_t&) { + sync_handles &handles = + windows_intermodule_singleton::get(); + winapi_semaphore_functions sem(handles.obtain_semaphore(this->id_, this, initial_count_)); + if (sem.post(static_cast(release_count)) == 0) { + return {GetLastError(), std::system_category()} ; + } + return {0, std::system_category()}; } diff --git a/include/boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp b/include/boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp index b8580486..fbb60630 100644 --- a/include/boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp +++ b/include/boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp @@ -47,10 +47,10 @@ class winapi_semaphore_functions : m_sem_hnd(hnd) {} - void post(long count = 1) + int post(long count = 1) { long prev_count; - winapi::release_semaphore(m_sem_hnd, count, &prev_count); + return winapi::release_semaphore(m_sem_hnd, count, &prev_count); } void wait() diff --git a/test/semaphore_test_template.hpp b/test/semaphore_test_template.hpp index 39152f9a..c0c05651 100644 --- a/test/semaphore_test_template.hpp +++ b/test/semaphore_test_template.hpp @@ -92,6 +92,14 @@ inline int test_all_semaphore() test::test_all_lock >(); test::test_all_recursive_lock >(); test::test_all_mutex >(); + + Semaphore s(0); + BOOST_INTERPROCESS_CHECK(!s.try_wait()); + BOOST_INTERPROCESS_CHECK(!s.post(std::nothrow)); + BOOST_INTERPROCESS_CHECK(s.try_wait()); + // TODO: not trivial to simulate failure as that would require + // failure injection (augmenting implementations for test mode) + return 0; }