#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 namespace boost { typedef LONG once_flag; #define BOOST_ONCE_INIT 0 namespace detail { struct handle_closer { HANDLE const handle_to_close; handle_closer(HANDLE handle_to_close_): handle_to_close(handle_to_close_) {} ~handle_closer() { ::CloseHandle(handle_to_close); } }; struct mutex_releaser { HANDLE const mutex_to_release; mutex_releaser(HANDLE mutex_to_release_): mutex_to_release(mutex_to_release_) {} ~mutex_releaser() { ::ReleaseMutex(mutex_to_release); } }; inline void pointer_to_string(void volatile* p, char* buf) { for(int i = 0; i < sizeof(void*)*2; ++i) { buf[i] = 'A' + static_cast((reinterpret_cast(p) >> (i*4)) & 0x7f); } } template void int_to_string(I p, char* buf) { int i; for(i = 0; i < sizeof(I)*2; ++i) { buf[i] = 'A' + static_cast((p >> (i*4)) & 0x7f); } 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: // if(0 == ::InterlockedCompareExchange(&flag , 1 ,1)) { // // 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(DWORD)*2] = { "{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag" }; BOOST_ASSERT(sizeof(mutex_name) == std::strlen(mutex_name) + sizeof(void*)*2 + sizeof(DWORD)*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(::GetCurrentProcessId(), mutex_name + 48 + sizeof(void*)*2); BOOST_ASSERT(sizeof(mutex_name) == std::strlen(mutex_name) + 1); HANDLE const mutex_handle(::CreateMutex(NULL, 0, mutex_name)); if(!mutex_handle) { // TODO: throw something here: abort(); } detail::handle_closer const closer(mutex_handle); ::WaitForSingleObject(mutex_handle,INFINITE); detail::mutex_releaser const releaser(mutex_handle); if(0 == ::InterlockedCompareExchange(&flag , 1 ,1)) { f(); ::InterlockedExchange(&flag,1); } } } } #endif