|
Boost-Commit : |
From: anthony_at_[hidden]
Date: 2007-11-16 17:51:53
Author: anthonyw
Date: 2007-11-16 17:51:52 EST (Fri, 16 Nov 2007)
New Revision: 41160
URL: http://svn.boost.org/trac/boost/changeset/41160
Log:
New implementation of pthread_once based on Mike Burrows' algorithm
Added:
trunk/libs/thread/src/pthread/once.cpp (contents, props changed)
Text files modified:
trunk/boost/thread/pthread/once.hpp | 70 ++++++++++++++++++++++++++++-----------
trunk/boost/thread/pthread/pthread_mutex_scoped_lock.hpp | 16 +++++++++
trunk/libs/thread/build/Jamfile.v2 | 1
3 files changed, 67 insertions(+), 20 deletions(-)
Modified: trunk/boost/thread/pthread/once.hpp
==============================================================================
--- trunk/boost/thread/pthread/once.hpp (original)
+++ trunk/boost/thread/pthread/once.hpp 2007-11-16 17:51:52 EST (Fri, 16 Nov 2007)
@@ -14,42 +14,72 @@
#include <pthread.h>
#include <boost/assert.hpp>
#include "pthread_mutex_scoped_lock.hpp"
+#include <boost/cstdint.hpp>
+#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
namespace boost {
struct once_flag
{
- pthread_mutex_t mutex;
- unsigned long flag;
+ boost::uintmax_t epoch;
};
-#define BOOST_ONCE_INIT {PTHREAD_MUTEX_INITIALIZER,0}
+ namespace detail
+ {
+ BOOST_THREAD_DECL boost::uintmax_t& get_once_per_thread_epoch();
+ extern BOOST_THREAD_DECL boost::uintmax_t once_global_epoch;
+ extern BOOST_THREAD_DECL pthread_mutex_t once_epoch_mutex;
+ extern BOOST_THREAD_DECL pthread_cond_t once_epoch_cv;
+ }
+
+#define BOOST_ONCE_INITIAL_FLAG_VALUE -1
+#define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE}
+
+ // Based on Mike Burrows fast_pthread_once algorithm as described in
+ // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html
template<typename Function>
void call_once(once_flag& flag,Function f)
{
- unsigned long const function_complete_flag_value=0xc15730e2ul;
-
-#ifdef BOOST_PTHREAD_HAS_ATOMICS
- if(::boost::detail::interlocked_read_acquire(&flag.flag)!=function_complete_flag_value)
+ static boost::uintmax_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
+ static boost::uintmax_t const being_initialized=uninitialized_flag-1;
+ boost::uintmax_t const epoch=flag.epoch;
+ boost::uintmax_t& this_thread_epoch=detail::get_once_per_thread_epoch();
+
+ if(epoch>this_thread_epoch)
{
-#endif
- pthread::pthread_mutex_scoped_lock const lock(&flag.mutex);
- if(flag.flag!=function_complete_flag_value)
+ pthread::pthread_mutex_scoped_lock lk(&detail::once_epoch_mutex);
+
+ while(flag.epoch>=being_initialized)
{
- f();
-#ifdef BOOST_PTHREAD_HAS_ATOMICS
- ::boost::detail::interlocked_write_release(&flag.flag,function_complete_flag_value);
-#else
- flag.flag=function_complete_flag_value;
-#endif
+ if(flag.epoch==uninitialized_flag)
+ {
+ flag.epoch=being_initialized;
+ try
+ {
+ pthread::pthread_mutex_scoped_unlock relocker(&detail::once_epoch_mutex);
+ f();
+ }
+ catch(...)
+ {
+ flag.epoch=uninitialized_flag;
+ BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
+ throw;
+ }
+ flag.epoch=++detail::once_global_epoch;
+ BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
+ }
+ else
+ {
+ while(flag.epoch==being_initialized)
+ {
+ BOOST_VERIFY(!pthread_cond_wait(&detail::once_epoch_cv,&detail::once_epoch_mutex));
+ }
+ }
}
-#ifdef BOOST_PTHREAD_HAS_ATOMICS
+ this_thread_epoch=detail::once_global_epoch;
}
-#endif
}
-
-
}
#endif
Modified: trunk/boost/thread/pthread/pthread_mutex_scoped_lock.hpp
==============================================================================
--- trunk/boost/thread/pthread/pthread_mutex_scoped_lock.hpp (original)
+++ trunk/boost/thread/pthread/pthread_mutex_scoped_lock.hpp 2007-11-16 17:51:52 EST (Fri, 16 Nov 2007)
@@ -28,6 +28,22 @@
}
};
+
+ class pthread_mutex_scoped_unlock
+ {
+ pthread_mutex_t* m;
+ public:
+ explicit pthread_mutex_scoped_unlock(pthread_mutex_t* m_):
+ m(m_)
+ {
+ BOOST_VERIFY(!pthread_mutex_unlock(m));
+ }
+ ~pthread_mutex_scoped_unlock()
+ {
+ BOOST_VERIFY(!pthread_mutex_lock(m));
+ }
+
+ };
}
}
Modified: trunk/libs/thread/build/Jamfile.v2
==============================================================================
--- trunk/libs/thread/build/Jamfile.v2 (original)
+++ trunk/libs/thread/build/Jamfile.v2 2007-11-16 17:51:52 EST (Fri, 16 Nov 2007)
@@ -191,6 +191,7 @@
pthread/thread.cpp
pthread/exceptions.cpp
pthread/tss.cpp
+ pthread/once.cpp
: ## requirements ##
<threadapi>pthread
;
Added: trunk/libs/thread/src/pthread/once.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/thread/src/pthread/once.cpp 2007-11-16 17:51:52 EST (Fri, 16 Nov 2007)
@@ -0,0 +1,51 @@
+// Copyright (C) 2007 Anthony Williams
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/thread/once.hpp>
+#include <boost/assert.hpp>
+#include <pthread.h>
+#include <stdlib.h>
+
+namespace boost
+{
+ namespace detail
+ {
+ boost::uintmax_t once_global_epoch=0;
+ pthread_mutex_t once_epoch_mutex=PTHREAD_MUTEX_INITIALIZER;
+ pthread_cond_t once_epoch_cv = PTHREAD_COND_INITIALIZER;
+
+ namespace
+ {
+ pthread_key_t epoch_tss_key;
+ pthread_once_t epoch_tss_key_flag=PTHREAD_ONCE_INIT;
+
+ extern "C" void delete_epoch_tss_data(void* data)
+ {
+ free(data);
+ }
+
+ extern "C" void create_epoch_tss_key()
+ {
+ BOOST_VERIFY(!pthread_key_create(&epoch_tss_key,delete_epoch_tss_data));
+ }
+
+ }
+
+ boost::uintmax_t& get_once_per_thread_epoch()
+ {
+ BOOST_VERIFY(!pthread_once(&epoch_tss_key_flag,create_epoch_tss_key));
+ void* data=pthread_getspecific(epoch_tss_key);
+ if(!data)
+ {
+ data=malloc(sizeof(boost::uintmax_t));
+ BOOST_VERIFY(!pthread_setspecific(epoch_tss_key,data));
+ *static_cast<boost::uintmax_t*>(data)=0;
+ }
+ return *static_cast<boost::uintmax_t*>(data);
+ }
+
+ }
+
+}
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