]> git.saurik.com Git - wxWidgets.git/blame - include/wx/thrimpl.cpp
adapting comment to new implementation
[wxWidgets.git] / include / wx / thrimpl.cpp
CommitLineData
9e84b847
VZ
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$
8// Copyright: (c) Vadim Zeitlin (2002)
65571936 9// Licence: wxWindows licence
9e84b847
VZ
10/////////////////////////////////////////////////////////////////////////////
11
12// this file is supposed to be included only by the various thread.cpp
13
14// ----------------------------------------------------------------------------
15// wxMutex
16// ----------------------------------------------------------------------------
17
18wxMutex::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
29wxMutex::~wxMutex()
30{
31 delete m_internal;
32}
33
34bool wxMutex::IsOk() const
35{
36 return m_internal != NULL;
37}
38
39wxMutexError wxMutex::Lock()
40{
41 wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
42 _T("wxMutex::Lock(): not initialized") );
43
44 return m_internal->Lock();
45}
46
47wxMutexError wxMutex::TryLock()
48{
49 wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
50 _T("wxMutex::TryLock(): not initialized") );
51
52 return m_internal->TryLock();
53}
54
55wxMutexError wxMutex::Unlock()
56{
57 wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
58 _T("wxMutex::Unlock(): not initialized") );
59
60 return m_internal->Unlock();
61}
62
d1bab566
SN
63// --------------------------------------------------------------------------
64// wxConditionInternal
65// --------------------------------------------------------------------------
66
55034339 67#if defined(__WXMSW__) || defined(__OS2__) || defined(__EMX__)
d1bab566
SN
68// Win32 and OS/2 don't have explicit support for the POSIX condition
69// variables and their events/event semaphores have quite different semantics,
70// so we reimplement the conditions from scratch using the mutexes and
71// semaphores
55034339 72#if defined(__OS2__) || defined(__EMX__)
d1bab566
SN
73void InterlockedIncrement(LONG *num)
74{
75 ::DosEnterCritSec();
76 (*num)++;
77 ::DosExitCritSec();
78}
79#endif
80
81class wxConditionInternal
82{
83public:
84 wxConditionInternal(wxMutex& mutex);
85
86 bool IsOk() const { return m_mutex.IsOk() && m_semaphore.IsOk(); }
87
88 wxCondError Wait();
89 wxCondError WaitTimeout(unsigned long milliseconds);
90
91 wxCondError Signal();
92 wxCondError Broadcast();
93
94private:
95 // the number of threads currently waiting for this condition
96 LONG m_numWaiters;
97
98 // the critical section protecting m_numWaiters
99 wxCriticalSection m_csWaiters;
100
101 wxMutex& m_mutex;
102 wxSemaphore m_semaphore;
103
104 DECLARE_NO_COPY_CLASS(wxConditionInternal)
105};
106
107wxConditionInternal::wxConditionInternal(wxMutex& mutex)
108 : m_mutex(mutex)
109{
110 // another thread can't access it until we return from ctor, so no need to
111 // protect access to m_numWaiters here
112 m_numWaiters = 0;
113}
114
115wxCondError wxConditionInternal::Wait()
116{
117 // increment the number of waiters
118 ::InterlockedIncrement(&m_numWaiters);
119
120 m_mutex.Unlock();
121
122 // a potential race condition can occur here
123 //
124 // after a thread increments nwaiters, and unlocks the mutex and before the
125 // semaphore.Wait() is called, if another thread can cause a signal to be
126 // generated
127 //
128 // this race condition is handled by using a semaphore and incrementing the
129 // semaphore only if 'nwaiters' is greater that zero since the semaphore,
130 // can 'remember' signals the race condition will not occur
131
132 // wait ( if necessary ) and decrement semaphore
133 wxSemaError err = m_semaphore.Wait();
134 m_mutex.Lock();
135
faeb3ced
JS
136 if ( err == wxSEMA_NO_ERROR )
137 return wxCOND_NO_ERROR;
138 else if ( err == wxSEMA_TIMEOUT )
139 return wxCOND_TIMEOUT;
140 else
141 return wxCOND_MISC_ERROR;
d1bab566
SN
142}
143
144wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds)
145{
146 ::InterlockedIncrement(&m_numWaiters);
147
148 m_mutex.Unlock();
149
150 // a race condition can occur at this point in the code
151 //
152 // please see the comments in Wait(), for details
153
154 wxSemaError err = m_semaphore.WaitTimeout(milliseconds);
155
dfc69c6d 156 if ( err == wxSEMA_TIMEOUT )
d1bab566
SN
157 {
158 // another potential race condition exists here it is caused when a
159 // 'waiting' thread timesout, and returns from WaitForSingleObject, but
160 // has not yet decremented 'nwaiters'.
161 //
162 // at this point if another thread calls signal() then the semaphore
163 // will be incremented, but the waiting thread will miss it.
164 //
165 // to handle this particular case, the waiting thread calls
166 // WaitForSingleObject again with a timeout of 0, after locking
167 // 'nwaiters_mutex'. this call does not block because of the zero
168 // timeout, but will allow the waiting thread to catch the missed
169 // signals.
170 wxCriticalSectionLocker lock(m_csWaiters);
171
172 err = m_semaphore.WaitTimeout(0);
173
174 if ( err != wxSEMA_NO_ERROR )
175 {
176 m_numWaiters--;
177 }
178 }
179
180 m_mutex.Lock();
181
dfc69c6d
VZ
182 return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR
183 : err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT
184 : wxCOND_MISC_ERROR;
d1bab566
SN
185}
186
187wxCondError 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
203wxCondError 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#endif
218
9e84b847
VZ
219// ----------------------------------------------------------------------------
220// wxCondition
221// ----------------------------------------------------------------------------
222
223wxCondition::wxCondition(wxMutex& mutex)
224{
225 m_internal = new wxConditionInternal(mutex);
226
227 if ( !m_internal->IsOk() )
228 {
229 delete m_internal;
230 m_internal = NULL;
231 }
232}
233
234wxCondition::~wxCondition()
235{
236 delete m_internal;
237}
238
239bool wxCondition::IsOk() const
240{
241 return m_internal != NULL;
242}
243
244wxCondError wxCondition::Wait()
245{
246 wxCHECK_MSG( m_internal, wxCOND_INVALID,
247 _T("wxCondition::Wait(): not initialized") );
248
249 return m_internal->Wait();
250}
251
252wxCondError wxCondition::WaitTimeout(unsigned long milliseconds)
253{
254 wxCHECK_MSG( m_internal, wxCOND_INVALID,
255 _T("wxCondition::Wait(): not initialized") );
256
257 return m_internal->WaitTimeout(milliseconds);
258}
259
260wxCondError wxCondition::Signal()
261{
262 wxCHECK_MSG( m_internal, wxCOND_INVALID,
263 _T("wxCondition::Signal(): not initialized") );
264
265 return m_internal->Signal();
266}
267
268wxCondError wxCondition::Broadcast()
269{
270 wxCHECK_MSG( m_internal, wxCOND_INVALID,
271 _T("wxCondition::Broadcast(): not initialized") );
272
273 return m_internal->Broadcast();
274}
275
276// --------------------------------------------------------------------------
277// wxSemaphore
278// --------------------------------------------------------------------------
279
280wxSemaphore::wxSemaphore(int initialcount, int maxcount)
281{
282 m_internal = new wxSemaphoreInternal( initialcount, maxcount );
283 if ( !m_internal->IsOk() )
284 {
285 delete m_internal;
286 m_internal = NULL;
287 }
288}
289
290wxSemaphore::~wxSemaphore()
291{
292 delete m_internal;
293}
294
295bool wxSemaphore::IsOk() const
296{
297 return m_internal != NULL;
298}
299
300wxSemaError wxSemaphore::Wait()
301{
302 wxCHECK_MSG( m_internal, wxSEMA_INVALID,
303 _T("wxSemaphore::Wait(): not initialized") );
304
305 return m_internal->Wait();
306}
307
308wxSemaError wxSemaphore::TryWait()
309{
310 wxCHECK_MSG( m_internal, wxSEMA_INVALID,
311 _T("wxSemaphore::TryWait(): not initialized") );
312
313 return m_internal->TryWait();
314}
315
316wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds)
317{
318 wxCHECK_MSG( m_internal, wxSEMA_INVALID,
319 _T("wxSemaphore::WaitTimeout(): not initialized") );
320
321 return m_internal->WaitTimeout(milliseconds);
322}
323
324wxSemaError wxSemaphore::Post()
325{
326 wxCHECK_MSG( m_internal, wxSEMA_INVALID,
327 _T("wxSemaphore::Post(): not initialized") );
328
329 return m_internal->Post();
330}
331