From: Jonathan Wakely <jwakely@redhat.com>
To: Thomas Rodgers <rodgert@appliantology.com>
Cc: gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org, trodgers@redhat.com
Subject: Re: [PATCH] t/trodgers/c2a_synchronization
Date: Fri, 23 Oct 2020 11:28:59 +0100 [thread overview]
Message-ID: <20201023102859.GA1525304@redhat.com> (raw)
In-Reply-To: <20201005225456.2168842-1-rodgert@appliantology.com>
On 05/10/20 15:54 -0700, Thomas Rodgers wrote:
>From: Thomas Rodgers <trodgers@redhat.com>
>
>This *should* be the correct patch this time.
There are still some review comments not addressed. I'll keep all my
comments on this version in a single reply, so they aren't lost among
multiple replies.
I think the significant issues like the handling of spurious wakeups
and the missing "no effects" case in _M_try_acquire() are resolved,
thanks.
>diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
>new file mode 100644
>index 00000000000..cd5b6aabc44
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
[...]
>+ struct __timed_waiters : __waiters
>+ {
>+ template<typename _Clock, typename _Duration>
>+ __atomic_wait_status
>+ _M_do_wait_until(__platform_wait_t __version,
>+ const chrono::time_point<_Clock, _Duration>& __atime)
>+ {
>+#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
>+ return __platform_wait_until(&_M_ver, __version, __atime);
Qualify to prevent ADL in associated namespaces of the _Clock and
_Duration types.
>+ template<typename _Tp, typename _Pred,
>+ typename _Clock, typename _Duration>
>+ bool
>+ __atomic_wait_until(const _Tp* __addr, _Tp __old, _Pred __pred,
>+ const chrono::time_point<_Clock, _Duration>&
>+ __atime) noexcept
>+ {
>+ using namespace __detail;
>+
>+ if (std::__atomic_spin(__pred))
>+ return true;
>+
>+ auto& __w = __timed_waiters::_S_timed_for((void*)__addr);
>+ auto __version = __w._M_enter_wait();
>+ do
>+ {
>+ __atomic_wait_status __res;
>+ if constexpr (__platform_wait_uses_type<_Tp>)
>+ {
>+ __res = __platform_wait_until((__platform_wait_t*)(void*) __addr,
Qualify to prevent ADL.
>diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
>new file mode 100644
>index 00000000000..30f682e828a
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/atomic_wait.h
>+ template<typename _Tp, typename _Pred>
>+ void
>+ __atomic_wait(const _Tp* __addr, _Tp __old, _Pred __pred) noexcept
>+ {
>+ using namespace __detail;
>+ if (__atomic_spin(__pred))
Qualify to prevent ADL.
>diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
>new file mode 100644
>index 00000000000..a32a6b12a1b
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/semaphore_base.h
>@@ -0,0 +1,298 @@
>+// -*- C++ -*- header.
>+
>+// Copyright (C) 2020 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.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file bits/semaphore_base.h
>+ * This is an internal header file, included by other library headers.
>+ * Do not attempt to use it directly. @headername{semaphore}
>+ */
>+
>+#ifndef _GLIBCXX_SEMAPHORE_BASE_H
>+#define _GLIBCXX_SEMAPHORE_BASE_H 1
>+
>+#pragma GCC system_header
>+
>+#include <bits/c++config.h>
>+#include <bits/atomic_base.h>
>+#include <bits/atomic_timed_wait.h>
>+
>+#include <ext/numeric_traits.h>
>+
>+#if __has_include(<semaphore.h>)
>+#define _GLIBCXX_HAVE_POSIX_SEMAPHORE 1
>+#include <semaphore.h>
>+#endif
>+
>+#include <chrono>
>+#include <type_traits>
>+
>+#include <iostream>
This shouldn't be here.
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
>+ struct __platform_semaphore
>+ {
>+ using __clock_t = chrono::system_clock;
>+ static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
>+
>+ explicit __platform_semaphore(ptrdiff_t __count) noexcept
>+ {
>+ sem_init(&_M_semaphore, 0, __count);
>+ }
>+
>+ __platform_semaphore(const __platform_semaphore&) = delete;
>+ __platform_semaphore& operator=(const __platform_semaphore&) = delete;
>+
>+ ~__platform_semaphore()
>+ { sem_destroy(&_M_semaphore); }
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ _M_acquire() noexcept
>+ {
>+ for (;;)
>+ {
>+ auto __err = sem_wait(&_M_semaphore);
>+ if (__err && (errno == EINTR))
>+ continue;
>+ else if (__err)
>+ std::terminate();
>+ else
>+ break;
>+ }
>+ }
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ _M_release(std::ptrdiff_t __update) noexcept
>+ {
>+ for(; __update != 0; --__update)
>+ {
>+ auto __err = sem_post(&_M_semaphore);
>+ if (__err)
>+ 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())
>+ };
>+
>+ for (;;)
>+ {
>+ auto __err = sem_timedwait(&_M_semaphore, &__ts);
>+ if (__err && (errno == EINTR))
>+ continue;
>+ else if (__err && (errno == ETIMEDOUT))
>+ return false;
>+ else if (__err && (errno == EINVAL))
>+ return false; // caller supplied an invalid __atime
>+ else if (__err)
>+ std::terminate();
>+ else
>+ break;
It looks like this would be simpler with just one check for __err:
auto __err = sem_timedwait(&_M_semaphore, &__ts);
if (__err)
{
if (errno == EINTR)
continue;
if (errno == ETIMEDOUT || errno == EINVAL)
return false;
else
std::terminate();
}
else
break;
Hopefully the compiler wouldn't actually keep testing __err but I think
it reads better this way anyway.
>+ }
>+ 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<__clock_t, _Clock>::value)
is_same_v (it's not just stylistic, the variable template is faster to
compile than the class template).
>+ {
>+ return _M_try_acquire_until_impl(__atime);
>+ }
>+ else
>+ {
>+ const typename _Clock::time_point __c_entry = _Clock::now();
>+ const __clock_t __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
>+
>+ template<typename _Tp>
>+ struct __atomic_semaphore
>+ {
>+ static_assert(std::is_integral_v<_Tp>);
>+ static_assert(__gnu_cxx::__int_traits<_Tp>::__max
>+ <= __gnu_cxx::__int_traits<ptrdiff_t>::__max);
>+ static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<_Tp>::__max;
>+
>+ explicit __atomic_semaphore(_Tp __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;
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ _M_acquire() noexcept
>+ {
>+ auto const __pred = [this]
>+ {
>+ auto __old = __atomic_impl::load(&this->_M_counter,
>+ memory_order::acquire);
>+ if (__old == 0)
>+ return false;
>+ return __atomic_impl::compare_exchange_strong(&this->_M_counter,
>+ __old, __old - 1,
>+ memory_order::acquire,
>+ memory_order::release);
>+ };
>+ auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
>+ __atomic_wait(&_M_counter, __old, __pred);
Qualify to prevent ADL.
>--- /dev/null
>+++ b/libstdc++-v3/include/std/latch
>@@ -0,0 +1,91 @@
>+// <latch> -*- C++ -*-
>+
>+// Copyright (C) 2020 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.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file include/latch
>+ * This is a Standard C++ Library header.
>+ */
>+
>+#ifndef _GLIBCXX_LATCH
>+#define _GLIBCXX_LATCH
>+
>+#pragma GCC system_header
>+
>+#if __cplusplus > 201703L
>+#define __cpp_lib_latch 201907L
>+
>+#include <bits/atomic_base.h>
>+#include <ext/numeric_traits.h>
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+ class latch
>+ {
>+ public:
>+ static constexpr ptrdiff_t
>+ max() noexcept
>+ { return __gnu_cxx::__int_traits<ptrdiff_t>::__max; }
>+
>+ constexpr explicit latch(ptrdiff_t __expected) noexcept
>+ : _M_a(__expected) { }
>+
>+ ~latch() = default;
>+ latch(const latch&) = delete;
>+ latch& operator=(const latch&) = delete;
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ count_down(ptrdiff_t __update = 1)
>+ {
>+ auto const __old = __atomic_impl::fetch_sub(&_M_a,
>+ __update, memory_order::release);
>+ if (__old == __update)
>+ __atomic_impl::notify_all(&_M_a);
>+ }
>+
>+ _GLIBCXX_ALWAYS_INLINE bool
>+ try_wait() const noexcept
>+ { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; }
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ wait() const noexcept
>+ {
>+ auto const __old = __atomic_impl::load(&_M_a, memory_order::acquire);
>+ __atomic_wait(&_M_a, __old, [this] { return this->try_wait(); });
Qualify to prevent ADL.
>+ }
>+
>+ _GLIBCXX_ALWAYS_INLINE void
>+ arrive_and_wait(ptrdiff_t __update = 1) noexcept
>+ {
>+ count_down(__update);
>+ wait();
>+ }
>+
>+ private:
>+ alignas(__alignof__(ptrdiff_t)) ptrdiff_t _M_a;
>+ };
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace
>+#endif // __cplusplus > 201703L
>+#endif // _GLIBCXX_LATCH
next prev parent reply other threads:[~2020-10-23 10:29 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-05-10 0:01 [PATCH] Add C++2a synchronization support Thomas Rodgers
2020-05-11 14:05 ` Jonathan Wakely
2020-05-11 15:43 ` Thomas Rodgers
2020-05-11 17:05 ` Jonathan Wakely
2020-05-11 20:59 ` Thomas Rodgers
2020-05-23 22:52 ` Thomas Rodgers
2020-05-24 17:41 ` Thomas Rodgers
2020-06-06 0:29 ` Thomas Rodgers
2020-07-08 16:43 ` Jonathan Wakely
2020-08-03 14:09 ` Jonathan Wakely
2020-08-03 20:19 ` Jonathan Wakely
2020-09-03 0:47 ` Thomas Rodgers
2020-09-03 0:54 ` Thomas Rodgers
2020-09-11 23:58 ` [PATCH] libstdc++: " Thomas Rodgers
2020-09-28 13:25 ` Jonathan Wakely
2020-10-01 23:37 ` Thomas Rodgers
2020-10-02 15:40 ` Thomas Rodgers
2020-10-05 22:54 ` [PATCH] t/trodgers/c2a_synchronization Thomas Rodgers
2020-10-23 10:28 ` Jonathan Wakely [this message]
2020-10-26 21:48 ` [PATCH] libstdc++: Add C++2a synchronization support Thomas Rodgers
2020-10-27 10:23 ` Jonathan Wakely
2020-11-20 22:44 ` Thomas Rodgers
2020-11-22 21:13 ` Stephan Bergmann
2020-11-23 18:33 ` Jonathan Wakely
2020-11-22 21:41 ` Stephan Bergmann
2020-11-23 18:32 ` Jonathan Wakely
2020-11-21 15:16 ` Andreas Schwab
2020-11-21 17:04 ` Jonathan Wakely
2020-11-21 17:39 ` Jonathan Wakely
2020-11-22 0:36 ` H.J. Lu
2020-11-23 14:50 ` Jonathan Wakely
2020-11-24 23:45 ` Jonathan Wakely
2020-11-25 1:07 ` Jonathan Wakely
2020-11-25 10:35 ` Jonathan Wakely
2020-11-25 12:32 ` Jonathan Wakely
2020-11-25 18:39 ` Jonathan Wakely
2020-11-26 16:26 ` Jonathan Wakely
2020-11-23 16:08 ` Jonathan Wakely
2020-09-28 13:30 ` Jonathan Wakely
2020-09-28 13:36 ` Jonathan Wakely
2020-09-28 21:29 ` Thomas Rodgers
2020-09-29 9:44 ` Jonathan Wakely
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20201023102859.GA1525304@redhat.com \
--to=jwakely@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=libstdc++@gcc.gnu.org \
--cc=rodgert@appliantology.com \
--cc=trodgers@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).