]> git.saurik.com Git - wxWidgets.git/blame - include/wx/thrimpl.cpp
Fixed ReadLine missing last character from text files with no final newline.
[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
d1bab566
SN
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
2d0bea2c 71#if defined(__WXMSW__) || defined(__OS2__) || defined(__EMX__)
d1bab566
SN
72
73class wxConditionInternal
74{
75public:
76 wxConditionInternal(wxMutex& mutex);
77
78 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
86private:
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
99wxConditionInternal::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
107wxCondError wxConditionInternal::Wait()
108{
109 // increment the number of waiters
2d0bea2c
VZ
110 {
111 wxCriticalSectionLocker lock(m_csWaiters);
112 m_numWaiters++;
113 }
d1bab566
SN
114
115 m_mutex.Unlock();
116
117 // a potential race condition can occur here
118 //
119 // after a thread increments nwaiters, and unlocks the mutex and before the
120 // semaphore.Wait() is called, if another thread can cause a signal to be
121 // generated
122 //
123 // this race condition is handled by using a semaphore and incrementing the
124 // semaphore only if 'nwaiters' is greater that zero since the semaphore,
125 // can 'remember' signals the race condition will not occur
126
127 // wait ( if necessary ) and decrement semaphore
128 wxSemaError err = m_semaphore.Wait();
129 m_mutex.Lock();
130
faeb3ced
JS
131 if ( err == wxSEMA_NO_ERROR )
132 return wxCOND_NO_ERROR;
133 else if ( err == wxSEMA_TIMEOUT )
134 return wxCOND_TIMEOUT;
135 else
136 return wxCOND_MISC_ERROR;
d1bab566
SN
137}
138
139wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds)
140{
2d0bea2c
VZ
141 {
142 wxCriticalSectionLocker lock(m_csWaiters);
143 m_numWaiters++;
144 }
d1bab566
SN
145
146 m_mutex.Unlock();
147
148 // a race condition can occur at this point in the code
149 //
150 // please see the comments in Wait(), for details
151
152 wxSemaError err = m_semaphore.WaitTimeout(milliseconds);
153
dfc69c6d 154 if ( err == wxSEMA_TIMEOUT )
d1bab566
SN
155 {
156 // another potential race condition exists here it is caused when a
157 // 'waiting' thread timesout, and returns from WaitForSingleObject, but
158 // has not yet decremented 'nwaiters'.
159 //
160 // at this point if another thread calls signal() then the semaphore
161 // will be incremented, but the waiting thread will miss it.
162 //
163 // to handle this particular case, the waiting thread calls
164 // WaitForSingleObject again with a timeout of 0, after locking
165 // 'nwaiters_mutex'. this call does not block because of the zero
166 // timeout, but will allow the waiting thread to catch the missed
167 // signals.
168 wxCriticalSectionLocker lock(m_csWaiters);
169
170 err = m_semaphore.WaitTimeout(0);
171
172 if ( err != wxSEMA_NO_ERROR )
173 {
174 m_numWaiters--;
175 }
176 }
177
178 m_mutex.Lock();
179
dfc69c6d
VZ
180 return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR
181 : err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT
182 : wxCOND_MISC_ERROR;
d1bab566
SN
183}
184
185wxCondError wxConditionInternal::Signal()
186{
187 wxCriticalSectionLocker lock(m_csWaiters);
188
189 if ( m_numWaiters > 0 )
190 {
191 // increment the semaphore by 1
192 if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
193 return wxCOND_MISC_ERROR;
194
195 m_numWaiters--;
196 }
197
198 return wxCOND_NO_ERROR;
199}
200
201wxCondError wxConditionInternal::Broadcast()
202{
203 wxCriticalSectionLocker lock(m_csWaiters);
204
205 while ( m_numWaiters > 0 )
206 {
207 if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
208 return wxCOND_MISC_ERROR;
209
210 m_numWaiters--;
211 }
212
213 return wxCOND_NO_ERROR;
214}
2d0bea2c
VZ
215
216#endif // MSW or OS2
d1bab566 217
9e84b847
VZ
218// ----------------------------------------------------------------------------
219// wxCondition
220// ----------------------------------------------------------------------------
221
222wxCondition::wxCondition(wxMutex& mutex)
223{
224 m_internal = new wxConditionInternal(mutex);
225
226 if ( !m_internal->IsOk() )
227 {
228 delete m_internal;
229 m_internal = NULL;
230 }
231}
232
233wxCondition::~wxCondition()
234{
235 delete m_internal;
236}
237
238bool wxCondition::IsOk() const
239{
240 return m_internal != NULL;
241}
242
243wxCondError wxCondition::Wait()
244{
245 wxCHECK_MSG( m_internal, wxCOND_INVALID,
246 _T("wxCondition::Wait(): not initialized") );
247
248 return m_internal->Wait();
249}
250
251wxCondError wxCondition::WaitTimeout(unsigned long milliseconds)
252{
253 wxCHECK_MSG( m_internal, wxCOND_INVALID,
254 _T("wxCondition::Wait(): not initialized") );
255
256 return m_internal->WaitTimeout(milliseconds);
257}
258
259wxCondError wxCondition::Signal()
260{
261 wxCHECK_MSG( m_internal, wxCOND_INVALID,
262 _T("wxCondition::Signal(): not initialized") );
263
264 return m_internal->Signal();
265}
266
267wxCondError wxCondition::Broadcast()
268{
269 wxCHECK_MSG( m_internal, wxCOND_INVALID,
270 _T("wxCondition::Broadcast(): not initialized") );
271
272 return m_internal->Broadcast();
273}
274
275// --------------------------------------------------------------------------
276// wxSemaphore
277// --------------------------------------------------------------------------
278
279wxSemaphore::wxSemaphore(int initialcount, int maxcount)
280{
281 m_internal = new wxSemaphoreInternal( initialcount, maxcount );
282 if ( !m_internal->IsOk() )
283 {
284 delete m_internal;
285 m_internal = NULL;
286 }
287}
288
289wxSemaphore::~wxSemaphore()
290{
291 delete m_internal;
292}
293
294bool wxSemaphore::IsOk() const
295{
296 return m_internal != NULL;
297}
298
299wxSemaError wxSemaphore::Wait()
300{
301 wxCHECK_MSG( m_internal, wxSEMA_INVALID,
302 _T("wxSemaphore::Wait(): not initialized") );
303
304 return m_internal->Wait();
305}
306
307wxSemaError wxSemaphore::TryWait()
308{
309 wxCHECK_MSG( m_internal, wxSEMA_INVALID,
310 _T("wxSemaphore::TryWait(): not initialized") );
311
312 return m_internal->TryWait();
313}
314
315wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds)
316{
317 wxCHECK_MSG( m_internal, wxSEMA_INVALID,
318 _T("wxSemaphore::WaitTimeout(): not initialized") );
319
320 return m_internal->WaitTimeout(milliseconds);
321}
322
323wxSemaError wxSemaphore::Post()
324{
325 wxCHECK_MSG( m_internal, wxSEMA_INVALID,
326 _T("wxSemaphore::Post(): not initialized") );
327
328 return m_internal->Post();
329}
330