2
0
mirror of https://github.com/boostorg/thread.git synced 2026-02-10 11:52:10 +00:00

Changed call_once to header-only template that takes arbitrary function objects; this changes parameter order

[SVN r39701]
This commit is contained in:
Anthony Williams
2007-10-05 12:10:06 +00:00
parent a0fff90c26
commit 4b5046366b
7 changed files with 78 additions and 248 deletions

View File

@@ -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 @@ 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<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 @@ 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.