Boost logo

Boost-Commit :

From: hinnant_at_[hidden]
Date: 2007-11-21 11:51:06


Author: hinnant
Date: 2007-11-21 11:51:06 EST (Wed, 21 Nov 2007)
New Revision: 41283
URL: http://svn.boost.org/trac/boost/changeset/41283

Log:
changed call_once to Borrows
Text files modified:
   sandbox/committee/LWG/ref_impl/mutex | 125 +++++++++++++++++++++++++--------------
   sandbox/committee/LWG/ref_impl/mutex.cpp | 87 +++++++++++++++++++++++++++
   sandbox/committee/LWG/ref_impl/thread | 8 ++
   3 files changed, 175 insertions(+), 45 deletions(-)

Modified: sandbox/committee/LWG/ref_impl/mutex
==============================================================================
--- sandbox/committee/LWG/ref_impl/mutex (original)
+++ sandbox/committee/LWG/ref_impl/mutex 2007-11-21 11:51:06 EST (Wed, 21 Nov 2007)
@@ -179,6 +179,7 @@
 #include <condition_variable>
 #include <hdate_time>
 #include <functional>
+#include <csignal>
 
 namespace std
 {
@@ -228,63 +229,99 @@
     void unlock();
 };
 
-struct once_flag;
+// This is a variation of the Mike Burrows fast_pthread_once algorithm
 
-template<class Callable, class ...Args>
-void
-call_once(once_flag& flag, Callable&& func, Args&&... args);
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided with
+// the distribution.
+// * Neither the name of Google Inc. nor the names
+// of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written
+// permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// once_flag should be a simple class with a constexpr default ctor setting a sig_atomic_t to 0
+typedef sig_atomic_t once_flag;
+
+once_flag __get_once_per_thread_epoch();
+void __set_once_per_thread_epoch(once_flag flag);
+once_flag& __get_call_once_global_epoch();
+extern pthread_mutex_t __call_once_mut;
+extern pthread_cond_t __call_once_cv;
 
-struct once_flag
+template <class F>
+void
+__call_once(once_flag& flag, F f)
 {
-private:
- pthread_mutex_t m_;
- bool completed_;
-
- once_flag(const once_flag&); // = default;
- once_flag& operator=(const once_flag&); // = default;
-
- template <class F> void run(F f);
-
- template<class Callable, class ...Args>
- friend
- void
- call_once(once_flag& flag, Callable&& func, Args&&... args);
-
-public:
- //constexpr
- once_flag() {pthread_mutex_init(&m_, 0);}
- ~once_flag()
+ once_flag x = flag;
+ if (x < __get_once_per_thread_epoch())
     {
- pthread_mutex_destroy(&m_);
+ pthread_mutex_lock(&__call_once_mut);
+ while (flag == once_flag(1))
+ pthread_cond_wait(&__call_once_cv, &__call_once_mut);
+ once_flag& global_epoch = __get_call_once_global_epoch();
+ if (flag == once_flag(0))
+ {
+ flag = once_flag(1);
+ pthread_mutex_unlock(&__call_once_mut);
+ try
+ {
+ f();
+ }
+ catch (...)
+ {
+ pthread_mutex_lock(&__call_once_mut);
+ flag = once_flag(0);
+ pthread_mutex_unlock(&__call_once_mut);
+ pthread_cond_broadcast(&__call_once_cv);
+ throw;
+ }
+ pthread_mutex_lock(&__call_once_mut);
+ flag = global_epoch;
+ --global_epoch;
+ pthread_cond_broadcast(&__call_once_cv);
+ }
+ __set_once_per_thread_epoch(global_epoch);
+ pthread_mutex_unlock(&__call_once_mut);
     }
-};
-
-struct __pthread_mutex_unlocker
-{
- void operator()(pthread_mutex_t* m) {pthread_mutex_unlock(m);}
-};
+}
 
 template <class F>
+inline
 void
-once_flag::run(F f)
+call_once(once_flag& flag, F f)
 {
- unique_ptr<pthread_mutex_t> p(new pthread_mutex_t);
- pthread_mutex_init(p.get(), 0);
-
- pthread_mutex_lock(&m_);
- unique_ptr<pthread_mutex_t, __pthread_mutex_unlocker> _(&m_);
- if (!completed_)
- {
- f();
- completed_ = true;
- }
+ if (flag < __get_once_per_thread_epoch())
+ __call_once(flag, std::move(f));
 }
 
-template<class Callable, class ...Args>
+template<class F, class ...Args>
+inline
 void
-call_once(once_flag& flag, Callable&& func, Args&&... args)
+call_once(once_flag& flag, F&& func, Args&&... args)
 {
- flag.run(bind(std::forward<Callable>(func), std::forward<Args>(args)...));
+ std::call_once(flag, bind(std::forward<F>(func), std::forward<Args>(args)...));
 }
 
 } // std

