blocxx
ThreadOnce.hpp
Go to the documentation of this file.
1/*******************************************************************************
2* Copyright (C) 2005, Vintela, Inc. All rights reserved.
3* Copyright (C) 2006, Novell, Inc. All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7*
8* * Redistributions of source code must retain the above copyright notice,
9* this list of conditions and the following disclaimer.
10* * Redistributions in binary form must reproduce the above copyright
11* notice, this list of conditions and the following disclaimer in the
12* documentation and/or other materials provided with the distribution.
13* * Neither the name of
14* Vintela, Inc.,
15* nor Novell, Inc.,
16* nor the names of its contributors or employees may be used to
17* endorse or promote products derived from this software without
18* specific prior written permission.
19*
20* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30* POSSIBILITY OF SUCH DAMAGE.
31*******************************************************************************/
32
33
37
38#ifndef BLOCXX_THREAD_ONCE_HPP_INCLUDE_GUARD_
39#define BLOCXX_THREAD_ONCE_HPP_INCLUDE_GUARD_
40#include "blocxx/BLOCXX_config.h"
41#include "blocxx/Assertion.hpp"
42
43#if defined(BLOCXX_USE_PTHREAD)
44#include <pthread.h>
45#include <csignal> // for sig_atomic_t
46#include <cassert>
48#elif defined(BLOCXX_WIN32)
49#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
50#include <wtypes.h>
51#endif
52
53namespace BLOCXX_NAMESPACE
54{
55
56#ifdef BLOCXX_NCR
57#ifndef PTHREAD_MUTEX_INITIALIZER
58#define PTHREAD_MUTEX_INITIALIZER {NULL, 0, 0}
59#endif
60#endif
61
62#if defined(BLOCXX_USE_PTHREAD)
63
64struct OnceFlag
65{
66 volatile ::sig_atomic_t flag;
67 ::pthread_mutex_t mtx;
68};
69
70#define BLOCXX_ONCE_INIT {0, PTHREAD_MUTEX_INITIALIZER}
71
72#elif defined(BLOCXX_WIN32)
73
74typedef long OnceFlag;
75#define BLOCXX_ONCE_INIT 0
76
77#else
78#error "Port me!"
79#endif
80
85template <typename FuncT>
86void BLOCXX_COMMON_API callOnce(OnceFlag& flag, FuncT F);
87
88
89
90#if defined(BLOCXX_USE_PTHREAD)
91
92class CallOnce_pthread_MutexLock
93{
94public:
95 CallOnce_pthread_MutexLock(::pthread_mutex_t* mtx)
96 : m_mtx(mtx)
97 {
98#ifdef BLOCXX_NCR //we get coredump without initialization
99 if (m_mtx->field1 == NULL)
100 {
101 pthread_mutexattr_t attr;
102 int ret = pthread_mutexattr_create(&attr);
103 assert(ret == 0);
104 ret = pthread_mutex_init(m_mtx, attr);
105 assert(ret == 0);
106 pthread_mutexattr_delete(&attr);
107 }
108#endif
109
110#ifndef NDEBUG
111 int res =
112#endif // Avoid unused variable warnings
113 pthread_mutex_lock(m_mtx);
114 assert(res == 0);
115 }
116 ~CallOnce_pthread_MutexLock()
117 {
118#ifndef NDEBUG
119 int res =
120#endif // Avoid unused variable warnings
121 pthread_mutex_unlock(m_mtx);
122 assert(res == 0);
123
124#ifdef BLOCXX_NCR
125 pthread_mutex_destroy(m_mtx);
126#endif
127 }
128private:
129 ::pthread_mutex_t* m_mtx;
130};
131
132template <typename FuncT>
133inline void callOnce(OnceFlag& flag, FuncT f)
134{
136 if (flag.flag == 0)
137 {
138 CallOnce_pthread_MutexLock lock(&flag.mtx);
139 if (flag.flag == 0)
140 {
141 f();
142 flag.flag = 1;
143 }
144 }
145}
146
147#endif
148
149#if defined(BLOCXX_WIN32)
150
151template <typename FuncT>
152inline void callOnce(OnceFlag& flag, FuncT f)
153{
154 // this is the double-checked locking pattern, but with a bit more strength than normally implemented :-)
155 if (InterlockedCompareExchange(&flag, 1, 1) == 0)
156 {
157 wchar_t mutexName[MAX_PATH];
158 _snwprintf(mutexName, MAX_PATH, L"%X-%p-587ccea9-c95a-4e81-ac51-ab0ddc6cef63", GetCurrentProcessId(), &flag);
159 mutexName[MAX_PATH - 1] = 0;
160
161 HANDLE mutex = CreateMutexW(NULL, FALSE, mutexName);
162 BLOCXX_ASSERT(mutex != NULL);
163
164 int res = 0;
165 res = WaitForSingleObject(mutex, INFINITE);
166 BLOCXX_ASSERT(res == WAIT_OBJECT_0);
167
168 if (InterlockedCompareExchange(&flag, 1, 1) == 0)
169 {
170 try
171 {
172 f();
173 }
174 catch (...)
175 {
176 res = ReleaseMutex(mutex);
177 BLOCXX_ASSERT(res);
178 res = CloseHandle(mutex);
179 BLOCXX_ASSERT(res);
180 throw;
181 }
182 InterlockedExchange(&flag, 1);
183 }
184
185 res = ReleaseMutex(mutex);
186 BLOCXX_ASSERT(res);
187 res = CloseHandle(mutex);
188 BLOCXX_ASSERT(res);
189 }
190}
191
192#endif
193
194} // end namespace BLOCXX_NAMESPACE
195
196#endif
197
#define BLOCXX_ASSERT(CON)
BLOCXX_ASSERT works similar to the assert() macro, but instead of calling abort(),...
Definition Assertion.hpp:57
#define F(x, y, z)
Definition MD5.cpp:209
Taken from RFC 1321.
void BLOCXX_COMMON_API callOnce(OnceFlag &flag, FuncT F)
The first time callOnce is called with a given onceFlag argument, it calls func with no argument and ...
void readWriteMemoryBarrier()
This function is solely for the use of libblocxx threading primitives.