]> gcc.gnu.org Git - gcc.git/blobdiff - libstdc++-v3/include/std/condition_variable
libstdc++: Fix -Wdeprecated-declarations warnings
[gcc.git] / libstdc++-v3 / include / std / condition_variable
index 71d2133a6e8509b7a587c1e216aff76cb3780698..a08cfc62705946f02a03f426656e30486c38ba63 100644 (file)
@@ -1,6 +1,6 @@
 // <condition_variable> -*- C++ -*-
 
-// Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+// Copyright (C) 2008-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
@@ -22,7 +22,7 @@
 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 // <http://www.gnu.org/licenses/>.
 
-/** @file condition_variable
+/** @file include/condition_variable
  *  This is a Standard C++ Library header.
  */
 
 
 #pragma GCC system_header
 
-#ifndef __GXX_EXPERIMENTAL_CXX0X__
+#if __cplusplus < 201103L
 # include <bits/c++0x_warning.h>
 #else
 
 #include <chrono>
-#include <mutex> // unique_lock
 
-#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
+#include <bits/std_mutex.h>
+#include <bits/unique_lock.h>
+#include <ext/concurrence.h>
+#include <bits/alloc_traits.h>
+#include <bits/allocator.h>
+#include <bits/unique_ptr.h>
+#include <bits/shared_ptr.h>
+#include <bits/cxxabi_forced.h>
 