Modified: sandbox/committee/LWG/ref_impl/mutex.cpp
==============================================================================
--- sandbox/committee/LWG/ref_impl/mutex.cpp (original)
+++ sandbox/committee/LWG/ref_impl/mutex.cpp 2007-11-21 11:51:06 EST (Wed, 21 Nov 2007)
@@ -3,11 +3,15 @@
 
 // mutex.cpp
 
+#define __STDC_LIMIT_MACROS
+
 #include "mutex"
 #include "system_error"
 #undef NDEBUG
 #include <cassert>
 
+#include <stdint.h>
+
 namespace std
 {
 
@@ -254,4 +258,87 @@
 const try_to_lock_t try_to_lock = try_to_lock_t();
 const adopt_lock_t adopt_lock = adopt_lock_t();
 
+///////////////
+// call_once //
+///////////////
+
+// This is a variation of the Mike Burrows fast_pthread_once algorithm
+
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided with
+// the distribution.
+// * Neither the name of Google Inc. nor the names
+// of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written
+// permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Using pthread_getspecific as a poor man's thread_local
+// Making non-portable assumption that a sig_atomic_t can be stored in a void*
+
+pthread_mutex_t __call_once_mut = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t __call_once_cv = PTHREAD_COND_INITIALIZER;
+static once_flag global_epoch(SIG_ATOMIC_MAX);
+
+once_flag& __get_call_once_global_epoch()
+{
+ return global_epoch;
+}
+
+static pthread_key_t key;
+static pthread_once_t call_once_key_init = PTHREAD_ONCE_INIT;
+
+extern "C"
+{
+void call_once_init_key()
+{
+ pthread_key_create(&key, 0);
+}
+} // extern "C"
+
+
+static
+pthread_key_t
+get_once_key()
+{
+ pthread_once(&call_once_key_init, call_once_init_key);
+ return key;
+}
+
+void
+__set_once_per_thread_epoch(once_flag flag)
+{
+ pthread_setspecific(get_once_key(), (void*)flag);
+}
+
+once_flag
+__get_once_per_thread_epoch()
+{
+ once_flag f = (once_flag)pthread_getspecific(get_once_key());
+ if (f == once_flag(0))
+ f = once_flag(SIG_ATOMIC_MAX);
+ return f;
+}
+
 } // std

Modified: sandbox/committee/LWG/ref_impl/thread
==============================================================================
--- sandbox/committee/LWG/ref_impl/thread (original)
+++ sandbox/committee/LWG/ref_impl/thread 2007-11-21 11:51:06 EST (Wed, 21 Nov 2007)
@@ -104,8 +104,10 @@
     friend class thread;
     explicit __thread_id(pthread_t t) : id_(t) {}
 public:
+ // Making non-portable assumption that pthread_t is a pointer
     __thread_id() : id_(0) {}
 
+ // Making non-portable assumption that pthread_t is a pointer
     friend bool operator==(const __thread_id& x, const __thread_id& y) {return x.id_ == y.id_;}
     friend bool operator!=(const __thread_id& x, const __thread_id& y) {return !(x == y);}
     friend bool operator< (const __thread_id& x, const __thread_id& y) {return x.id_ < y.id_;}
@@ -113,6 +115,7 @@
     friend bool operator> (const __thread_id& x, const __thread_id& y) {return y < x ;}
     friend bool operator>=(const __thread_id& x, const __thread_id& y) {return !(x < y);}
 
+ // Making non-portable assumption that pthread_t is a pointer
     template<class charT, class traits> friend
     basic_ostream<charT, traits>&
     operator<< (basic_ostream<charT, traits>&& out, const __thread_id& x)
@@ -123,6 +126,7 @@
 {
     pthread_t id_;
 public:
+ // Making non-portable assumption that pthread_t is a pointer
     thread() : id_(0) {}
     template <class F> explicit thread(F f);
     template <class F, class ...Args> thread(F&& f, Args&&... args)
@@ -136,6 +140,7 @@
     private: thread(const thread&); public:// = delete;
     private: thread& operator=(const thread&); public:// = delete;
 
+ // Making non-portable assumption that pthread_t is a pointer
     thread(thread&& t) : id_(t.id_) {t.id_ = 0;}
     thread& operator=(thread&& t)
     {
@@ -151,6 +156,7 @@
         t.id_ = temp;
     }
 
+ // Making non-portable assumption that pthread_t is a pointer
     bool joinable() const {return id_ != 0;}
     void join();
     void detach();
@@ -216,8 +222,8 @@
     {
     lock_guard<mutex> _(mut_);
     started_ = true;
- }
     cv_.notify_one();
+ }
     try
     {
         f();


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk