From 01297016bda3dc1c718b8448a0a5cf4d85ea5141 Mon Sep 17 00:00:00 2001 From: Anthony Williams Date: Tue, 13 Sep 2005 18:44:59 +0000 Subject: [PATCH] Reverted trunk to before adding new threads code [SVN r30957] --- include/boost/thread/detail/once_win32.hpp | 104 --------------- .../thread/detail/win32_thread_primitives.hpp | 52 -------- include/boost/thread/once.hpp | 16 +-- src/once.cpp | 126 +++++++++++++++++- 4 files changed, 124 insertions(+), 174 deletions(-) delete mode 100644 include/boost/thread/detail/once_win32.hpp delete mode 100644 include/boost/thread/detail/win32_thread_primitives.hpp diff --git a/include/boost/thread/detail/once_win32.hpp b/include/boost/thread/detail/once_win32.hpp deleted file mode 100644 index 16538e43..00000000 --- a/include/boost/thread/detail/once_win32.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef BOOST_WIN32_ONCE_HPP -#define BOOST_WIN32_ONCE_HPP - -// once.hpp -// -// (C) Copyright 2005 Anthony Williams -// (C) Copyright 2005 John Maddock -// -// 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 -#include - -namespace boost -{ - typedef long once_flag; - -#define BOOST_ONCE_INIT 0 - - namespace detail - { - struct handle_closer - { - void* const handle_to_close; - handle_closer(void* handle_to_close_): - handle_to_close(handle_to_close_) - {} - ~handle_closer() - { - BOOST_CLOSE_HANDLE(handle_to_close); - } - }; - - struct mutex_releaser - { - void* const mutex_to_release; - mutex_releaser(void* mutex_to_release_): - mutex_to_release(mutex_to_release_) - {} - ~mutex_releaser() - { - BOOST_RELEASE_MUTEX(mutex_to_release); - } - }; - - template - void int_to_string(I p, char* buf) - { - unsigned i=0; - for(; i < sizeof(I)*2; ++i) - { - buf[i] = 'A' + static_cast((p >> (i*4)) & 0x0f); - } - buf[i] = 0; - } - } - - - template - void call_once(Function f,once_flag& flag) - { - // - // Try for a quick win: if the proceedure has already been called - // just skip through: - // - long const function_complete_flag_value=0xc15730e2; - - if(!BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag,function_complete_flag_value, - function_complete_flag_value)) - { - // - // create a name for our mutex, it doesn't really matter what this name is - // as long as it is unique both to this process, and to the address of "flag": - // - char mutex_name[49+sizeof(void*)*2+sizeof(unsigned long)*2] = { "{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag" }; - BOOST_ASSERT(sizeof(mutex_name) == std::strlen(mutex_name) + sizeof(void*)*2 + sizeof(unsigned long)*2 + 1); - BOOST_STATIC_ASSERT(sizeof(void*) == sizeof(std::ptrdiff_t)); - detail::int_to_string(reinterpret_cast(&flag), mutex_name + 48); - detail::int_to_string(BOOST_GET_PROCESS_ID(), mutex_name + 48 + sizeof(void*)*2); - BOOST_ASSERT(sizeof(mutex_name) == std::strlen(mutex_name) + 1); - - void* const mutex_handle(BOOST_CREATE_MUTEX(NULL, 0, mutex_name)); - BOOST_ASSERT(mutex_handle); - detail::handle_closer const closer(mutex_handle); - BOOST_WAIT_FOR_SINGLE_OBJECT(mutex_handle,BOOST_INFINITE); - detail::mutex_releaser const releaser(mutex_handle); - - if(!BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag,function_complete_flag_value, - function_complete_flag_value)) - { - f(); - BOOST_INTERLOCKED_EXCHANGE(&flag,function_complete_flag_value); - } - } - } -} - -#endif diff --git a/include/boost/thread/detail/win32_thread_primitives.hpp b/include/boost/thread/detail/win32_thread_primitives.hpp deleted file mode 100644 index 07a68a89..00000000 --- a/include/boost/thread/detail/win32_thread_primitives.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef BOOST_WIN32_THREAD_PRIMITIVES_HPP -#define BOOST_WIN32_THREAD_PRIMITIVES_HPP - -// win32_thread_primitives.hpp -// -// (C) Copyright 2005 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 - -#if defined( BOOST_USE_WINDOWS_H ) -# include -# define BOOST_CLOSE_HANDLE ::CloseHandle -# define BOOST_RELEASE_MUTEX ::ReleaseMutex -# define BOOST_CREATE_MUTEX ::CreateMutexA -# define BOOST_GET_PROCESS_ID ::GetCurrentProcessId -# define BOOST_WAIT_FOR_SINGLE_OBJECT ::WaitForSingleObject -# define BOOST_CREATE_SEMAPHORE ::CreateSemaphoreA -# define BOOST_RELEASE_SEMAPHORE ::ReleaseSemaphore -# define BOOST_INFINITE INFINITE -#elif defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ ) -namespace boost -{ - namespace detail - { - extern "C" __declspec(dllimport) int __stdcall CloseHandle(void*); - extern "C" __declspec(dllimport) int __stdcall ReleaseMutex(void*); - extern "C" struct _SECURITY_ATTRIBUTES; - extern "C" __declspec(dllimport) void* __stdcall CreateMutexA(_SECURITY_ATTRIBUTES*,int,char const*); - extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentProcessId(); - extern "C" __declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void*,unsigned long); - extern "C" __declspec(dllimport) int __stdcall ReleaseSemaphore(void*,long,long*); - extern "C" __declspec(dllimport) void* __stdcall CreateSemaphoreA(_SECURITY_ATTRIBUTES*,long,long,char const*); - } -} -# define BOOST_CLOSE_HANDLE ::boost::detail::CloseHandle -# define BOOST_RELEASE_MUTEX ::boost::detail::ReleaseMutex -# define BOOST_CREATE_MUTEX ::boost::detail::CreateMutexA -# define BOOST_GET_PROCESS_ID ::boost::detail::GetCurrentProcessId -# define BOOST_WAIT_FOR_SINGLE_OBJECT ::boost::detail::WaitForSingleObject -# define BOOST_CREATE_SEMAPHORE ::boost::detail::CreateSemaphoreA -# define BOOST_RELEASE_SEMAPHORE ::boost::detail::ReleaseSemaphore -# define BOOST_INFINITE 0xffffffff -#else -# error "Win32 functions not available" -#endif - - -#endif diff --git a/include/boost/thread/once.hpp b/include/boost/thread/once.hpp index 9acb6aad..66666f83 100644 --- a/include/boost/thread/once.hpp +++ b/include/boost/thread/once.hpp @@ -8,8 +8,6 @@ // in supporting documentation. William E. Kempf makes no representations // about the suitability of this software for any purpose. // It is provided "as is" without express or implied warranty. -// -// (C) Copyright 2005 Anthony Williams #ifndef BOOST_ONCE_WEK080101_HPP #define BOOST_ONCE_WEK080101_HPP @@ -20,12 +18,6 @@ # include #endif -#if defined(BOOST_HAS_WINTHREADS) - -#include - -#else - namespace boost { #if defined(BOOST_HAS_PTHREADS) @@ -33,16 +25,18 @@ namespace boost { 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 BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag); } // namespace boost -#endif - // Change Log: // 1 Aug 01 WEKEMPF Initial version. -// 6 Sep 05 Anthony Williams. Split win32 stuff into detail/once_win32.hpp #endif // BOOST_ONCE_WEK080101_HPP diff --git a/src/once.cpp b/src/once.cpp index 32361968..67fcf9a9 100644 --- a/src/once.cpp +++ b/src/once.cpp @@ -11,8 +11,6 @@ #include -#ifndef BOOST_HAS_WINTHREADS - #include #include @@ -20,7 +18,27 @@ #include -#if defined(BOOST_HAS_MPTASKS) +#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 @@ -68,13 +86,110 @@ 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) +{ + return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp); +} +} #endif namespace boost { void call_once(void (*func)(), once_flag& flag) { -#if defined(BOOST_HAS_PTHREADS) +#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) + USES_CONVERSION; + HANDLE mutex = CreateMutexW(NULL, FALSE, A2CW(strm.str())); +# 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); @@ -92,8 +207,5 @@ void call_once(void (*func)(), once_flag& flag) } -#endif - // Change Log: // 1 Aug 01 WEKEMPF Initial version. -// 6 Sep 05 Anthony Williams. Removed win32 implementation