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. #include <condition_variable>
  26. #include <cstdlib>
  27.  
  28. #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
  29.  
  30. namespace std _GLIBCXX_VISIBILITY(default)
  31. {
  32. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  33.  
  34. #ifdef __GTHREAD_COND_INIT
  35.   condition_variable::condition_variable() noexcept = default;
  36. #else
  37.   condition_variable::condition_variable() noexcept
  38.   {
  39.     __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
  40.   }
  41. #endif
  42.  
  43.   condition_variable::~condition_variable() noexcept
  44.   {
  45.     // XXX no thread blocked
  46.     /* int __e = */ __gthread_cond_destroy(&_M_cond);
  47.     // if __e == EBUSY then blocked
  48.   }
  49.  
  50.   void
  51.   condition_variable::wait(unique_lock<mutex>& __lock)
  52.   {
  53.     int __e = __gthread_cond_wait(&_M_cond, __lock.mutex()->native_handle());
  54.  
  55.     if (__e)
  56.       __throw_system_error(__e);
  57.   }
  58.  
  59.   void
  60.   condition_variable::notify_one() noexcept
  61.   {
  62.     int __e = __gthread_cond_signal(&_M_cond);
  63.  
  64.     // XXX not in spec
  65.     // EINVAL
  66.     if (__e)
  67.       __throw_system_error(__e);
  68.   }
  69.  
  70.   void
  71.   condition_variable::notify_all() noexcept
  72.   {
  73.     int __e = __gthread_cond_broadcast(&_M_cond);
  74.  
  75.     // XXX not in spec
  76.     // EINVAL
  77.     if (__e)
  78.       __throw_system_error(__e);
  79.   }
  80.  
  81.   extern void
  82.   __at_thread_exit(__at_thread_exit_elt*);
  83.  
  84.   namespace
  85.   {
  86.     __gthread_key_t key;
  87.  
  88.     void run(void* p)
  89.     {
  90.       auto elt = (__at_thread_exit_elt*)p;
  91.       while (elt)
  92.         {
  93.           auto next = elt->_M_next;
  94.           elt->_M_cb(elt);
  95.           elt = next;
  96.         }
  97.     }
  98.  
  99.     void run()
  100.     {
  101.       auto elt = (__at_thread_exit_elt*)__gthread_getspecific(key);
  102.       __gthread_setspecific(key, nullptr);
  103.       run(elt);
  104.     }
  105.  
  106.     struct notifier final : __at_thread_exit_elt
  107.     {
  108.       notifier(condition_variable& cv, unique_lock<mutex>& l)
  109.       : cv(&cv), mx(l.release())
  110.       {
  111.         _M_cb = &notifier::run;
  112.         __at_thread_exit(this);
  113.       }
  114.  
  115.       ~notifier()
  116.       {
  117.         mx->unlock();
  118.         cv->notify_all();
  119.       }
  120.  
  121.       condition_variable* cv;
  122.       mutex* mx;
  123.  
  124.       static void run(void* p) { delete static_cast<notifier*>(p); }
  125.     };
  126.  
  127.  
  128.     void key_init() {
  129.       struct key_s {
  130.         key_s() { __gthread_key_create (&key, run); }
  131.         ~key_s() { __gthread_key_delete (key); }
  132.       };
  133.       static key_s ks;
  134.       // Also make sure the callbacks are run by std::exit.
  135.       std::atexit (run);
  136.     }
  137.   }
  138.  
  139.   void
  140.   __at_thread_exit(__at_thread_exit_elt* elt)
  141.   {
  142.     static __gthread_once_t once = __GTHREAD_ONCE_INIT;
  143.     __gthread_once (&once, key_init);
  144.  
  145.     elt->_M_next = (__at_thread_exit_elt*)__gthread_getspecific(key);
  146.     __gthread_setspecific(key, elt);
  147.   }
  148.  
  149.   void
  150.   notify_all_at_thread_exit(condition_variable& cv, unique_lock<mutex> l)
  151.   {
  152.     (void) new notifier{cv, l};
  153.   }
  154.  
  155. _GLIBCXX_END_NAMESPACE_VERSION
  156. } // namespace
  157.  
  158. #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
  159.