Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/libs/thread/src/once.cpp @ 12

Last change on this file since 12 was 12, checked in by landauf, 17 years ago

added boost

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