diff --git a/doc/once-ref.xml b/doc/once-ref.xml
index ba6b5ffc..12480f57 100644
--- a/doc/once-ref.xml
+++ b/doc/once-ref.xml
@@ -65,25 +65,23 @@ void init()
void thread_proc()
{
- boost::call_once(&init, once);
+ boost::call_once(once, &init);
}
-
- void (*func)()
-
-
once_flag&
-
- The function func shall not throw
- exceptions.
+
+
+ Function func
+
As if (in an atomic fashion):
- if (flag == BOOST_ONCE_INIT) func();
+ if (flag == BOOST_ONCE_INIT) func();. If func() throws an exception, it shall be as if this
+thread never invoked call_once
- flag != BOOST_ONCE_INIT
+ flag != BOOST_ONCE_INIT unless func() throws an exception.
diff --git a/include/boost/thread/once.hpp b/include/boost/thread/once.hpp
index 286465c6..7ff1464a 100644
--- a/include/boost/thread/once.hpp
+++ b/include/boost/thread/once.hpp
@@ -1,37 +1,28 @@
-// Copyright (C) 2001-2003
-// William E. Kempf
+#ifndef BOOST_THREAD_ONCE_HPP
+#define BOOST_THREAD_ONCE_HPP
+
+// once.hpp
//
-// 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)
-
-#ifndef BOOST_ONCE_WEK080101_HPP
-#define BOOST_ONCE_WEK080101_HPP
-
-#include
-
-#if defined(BOOST_HAS_PTHREADS)
-# include
-#endif
+// (C) Copyright 2006-7 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
+#ifdef BOOST_HAS_MPTASKS
namespace boost {
-#if defined(BOOST_HAS_PTHREADS)
-
-typedef pthread_once_t once_flag;
-#define BOOST_ONCE_INIT PTHREAD_ONCE_INIT
-
-#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
-
typedef long once_flag;
#define BOOST_ONCE_INIT 0
+void call_once(once_flag& flag, void (*func)());
+
+}
+
+#else
+#include BOOST_THREAD_PLATFORM(once.hpp)
#endif
-void BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag);
-} // namespace boost
-
-// Change Log:
-// 1 Aug 01 WEKEMPF Initial version.
-
-#endif // BOOST_ONCE_WEK080101_HPP
+#endif
diff --git a/src/mutex.inl b/src/mutex.inl
index 0c3cc9a8..b2c625e0 100644
--- a/src/mutex.inl
+++ b/src/mutex.inl
@@ -38,7 +38,7 @@ void init_TryEnterCriticalSection()
inline bool has_TryEnterCriticalSection()
{
- boost::call_once(init_TryEnterCriticalSection, once_init_TryEnterCriticalSection);
+ boost::call_once(once_init_TryEnterCriticalSection, init_TryEnterCriticalSection);
return g_TryEnterCriticalSection != 0;
}
diff --git a/src/once.cpp b/src/once.cpp
index 47634da4..0215995f 100644
--- a/src/once.cpp
+++ b/src/once.cpp
@@ -6,6 +6,7 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include
+#ifdef BOOST_HAS_MPTASKS
#include
@@ -13,59 +14,8 @@
#include
#include
+#include
-#if defined(BOOST_HAS_WINTHREADS)
-# if BOOST_WORKAROUND(__BORLANDC__,<= 0x551)
- using std::size_t;
-# endif
-# include
-# if defined(BOOST_NO_STRINGSTREAM)
-# include
-
-class unfreezer
-{
-public:
- unfreezer(std::ostrstream& s) : m_stream(s) {}
- ~unfreezer() { m_stream.freeze(false); }
-private:
- std::ostrstream& m_stream;
-};
-
-# else
-# include
-# endif
-#elif defined(BOOST_HAS_MPTASKS)
-# include
-#endif
-
-#ifdef BOOST_NO_STDC_NAMESPACE
-namespace std { using ::sprintf; }
-#endif
-
-#if defined(BOOST_HAS_PTHREADS)
-namespace {
-pthread_key_t key;
-pthread_once_t once = PTHREAD_ONCE_INIT;
-
-typedef void (*once_callback)();
-}
-
-extern "C" {
-
- static void key_init()
- {
- pthread_key_create(&key, 0);
- }
-
- static void do_once()
- {
- once_callback* cb = reinterpret_cast(
- pthread_getspecific(key));
- (**cb)();
- }
-
-}
-#elif defined(BOOST_HAS_MPTASKS)
namespace {
void *remote_call_proxy(void *pData)
{
@@ -82,125 +32,10 @@ void *remote_call_proxy(void *pData)
}
}
-#elif defined(BOOST_HAS_WINTHREADS)
-namespace {
-// The signature for InterlockedCompareExchange has changed with the
-// addition of Win64 support. I can't determine any (consistent and
-// portable) way of using conditional compilation to detect this, so
-// we use these type wrappers. Unfortunately, the various vendors
-// use different calling conventions and other signature anamolies,
-// and thus have unique types as well. This is known to work on VC6,
-// VC7, Borland 5.5.2 and gcc 3.2. Are there other signatures for
-// other platforms?
-inline LONG ice_wrapper(LONG (__stdcall *ice)(LONG*, LONG, LONG),
- volatile LONG* dest, LONG exch, LONG cmp)
-{
- return (*ice)(const_cast(dest), exch, cmp);
-}
-
-inline LONG ice_wrapper(LONG (__stdcall *ice)(volatile LONG*, LONG, LONG),
- volatile LONG* dest, LONG exch, LONG cmp)
-{
- return (*ice)(dest, exch, cmp);
-}
-
-inline LONG ice_wrapper(LPVOID (__stdcall *ice)(LPVOID*, LPVOID, LPVOID),
- volatile LONG* dest, LONG exch, LONG cmp)
-{
- return (LONG)(*ice)((LPVOID*)dest, (LPVOID)exch, (LPVOID)cmp);
-}
-
-// The friendly form of InterlockedCompareExchange that defers
-// according to the above function type wrappers.
-inline LONG compare_exchange(volatile LPLONG dest, LONG exch, LONG cmp)
-{
-#ifdef _WIN64
- // Original patch from Anthony Williams.
- // I (Roland Schwarz) am trying this for RC_1_34_0, since x64 regressions are
- // currently not run on x64 platforms for HEAD
- return InterlockedCompareExchange(dest, exch,cmp);
-#else
- return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp);
-#endif
-}
-}
-#endif
-
namespace boost {
-void call_once(void (*func)(), once_flag& flag)
+ void call_once(once_flag& flag, void (*func)())
{
-#if defined(BOOST_HAS_WINTHREADS)
- if (compare_exchange(&flag, 1, 1) == 0)
- {
-#if defined(BOOST_NO_STRINGSTREAM)
- std::ostrstream strm;
- strm << "2AC1A572DB6944B0A65C38C4140AF2F4"
- << std::hex
- << GetCurrentProcessId()
- << &flag
- << std::ends;
- unfreezer unfreeze(strm);
-# if defined (BOOST_NO_ANSI_APIS)
- int const num_wide_chars = ::MultiByteToWideChar(CP_ACP, 0, strm.str(), -1, 0, 0);
- LPWSTR const wide_name = (LPWSTR)_alloca( (num_wide_chars+1) * 2 );
- int const res=::MultiByteToWideChar(CP_ACP, 0, name, -1, wide_name, num_wide_chars);
- if(!res)
- throw boost::thread_resource_error();
- HANDLE mutex = CreateMutexW(NULL, FALSE, wide_name);
-# else
- HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str());
-# endif
-#else
-# if defined (BOOST_NO_ANSI_APIS)
- std::wostringstream strm;
- strm << L"2AC1A572DB6944B0A65C38C4140AF2F4"
- << std::hex
- << GetCurrentProcessId()
- << &flag;
- HANDLE mutex = CreateMutexW(NULL, FALSE, strm.str().c_str());
-# else
- std::ostringstream strm;
- strm << "2AC1A572DB6944B0A65C38C4140AF2F4"
- << std::hex
- << GetCurrentProcessId()
- << &flag;
- HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str().c_str());
-# endif
-#endif
- assert(mutex != NULL);
-
- int res = 0;
- res = WaitForSingleObject(mutex, INFINITE);
- assert(res == WAIT_OBJECT_0);
-
- if (compare_exchange(&flag, 1, 1) == 0)
- {
- try
- {
- func();
- }
- catch (...)
- {
- res = ReleaseMutex(mutex);
- assert(res);
- res = CloseHandle(mutex);
- assert(res);
- throw;
- }
- InterlockedExchange(&flag, 1);
- }
-
- res = ReleaseMutex(mutex);
- assert(res);
- res = CloseHandle(mutex);
- assert(res);
- }
-#elif defined(BOOST_HAS_PTHREADS)
- pthread_once(&once, &key_init);
- pthread_setspecific(key, &func);
- pthread_once(&flag, do_once);
-#elif defined(BOOST_HAS_MPTASKS)
if(flag == false)
{
// all we do here is make a remote call to blue, as blue is not
@@ -209,10 +44,7 @@ void call_once(void (*func)(), once_flag& flag)
MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext);
assert(flag == true);
}
+}
+
+}
#endif
-}
-
-}
-
-// Change Log:
-// 1 Aug 01 WEKEMPF Initial version.
diff --git a/src/tss.cpp b/src/tss.cpp
index 5c77bb52..33f635b9 100644
--- a/src/tss.cpp
+++ b/src/tss.cpp
@@ -182,7 +182,7 @@ namespace boost {
namespace detail {
void tss::init(boost::function1* pcleanup)
{
- boost::call_once(&init_tss_data, tss_data_once);
+ boost::call_once(tss_data_once, &init_tss_data);
if (tss_data_cleanup_handlers == 0)
throw thread_resource_error();
boost::mutex::scoped_lock lock(*tss_data_mutex);
diff --git a/src/tss_hooks.cpp b/src/tss_hooks.cpp
index be4bb097..ba7c1972 100644
--- a/src/tss_hooks.cpp
+++ b/src/tss_hooks.cpp
@@ -74,7 +74,7 @@
thread_exit_handler exit_handler
)
{
- boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
+ boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
//boost::mutex::scoped_lock lock(*threadmon_mutex);
CScopedCSLock lock(&threadmon_mutex);
@@ -141,7 +141,7 @@
extern "C" BOOST_THREAD_DECL void on_process_enter(void)
{
- boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
+ boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
// boost::mutex::scoped_lock lock(*threadmon_mutex);
CScopedCSLock lock(&threadmon_mutex);
@@ -150,7 +150,7 @@
extern "C" BOOST_THREAD_DECL void on_process_exit(void)
{
- boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
+ boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
// boost::mutex::scoped_lock lock(*threadmon_mutex);
CScopedCSLock lock(&threadmon_mutex);
@@ -173,7 +173,7 @@
extern "C" BOOST_THREAD_DECL void on_thread_exit(void)
{
- boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
+ boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
// boost::mutex::scoped_lock lock(*threadmon_mutex);
CScopedCSLock lock(&threadmon_mutex);
diff --git a/test/test_once.cpp b/test/test_once.cpp
index d5c6eb9a..f9f59b79 100644
--- a/test/test_once.cpp
+++ b/test/test_once.cpp
@@ -1,52 +1,61 @@
-// Copyright (C) 2001-2003
-// William E. Kempf
-//
-// 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
-
-#include
-#include
+// (C) Copyright 2006-7 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
+#include
+#include
+#include
-#include
+boost::once_flag flag=BOOST_ONCE_INIT;
+int var_to_init=0;
+boost::mutex m;
-int once_value = 0;
-boost::once_flag once = BOOST_ONCE_INIT;
-
-void init_once_value()
+void initialize_variable()
{
- once_value++;
+ // ensure that if multiple threads get in here, they are serialized, so we can see the effect
+ boost::mutex::scoped_lock lock(m);
+ ++var_to_init;
}
-void test_once_thread()
+void call_once_thread()
{
- boost::call_once(init_once_value, once);
+ unsigned const loop_count=100;
+ int my_once_value=0;
+ for(unsigned i=0;iadd(BOOST_TEST_CASE(test_once));
+ test->add(BOOST_TEST_CASE(test_call_once));
return test;
}