mirror of
https://gcc.gnu.org/git/gcc.git
synced 2026-02-22 03:46:53 -05:00
libstdc++: Rewrite std::counting_semaphore base class [PR118494]
Remove __platform_semaphore. Replace __atomic_semaphore with __semaphore_base<bool> and change its counter to be ptrdiff_t when the count doesn't fit in __platform_wait_t (PR 118494). Make the std::counting_semaphore constructor constexpr to support constant initialization (PR 110854). Add precondition checks to the constructor and release member functions (PR 98749). libstdc++-v3/ChangeLog: PR libstdc++/118494 PR libstdc++/110854 PR libstdc++/98749 * acinclude.m4 (GLIBCXX_CHECK_GTHREADS): Remove checks for sem_timedwait. Do not define _GLIBCXX_HAVE_POSIX_SEMAPHORE. * config.h.in: Regenerate. * configure: Regenerate. * include/bits/semaphore_base.h (__platform_semaphore): Remove. (__atomic_semaphore): Replace with __semaphore_base<bool> and make type of _M_count depend on template parameter. Fix _S_max constant to use correct type. (__semaphore_base::_M_try_acquire): Qualify to avoid ADL. (__semaphore_base::_M_release): Return old value. Remove FIXME comment. (__semaphore_impl): Replace typedef with alias template. * include/bits/version.def (semaphore): Do not depend on _GLIBCXX_HAVE_POSIX_SEMAPHORE. * include/bits/version.h: Regenerate. * include/std/semaphore (semaphore): Adjust type of _M_sem member. Add constexpr to constructor. Add assertions to (semaphore::semaphore(ptrdiff_t)): Add constexpr. Add assertion for precondition. (semaphore::release): Add assertion using value returned from _M_release. * testsuite/30_threads/semaphore/100806.cc: Increase template argument for std::counting_semaphore, so constructor precondition is met. * testsuite/30_threads/semaphore/cons.cc: New test. * testsuite/30_threads/semaphore/try_acquire_posix.cc: Remove. * testsuite/30_threads/semaphore/platform_try_acquire_for.cc: Removed.
This commit is contained in:
committed by
Jonathan Wakely
parent
42fc1e9712
commit
3e9fff1b7f
@@ -4293,43 +4293,6 @@ AC_DEFUN([GLIBCXX_CHECK_GTHREADS], [
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_CHECK_HEADER(semaphore.h, [
|
||||
AC_MSG_CHECKING([for POSIX Semaphores and sem_timedwait])
|
||||
AC_TRY_COMPILE([
|
||||
#include <unistd.h>
|
||||
#include <semaphore.h>
|
||||
#include <limits.h>
|
||||
],
|
||||
[
|
||||
#if !defined _POSIX_TIMEOUTS || _POSIX_TIMEOUTS <= 0
|
||||
# error "POSIX Timeouts option not supported"
|
||||
#elif !defined _POSIX_SEMAPHORES || _POSIX_SEMAPHORES <= 0
|
||||
# error "POSIX Semaphores option not supported"
|
||||
#else
|
||||
#if defined SEM_VALUE_MAX
|
||||
constexpr int sem_value_max = SEM_VALUE_MAX;
|
||||
#elif defined _POSIX_SEM_VALUE_MAX
|
||||
constexpr int sem_value_max = _POSIX_SEM_VALUE_MAX;
|
||||
#else
|
||||
# error "SEM_VALUE_MAX not available"
|
||||
#endif
|
||||
sem_t sem;
|
||||
sem_init(&sem, 0, sem_value_max);
|
||||
struct timespec ts = { 0 };
|
||||
sem_timedwait(&sem, &ts);
|
||||
#endif
|
||||
],
|
||||
[ac_have_posix_semaphore=yes],
|
||||
[ac_have_posix_semaphore=no])],
|
||||
[ac_have_posix_semaphore=no])
|
||||
|
||||
if test $ac_have_posix_semaphore = yes ; then
|
||||
AC_DEFINE(HAVE_POSIX_SEMAPHORE,
|
||||
1,
|
||||
[Define to 1 if POSIX Semaphores with sem_timedwait are available in <semaphore.h>.])
|
||||
fi
|
||||
AC_MSG_RESULT([$ac_have_posix_semaphore])
|
||||
|
||||
CXXFLAGS="$ac_save_CXXFLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
|
||||
@@ -314,10 +314,6 @@
|
||||
/* Define to 1 if you have the `posix_memalign' function. */
|
||||
#undef HAVE_POSIX_MEMALIGN
|
||||
|
||||
/* Define to 1 if POSIX Semaphores with sem_timedwait are available in
|
||||
<semaphore.h>. */
|
||||
#undef HAVE_POSIX_SEMAPHORE
|
||||
|
||||
/* Define to 1 if you have the `powf' function. */
|
||||
#undef HAVE_POWF
|
||||
|
||||
|
||||
60
libstdc++-v3/configure
vendored
60
libstdc++-v3/configure
vendored
@@ -51990,64 +51990,6 @@ fi
|
||||
fi
|
||||
fi
|
||||
|
||||
ac_fn_cxx_check_header_mongrel "$LINENO" "semaphore.h" "ac_cv_header_semaphore_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_semaphore_h" = xyes; then :
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for POSIX Semaphores and sem_timedwait" >&5
|
||||
$as_echo_n "checking for POSIX Semaphores and sem_timedwait... " >&6; }
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
#include <unistd.h>
|
||||
#include <semaphore.h>
|
||||
#include <limits.h>
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
#if !defined _POSIX_TIMEOUTS || _POSIX_TIMEOUTS <= 0
|
||||
# error "POSIX Timeouts option not supported"
|
||||
#elif !defined _POSIX_SEMAPHORES || _POSIX_SEMAPHORES <= 0
|
||||
# error "POSIX Semaphores option not supported"
|
||||
#else
|
||||
#if defined SEM_VALUE_MAX
|
||||
constexpr int sem_value_max = SEM_VALUE_MAX;
|
||||
#elif defined _POSIX_SEM_VALUE_MAX
|
||||
constexpr int sem_value_max = _POSIX_SEM_VALUE_MAX;
|
||||
#else
|
||||
# error "SEM_VALUE_MAX not available"
|
||||
#endif
|
||||
sem_t sem;
|
||||
sem_init(&sem, 0, sem_value_max);
|
||||
struct timespec ts = { 0 };
|
||||
sem_timedwait(&sem, &ts);
|
||||
#endif
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_cxx_try_compile "$LINENO"; then :
|
||||
ac_have_posix_semaphore=yes
|
||||
else
|
||||
ac_have_posix_semaphore=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
else
|
||||
ac_have_posix_semaphore=no
|
||||
fi
|
||||
|
||||
|
||||
|
||||
if test $ac_have_posix_semaphore = yes ; then
|
||||
|
||||
$as_echo "#define HAVE_POSIX_SEMAPHORE 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_have_posix_semaphore" >&5
|
||||
$as_echo "$ac_have_posix_semaphore" >&6; }
|
||||
|
||||
CXXFLAGS="$ac_save_CXXFLAGS"
|
||||
ac_ext=c
|
||||
ac_cpp='$CPP $CPPFLAGS'
|
||||
@@ -53601,7 +53543,7 @@ $as_echo "$glibcxx_cv_libbacktrace_atomics" >&6; }
|
||||
CXXFLAGS='-O0 -S'
|
||||
|
||||
cat > conftest.$ac_ext << EOF
|
||||
#line 53604 "configure"
|
||||
#line 53546 "configure"
|
||||
#include <stddef.h>
|
||||
int main()
|
||||
{
|
||||
|
||||
@@ -34,162 +34,44 @@
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include <bits/version.h>
|
||||
|
||||
#ifdef __glibcxx_semaphore // C++ >= 20 && hosted && atomic_wait
|
||||
#include <bits/atomic_base.h>
|
||||
#include <bits/chrono.h>
|
||||
#if __glibcxx_atomic_wait
|
||||
#include <bits/atomic_timed_wait.h>
|
||||
#include <ext/numeric_traits.h>
|
||||
#endif // __cpp_lib_atomic_wait
|
||||
|
||||
#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
|
||||
# include <cerrno> // errno, EINTR, EAGAIN etc.
|
||||
# include <limits.h> // SEM_VALUE_MAX
|
||||
# include <semaphore.h> // sem_t, sem_init, sem_wait, sem_post etc.
|
||||
#elif defined(_GLIBCXX_USE_POSIX_SEMAPHORE)
|
||||
# warning "POSIX semaphore not available, ignoring _GLIBCXX_USE_POSIX_SEMAPHORE"
|
||||
# undef _GLIBCXX_USE_POSIX_SEMAPHORE
|
||||
#endif
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
{
|
||||
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
||||
#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
|
||||
struct __platform_semaphore
|
||||
template<bool _Platform_wait>
|
||||
struct __semaphore_base
|
||||
{
|
||||
using __clock_t = chrono::system_clock;
|
||||
#ifdef SEM_VALUE_MAX
|
||||
static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
|
||||
#else
|
||||
static constexpr ptrdiff_t _S_max = _POSIX_SEM_VALUE_MAX;
|
||||
#endif
|
||||
using __count_type = __conditional_t<_Platform_wait,
|
||||
__detail::__platform_wait_t,
|
||||
ptrdiff_t>;
|
||||
|
||||
explicit __platform_semaphore(ptrdiff_t __count) noexcept
|
||||
{
|
||||
sem_init(&_M_semaphore, 0, __count);
|
||||
}
|
||||
static constexpr ptrdiff_t _S_max
|
||||
= __gnu_cxx::__int_traits<__count_type>::__max;
|
||||
|
||||
__platform_semaphore(const __platform_semaphore&) = delete;
|
||||
__platform_semaphore& operator=(const __platform_semaphore&) = delete;
|
||||
constexpr explicit
|
||||
__semaphore_base(__count_type __count) noexcept
|
||||
: _M_counter(__count)
|
||||
{ }
|
||||
|
||||
~__platform_semaphore()
|
||||
{ sem_destroy(&_M_semaphore); }
|
||||
__semaphore_base(const __semaphore_base&) = delete;
|
||||
__semaphore_base& operator=(const __semaphore_base&) = delete;
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
_M_acquire() noexcept
|
||||
{
|
||||
while (sem_wait(&_M_semaphore))
|
||||
if (errno != EINTR)
|
||||
std::__terminate();
|
||||
}
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE bool
|
||||
_M_try_acquire() noexcept
|
||||
{
|
||||
while (sem_trywait(&_M_semaphore))
|
||||
{
|
||||
if (errno == EAGAIN) // already locked
|
||||
return false;
|
||||
else if (errno != EINTR)
|
||||
std::__terminate();
|
||||
// else got EINTR so retry
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
_M_release(ptrdiff_t __update) noexcept
|
||||
{
|
||||
for(; __update != 0; --__update)
|
||||
if (sem_post(&_M_semaphore))
|
||||
std::__terminate();
|
||||
}
|
||||
|
||||
bool
|
||||
_M_try_acquire_until_impl(const chrono::time_point<__clock_t>& __atime)
|
||||
noexcept
|
||||
{
|
||||
auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
|
||||
auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
|
||||
|
||||
struct timespec __ts =
|
||||
{
|
||||
static_cast<std::time_t>(__s.time_since_epoch().count()),
|
||||
static_cast<long>(__ns.count())
|
||||
};
|
||||
|
||||
while (sem_timedwait(&_M_semaphore, &__ts))
|
||||
{
|
||||
if (errno == ETIMEDOUT)
|
||||
return false;
|
||||
else if (errno != EINTR)
|
||||
std::__terminate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename _Clock, typename _Duration>
|
||||
bool
|
||||
_M_try_acquire_until(const chrono::time_point<_Clock,
|
||||
_Duration>& __atime) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<__clock_t, _Clock>)
|
||||
{
|
||||
using _Dur = __clock_t::duration;
|
||||
return _M_try_acquire_until_impl(chrono::ceil<_Dur>(__atime));
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: if _Clock is monotonic_clock we could use
|
||||
// sem_clockwait with CLOCK_MONOTONIC.
|
||||
|
||||
const typename _Clock::time_point __c_entry = _Clock::now();
|
||||
const auto __s_entry = __clock_t::now();
|
||||
const auto __delta = __atime - __c_entry;
|
||||
const auto __s_atime = __s_entry + __delta;
|
||||
if (_M_try_acquire_until_impl(__s_atime))
|
||||
return true;
|
||||
|
||||
// We got a timeout when measured against __clock_t but
|
||||
// we need to check against the caller-supplied clock
|
||||
// to tell whether we should return a timeout.
|
||||
return (_Clock::now() < __atime);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _Rep, typename _Period>
|
||||
_GLIBCXX_ALWAYS_INLINE bool
|
||||
_M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime)
|
||||
noexcept
|
||||
{ return _M_try_acquire_until(__clock_t::now() + __rtime); }
|
||||
|
||||
private:
|
||||
sem_t _M_semaphore;
|
||||
};
|
||||
#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
|
||||
|
||||
#if __glibcxx_atomic_wait
|
||||
struct __atomic_semaphore
|
||||
{
|
||||
static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<int>::__max;
|
||||
explicit __atomic_semaphore(__detail::__platform_wait_t __count) noexcept
|
||||
: _M_counter(__count)
|
||||
{
|
||||
__glibcxx_assert(__count >= 0 && __count <= _S_max);
|
||||
}
|
||||
|
||||
__atomic_semaphore(const __atomic_semaphore&) = delete;
|
||||
__atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
|
||||
|
||||
static _GLIBCXX_ALWAYS_INLINE __detail::__platform_wait_t
|
||||
_S_get_current(__detail::__platform_wait_t* __counter) noexcept
|
||||
static _GLIBCXX_ALWAYS_INLINE __count_type
|
||||
_S_get_current(__count_type* __counter) noexcept
|
||||
{
|
||||
return __atomic_impl::load(__counter, memory_order::acquire);
|
||||
}
|
||||
|
||||
static _GLIBCXX_ALWAYS_INLINE bool
|
||||
_S_do_try_acquire(__detail::__platform_wait_t* __counter,
|
||||
__detail::__platform_wait_t __old) noexcept
|
||||
_S_do_try_acquire(__count_type* __counter, __count_type __old) noexcept
|
||||
{
|
||||
if (__old == 0)
|
||||
return false;
|
||||
@@ -204,8 +86,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
_M_acquire() noexcept
|
||||
{
|
||||
auto const __vfn = [this]{ return _S_get_current(&this->_M_counter); };
|
||||
auto const __pred = [this](__detail::__platform_wait_t __cur)
|
||||
{ return _S_do_try_acquire(&this->_M_counter, __cur); };
|
||||
auto const __pred = [this](__count_type __cur) {
|
||||
return _S_do_try_acquire(&this->_M_counter, __cur);
|
||||
};
|
||||
std::__atomic_wait_address(&_M_counter, __pred, __vfn, true);
|
||||
}
|
||||
|
||||
@@ -213,23 +96,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
_M_try_acquire() noexcept
|
||||
{
|
||||
auto const __vfn = [this]{ return _S_get_current(&this->_M_counter); };
|
||||
auto const __pred = [this](__detail::__platform_wait_t __cur)
|
||||
{ return _S_do_try_acquire(&this->_M_counter, __cur); };
|
||||
return __atomic_wait_address_for(&_M_counter, __pred, __vfn,
|
||||
__detail::__wait_clock_t::duration(),
|
||||
true);
|
||||
auto const __pred = [this](__count_type __cur) {
|
||||
return _S_do_try_acquire(&this->_M_counter, __cur);
|
||||
};
|
||||
using __detail::__wait_clock_t;
|
||||
return std::__atomic_wait_address_for(&_M_counter, __pred, __vfn,
|
||||
__wait_clock_t::duration(),
|
||||
true);
|
||||
}
|
||||
|
||||
template<typename _Clock, typename _Duration>
|
||||
_GLIBCXX_ALWAYS_INLINE bool
|
||||
_M_try_acquire_until(const chrono::time_point<_Clock,
|
||||
_Duration>& __atime) noexcept
|
||||
_M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
|
||||
{
|
||||
auto const __vfn = [this]{ return _S_get_current(&this->_M_counter); };
|
||||
auto const __pred = [this](__detail::__platform_wait_t __cur)
|
||||
{ return _S_do_try_acquire(&this->_M_counter, __cur); };
|
||||
return std::__atomic_wait_address_until(&_M_counter,
|
||||
__pred, __vfn, __atime, true);
|
||||
auto const __pred = [this](__count_type __cur) {
|
||||
return _S_do_try_acquire(&this->_M_counter, __cur);
|
||||
};
|
||||
return std::__atomic_wait_address_until(&_M_counter, __pred, __vfn,
|
||||
__atime, true);
|
||||
}
|
||||
|
||||
template<typename _Rep, typename _Period>
|
||||
@@ -237,39 +122,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
_M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
|
||||
{
|
||||
auto const __vfn = [this]{ return _S_get_current(&this->_M_counter); };
|
||||
auto const __pred = [this](__detail::__platform_wait_t __cur)
|
||||
{ return _S_do_try_acquire(&this->_M_counter, __cur); };
|
||||
return std::__atomic_wait_address_for(&_M_counter,
|
||||
__pred, __vfn, __rtime, true);
|
||||
auto const __pred = [this](__count_type __cur) {
|
||||
return _S_do_try_acquire(&this->_M_counter, __cur);
|
||||
};
|
||||
return std::__atomic_wait_address_for(&_M_counter, __pred, __vfn,
|
||||
__rtime, true);
|
||||
}
|
||||
|
||||
_GLIBCXX_ALWAYS_INLINE void
|
||||
_GLIBCXX_ALWAYS_INLINE ptrdiff_t
|
||||
_M_release(ptrdiff_t __update) noexcept
|
||||
{
|
||||
if (0 < __atomic_impl::fetch_add(&_M_counter, __update, memory_order_release))
|
||||
return;
|
||||
if (__update > 1)
|
||||
auto __old = __atomic_impl::fetch_add(&_M_counter, __update,
|
||||
memory_order::release);
|
||||
if (__old == 0 && __update > 0)
|
||||
__atomic_notify_address(&_M_counter, true, true);
|
||||
else
|
||||
__atomic_notify_address(&_M_counter, true, true);
|
||||
// FIXME - Figure out why this does not wake a waiting thread
|
||||
// __atomic_notify_address_bare(&_M_counter, false);
|
||||
return __old;
|
||||
}
|
||||
|
||||
private:
|
||||
alignas(__detail::__platform_wait_alignment)
|
||||
__detail::__platform_wait_t _M_counter;
|
||||
alignas(_Platform_wait ? __detail::__platform_wait_alignment
|
||||
: __alignof__(__count_type))
|
||||
__count_type _M_counter;
|
||||
};
|
||||
#endif // __cpp_lib_atomic_wait
|
||||
|
||||
// Note: the _GLIBCXX_USE_POSIX_SEMAPHORE macro can be used to force the
|
||||
// use of Posix semaphores (sem_t). Doing so however, alters the ABI.
|
||||
#if defined __glibcxx_atomic_wait && !_GLIBCXX_USE_POSIX_SEMAPHORE
|
||||
using __semaphore_impl = __atomic_semaphore;
|
||||
#elif _GLIBCXX_HAVE_POSIX_SEMAPHORE
|
||||
using __semaphore_impl = __platform_semaphore;
|
||||
#endif
|
||||
template<ptrdiff_t _Max>
|
||||
using __semaphore_impl
|
||||
= __semaphore_base<(_Max <= __semaphore_base<true>::_S_max)>;
|
||||
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace std
|
||||
#endif // __glibcxx_semaphore
|
||||
#endif // _GLIBCXX_SEMAPHORE_BASE_H
|
||||
|
||||
@@ -1363,7 +1363,7 @@ ftms = {
|
||||
v = 201907;
|
||||
cxxmin = 20;
|
||||
hosted = yes;
|
||||
extra_cond = "__glibcxx_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE";
|
||||
extra_cond = "__glibcxx_atomic_wait";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1499,7 +1499,7 @@
|
||||
#undef __glibcxx_want_move_iterator_concept
|
||||
|
||||
#if !defined(__cpp_lib_semaphore)
|
||||
# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED && (__glibcxx_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE)
|
||||
# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED && (__glibcxx_atomic_wait)
|
||||
# define __glibcxx_semaphore 201907L
|
||||
# if defined(__glibcxx_want_all) || defined(__glibcxx_want_semaphore)
|
||||
# define __cpp_lib_semaphore 201907L
|
||||
|
||||
@@ -35,29 +35,29 @@
|
||||
|
||||
#include <bits/requires_hosted.h> // concurrency
|
||||
|
||||
#if __cplusplus > 201703L
|
||||
#include <bits/semaphore_base.h>
|
||||
|
||||
#define __glibcxx_want_semaphore
|
||||
#include <bits/version.h>
|
||||
|
||||
#ifdef __cpp_lib_semaphore // C++ >= 20 && hosted && (atomic_wait || posix_sem)
|
||||
#ifdef __cpp_lib_semaphore // C++ >= 20 && hosted && atomic_wait
|
||||
#include <bits/semaphore_base.h>
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
{
|
||||
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
||||
template<ptrdiff_t __least_max_value = __semaphore_impl::_S_max>
|
||||
template<ptrdiff_t __least_max_value = __semaphore_base<true>::_S_max>
|
||||
class counting_semaphore
|
||||
{
|
||||
static_assert(__least_max_value >= 0);
|
||||
static_assert(__least_max_value <= __semaphore_impl::_S_max);
|
||||
|
||||
__semaphore_impl _M_sem;
|
||||
using _Impl = __semaphore_impl<__least_max_value>;
|
||||
_Impl _M_sem;
|
||||
|
||||
public:
|
||||
explicit counting_semaphore(ptrdiff_t __desired) noexcept
|
||||
: _M_sem(__desired)
|
||||
{ }
|
||||
constexpr explicit
|
||||
counting_semaphore(ptrdiff_t __desired) noexcept
|
||||
: _M_sem(__desired)
|
||||
{ __glibcxx_assert(__desired >= 0 && __desired <= max()); }
|
||||
|
||||
~counting_semaphore() = default;
|
||||
|
||||
@@ -69,8 +69,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
{ return __least_max_value; }
|
||||
|
||||
void
|
||||
release(ptrdiff_t __update = 1) noexcept(noexcept(_M_sem._M_release(1)))
|
||||
{ _M_sem._M_release(__update); }
|
||||
release(ptrdiff_t __update = 1) noexcept
|
||||
{
|
||||
[[maybe_unused]] ptrdiff_t __old = _M_sem._M_release(__update);
|
||||
__glibcxx_assert(__update >= 0 && __update <= max() - __old);
|
||||
}
|
||||
|
||||
void
|
||||
acquire() noexcept(noexcept(_M_sem._M_acquire()))
|
||||
@@ -91,10 +94,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
{ return _M_sem._M_try_acquire_until(__atime); }
|
||||
};
|
||||
|
||||
/** @brief A binary semaphore
|
||||
*
|
||||
* @since C++20
|
||||
*/
|
||||
using binary_semaphore = std::counting_semaphore<1>;
|
||||
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace
|
||||
#endif // cpp_lib_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE
|
||||
#endif // __cpp_lib_semaphore
|
||||
#endif // _GLIBCXX_SEMAPHORE
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
|
||||
std::counting_semaphore<4> semaphore{6};
|
||||
std::counting_semaphore<6> semaphore{6};
|
||||
|
||||
std::mutex mtx;
|
||||
std::vector<std::string> results;
|
||||
|
||||
7
libstdc++-v3/testsuite/30_threads/semaphore/cons.cc
Normal file
7
libstdc++-v3/testsuite/30_threads/semaphore/cons.cc
Normal file
@@ -0,0 +1,7 @@
|
||||
// { dg-do compile { target c++20 } }
|
||||
|
||||
#include <semaphore>
|
||||
|
||||
// PR 110854 Constructor of std::counting_semaphore is not constexpr
|
||||
constinit std::binary_semaphore b(0);
|
||||
constinit std::counting_semaphore<5> c(2);
|
||||
@@ -1,9 +0,0 @@
|
||||
// { dg-options "-D_GLIBCXX_USE_POSIX_SEMAPHORE" }
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-additional-options "-pthread" { target pthread } }
|
||||
// { dg-require-gthreads "" }
|
||||
// { dg-add-options libatomic }
|
||||
|
||||
#include "try_acquire_for.cc"
|
||||
|
||||
// { dg-prune-output "ignoring _GLIBCXX_USE_POSIX_SEMAPHORE" }
|
||||
@@ -1,153 +0,0 @@
|
||||
// Copyright (C) 2020-2025 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-do run { target c++20 } }
|
||||
// { dg-additional-options "-pthread" { target pthread } }
|
||||
// { dg-require-gthreads "" }
|
||||
// { dg-add-options libatomic }
|
||||
|
||||
#include <semaphore>
|
||||
#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void test01()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
std::__platform_semaphore s(2);
|
||||
s._M_acquire();
|
||||
|
||||
auto const dur = 250ms;
|
||||
{
|
||||
auto const t0 = std::chrono::steady_clock::now();
|
||||
VERIFY( s._M_try_acquire_for(dur) );
|
||||
auto const diff = std::chrono::steady_clock::now() - t0;
|
||||
VERIFY( diff < dur );
|
||||
}
|
||||
|
||||
{
|
||||
auto const t0 = std::chrono::steady_clock::now();
|
||||
VERIFY( !s._M_try_acquire_for(dur) );
|
||||
auto const diff = std::chrono::steady_clock::now() - t0;
|
||||
VERIFY( diff >= dur );
|
||||
}
|
||||
}
|
||||
|
||||
void test02()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
std::__platform_semaphore s(1);
|
||||
std::atomic<int> a(0), b(0);
|
||||
std::thread t([&] {
|
||||
a.wait(0);
|
||||
auto const dur = 250ms;
|
||||
VERIFY( !s._M_try_acquire_for(dur) );
|
||||
b++;
|
||||
b.notify_one();
|
||||
|
||||
a.wait(1);
|
||||
VERIFY( s._M_try_acquire_for(dur) );
|
||||
b++;
|
||||
b.notify_one();
|
||||
});
|
||||
t.detach();
|
||||
|
||||
s._M_acquire();
|
||||
a++;
|
||||
a.notify_one();
|
||||
b.wait(0);
|
||||
s._M_release(1);
|
||||
a++;
|
||||
a.notify_one();
|
||||
|
||||
b.wait(1);
|
||||
}
|
||||
|
||||
void test03()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
std::__platform_semaphore s(2);
|
||||
s._M_acquire();
|
||||
|
||||
auto const dur = 250ms;
|
||||
{
|
||||
auto const at = std::chrono::system_clock::now() + dur;
|
||||
auto const t0 = std::chrono::steady_clock::now();
|
||||
VERIFY( s._M_try_acquire_until(at) );
|
||||
auto const diff = std::chrono::steady_clock::now() - t0;
|
||||
VERIFY( diff < dur );
|
||||
}
|
||||
|
||||
{
|
||||
auto const at = std::chrono::system_clock::now() + dur;
|
||||
auto const t0 = std::chrono::steady_clock::now();
|
||||
VERIFY( !s._M_try_acquire_until(at) );
|
||||
auto const diff = std::chrono::steady_clock::now() - t0;
|
||||
VERIFY( diff >= dur );
|
||||
}
|
||||
}
|
||||
|
||||
void test04()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
std::__platform_semaphore s(1);
|
||||
std::atomic<int> a(0), b(0);
|
||||
std::thread t([&] {
|
||||
a.wait(0);
|
||||
auto const dur = 250ms;
|
||||
{
|
||||
auto const at = std::chrono::system_clock::now() + dur;
|
||||
VERIFY( !s._M_try_acquire_until(at) );
|
||||
|
||||
b++;
|
||||
b.notify_one();
|
||||
}
|
||||
|
||||
a.wait(1);
|
||||
{
|
||||
auto const at = std::chrono::system_clock::now() + dur;
|
||||
VERIFY( s._M_try_acquire_until(at) );
|
||||
}
|
||||
b++;
|
||||
b.notify_one();
|
||||
});
|
||||
t.detach();
|
||||
|
||||
s._M_acquire();
|
||||
a++;
|
||||
a.notify_one();
|
||||
b.wait(0);
|
||||
s._M_release(1);
|
||||
a++;
|
||||
a.notify_one();
|
||||
|
||||
b.wait(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
|
||||
test01();
|
||||
test02();
|
||||
test03();
|
||||
test04();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user