Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/thread/src/once.cpp @ 29

Last change on this file since 29 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 5.5 KB
Line 
1// Copyright (C) 2001-2003
2// William E. Kempf
3//
4//  Distributed under the Boost Software License, Version 1.0. (See accompanying
5//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7#include <boost/thread/detail/config.hpp>
8
9#include <boost/detail/workaround.hpp>
10
11#include <boost/thread/once.hpp>
12#include <cstdio>
13#include <cassert>
14
15
16#if defined(BOOST_HAS_WINTHREADS)
17#   if BOOST_WORKAROUND(__BORLANDC__,<= 0x551)
18      using std::size_t;
19#   endif
20#   include <windows.h>
21#   if defined(BOOST_NO_STRINGSTREAM)
22#       include <strstream>
23
24class unfreezer
25{
26public:
27    unfreezer(std::ostrstream& s) : m_stream(s) {}
28    ~unfreezer() { m_stream.freeze(false); }
29private:
30    std::ostrstream& m_stream;
31};
32
33#   else
34#       include <sstream>
35#   endif
36#elif defined(BOOST_HAS_MPTASKS)
37#   include <Multiprocessing.h>
38#endif
39
40#ifdef BOOST_NO_STDC_NAMESPACE
41namespace std { using ::sprintf; }
42#endif
43
44#if defined(BOOST_HAS_PTHREADS)
45namespace {
46pthread_key_t key;
47pthread_once_t once = PTHREAD_ONCE_INIT;
48
49typedef void (*once_callback)();
50}
51
52extern "C" {
53
54    static void key_init()
55    {
56        pthread_key_create(&key, 0);
57    }
58
59    static void do_once()
60    {
61        once_callback* cb = reinterpret_cast<once_callback*>(
62            pthread_getspecific(key));
63        (**cb)();
64    }
65
66}
67#elif defined(BOOST_HAS_MPTASKS)
68namespace {
69void *remote_call_proxy(void *pData)
70{
71    std::pair<void (*)(), boost::once_flag *> &rData(
72        *reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
73
74    if(*rData.second == false)
75    {
76        rData.first();
77        *rData.second = true;
78    }
79
80    return(NULL);
81}
82}
83
84#elif defined(BOOST_HAS_WINTHREADS)
85namespace {
86// The signature for InterlockedCompareExchange has changed with the
87// addition of Win64 support. I can't determine any (consistent and
88// portable) way of using conditional compilation to detect this, so
89// we use these type wrappers.  Unfortunately, the various vendors
90// use different calling conventions and other signature anamolies,
91// and thus have unique types as well.  This is known to work on VC6,
92// VC7, Borland 5.5.2 and gcc 3.2.  Are there other signatures for
93// other platforms?
94inline LONG ice_wrapper(LONG (__stdcall *ice)(LONG*, LONG, LONG),
95    volatile LONG* dest, LONG exch, LONG cmp)
96{
97    return (*ice)(const_cast<LONG*>(dest), exch, cmp);
98}
99
100inline LONG ice_wrapper(LONG (__stdcall *ice)(volatile LONG*, LONG, LONG),
101    volatile LONG* dest, LONG exch, LONG cmp)
102{
103    return (*ice)(dest, exch, cmp);
104}
105
106inline LONG ice_wrapper(LPVOID (__stdcall *ice)(LPVOID*, LPVOID, LPVOID),
107    volatile LONG* dest, LONG exch, LONG cmp)
108{
109    return (LONG)(*ice)((LPVOID*)dest, (LPVOID)exch, (LPVOID)cmp);
110}
111
112// The friendly form of InterlockedCompareExchange that defers
113// according to the above function type wrappers.
114inline LONG compare_exchange(volatile LPLONG dest, LONG exch, LONG cmp)
115{
116#ifdef _WIN64
117    // Original patch from Anthony Williams.
118    // I (Roland Schwarz) am trying this for RC_1_34_0, since x64 regressions are
119    // currently not run on x64 platforms for HEAD
120    return InterlockedCompareExchange(dest, exch,cmp);
121#else   
122    return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp);
123#endif
124}
125}
126#endif
127
128namespace boost {
129
130void call_once(void (*func)(), once_flag& flag)
131{
132#if defined(BOOST_HAS_WINTHREADS)
133    if (compare_exchange(&flag, 1, 1) == 0)
134    {
135#if defined(BOOST_NO_STRINGSTREAM)
136        std::ostrstream strm;
137        strm << "2AC1A572DB6944B0A65C38C4140AF2F4" 
138             << std::hex
139             << GetCurrentProcessId() 
140             << &flag
141             << std::ends;
142        unfreezer unfreeze(strm);
143#   if defined (BOOST_NO_ANSI_APIS)
144        USES_CONVERSION;
145        HANDLE mutex = CreateMutexW(NULL, FALSE, A2CW(strm.str()));
146#   else
147        HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str());
148#   endif
149#else
150#   if defined (BOOST_NO_ANSI_APIS)
151        std::wostringstream strm;
152        strm << L"2AC1A572DB6944B0A65C38C4140AF2F4" 
153             << std::hex
154             << GetCurrentProcessId() 
155             << &flag;
156        HANDLE mutex = CreateMutexW(NULL, FALSE, strm.str().c_str());
157#   else
158        std::ostringstream strm;
159        strm << "2AC1A572DB6944B0A65C38C4140AF2F4" 
160             << std::hex
161             << GetCurrentProcessId() 
162             << &flag;
163        HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str().c_str());
164#   endif
165#endif
166        assert(mutex != NULL);
167
168        int res = 0;
169        res = WaitForSingleObject(mutex, INFINITE);
170        assert(res == WAIT_OBJECT_0);
171
172        if (compare_exchange(&flag, 1, 1) == 0)
173        {
174            try
175            {
176                func();
177            }
178            catch (...)
179            {
180                res = ReleaseMutex(mutex);
181                assert(res);
182                res = CloseHandle(mutex);
183                assert(res);
184                throw;
185            }
186            InterlockedExchange(&flag, 1);
187        }
188
189        res = ReleaseMutex(mutex);
190        assert(res);
191        res = CloseHandle(mutex);
192        assert(res);
193    }
194#elif defined(BOOST_HAS_PTHREADS)
195    pthread_once(&once, &key_init);
196    pthread_setspecific(key, &func);
197    pthread_once(&flag, do_once);
198#elif defined(BOOST_HAS_MPTASKS)
199    if(flag == false)
200    {
201        // all we do here is make a remote call to blue, as blue is not
202        // reentrant.
203        std::pair<void (*)(), once_flag *> sData(func, &flag);
204        MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext);
205        assert(flag == true);
206    }
207#endif
208}
209
210}
211
212// Change Log:
213//   1 Aug 01  WEKEMPF Initial version.
Note: See TracBrowser for help on using the repository browser.