-_GLIBCXX_BEGIN_NAMESPACE(std)
+#if __cplusplus > 201703L
+# include <stop_token>
+#endif
+
+#if defined(_GLIBCXX_HAS_GTHREADS)
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   /**
    * @defgroup condition_variables Condition Variables
@@ -52,31 +66,42 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
 
   /// cv_status
   enum class cv_status { no_timeout, timeout };
-  
+
   /// condition_variable
   class condition_variable
   {
-    typedef chrono::system_clock       __clock_t;
+    using steady_clock = chrono::steady_clock;
+    using system_clock = chrono::system_clock;
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+    using __clock_t = steady_clock;
+#else
+    using __clock_t = system_clock;
+#endif
     typedef __gthread_cond_t           __native_type;
+
+#ifdef __GTHREAD_COND_INIT
+    __native_type                      _M_cond = __GTHREAD_COND_INIT;
+#else
     __native_type                      _M_cond;
+#endif
 
   public:
     typedef __native_type*             native_handle_type;
 
-    condition_variable() throw ();
-    ~condition_variable() throw ();
+    condition_variable() noexcept;
+    ~condition_variable() noexcept;
 
     condition_variable(const condition_variable&) = delete;
     condition_variable& operator=(const condition_variable&) = delete;
 
     void
-    notify_one();
+    notify_one() noexcept;
 
     void
-    notify_all();
+    notify_all() noexcept;
 
     void
-    wait(unique_lock<mutex>& __lock);
+    wait(unique_lock<mutex>& __lock) noexcept;
 
     template<typename _Predicate>
       void
@@ -86,10 +111,18 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
          wait(__lock);
       }
 
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+    template<typename _Duration>
+      cv_status
+      wait_until(unique_lock<mutex>& __lock,
+                const chrono::time_point<steady_clock, _Duration>& __atime)
+      { return __wait_until_impl(__lock, __atime); }
+#endif
+
     template<typename _Duration>
       cv_status
       wait_until(unique_lock<mutex>& __lock,
-                const chrono::time_point<__clock_t, _Duration>& __atime)
+                const chrono::time_point<system_clock, _Duration>& __atime)
       { return __wait_until_impl(__lock, __atime); }
 
     template<typename _Clock, typename _Duration>
@@ -97,13 +130,22 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
       wait_until(unique_lock<mutex>& __lock,
                 const chrono::time_point<_Clock, _Duration>& __atime)
       {
-       // DR 887 - Sync unknown clock to known clock.
+#if __cplusplus > 201703L
+       static_assert(chrono::is_clock_v<_Clock>);
+#endif
        const typename _Clock::time_point __c_entry = _Clock::now();
        const __clock_t::time_point __s_entry = __clock_t::now();
-       const chrono::nanoseconds __delta = __atime - __c_entry;
-       const __clock_t::time_point __s_atime = __s_entry + __delta;
-
-       return __wait_until_impl(__lock, __s_atime);
+       const auto __delta = __atime - __c_entry;
+       const auto __s_atime = __s_entry + __delta;
+
+       if (__wait_until_impl(__lock, __s_atime) == cv_status::no_timeout)
+         return cv_status::no_timeout;
+       // 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.
+       if (_Clock::now() < __atime)
+         return cv_status::no_timeout;
+       return cv_status::timeout;
       }
 
     template<typename _Clock, typename _Duration, typename _Predicate>
@@ -122,30 +164,64 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
       cv_status
       wait_for(unique_lock<mutex>& __lock,
               const chrono::duration<_Rep, _Period>& __rtime)
-      { return wait_until(__lock, __clock_t::now() + __rtime); }
+      {
+       using __dur = typename steady_clock::duration;
+       auto __reltime = chrono::duration_cast<__dur>(__rtime);
+       if (__reltime < __rtime)
+         ++__reltime;
+       return wait_until(__lock, steady_clock::now() + __reltime);
+      }
 
     template<typename _Rep, typename _Period, typename _Predicate>
       bool
       wait_for(unique_lock<mutex>& __lock,
               const chrono::duration<_Rep, _Period>& __rtime,
               _Predicate __p)
-      { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
+      {
+       using __dur = typename steady_clock::duration;
+       auto __reltime = chrono::duration_cast<__dur>(__rtime);
+       if (__reltime < __rtime)
+         ++__reltime;
+       return wait_until(__lock, steady_clock::now() + __reltime,
+                         std::move(__p));
+      }
 
     native_handle_type
     native_handle()
     { return &_M_cond; }
 
   private:
-    template<typename _Clock, typename _Duration>
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+    template<typename _Dur>
       cv_status
       __wait_until_impl(unique_lock<mutex>& __lock,
-                       const chrono::time_point<_Clock, _Duration>& __atime)
+                       const chrono::time_point<steady_clock, _Dur>& __atime)
       {
-       chrono::time_point<__clock_t, chrono::seconds> __s =
-         chrono::time_point_cast<chrono::seconds>(__atime);
+       auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+       auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+
+       __gthread_time_t __ts =
+         {
+           static_cast<std::time_t>(__s.time_since_epoch().count()),
+           static_cast<long>(__ns.count())
+         };
+
+       pthread_cond_clockwait(&_M_cond, __lock.mutex()->native_handle(),
+                                        CLOCK_MONOTONIC,
+                                        &__ts);
+
+       return (steady_clock::now() < __atime
+               ? cv_status::no_timeout : cv_status::timeout);
+      }
+#endif
 
-       chrono::nanoseconds __ns =
-         chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+    template<typename _Dur>
+      cv_status
+      __wait_until_impl(unique_lock<mutex>& __lock,
+                       const chrono::time_point<system_clock, _Dur>& __atime)
+      {
+       auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
+       auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
 
        __gthread_time_t __ts =
          {
@@ -156,39 +232,82 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
        __gthread_cond_timedwait(&_M_cond, __lock.mutex()->native_handle(),
                                 &__ts);
 
-       return (_Clock::now() < __atime
+       return (system_clock::now() < __atime
                ? cv_status::no_timeout : cv_status::timeout);
       }
   };
 
+  void
+  notify_all_at_thread_exit(condition_variable&, unique_lock<mutex>);
+
+  struct __at_thread_exit_elt
+  {
+    __at_thread_exit_elt* _M_next;
+    void (*_M_cb)(void*);
+  };
+
+  inline namespace _V2 {
+
   /// condition_variable_any
   // Like above, but mutex is not required to have try_lock.
   class condition_variable_any
   {
-    typedef chrono::system_clock       __clock_t;
+#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
+    using __clock_t = chrono::steady_clock;
+#else
+    using __clock_t = chrono::system_clock;
+#endif
     condition_variable                 _M_cond;
-    mutex                              _M_mutex;
+    shared_ptr<mutex>                  _M_mutex;
 
-  public:
-    typedef condition_variable::native_handle_type     native_handle_type;
+    // scoped unlock - unlocks in ctor, re-locks in dtor
+    template<typename _Lock>
+      struct _Unlock
+      {
+       explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); }
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+       ~_Unlock() noexcept(false)
+       {
+         if (uncaught_exception())
+           {
+             __try
+             { _M_lock.lock(); }
+             __catch(const __cxxabiv1::__forced_unwind&)
+             { __throw_exception_again; }
+             __catch(...)
+             { }
+           }
+         else
+           _M_lock.lock();
+       }
+#pragma GCC diagnostic pop
+
+       _Unlock(const _Unlock&) = delete;
+       _Unlock& operator=(const _Unlock&) = delete;
+
+       _Lock& _M_lock;
+      };
 
-    condition_variable_any() throw ();
-    ~condition_variable_any() throw ();
+  public:
+    condition_variable_any() : _M_mutex(std::make_shared<mutex>()) { }
+    ~condition_variable_any() = default;
 
     condition_variable_any(const condition_variable_any&) = delete;
     condition_variable_any& operator=(const condition_variable_any&) = delete;
 
     void
-    notify_one()
+    notify_one() noexcept
     {
-      lock_guard<mutex> __lock(_M_mutex);
+      lock_guard<mutex> __lock(*_M_mutex);
       _M_cond.notify_one();
     }
 
     void
-    notify_all()
+    notify_all() noexcept
     {
-      lock_guard<mutex> __lock(_M_mutex);
+      lock_guard<mutex> __lock(*_M_mutex);
       _M_cond.notify_all();
     }
 
@@ -196,12 +315,15 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
       void
       wait(_Lock& __lock)
       {
-        unique_lock<mutex> __my_lock(_M_mutex);
-        __lock.unlock();
-        _M_cond.wait(__my_lock);
-        __lock.lock();
+       shared_ptr<mutex> __mutex = _M_mutex;
+       unique_lock<mutex> __my_lock(*__mutex);
+       _Unlock<_Lock> __unlock(__lock);
+       // *__mutex must be unlocked before re-locking __lock so move
+       // ownership of *__mutex lock to an object with shorter lifetime.
+       unique_lock<mutex> __my_lock2(std::move(__my_lock));
+       _M_cond.wait(__my_lock2);
       }
-      
+
 
     template<typename _Lock, typename _Predicate>
       void
@@ -216,11 +338,13 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
       wait_until(_Lock& __lock,
                 const chrono::time_point<_Clock, _Duration>& __atime)
       {
-        unique_lock<mutex> __my_lock(_M_mutex);
-        __lock.unlock();
-        cv_status __status = _M_cond.wait_until(__my_lock, __atime);
-        __lock.lock();
-        return __status;
+       shared_ptr<mutex> __mutex = _M_mutex;
+       unique_lock<mutex> __my_lock(*__mutex);
+       _Unlock<_Lock> __unlock(__lock);
+       // *__mutex must be unlocked before re-locking __lock so move
+       // ownership of *__mutex lock to an object with shorter lifetime.
+       unique_lock<mutex> __my_lock2(std::move(__my_lock));
+       return _M_cond.wait_until(__my_lock2, __atime);
       }
 
     template<typename _Lock, typename _Clock,
@@ -248,16 +372,91 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
               const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p)
       { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
 
-    native_handle_type
-    native_handle()
-    { return _M_cond.native_handle(); }
-  };
+#ifdef __cpp_lib_jthread
+    template <class _Lock, class _Predicate>
+    bool wait(_Lock& __lock,
+              stop_token __stoken,
+              _Predicate __p)
+    {
+      if (__stoken.stop_requested())
+        {
+          return __p();
+        }
+      std::stop_callback __cb(__stoken, [this] { notify_all(); });
+      shared_ptr<mutex> __mutex = _M_mutex;
+      while (!__p())
+        {
+          unique_lock<mutex> __my_lock(*__mutex);
+          if (__stoken.stop_requested())
+            {
+              return false;
+            }
+          // *__mutex must be unlocked before re-locking __lock so move
+          // ownership of *__mutex lock to an object with shorter lifetime.
+          _Unlock<_Lock> __unlock(__lock);
+          unique_lock<mutex> __my_lock2(std::move(__my_lock));
+          _M_cond.wait(__my_lock2);
+        }
+      return true;
+    }
 
-  // @} group condition_variables
-_GLIBCXX_END_NAMESPACE
+    template <class _Lock, class _Clock, class _Duration, class _Predicate>
+    bool wait_until(_Lock& __lock,
+                    stop_token __stoken,
+                    const chrono::time_point<_Clock, _Duration>& __abs_time,
+                    _Predicate __p)
+    {
+      if (__stoken.stop_requested())
+        {
+          return __p();
+        }
+
+      std::stop_callback __cb(__stoken, [this] { notify_all(); });
+      shared_ptr<mutex> __mutex = _M_mutex;
+      while (!__p())
+        {
+          bool __stop;
+          {
+            unique_lock<mutex> __my_lock(*__mutex);
+            if (__stoken.stop_requested())
+              {
+                return false;
+              }
+            _Unlock<_Lock> __u(__lock);
+            unique_lock<mutex> __my_lock2(std::move(__my_lock));
+            const auto __status = _M_cond.wait_until(__my_lock2, __abs_time);
+            __stop = (__status == std::cv_status::timeout) || __stoken.stop_requested();
+          }
+          if (__stop)
+            {
+              return __p();
+            }
+        }
+      return true;
+    }
 
-#endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
+    template <class _Lock, class _Rep, class _Period, class _Predicate>
+    bool wait_for(_Lock& __lock,
+                  stop_token __stoken,
+                  const chrono::duration<_Rep, _Period>& __rel_time,
+                  _Predicate __p)
+    {
+      auto __abst = std::chrono::steady_clock::now() + __rel_time;
+      return wait_until(__lock,
+                        std::move(__stoken),
+                        __abst,
+                        std::move(__p));
+    }
+#endif
+  };
+
+  } // end inline namespace
 
-#endif // __GXX_EXPERIMENTAL_CXX0X__
+  // @} group condition_variables
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
 
+#endif // _GLIBCXX_HAS_GTHREADS
+#endif // C++11
 #endif // _GLIBCXX_CONDITION_VARIABLE
This page took 0.042891 seconds and 5 git commands to generate.