PageRenderTime 16ms CodeModel.GetById 1ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Dependencies/Boost/boost/thread/win32/once.hpp

http://hadesmem.googlecode.com/
C++ Header | 205 lines | 176 code | 19 blank | 10 comment | 16 complexity | a133dfb6b6be3fbc049ee25bc7f3272e MD5 | raw file
  1#ifndef BOOST_THREAD_WIN32_ONCE_HPP
  2#define BOOST_THREAD_WIN32_ONCE_HPP
  3
  4//  once.hpp
  5//
  6//  (C) Copyright 2005-7 Anthony Williams 
  7//  (C) Copyright 2005 John Maddock
  8//
  9//  Distributed under the Boost Software License, Version 1.0. (See
 10//  accompanying file LICENSE_1_0.txt or copy at
 11//  http://www.boost.org/LICENSE_1_0.txt)
 12
 13#include <cstring>
 14#include <cstddef>
 15#include <boost/assert.hpp>
 16#include <boost/static_assert.hpp>
 17#include <boost/detail/interlocked.hpp>
 18#include <boost/thread/win32/thread_primitives.hpp>
 19#include <boost/thread/win32/interlocked_read.hpp>
 20
 21#include <boost/config/abi_prefix.hpp>
 22
 23#ifdef BOOST_NO_STDC_NAMESPACE
 24namespace std
 25{
 26    using ::memcpy;
 27    using ::ptrdiff_t;
 28}
 29#endif
 30
 31namespace boost
 32{
 33    struct once_flag
 34    {
 35        long status;
 36        long count;
 37    };
 38
 39#define BOOST_ONCE_INIT {0,0}
 40
 41    namespace detail
 42    {
 43#ifdef BOOST_NO_ANSI_APIS
 44        typedef wchar_t once_char_type;
 45#else
 46        typedef char once_char_type;
 47#endif
 48        unsigned const once_mutex_name_fixed_length=54;
 49        unsigned const once_mutex_name_length=once_mutex_name_fixed_length+
 50            sizeof(void*)*2+sizeof(unsigned long)*2+1;
 51
 52        template <class I>
 53        void int_to_string(I p, once_char_type* buf)
 54        {
 55            for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
 56            {
 57#ifdef BOOST_NO_ANSI_APIS
 58                once_char_type const a=L'A';
 59#else
 60                once_char_type const a='A';
 61#endif
 62                *buf = a + static_cast<once_char_type>((p >> (i*4)) & 0x0f);
 63            }
 64            *buf = 0;
 65        }
 66
 67        inline void name_once_mutex(once_char_type* mutex_name,void* flag_address)
 68        {
 69#ifdef BOOST_NO_ANSI_APIS
 70            static const once_char_type fixed_mutex_name[]=L"Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
 71#else
 72            static const once_char_type fixed_mutex_name[]="Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
 73#endif
 74            BOOST_STATIC_ASSERT(sizeof(fixed_mutex_name) == 
 75                                (sizeof(once_char_type)*(once_mutex_name_fixed_length+1)));
 76            
 77            std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name));
 78            detail::int_to_string(reinterpret_cast<std::ptrdiff_t>(flag_address), 
 79                                  mutex_name + once_mutex_name_fixed_length);
 80            detail::int_to_string(win32::GetCurrentProcessId(), 
 81                                  mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2);
 82        }
 83                        
 84        inline void* open_once_event(once_char_type* mutex_name,void* flag_address)
 85        {
 86            if(!*mutex_name)
 87            {
 88                name_once_mutex(mutex_name,flag_address);
 89            }
 90            
 91#ifdef BOOST_NO_ANSI_APIS                        
 92            return ::boost::detail::win32::OpenEventW(
 93#else
 94            return ::boost::detail::win32::OpenEventA(
 95#endif
 96                ::boost::detail::win32::synchronize | 
 97                ::boost::detail::win32::event_modify_state,
 98                false,
 99                mutex_name);
100        }
101
102        inline void* create_once_event(once_char_type* mutex_name,void* flag_address)
103        {
104            if(!*mutex_name)
105            {
106                name_once_mutex(mutex_name,flag_address);
107            }
108#ifdef BOOST_NO_ANSI_APIS                        
109            return ::boost::detail::win32::CreateEventW(
110#else
111            return ::boost::detail::win32::CreateEventA(
112#endif
113                0,::boost::detail::win32::manual_reset_event,
114                ::boost::detail::win32::event_initially_reset,
115                mutex_name);
116        }
117    }
118    
119
120    template<typename Function>
121    void call_once(once_flag& flag,Function f)
122    {
123        // Try for a quick win: if the procedure has already been called
124        // just skip through:
125        long const function_complete_flag_value=0xc15730e2;
126        long const running_value=0x7f0725e3;
127        long status;
128        bool counted=false;
129        detail::win32::handle_manager event_handle;
130        detail::once_char_type mutex_name[detail::once_mutex_name_length];
131        mutex_name[0]=0;
132
133        while((status=::boost::detail::interlocked_read_acquire(&flag.status))
134              !=function_complete_flag_value)
135        {
136            status=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag.status,running_value,0);
137            if(!status)
138            {
139                try
140                {
141                    if(!event_handle)
142                    {
143                        event_handle=detail::open_once_event(mutex_name,&flag);
144                    }
145                    if(event_handle)
146                    {
147                        ::boost::detail::win32::ResetEvent(event_handle);
148                    }
149                    f();
150                    if(!counted)
151                    {
152                        BOOST_INTERLOCKED_INCREMENT(&flag.count);
153                        counted=true;
154                    }
155                    BOOST_INTERLOCKED_EXCHANGE(&flag.status,function_complete_flag_value);
156                    if(!event_handle && 
157                       (::boost::detail::interlocked_read_acquire(&flag.count)>1))
158                    {
159                        event_handle=detail::create_once_event(mutex_name,&flag);
160                    }
161                    if(event_handle)
162                    {
163                        ::boost::detail::win32::SetEvent(event_handle);
164                    }
165                    break;
166                }
167                catch(...)
168                {
169                    BOOST_INTERLOCKED_EXCHANGE(&flag.status,0);
170                    if(!event_handle)
171                    {
172                        event_handle=detail::open_once_event(mutex_name,&flag);
173                    }
174                    if(event_handle)
175                    {
176                        ::boost::detail::win32::SetEvent(event_handle);
177                    }
178                    throw;
179                }
180            }
181
182            if(!counted)
183            {
184                BOOST_INTERLOCKED_INCREMENT(&flag.count);
185                counted=true;
186                status=::boost::detail::interlocked_read_acquire(&flag.status);
187                if(status==function_complete_flag_value)
188                {
189                    break;
190                }
191                if(!event_handle)
192                {
193                    event_handle=detail::create_once_event(mutex_name,&flag);
194                    continue;
195                }
196            }
197            BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
198                             event_handle,::boost::detail::win32::infinite));
199        }
200    }
201}
202
203#include <boost/config/abi_suffix.hpp>
204
205#endif