Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. // <condition_variable> -*- C++ -*-
  2.  
  3. // Copyright (C) 2008-2015 Free Software Foundation, Inc.
  4. //
  5. // This file is part of the GNU ISO C++ Library.  This library is free
  6. // software; you can redistribute it and/or modify it under the
  7. // terms of the GNU General Public License as published by the
  8. // Free Software Foundation; either version 3, or (at your option)
  9. // any later version.
  10.  
  11. // This library is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. // GNU General Public License for more details.
  15.  
  16. // Under Section 7 of GPL version 3, you are granted additional
  17. // permissions described in the GCC Runtime Library Exception, version
  18. // 3.1, as published by the Free Software Foundation.
  19.  
  20. // You should have received a copy of the GNU General Public License and
  21. // a copy of the GCC Runtime Library Exception along with this program;
  22. // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
  23. // <http://www.gnu.org/licenses/>.
  24.  
  25. /** @file include/condition_variable
  26.  *  This is a Standard C++ Library header.
  27.  */
  28.  
  29. #ifndef _GLIBCXX_CONDITION_VARIABLE
  30. #define _GLIBCXX_CONDITION_VARIABLE 1
  31.  
  32. #pragma GCC system_header
  33.  
  34. #if __cplusplus < 201103L
  35. # include <bits/c++0x_warning.h>
  36. #else
  37.  
  38. #include <chrono>
  39. #include <mutex>
  40. #include <ext/concurrence.h>
  41. #include <bits/alloc_traits.h>
  42. #include <bits/allocator.h>
  43. #include <bits/unique_ptr.h>
  44. #include <bits/shared_ptr.h>
  45.  
  46. #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
  47.  
  48. namespace std _GLIBCXX_VISIBILITY(default)
  49. {
  50. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  51.  
  52.   /**
  53.    * @defgroup condition_variables Condition Variables
  54.    * @ingroup concurrency
  55.    *
  56.    * Classes for condition_variable support.
  57.    * @{
  58.    */
  59.  
  60.   /// cv_status
  61.   enum class cv_status { no_timeout, timeout };
  62.  
  63.   /// condition_variable
  64.   class condition_variable
  65.   {
  66.     typedef chrono::system_clock        __clock_t;
  67.     typedef __gthread_cond_t            __native_type;
  68.  
  69. #ifdef __GTHREAD_COND_INIT
  70.     __native_type                       _M_cond = __GTHREAD_COND_INIT;
  71. #else
  72.     __native_type                       _M_cond;
  73. #endif
  74.  
  75.   public:
  76.     typedef __native_type*              native_handle_type;
  77.  
  78.     condition_variable() noexcept;
  79.     ~condition_variable() noexcept;
  80.  
  81.     condition_variable(const condition_variable&) = delete;
  82.     condition_variable& operator=(const condition_variable&) = delete;
  83.  
  84.     void
  85.     notify_one() noexcept;
  86.  
  87.     void
  88.     notify_all() noexcept;
  89.  
  90.     void
  91.     wait(unique_lock<mutex>& __lock);
  92.  
  93.     template<typename _Predicate>
  94.       void
  95.       wait(unique_lock<mutex>& __lock, _Predicate __p)
  96.       {
  97.         while (!__p())
  98.           wait(__lock);
  99.       }
  100.  
  101.     template<typename _Duration>
  102.       cv_status
  103.       wait_until(unique_lock<mutex>& __lock,
  104.                  const chrono::time_point<__clock_t, _Duration>& __atime)
  105.       { return __wait_until_impl(__lock, __atime); }
  106.  
  107.     template<typename _Clock, typename _Duration>
  108.       cv_status
  109.       wait_until(unique_lock<mutex>& __lock,
  110.                  const chrono::time_point<_Clock, _Duration>& __atime)
  111.       {
  112.         // DR 887 - Sync unknown clock to known clock.
  113.         const typename _Clock::time_point __c_entry = _Clock::now();
  114.         const __clock_t::time_point __s_entry = __clock_t::now();
  115.         const auto __delta = __atime - __c_entry;
  116.         const auto __s_atime = __s_entry + __delta;
  117.  
  118.         return __wait_until_impl(__lock, __s_atime);
  119.       }
  120.  
  121.     template<typename _Clock, typename _Duration, typename _Predicate>
  122.       bool
  123.       wait_until(unique_lock<mutex>& __lock,
  124.                  const chrono::time_point<_Clock, _Duration>& __atime,
  125.                  _Predicate __p)
  126.       {
  127.         while (!__p())
  128.           if (wait_until(__lock, __atime) == cv_status::timeout)
  129.             return __p();
  130.         return true;
  131.       }
  132.  
  133.     template<typename _Rep, typename _Period>
  134.       cv_status
  135.       wait_for(unique_lock<mutex>& __lock,
  136.                const chrono::duration<_Rep, _Period>& __rtime)
  137.       { return wait_until(__lock, __clock_t::now() + __rtime); }
  138.  
  139.     template<typename _Rep, typename _Period, typename _Predicate>
  140.       bool
  141.       wait_for(unique_lock<mutex>& __lock,
  142.                const chrono::duration<_Rep, _Period>& __rtime,
  143.                _Predicate __p)
  144.       { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
  145.  
  146.     native_handle_type
  147.     native_handle()
  148.     { return &_M_cond; }
  149.  
  150.   private:
  151.     template<typename _Dur>
  152.       cv_status
  153.       __wait_until_impl(unique_lock<mutex>& __lock,
  154.                         const chrono::time_point<__clock_t, _Dur>& __atime)
  155.       {
  156.         auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
  157.         auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
  158.  
  159.         __gthread_time_t __ts =
  160.           {
  161.             static_cast<std::time_t>(__s.time_since_epoch().count()),
  162.             static_cast<long>(__ns.count())
  163.           };
  164.  
  165.         __gthread_cond_timedwait(&_M_cond, __lock.mutex()->native_handle(),
  166.                                  &__ts);
  167.  
  168.         return (__clock_t::now() < __atime
  169.                 ? cv_status::no_timeout : cv_status::timeout);
  170.       }
  171.   };
  172.  
  173.   void
  174.   notify_all_at_thread_exit(condition_variable&, unique_lock<mutex>);
  175.  
  176.   struct __at_thread_exit_elt
  177.   {
  178.     __at_thread_exit_elt* _M_next;
  179.     void (*_M_cb)(void*);
  180.   };
  181.  
  182.   inline namespace _V2 {
  183.  
  184.   /// condition_variable_any
  185.   // Like above, but mutex is not required to have try_lock.
  186.   class condition_variable_any
  187.   {
  188.     typedef chrono::system_clock        __clock_t;
  189.     condition_variable                  _M_cond;
  190.     shared_ptr<mutex>                   _M_mutex;
  191.  
  192.     // scoped unlock - unlocks in ctor, re-locks in dtor
  193.     template<typename _Lock>
  194.       struct _Unlock
  195.       {
  196.         explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); }
  197.  
  198.         ~_Unlock() noexcept(false)
  199.         {
  200.           if (uncaught_exception())
  201.             {
  202.               __try
  203.               { _M_lock.lock(); }
  204.               __catch(const __cxxabiv1::__forced_unwind&)
  205.               { __throw_exception_again; }
  206.               __catch(...)
  207.               { }
  208.             }
  209.           else
  210.             _M_lock.lock();
  211.         }
  212.  
  213.         _Unlock(const _Unlock&) = delete;
  214.         _Unlock& operator=(const _Unlock&) = delete;
  215.  
  216.         _Lock& _M_lock;
  217.       };
  218.  
  219.   public:
  220.     condition_variable_any() : _M_mutex(std::make_shared<mutex>()) { }
  221.     ~condition_variable_any() = default;
  222.  
  223.     condition_variable_any(const condition_variable_any&) = delete;
  224.     condition_variable_any& operator=(const condition_variable_any&) = delete;
  225.  
  226.     void
  227.     notify_one() noexcept
  228.     {
  229.       lock_guard<mutex> __lock(*_M_mutex);
  230.       _M_cond.notify_one();
  231.     }
  232.  
  233.     void
  234.     notify_all() noexcept
  235.     {
  236.       lock_guard<mutex> __lock(*_M_mutex);
  237.       _M_cond.notify_all();
  238.     }
  239.  
  240.     template<typename _Lock>
  241.       void
  242.       wait(_Lock& __lock)
  243.       {
  244.         shared_ptr<mutex> __mutex = _M_mutex;
  245.         unique_lock<mutex> __my_lock(*__mutex);
  246.         _Unlock<_Lock> __unlock(__lock);
  247.         // *__mutex must be unlocked before re-locking __lock so move
  248.         // ownership of *__mutex lock to an object with shorter lifetime.
  249.         unique_lock<mutex> __my_lock2(std::move(__my_lock));
  250.         _M_cond.wait(__my_lock2);
  251.       }
  252.      
  253.  
  254.     template<typename _Lock, typename _Predicate>
  255.       void
  256.       wait(_Lock& __lock, _Predicate __p)
  257.       {
  258.         while (!__p())
  259.           wait(__lock);
  260.       }
  261.  
  262.     template<typename _Lock, typename _Clock, typename _Duration>
  263.       cv_status
  264.       wait_until(_Lock& __lock,
  265.                  const chrono::time_point<_Clock, _Duration>& __atime)
  266.       {
  267.         shared_ptr<mutex> __mutex = _M_mutex;
  268.         unique_lock<mutex> __my_lock(*__mutex);
  269.         _Unlock<_Lock> __unlock(__lock);
  270.         // *__mutex must be unlocked before re-locking __lock so move
  271.         // ownership of *__mutex lock to an object with shorter lifetime.
  272.         unique_lock<mutex> __my_lock2(std::move(__my_lock));
  273.         return _M_cond.wait_until(__my_lock2, __atime);
  274.       }
  275.  
  276.     template<typename _Lock, typename _Clock,
  277.              typename _Duration, typename _Predicate>
  278.       bool
  279.       wait_until(_Lock& __lock,
  280.                  const chrono::time_point<_Clock, _Duration>& __atime,
  281.                  _Predicate __p)
  282.       {
  283.         while (!__p())
  284.           if (wait_until(__lock, __atime) == cv_status::timeout)
  285.             return __p();
  286.         return true;
  287.       }
  288.  
  289.     template<typename _Lock, typename _Rep, typename _Period>
  290.       cv_status
  291.       wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __rtime)
  292.       { return wait_until(__lock, __clock_t::now() + __rtime); }
  293.  
  294.     template<typename _Lock, typename _Rep,
  295.              typename _Period, typename _Predicate>
  296.       bool
  297.       wait_for(_Lock& __lock,
  298.                const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p)
  299.       { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
  300.   };
  301.  
  302.   } // end inline namespace
  303.  
  304.   // @} group condition_variables
  305. _GLIBCXX_END_NAMESPACE_VERSION
  306. } // namespace
  307.  
  308. #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
  309.  
  310. #endif // C++11
  311.  
  312. #endif // _GLIBCXX_CONDITION_VARIABLE
  313.