]> git.saurik.com Git - wxWidgets.git/blob - include/wx/thrimpl.cpp
Applied #15226 wxRichTextCtrl: Implement setting properties with undo for objects...
[wxWidgets.git] / include / wx / thrimpl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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 // Copyright: (c) Vadim Zeitlin (2002)
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // this file is supposed to be included only by the various thread.cpp
12
13 // ----------------------------------------------------------------------------
14 // wxMutex
15 // ----------------------------------------------------------------------------
16
17 wxMutex::wxMutex(wxMutexType mutexType)
18 {
19 m_internal = new wxMutexInternal(mutexType);
20
21 if ( !m_internal->IsOk() )
22 {
23 delete m_internal;
24 m_internal = NULL;
25 }
26 }
27
28 wxMutex::~wxMutex()
29 {
30 delete m_internal;
31 }
32
33 bool wxMutex::IsOk() const
34 {
35 return m_internal != NULL;
36 }
37
38 wxMutexError wxMutex::Lock()
39 {
40 wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
41 wxT("wxMutex::Lock(): not initialized") );
42
43 return m_internal->Lock();
44 }
45
46 wxMutexError wxMutex::LockTimeout(unsigned long ms)
47 {
48 wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
49 wxT("wxMutex::Lock(): not initialized") );
50
51 return m_internal->Lock(ms);
52 }
53
54 wxMutexError wxMutex::TryLock()
55 {
56 wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
57 wxT("wxMutex::TryLock(): not initialized") );
58
59 return m_internal->TryLock();
60 }
61
62 wxMutexError wxMutex::Unlock()
63 {
64 wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
65 wxT("wxMutex::Unlock(): not initialized") );
66
67 return m_internal->Unlock();
68 }
69
70 // --------------------------------------------------------------------------
71 // wxConditionInternal
72 // --------------------------------------------------------------------------
73
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
77 // semaphores
78 #if defined(__WINDOWS__) || defined(__OS2__) || defined(__EMX__)
79
80 class wxConditionInternal
81 {
82 public:
83 wxConditionInternal(wxMutex& mutex);
84
85 bool IsOk() const { return m_mutex.IsOk() && m_semaphore.IsOk(); }
86
87 wxCondError Wait();
88 wxCondError WaitTimeout(unsigned long milliseconds);
89
90 wxCondError Signal();
91 wxCondError Broadcast();
92
93 private:
94 // the number of threads currently waiting for this condition
95 LONG m_numWaiters;
96
97 // the critical section protecting m_numWaiters
98 wxCriticalSection m_csWaiters;
99
100 wxMutex& m_mutex;
101 wxSemaphore m_semaphore;
102
103 wxDECLARE_NO_COPY_CLASS(wxConditionInternal);
104 };
105
106 wxConditionInternal::wxConditionInternal(wxMutex& mutex)
107 : m_mutex(mutex)
108 {
109 // another thread can't access it until we return from ctor, so no need to
110 // protect access to m_numWaiters here
111 m_numWaiters = 0;
112 }
113
114 wxCondError wxConditionInternal::Wait()
115 {
116 // increment the number of waiters
117 {
118 wxCriticalSectionLocker lock(m_csWaiters);
119 m_numWaiters++;
120 }
121
122 m_mutex.Unlock();
123
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
127 // start to Wait()
128 const wxSemaError err = m_semaphore.Wait();
129
130 m_mutex.Lock();
131
132 if ( err == wxSEMA_NO_ERROR )
133 {
134 // m_numWaiters was decremented by Signal()
135 return wxCOND_NO_ERROR;
136 }
137
138 // but in case of an error we need to do it manually
139 {
140 wxCriticalSectionLocker lock(m_csWaiters);
141 m_numWaiters--;
142 }
143
144 return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR;
145 }
146
147 wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds)
148 {
149 {
150 wxCriticalSectionLocker lock(m_csWaiters);
151 m_numWaiters++;
152 }
153
154 m_mutex.Unlock();
155
156 wxSemaError err = m_semaphore.WaitTimeout(milliseconds);
157
158 m_mutex.Lock();
159
160 if ( err == wxSEMA_NO_ERROR )
161 return wxCOND_NO_ERROR;
162
163 if ( err == wxSEMA_TIMEOUT )
164 {
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
168 //
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);
173
174 err = m_semaphore.WaitTimeout(0);
175 if ( err == wxSEMA_NO_ERROR )
176 return wxCOND_NO_ERROR;
177
178 // we need to decrement m_numWaiters ourselves as it wasn't done by
179 // Signal()
180 m_numWaiters--;
181
182 return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR;
183 }
184
185 // undo m_numWaiters++ above in case of an error
186 {
187 wxCriticalSectionLocker lock(m_csWaiters);
188 m_numWaiters--;
189 }
190
191 return wxCOND_MISC_ERROR;
192 }
193
194 wxCondError wxConditionInternal::Signal()
195 {
196 wxCriticalSectionLocker lock(m_csWaiters);
197
198 if ( m_numWaiters > 0 )
199 {
200 // increment the semaphore by 1
201 if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
202 return wxCOND_MISC_ERROR;
203
204 m_numWaiters--;
205 }
206
207 return wxCOND_NO_ERROR;
208 }
209
210 wxCondError wxConditionInternal::Broadcast()
211 {
212 wxCriticalSectionLocker lock(m_csWaiters);
213
214 while ( m_numWaiters > 0 )
215 {
216 if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
217 return wxCOND_MISC_ERROR;
218
219 m_numWaiters--;
220 }
221
222 return wxCOND_NO_ERROR;
223 }
224
225 #endif // __WINDOWS__ || __OS2__ || __EMX__
226
227 // ----------------------------------------------------------------------------
228 // wxCondition
229 // ----------------------------------------------------------------------------
230
231 wxCondition::wxCondition(wxMutex& mutex)
232 {
233 m_internal = new wxConditionInternal(mutex);
234
235 if ( !m_internal->IsOk() )
236 {
237 delete m_internal;
238 m_internal = NULL;
239 }
240 }
241
242 wxCondition::~wxCondition()
243 {
244 delete m_internal;
245 }
246
247 bool wxCondition::IsOk() const
248 {
249 return m_internal != NULL;
250 }
251
252 wxCondError wxCondition::Wait()
253 {
254 wxCHECK_MSG( m_internal, wxCOND_INVALID,
255 wxT("wxCondition::Wait(): not initialized") );
256
257 return m_internal->Wait();
258 }
259
260 wxCondError wxCondition::WaitTimeout(unsigned long milliseconds)
261 {
262 wxCHECK_MSG( m_internal, wxCOND_INVALID,
263 wxT("wxCondition::Wait(): not initialized") );
264
265 return m_internal->WaitTimeout(milliseconds);
266 }
267
268 wxCondError wxCondition::Signal()
269 {
270 wxCHECK_MSG( m_internal, wxCOND_INVALID,
271 wxT("wxCondition::Signal(): not initialized") );
272
273 return m_internal->Signal();
274 }
275
276 wxCondError wxCondition::Broadcast()
277 {
278 wxCHECK_MSG( m_internal, wxCOND_INVALID,
279 wxT("wxCondition::Broadcast(): not initialized") );
280
281 return m_internal->Broadcast();
282 }
283
284 // --------------------------------------------------------------------------
285 // wxSemaphore
286 // --------------------------------------------------------------------------
287
288 wxSemaphore::wxSemaphore(int initialcount, int maxcount)
289 {
290 m_internal = new wxSemaphoreInternal( initialcount, maxcount );
291 if ( !m_internal->IsOk() )
292 {
293 delete m_internal;
294 m_internal = NULL;
295 }
296 }
297
298 wxSemaphore::~wxSemaphore()
299 {
300 delete m_internal;
301 }
302
303 bool wxSemaphore::IsOk() const
304 {
305 return m_internal != NULL;
306 }
307
308 wxSemaError wxSemaphore::Wait()
309 {
310 wxCHECK_MSG( m_internal, wxSEMA_INVALID,
311 wxT("wxSemaphore::Wait(): not initialized") );
312
313 return m_internal->Wait();
314 }
315
316 wxSemaError wxSemaphore::TryWait()
317 {
318 wxCHECK_MSG( m_internal, wxSEMA_INVALID,
319 wxT("wxSemaphore::TryWait(): not initialized") );
320
321 return m_internal->TryWait();
322 }
323
324 wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds)
325 {
326 wxCHECK_MSG( m_internal, wxSEMA_INVALID,
327 wxT("wxSemaphore::WaitTimeout(): not initialized") );
328
329 return m_internal->WaitTimeout(milliseconds);
330 }
331
332 wxSemaError wxSemaphore::Post()
333 {
334 wxCHECK_MSG( m_internal, wxSEMA_INVALID,
335 wxT("wxSemaphore::Post(): not initialized") );
336
337 return m_internal->Post();
338 }
339
340 // ----------------------------------------------------------------------------
341 // wxThread
342 // ----------------------------------------------------------------------------
343
344 #include "wx/utils.h"
345 #include "wx/private/threadinfo.h"
346 #include "wx/scopeguard.h"
347
348 void wxThread::Sleep(unsigned long milliseconds)
349 {
350 wxMilliSleep(milliseconds);
351 }
352
353 void *wxThread::CallEntry()
354 {
355 wxON_BLOCK_EXIT0(wxThreadSpecificInfo::ThreadCleanUp);
356 return Entry();
357 }