Boost logo

Boost-Commit :

From: anthony_at_[hidden]
Date: 2007-10-05 08:10:20


Author: anthonyw
Date: 2007-10-05 08:10:06 EDT (Fri, 05 Oct 2007)
New Revision: 39701
URL: http://svn.boost.org/trac/boost/changeset/39701

Log:
Changed call_once to header-only template that takes arbitrary function objects; this changes parameter order
Text files modified:
   trunk/boost/spirit/core/non_terminal/impl/object_with_id.ipp | 2
   trunk/boost/spirit/phoenix/closures.hpp | 2
   trunk/boost/thread/once.hpp | 43 +++-----
   trunk/libs/regex/src/static_mutex.cpp | 2
   trunk/libs/regex/test/regress/info.hpp | 2
   trunk/libs/thread/doc/once-ref.xml | 18 +--
   trunk/libs/thread/src/mutex.inl | 2
   trunk/libs/thread/src/once.cpp | 176 ---------------------------------------
   trunk/libs/thread/src/tss.cpp | 2
   trunk/libs/thread/src/tss_hooks.cpp | 8
   trunk/libs/thread/test/test_once.cpp | 71 +++++++++-------
   11 files changed, 79 insertions(+), 249 deletions(-)

Modified: trunk/boost/spirit/core/non_terminal/impl/object_with_id.ipp
==============================================================================
--- trunk/boost/spirit/core/non_terminal/impl/object_with_id.ipp (original)
+++ trunk/boost/spirit/core/non_terminal/impl/object_with_id.ipp 2007-10-05 08:10:06 EDT (Fri, 05 Oct 2007)
@@ -133,7 +133,7 @@
             {
 #ifdef BOOST_SPIRIT_THREADSAFE
                 static boost::once_flag been_here = BOOST_ONCE_INIT;
- boost::call_once(mutex_init, been_here);
+ boost::call_once(been_here, mutex_init);
                 boost::mutex &mutex = mutex_instance();
                 boost::mutex::scoped_lock lock(mutex);
 #endif

Modified: trunk/boost/spirit/phoenix/closures.hpp
==============================================================================
--- trunk/boost/spirit/phoenix/closures.hpp (original)
+++ trunk/boost/spirit/phoenix/closures.hpp 2007-10-05 08:10:06 EDT (Fri, 05 Oct 2007)
@@ -418,7 +418,7 @@
     {
 #ifdef PHOENIX_THREADSAFE
         static boost::once_flag been_here = BOOST_ONCE_INIT;
- boost::call_once(tsp_frame_instance_init, been_here);
+ boost::call_once(been_here, tsp_frame_instance_init);
         boost::thread_specific_ptr<holder_t*> &tsp_frame = tsp_frame_instance();
         if (!tsp_frame.get())
             tsp_frame.reset(new holder_t *(0));

Modified: trunk/boost/thread/once.hpp
==============================================================================
--- trunk/boost/thread/once.hpp (original)
+++ trunk/boost/thread/once.hpp 2007-10-05 08:10:06 EDT (Fri, 05 Oct 2007)
@@ -1,37 +1,28 @@
-// 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)
-
-#ifndef BOOST_ONCE_WEK080101_HPP
-#define BOOST_ONCE_WEK080101_HPP
-
-#include <boost/thread/detail/config.hpp>
+#ifndef BOOST_THREAD_ONCE_HPP
+#define BOOST_THREAD_ONCE_HPP
 
-#if defined(BOOST_HAS_PTHREADS)
-# include <pthread.h>
-#endif
+// once.hpp
+//
+// (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 <boost/thread/detail/platform.hpp>
+#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
 
-#endif
+void call_once(once_flag& flag, void (*func)());
 
-void BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag);
+}
 
-} // namespace boost
+#else
+#include BOOST_THREAD_PLATFORM(once.hpp)
+#endif
 
-// Change Log:
-// 1 Aug 01 WEKEMPF Initial version.
 
-#endif // BOOST_ONCE_WEK080101_HPP
+#endif

