1 /////////////////////////////////////////////////////////////////////////////
2 // Name: include/wx/thrimpl.cpp
3 // Purpose: common part of wxThread Implementations
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 04.06.02 (extracted from src/*/thread.cpp files)
7 // RCS-ID: $Id: thrimpl.cpp 66922 2011-02-16 22:26:57Z JS $
8 // Copyright: (c) Vadim Zeitlin (2002)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // this file is supposed to be included only by the various thread.cpp
13
14 // ----------------------------------------------------------------------------
15 // wxMutex
16 // ----------------------------------------------------------------------------
17
wxMutex(wxMutexType mutexType)18 wxMutex::wxMutex(wxMutexType mutexType)
19 {
20 m_internal = new wxMutexInternal(mutexType);
21
22 if ( !m_internal->IsOk() )
23 {
24 delete m_internal;
25 m_internal = NULL;
26 }
27 }
28
~wxMutex()29 wxMutex::~wxMutex()
30 {
31 delete m_internal;
32 }
33
IsOk() const34 bool wxMutex::IsOk() const
35 {
36 return m_internal != NULL;
37 }
38
Lock()39 wxMutexError wxMutex::Lock()
40 {
41 wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
42 wxT("wxMutex::Lock(): not initialized") );
43
44 return m_internal->Lock();
45 }
46
TryLock()47 wxMutexError wxMutex::TryLock()
48 {
49 wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
50 wxT("wxMutex::TryLock(): not initialized") );
51
52 return m_internal->TryLock();
53 }
54
Unlock()55 wxMutexError wxMutex::Unlock()
56 {
57 wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
58 wxT("wxMutex::Unlock(): not initialized") );
59
60 return m_internal->Unlock();
61 }
62
63 // --------------------------------------------------------------------------
64 // wxConditionInternal
65 // --------------------------------------------------------------------------
66
67 // Win32 and OS/2 don't have explicit support for the POSIX condition
68 // variables and their events/event semaphores have quite different semantics,
69 // so we reimplement the conditions from scratch using the mutexes and
70 // semaphores
71 #if defined(__WXMSW__) || defined(__OS2__) || defined(__EMX__)
72
73 class wxConditionInternal
74 {
75 public:
76 wxConditionInternal(wxMutex& mutex);
77
IsOk() const78 bool IsOk() const { return m_mutex.IsOk() && m_semaphore.IsOk(); }
79
80 wxCondError Wait();
81 wxCondError WaitTimeout(unsigned long milliseconds);
82
83 wxCondError Signal();
84 wxCondError Broadcast();
85
86 private:
87 // the number of threads currently waiting for this condition
88 LONG m_numWaiters;
89
90 // the critical section protecting m_numWaiters
91 wxCriticalSection m_csWaiters;
92
93 wxMutex& m_mutex;
94 wxSemaphore m_semaphore;
95
96 DECLARE_NO_COPY_CLASS(wxConditionInternal)
97 };
98
wxConditionInternal(wxMutex & mutex)99 wxConditionInternal::wxConditionInternal(wxMutex& mutex)
100 : m_mutex(mutex)
101 {
102 // another thread can't access it until we return from ctor, so no need to
103 // protect access to m_numWaiters here
104 m_numWaiters = 0;
105 }
106
Wait()107 wxCondError wxConditionInternal::Wait()
108 {
109 // increment the number of waiters
110 {
111 wxCriticalSectionLocker lock(m_csWaiters);
112 m_numWaiters++;
113 }
114
115 m_mutex.Unlock();
116
117 // after unlocking the mutex other threads may Signal() us, but it is ok
118 // now as we had already incremented m_numWaiters so Signal() will post the
119 // semaphore and decrement m_numWaiters back even if it is called before we
120 // start to Wait()
121 const wxSemaError err = m_semaphore.Wait();
122
123 m_mutex.Lock();
124
125 if ( err == wxSEMA_NO_ERROR )
126 {
127 // m_numWaiters was decremented by Signal()
128 return wxCOND_NO_ERROR;
129 }
130
131 // but in case of an error we need to do it manually
132 {
133 wxCriticalSectionLocker lock(m_csWaiters);
134 m_numWaiters--;
135 }
136
137 return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR;
138 }
139
WaitTimeout(unsigned long milliseconds)140 wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds)
141 {
142 {
143 wxCriticalSectionLocker lock(m_csWaiters);
144 m_numWaiters++;
145 }
146
147 m_mutex.Unlock();
148
149 wxSemaError err = m_semaphore.WaitTimeout(milliseconds);
150
151 m_mutex.Lock();
152
153 if ( err == wxSEMA_NO_ERROR )
154 return wxCOND_NO_ERROR;
155
156 if ( err == wxSEMA_TIMEOUT )
157 {
158 // a potential race condition exists here: it happens when a waiting
159 // thread times out but doesn't have time to decrement m_numWaiters yet
160 // before Signal() is called in another thread
161 //
162 // to handle this particular case, check the semaphore again after
163 // acquiring m_csWaiters lock -- this will catch the signals missed
164 // during this window
165 wxCriticalSectionLocker lock(m_csWaiters);
166
167 err = m_semaphore.WaitTimeout(0);
168 if ( err == wxSEMA_NO_ERROR )
169 return wxCOND_NO_ERROR;
170
171 // we need to decrement m_numWaiters ourselves as it wasn't done by
172 // Signal()
173 m_numWaiters--;
174
175 return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR;
176 }
177
178 // undo m_numWaiters++ above in case of an error
179 {
180 wxCriticalSectionLocker lock(m_csWaiters);
181 m_numWaiters--;
182 }
183
184 return wxCOND_MISC_ERROR;
185 }
186
Signal()187 wxCondError wxConditionInternal::Signal()
188 {
189 wxCriticalSectionLocker lock(m_csWaiters);
190
191 if ( m_numWaiters > 0 )
192 {
193 // increment the semaphore by 1
194 if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
195 return wxCOND_MISC_ERROR;
196
197 m_numWaiters--;
198 }
199
200 return wxCOND_NO_ERROR;
201 }
202
Broadcast()203 wxCondError wxConditionInternal::Broadcast()
204 {
205 wxCriticalSectionLocker lock(m_csWaiters);
206
207 while ( m_numWaiters > 0 )
208 {
209 if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
210 return wxCOND_MISC_ERROR;
211
212 m_numWaiters--;
213 }
214
215 return wxCOND_NO_ERROR;
216 }
217
218 #endif // MSW or OS2
219
220 // ----------------------------------------------------------------------------
221 // wxCondition
222 // ----------------------------------------------------------------------------
223
wxCondition(wxMutex & mutex)224 wxCondition::wxCondition(wxMutex& mutex)
225 {
226 m_internal = new wxConditionInternal(mutex);
227
228 if ( !m_internal->IsOk() )
229 {
230 delete m_internal;
231 m_internal = NULL;
232 }
233 }
234
~wxCondition()235 wxCondition::~wxCondition()
236 {
237 delete m_internal;
238 }
239
IsOk() const240 bool wxCondition::IsOk() const
241 {
242 return m_internal != NULL;
243 }
244
Wait()245 wxCondError wxCondition::Wait()
246 {
247 wxCHECK_MSG( m_internal, wxCOND_INVALID,
248 wxT("wxCondition::Wait(): not initialized") );
249
250 return m_internal->Wait();
251 }
252
WaitTimeout(unsigned long milliseconds)253 wxCondError wxCondition::WaitTimeout(unsigned long milliseconds)
254 {
255 wxCHECK_MSG( m_internal, wxCOND_INVALID,
256 wxT("wxCondition::Wait(): not initialized") );
257
258 return m_internal->WaitTimeout(milliseconds);
259 }
260
Signal()261 wxCondError wxCondition::Signal()
262 {
263 wxCHECK_MSG( m_internal, wxCOND_INVALID,
264 wxT("wxCondition::Signal(): not initialized") );
265
266 return m_internal->Signal();
267 }
268
Broadcast()269 wxCondError wxCondition::Broadcast()
270 {
271 wxCHECK_MSG( m_internal, wxCOND_INVALID,
272 wxT("wxCondition::Broadcast(): not initialized") );
273
274 return m_internal->Broadcast();
275 }
276
277 // --------------------------------------------------------------------------
278 // wxSemaphore
279 // --------------------------------------------------------------------------
280
wxSemaphore(int initialcount,int maxcount)281 wxSemaphore::wxSemaphore(int initialcount, int maxcount)
282 {
283 m_internal = new wxSemaphoreInternal( initialcount, maxcount );
284 if ( !m_internal->IsOk() )
285 {
286 delete m_internal;
287 m_internal = NULL;
288 }
289 }
290
~wxSemaphore()291 wxSemaphore::~wxSemaphore()
292 {
293 delete m_internal;
294 }
295
IsOk() const296 bool wxSemaphore::IsOk() const
297 {
298 return m_internal != NULL;
299 }
300
Wait()301 wxSemaError wxSemaphore::Wait()
302 {
303 wxCHECK_MSG( m_internal, wxSEMA_INVALID,
304 wxT("wxSemaphore::Wait(): not initialized") );
305
306 return m_internal->Wait();
307 }
308
TryWait()309 wxSemaError wxSemaphore::TryWait()
310 {
311 wxCHECK_MSG( m_internal, wxSEMA_INVALID,
312 wxT("wxSemaphore::TryWait(): not initialized") );
313
314 return m_internal->TryWait();
315 }
316
WaitTimeout(unsigned long milliseconds)317 wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds)
318 {
319 wxCHECK_MSG( m_internal, wxSEMA_INVALID,
320 wxT("wxSemaphore::WaitTimeout(): not initialized") );
321
322 return m_internal->WaitTimeout(milliseconds);
323 }
324
Post()325 wxSemaError wxSemaphore::Post()
326 {
327 wxCHECK_MSG( m_internal, wxSEMA_INVALID,
328 wxT("wxSemaphore::Post(): not initialized") );
329
330 return m_internal->Post();
331 }
332
333