1 /////////////////////////////////////////////////////////////////////////////
2 // Name: wx/thrimpl.cpp
3 // Purpose: common part of wxThread Implementations
4 // Author: Vadim Zeitlin
6 // Created: 04.06.02 (extracted from src/*/thread.cpp files)
7 // Copyright: (c) Vadim Zeitlin (2002)
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // this file is supposed to be included only by the various thread.cpp
13 // ----------------------------------------------------------------------------
15 // ----------------------------------------------------------------------------
17 wxMutex
::wxMutex(wxMutexType mutexType
)
19 m_internal
= new wxMutexInternal(mutexType
);
21 if ( !m_internal
->IsOk() )
33 bool wxMutex
::IsOk() const
35 return m_internal
!= NULL
;
38 wxMutexError wxMutex
::Lock()
40 wxCHECK_MSG( m_internal
, wxMUTEX_INVALID
,
41 wxT("wxMutex::Lock(): not initialized") );
43 return m_internal
->Lock();
46 wxMutexError wxMutex
::LockTimeout(unsigned long ms
)
48 wxCHECK_MSG( m_internal
, wxMUTEX_INVALID
,
49 wxT("wxMutex::Lock(): not initialized") );
51 return m_internal
->Lock(ms
);
54 wxMutexError wxMutex
::TryLock()
56 wxCHECK_MSG( m_internal
, wxMUTEX_INVALID
,
57 wxT("wxMutex::TryLock(): not initialized") );
59 return m_internal
->TryLock();
62 wxMutexError wxMutex
::Unlock()
64 wxCHECK_MSG( m_internal
, wxMUTEX_INVALID
,
65 wxT("wxMutex::Unlock(): not initialized") );
67 return m_internal
->Unlock();
70 // --------------------------------------------------------------------------
71 // wxConditionInternal
72 // --------------------------------------------------------------------------
74 // Win32 and OS/2 don't have explicit support for the POSIX condition
75 // variables and their events/event semaphores have quite different semantics,
76 // so we reimplement the conditions from scratch using the mutexes and
78 #if defined(__WINDOWS__) || defined(__OS2__) || defined(__EMX__)
80 class wxConditionInternal
83 wxConditionInternal(wxMutex
& mutex
);
85 bool IsOk() const { return m_mutex
.IsOk() && m_semaphore
.IsOk(); }
88 wxCondError
WaitTimeout(unsigned long milliseconds
);
91 wxCondError
Broadcast();
94 // the number of threads currently waiting for this condition
97 // the critical section protecting m_numWaiters
98 wxCriticalSection m_csWaiters
;
101 wxSemaphore m_semaphore
;
103 wxDECLARE_NO_COPY_CLASS(wxConditionInternal
);
106 wxConditionInternal
::wxConditionInternal(wxMutex
& mutex
)
109 // another thread can't access it until we return from ctor, so no need to
110 // protect access to m_numWaiters here
114 wxCondError wxConditionInternal
::Wait()
116 // increment the number of waiters
118 wxCriticalSectionLocker
lock(m_csWaiters
);
124 // after unlocking the mutex other threads may Signal() us, but it is ok
125 // now as we had already incremented m_numWaiters so Signal() will post the
126 // semaphore and decrement m_numWaiters back even if it is called before we
128 const wxSemaError err
= m_semaphore
.Wait();
132 if ( err
== wxSEMA_NO_ERROR
)
134 // m_numWaiters was decremented by Signal()
135 return wxCOND_NO_ERROR
;
138 // but in case of an error we need to do it manually
140 wxCriticalSectionLocker
lock(m_csWaiters
);
144 return err
== wxSEMA_TIMEOUT ? wxCOND_TIMEOUT
: wxCOND_MISC_ERROR
;
147 wxCondError wxConditionInternal
::WaitTimeout(unsigned long milliseconds
)
150 wxCriticalSectionLocker
lock(m_csWaiters
);
156 wxSemaError err
= m_semaphore
.WaitTimeout(milliseconds
);
160 if ( err
== wxSEMA_NO_ERROR
)
161 return wxCOND_NO_ERROR
;
163 if ( err
== wxSEMA_TIMEOUT
)
165 // a potential race condition exists here: it happens when a waiting
166 // thread times out but doesn't have time to decrement m_numWaiters yet
167 // before Signal() is called in another thread
169 // to handle this particular case, check the semaphore again after
170 // acquiring m_csWaiters lock -- this will catch the signals missed
171 // during this window
172 wxCriticalSectionLocker
lock(m_csWaiters
);
174 err
= m_semaphore
.WaitTimeout(0);
175 if ( err
== wxSEMA_NO_ERROR
)
176 return wxCOND_NO_ERROR
;
178 // we need to decrement m_numWaiters ourselves as it wasn't done by
182 return err
== wxSEMA_TIMEOUT ? wxCOND_TIMEOUT
: wxCOND_MISC_ERROR
;
185 // undo m_numWaiters++ above in case of an error
187 wxCriticalSectionLocker
lock(m_csWaiters
);
191 return wxCOND_MISC_ERROR
;
194 wxCondError wxConditionInternal
::Signal()
196 wxCriticalSectionLocker
lock(m_csWaiters
);
198 if ( m_numWaiters
> 0 )
200 // increment the semaphore by 1
201 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
202 return wxCOND_MISC_ERROR
;
207 return wxCOND_NO_ERROR
;
210 wxCondError wxConditionInternal
::Broadcast()
212 wxCriticalSectionLocker
lock(m_csWaiters
);
214 while ( m_numWaiters
> 0 )
216 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
217 return wxCOND_MISC_ERROR
;
222 return wxCOND_NO_ERROR
;
225 #endif // __WINDOWS__ || __OS2__ || __EMX__
227 // ----------------------------------------------------------------------------
229 // ----------------------------------------------------------------------------
231 wxCondition
::wxCondition(wxMutex
& mutex
)
233 m_internal
= new wxConditionInternal(mutex
);
235 if ( !m_internal
->IsOk() )
242 wxCondition
::~wxCondition()
247 bool wxCondition
::IsOk() const
249 return m_internal
!= NULL
;
252 wxCondError wxCondition
::Wait()
254 wxCHECK_MSG( m_internal
, wxCOND_INVALID
,
255 wxT("wxCondition::Wait(): not initialized") );
257 return m_internal
->Wait();
260 wxCondError wxCondition
::WaitTimeout(unsigned long milliseconds
)
262 wxCHECK_MSG( m_internal
, wxCOND_INVALID
,
263 wxT("wxCondition::Wait(): not initialized") );
265 return m_internal
->WaitTimeout(milliseconds
);
268 wxCondError wxCondition
::Signal()
270 wxCHECK_MSG( m_internal
, wxCOND_INVALID
,
271 wxT("wxCondition::Signal(): not initialized") );
273 return m_internal
->Signal();
276 wxCondError wxCondition
::Broadcast()
278 wxCHECK_MSG( m_internal
, wxCOND_INVALID
,
279 wxT("wxCondition::Broadcast(): not initialized") );
281 return m_internal
->Broadcast();
284 // --------------------------------------------------------------------------
286 // --------------------------------------------------------------------------
288 wxSemaphore
::wxSemaphore(int initialcount
, int maxcount
)
290 m_internal
= new wxSemaphoreInternal( initialcount
, maxcount
);
291 if ( !m_internal
->IsOk() )
298 wxSemaphore
::~wxSemaphore()
303 bool wxSemaphore
::IsOk() const
305 return m_internal
!= NULL
;
308 wxSemaError wxSemaphore
::Wait()
310 wxCHECK_MSG( m_internal
, wxSEMA_INVALID
,
311 wxT("wxSemaphore::Wait(): not initialized") );
313 return m_internal
->Wait();
316 wxSemaError wxSemaphore
::TryWait()
318 wxCHECK_MSG( m_internal
, wxSEMA_INVALID
,
319 wxT("wxSemaphore::TryWait(): not initialized") );
321 return m_internal
->TryWait();
324 wxSemaError wxSemaphore
::WaitTimeout(unsigned long milliseconds
)
326 wxCHECK_MSG( m_internal
, wxSEMA_INVALID
,
327 wxT("wxSemaphore::WaitTimeout(): not initialized") );
329 return m_internal
->WaitTimeout(milliseconds
);
332 wxSemaError wxSemaphore
::Post()
334 wxCHECK_MSG( m_internal
, wxSEMA_INVALID
,
335 wxT("wxSemaphore::Post(): not initialized") );
337 return m_internal
->Post();
340 // ----------------------------------------------------------------------------
342 // ----------------------------------------------------------------------------
344 #include "wx/utils.h"
345 #include "wx/private/threadinfo.h"
346 #include "wx/scopeguard.h"
348 void wxThread
::Sleep(unsigned long milliseconds
)
350 wxMilliSleep(milliseconds
);
353 void *wxThread
::CallEntry()
355 wxON_BLOCK_EXIT0(wxThreadSpecificInfo
::ThreadCleanUp
);