Modified: trunk/libs/regex/src/static_mutex.cpp
==============================================================================
--- trunk/libs/regex/src/static_mutex.cpp (original)
+++ trunk/libs/regex/src/static_mutex.cpp 2007-10-05 08:10:06 EDT (Fri, 05 Oct 2007)
@@ -155,7 +155,7 @@
 {
    if(0 == m_have_lock)
    {
- boost::call_once(&static_mutex::init, static_mutex::m_once);
+ boost::call_once(static_mutex::m_once,&static_mutex::init);
       if(0 == m_plock)
          m_plock = new boost::recursive_mutex::scoped_lock(*static_mutex::m_pmutex, false);
       m_plock->lock();

Modified: trunk/libs/regex/test/regress/info.hpp
==============================================================================
--- trunk/libs/regex/test/regress/info.hpp (original)
+++ trunk/libs/regex/test/regress/info.hpp 2007-10-05 08:10:06 EDT (Fri, 05 Oct 2007)
@@ -67,7 +67,7 @@
    {
 #ifdef TEST_THREADS
       static boost::once_flag f = BOOST_ONCE_INIT;
- boost::call_once(&init_data, f);
+ boost::call_once(f,&init_data);
       return do_get_data();
 #else
       static data_type d;

Modified: trunk/libs/thread/doc/once-ref.xml
==============================================================================
--- trunk/libs/thread/doc/once-ref.xml (original)
+++ trunk/libs/thread/doc/once-ref.xml 2007-10-05 08:10:06 EDT (Fri, 05 Oct 2007)
@@ -65,25 +65,23 @@
 
 void thread_proc()
 {
- boost::call_once(&amp;init, once);
+ boost::call_once(once, &amp;init);
 }</programlisting>
                         </para></description>
                         
- <parameter name="func">
- <paramtype>void (*func)()</paramtype>
- </parameter>
-
                         <parameter name="flag">
                                 <paramtype>once_flag&amp;</paramtype>
                         </parameter>
-
- <requires>The function <code>func</code> shall not throw
- exceptions.</requires>
+
+ <parameter name="func">
+ <paramtype>Function func</paramtype>
+ </parameter>
                         
                         <effects>As if (in an atomic fashion):
- <code>if (flag == BOOST_ONCE_INIT) func();</code></effects>
+ <code>if (flag == BOOST_ONCE_INIT) func();</code>. If <code>func()</code> throws an exception, it shall be as if this
+thread never invoked <code>call_once</code></effects>
                         
- <postconditions><code>flag != BOOST_ONCE_INIT</code>
+ <postconditions><code>flag != BOOST_ONCE_INIT</code> unless <code>func()</code> throws an exception.
                         </postconditions>
                 </function>
         </namespace>

Modified: trunk/libs/thread/src/mutex.inl
==============================================================================
--- trunk/libs/thread/src/mutex.inl (original)
+++ trunk/libs/thread/src/mutex.inl 2007-10-05 08:10:06 EDT (Fri, 05 Oct 2007)
@@ -38,7 +38,7 @@
 
 inline bool has_TryEnterCriticalSection()
 {
- boost::call_once(init_TryEnterCriticalSection, once_init_TryEnterCriticalSection);
+ boost::call_once(once_init_TryEnterCriticalSection, init_TryEnterCriticalSection);
     return g_TryEnterCriticalSection != 0;
 }
 

Modified: trunk/libs/thread/src/once.cpp
==============================================================================
--- trunk/libs/thread/src/once.cpp (original)
+++ trunk/libs/thread/src/once.cpp 2007-10-05 08:10:06 EDT (Fri, 05 Oct 2007)
@@ -6,6 +6,7 @@
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
 #include <boost/thread/detail/config.hpp>
+#ifdef BOOST_HAS_MPTASKS
 
 #include <boost/detail/workaround.hpp>
 
@@ -13,59 +14,8 @@
 #include <cstdio>
 #include <cassert>
 
+#include <Multiprocessing.h>
 
-#if defined(BOOST_HAS_WINTHREADS)
-# if BOOST_WORKAROUND(__BORLANDC__,<= 0x551)
- using std::size_t;
-# endif
-# include <windows.h>
-# if defined(BOOST_NO_STRINGSTREAM)
-# include <strstream>
-
-class unfreezer
-{
-public:
- unfreezer(std::ostrstream& s) : m_stream(s) {}
- ~unfreezer() { m_stream.freeze(false); }
-private:
- std::ostrstream& m_stream;
-};
-
-# else
-# include <sstream>
-# endif
-#elif defined(BOOST_HAS_MPTASKS)
-# include <Multiprocessing.h>
-#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<once_callback*>(
- pthread_getspecific(key));
- (**cb)();
- }
-
-}
-#elif defined(BOOST_HAS_MPTASKS)
 namespace {
 void *remote_call_proxy(void *pData)
 {
@@ -82,125 +32,10 @@
 }
 }
 
