|
Boost-Commit : |
From: anthony_at_[hidden]
Date: 2007-10-05 08:20:59
Author: anthonyw
Date: 2007-10-05 08:20:50 EDT (Fri, 05 Oct 2007)
New Revision: 39702
URL: http://svn.boost.org/trac/boost/changeset/39702
Log:
added platform-specific call_once implementations
Added:
trunk/boost/thread/pthread/
trunk/boost/thread/pthread/once.hpp (contents, props changed)
trunk/boost/thread/win32/
trunk/boost/thread/win32/interlocked_read.hpp (contents, props changed)
trunk/boost/thread/win32/once.hpp (contents, props changed)
trunk/boost/thread/win32/thread_primitives.hpp (contents, props changed)
Added: trunk/boost/thread/pthread/once.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/thread/pthread/once.hpp 2007-10-05 08:20:50 EDT (Fri, 05 Oct 2007)
@@ -0,0 +1,74 @@
+#ifndef BOOST_THREAD_PTHREAD_ONCE_HPP
+#define BOOST_THREAD_PTHREAD_ONCE_HPP
+
+// once.hpp
+//
+// (C) Copyright 2007 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/pthread/config.hpp>
+
+#include <pthread.h>
+#include <boost/assert.hpp>
+
+namespace boost {
+
+ struct once_flag
+ {
+ pthread_mutex_t mutex;
+ unsigned flag;
+ };
+
+#define BOOST_ONCE_INIT {PTHREAD_MUTEX_INITIALIZER,0}
+
+ namespace detail
+ {
+ struct pthread_mutex_scoped_lock
+ {
+ pthread_mutex_t * mutex;
+
+ explicit pthread_mutex_scoped_lock(pthread_mutex_t* mutex_):
+ mutex(mutex_)
+ {
+ int const res=pthread_mutex_lock(mutex);
+ BOOST_ASSERT(!res);
+ }
+ ~pthread_mutex_scoped_lock()
+ {
+ int const res=pthread_mutex_unlock(mutex);
+ BOOST_ASSERT(!res);
+ }
+ };
+ }
+
+ template<typename Function>
+ void call_once(once_flag& flag,Function f)
+ {
+ long const function_complete_flag_value=0xc15730e2;
+
+#ifdef BOOST_PTHREAD_HAS_ATOMICS
+ if(::boost::detail::interlocked_read_acquire(&flag.flag)!=function_complete_flag_value)
+ {
+#endif
+ detail::pthread_mutex_scoped_lock const lock(&flag.mutex);
+ if(flag.flag!=function_complete_flag_value)
+ {
+ f();
+#ifdef BOOST_PTHREAD_HAS_ATOMICS
+ ::boost::detail::interlocked_write_release(&flag.flag,function_complete_flag_value);
+#else
+ flag.flag=function_complete_flag_value;
+#endif
+ }
+#ifdef BOOST_PTHREAD_HAS_ATOMICS
+ }
+#endif
+ }
+
+
+}
+
+#endif
Added: trunk/boost/thread/win32/interlocked_read.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/thread/win32/interlocked_read.hpp 2007-10-05 08:20:50 EDT (Fri, 05 Oct 2007)
@@ -0,0 +1,36 @@
+#ifndef BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP
+#define BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP
+
+// interlocked_read_win32.hpp
+//
+// (C) Copyright 2005-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/detail/interlocked.hpp>
+
+extern "C" void _ReadWriteBarrier(void);
+#pragma intrinsic(_ReadWriteBarrier)
+
+namespace boost
+{
+ namespace detail
+ {
+ inline long interlocked_read_acquire(long volatile* x)
+ {
+ long const res=*x;
+ _ReadWriteBarrier();
+ return res;
+ }
+ inline void* interlocked_read_acquire(void* volatile* x)
+ {
+ void* const res=*x;
+ _ReadWriteBarrier();
+ return res;
+ }
+ }
+}
+
+#endif
Added: trunk/boost/thread/win32/once.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/thread/win32/once.hpp 2007-10-05 08:20:50 EDT (Fri, 05 Oct 2007)
@@ -0,0 +1,132 @@
+#ifndef BOOST_THREAD_WIN32_ONCE_HPP
+#define BOOST_THREAD_WIN32_ONCE_HPP
+
+// once.hpp
+//
+// (C) Copyright 2005-7 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 <cstring>
+#include <cstddef>
+#include <boost/assert.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/detail/interlocked.hpp>
+#include <boost/thread/win32/thread_primitives.hpp>
+#include <boost/thread/win32/interlocked_read.hpp>
+
+#ifdef BOOST_NO_STDC_NAMESPACE
+namespace std
+{
+ using ::memcpy;
+ using ::ptrdiff_t;
+}
+#endif
+
+namespace boost
+{
+ typedef long once_flag;
+
+#define BOOST_ONCE_INIT 0
+
+ namespace detail
+ {
+ struct win32_mutex_scoped_lock
+ {
+ void* const mutex_handle;
+ explicit win32_mutex_scoped_lock(void* mutex_handle_):
+ mutex_handle(mutex_handle_)
+ {
+ unsigned long const res=win32::WaitForSingleObject(mutex_handle,win32::infinite);
+ BOOST_ASSERT(!res);
+ }
+ ~win32_mutex_scoped_lock()
+ {
+ bool const success=win32::ReleaseMutex(mutex_handle)!=0;
+ BOOST_ASSERT(success);
+ }
+ };
+
+#ifdef BOOST_NO_ANSI_APIS
+ template <class I>
+ void int_to_string(I p, wchar_t* buf)
+ {
+ for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
+ {
+ *buf = L'A' + static_cast<wchar_t>((p >> (i*4)) & 0x0f);
+ }
+ *buf = 0;
+ }
+#else
+ template <class I>
+ void int_to_string(I p, char* buf)
+ {
+ for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
+ {
+ *buf = 'A' + static_cast<char>((p >> (i*4)) & 0x0f);
+ }
+ *buf = 0;
+ }
+#endif
+
+ // create a named 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":
+ inline void* create_once_mutex(void* flag_address)
+ {
+
+#ifdef BOOST_NO_ANSI_APIS
+ typedef wchar_t char_type;
+ static const char_type fixed_mutex_name[]=L"{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
+#else
+ typedef char char_type;
+ static const char_type fixed_mutex_name[]="{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
+#endif
+ unsigned const once_mutex_name_fixed_buffer_size=sizeof(fixed_mutex_name)/sizeof(char_type);
+ unsigned const once_mutex_name_fixed_length=once_mutex_name_fixed_buffer_size-1;
+ unsigned const once_mutex_name_length=once_mutex_name_fixed_buffer_size+sizeof(void*)*2+sizeof(unsigned long)*2;
+ char_type mutex_name[once_mutex_name_length];
+
+ std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name));
+
+ BOOST_STATIC_ASSERT(sizeof(void*) == sizeof(std::ptrdiff_t));
+ detail::int_to_string(reinterpret_cast<std::ptrdiff_t>(flag_address), mutex_name + once_mutex_name_fixed_length);
+ detail::int_to_string(win32::GetCurrentProcessId(), mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2);
+
+#ifdef BOOST_NO_ANSI_APIS
+ return win32::CreateMutexW(NULL, 0, mutex_name);
+#else
+ return win32::CreateMutexA(NULL, 0, mutex_name);
+#endif
+ }
+
+
+ }
+
+
+ template<typename Function>
+ void call_once(once_flag& flag,Function f)
+ {
+ // Try for a quick win: if the procedure has already been called
+ // just skip through:
+ long const function_complete_flag_value=0xc15730e2;
+
+ if(::boost::detail::interlocked_read_acquire(&flag)!=function_complete_flag_value)
+ {
+ void* const mutex_handle(::boost::detail::create_once_mutex(&flag));
+ BOOST_ASSERT(mutex_handle);
+ detail::win32::handle_manager const closer(mutex_handle);
+ detail::win32_mutex_scoped_lock const lock(mutex_handle);
+
+ if(flag!=function_complete_flag_value)
+ {
+ f();
+ BOOST_INTERLOCKED_EXCHANGE(&flag,function_complete_flag_value);
+ }
+ }
+ }
+}
+
+#endif
Added: trunk/boost/thread/win32/thread_primitives.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/thread/win32/thread_primitives.hpp 2007-10-05 08:20:50 EDT (Fri, 05 Oct 2007)
@@ -0,0 +1,198 @@
+#ifndef BOOST_WIN32_THREAD_PRIMITIVES_HPP
+#define BOOST_WIN32_THREAD_PRIMITIVES_HPP
+
+// win32_thread_primitives.hpp
+//
+// (C) Copyright 2005-6 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/config.hpp>
+#include <boost/assert.hpp>
+#include <boost/thread/exceptions.hpp>
+
+#if defined( BOOST_USE_WINDOWS_H )
+# include <windows.h>
+namespace boost
+{
+ namespace detail
+ {
+ namespace win32
+ {
+ typedef ULONG_PTR ulong_ptr;
+ typedef HANDLE handle;
+ unsigned const infinite=INFINITE;
+ unsigned const timeout=WAIT_TIMEOUT;
+
+ using ::CreateMutexA;
+ using ::CreateEventA;
+ using ::CreateSemaphoreA;
+ using ::CloseHandle;
+ using ::ReleaseMutex;
+ using ::ReleaseSemaphore;
+ using ::SetEvent;
+ using ::ResetEvent;
+ using ::WaitForMultipleObjects;
+ using ::WaitForSingleObject;
+ using ::GetCurrentProcessId;
+ using ::GetCurrentThreadId;
+ using ::GetCurrentThread;
+ using ::GetCurrentProcess;
+ using ::DuplicateHandle;
+ using ::SleepEx;
+ using ::QueueUserAPC;
+ }
+ }
+}
+#elif defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ )
+namespace boost
+{
+ namespace detail
+ {
+ namespace win32
+ {
+
+# ifdef _WIN64
+ typedef unsigned __int64 ulong_ptr;
+# else
+ typedef unsigned long ulong_ptr;
+# endif
+ typedef void* handle;
+ unsigned const infinite=~0U;
+ unsigned const timeout=258U;
+
+ extern "C"
+ {
+ struct _SECURITY_ATTRIBUTES;
+ __declspec(dllimport) void* __stdcall CreateMutexA(_SECURITY_ATTRIBUTES*,int,char const*);
+ __declspec(dllimport) void* __stdcall CreateSemaphoreA(_SECURITY_ATTRIBUTES*,long,long,char const*);
+ __declspec(dllimport) void* __stdcall CreateEventA(_SECURITY_ATTRIBUTES*,int,int,char const*);
+ __declspec(dllimport) int __stdcall CloseHandle(void*);
+ __declspec(dllimport) int __stdcall ReleaseMutex(void*);
+ __declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
+ __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId();
+ __declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void*,unsigned long);
+ __declspec(dllimport) int __stdcall ReleaseSemaphore(void*,long,long*);
+ __declspec(dllimport) void* __stdcall GetCurrentThread();
+ __declspec(dllimport) void* __stdcall GetCurrentProcess();
+ __declspec(dllimport) int __stdcall DuplicateHandle(void*,void*,void*,void**,unsigned long,int,unsigned long);
+ __declspec(dllimport) unsigned long __stdcall SleepEx(unsigned long,int);
+ typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr);
+ __declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr);
+ __declspec(dllimport) int __stdcall SetEvent(void*);
+ __declspec(dllimport) int __stdcall ResetEvent(void*);
+ __declspec(dllimport) unsigned long __stdcall WaitForMultipleObjects(unsigned long nCount,void* const * lpHandles,int bWaitAll,unsigned long dwMilliseconds);
+ }
+ }
+ }
+}
+#else
+# error "Win32 functions not available"
+#endif
+
+namespace boost
+{
+ namespace detail
+ {
+ namespace win32
+ {
+ enum event_type
+ {
+ auto_reset_event=false,
+ manual_reset_event=true
+ };
+
+ enum initial_event_state
+ {
+ event_initially_reset=false,
+ event_initially_set=true
+ };
+
+ inline handle create_anonymous_event(event_type type,initial_event_state state)
+ {
+ handle const res=CreateEventA(0,type,state,0);
+ return res?res:throw thread_resource_error();
+ }
+
+ inline handle create_anonymous_semaphore(long initial_count,long max_count)
+ {
+ handle const res=CreateSemaphoreA(NULL,initial_count,max_count,NULL);
+ return res?res:throw thread_resource_error();
+ }
+
+ inline handle duplicate_handle(handle source)
+ {
+ handle const current_process=GetCurrentProcess();
+ long const same_access_flag=2;
+ handle new_handle=0;
+ bool const success=DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0;
+ return success?new_handle:throw thread_resource_error();
+ }
+
+ inline void release_semaphore(handle semaphore,long count)
+ {
+ bool const success=ReleaseSemaphore(semaphore,count,0)!=0;
+ BOOST_ASSERT(success);
+ }
+
+ class handle_manager
+ {
+ private:
+ handle handle_to_manage;
+ handle_manager(handle_manager&);
+ handle_manager& operator=(handle_manager&);
+
+ void cleanup()
+ {
+ if(handle_to_manage)
+ {
+ unsigned long result=CloseHandle(handle_to_manage);
+ BOOST_ASSERT(result);
+ }
+ }
+
+ public:
+ explicit handle_manager(handle handle_to_manage_):
+ handle_to_manage(handle_to_manage_)
+ {}
+ handle_manager():
+ handle_to_manage(0)
+ {}
+
+ handle_manager& operator=(handle new_handle)
+ {
+ cleanup();
+ handle_to_manage=new_handle;
+ }
+
+ operator handle() const
+ {
+ return handle_to_manage;
+ }
+
+ handle release()
+ {
+ handle const res=handle_to_manage;
+ handle_to_manage=0;
+ return res;
+ }
+
+ bool operator!() const
+ {
+ return !handle_to_manage;
+ }
+
+ ~handle_manager()
+ {
+ cleanup();
+ }
+ };
+
+ }
+ }
+}
+
+
+#endif
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