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