-#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<LONG*>(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 @@
         MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext);
         assert(flag == true);
     }
-#endif
 }
 
 }
-
-// Change Log:
-// 1 Aug 01 WEKEMPF Initial version.
+#endif

Modified: trunk/libs/thread/src/tss.cpp
==============================================================================
--- trunk/libs/thread/src/tss.cpp (original)
+++ trunk/libs/thread/src/tss.cpp 2007-10-05 08:10:06 EDT (Fri, 05 Oct 2007)
@@ -182,7 +182,7 @@
 namespace detail {
 void tss::init(boost::function1<void, void*>* 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);

Modified: trunk/libs/thread/src/tss_hooks.cpp
==============================================================================
--- trunk/libs/thread/src/tss_hooks.cpp (original)
+++ trunk/libs/thread/src/tss_hooks.cpp 2007-10-05 08:10:06 EDT (Fri, 05 Oct 2007)
@@ -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);
 

Modified: trunk/libs/thread/test/test_once.cpp
==============================================================================
--- trunk/libs/thread/test/test_once.cpp (original)
+++ trunk/libs/thread/test/test_once.cpp 2007-10-05 08:10:06 EDT (Fri, 05 Oct 2007)
@@ -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 <boost/thread/detail/config.hpp>
-
-#include <boost/thread/once.hpp>
-#include <boost/thread/thread.hpp>
+// (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 <boost/test/unit_test.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/once.hpp>
 
-#include <libs/thread/test/util.inl>
-
-int once_value = 0;
-boost::once_flag once = BOOST_ONCE_INIT;
+boost::once_flag flag=BOOST_ONCE_INIT;
+int var_to_init=0;
+boost::mutex m;
 
-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;i<loop_count;++i)
+ {
+ boost::call_once(flag, initialize_variable);
+ my_once_value=var_to_init;
+ if(my_once_value!=1)
+ {
+ break;
+ }
+ }
+ boost::mutex::scoped_lock lock(m);
+ BOOST_CHECK_EQUAL(my_once_value, 1);
 }
 
-void do_test_once()
+void test_call_once()
 {
- const int NUMTHREADS=5;
- boost::thread_group threads;
- for (int i=0; i<NUMTHREADS; ++i)
- threads.create_thread(&test_once_thread);
- threads.join_all();
- BOOST_CHECK_EQUAL(once_value, 1);
+ unsigned const num_threads=100;
+ boost::thread_group group;
+
+ for(unsigned i=0;i<num_threads;++i)
+ {
+ group.create_thread(&call_once_thread);
+ }
+ group.join_all();
+ BOOST_CHECK_EQUAL(var_to_init,1);
 }
 
-void test_once()
-{
- timed_test(&do_test_once, 2);
-}
 
 boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
 {
     boost::unit_test_framework::test_suite* test =
- BOOST_TEST_SUITE("Boost.Threads: once test suite");
+ BOOST_TEST_SUITE("Boost.Threads: call_once test suite");
 
- test->add(BOOST_TEST_CASE(test_once));
+ test->add(BOOST_TEST_CASE(test_call_once));
 
     return test;
 }


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