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; }