$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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