public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
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


  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).