/src/wxwidgets/include/wx/thrimpl.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | ///////////////////////////////////////////////////////////////////////////// |
2 | | // Name: wx/thrimpl.cpp |
3 | | // Purpose: common part of wxThread Implementations |
4 | | // Author: Vadim Zeitlin |
5 | | // Created: 04.06.02 (extracted from src/*/thread.cpp files) |
6 | | // Copyright: (c) Vadim Zeitlin (2002) |
7 | | // Licence: wxWindows licence |
8 | | ///////////////////////////////////////////////////////////////////////////// |
9 | | |
10 | | // this file is supposed to be included only by the various thread.cpp |
11 | | |
12 | | // ---------------------------------------------------------------------------- |
13 | | // wxMutex |
14 | | // ---------------------------------------------------------------------------- |
15 | | |
16 | | wxMutex::wxMutex(wxMutexType mutexType) |
17 | 8 | { |
18 | 8 | m_internal = new wxMutexInternal(mutexType); |
19 | | |
20 | 8 | if ( !m_internal->IsOk() ) |
21 | 0 | { |
22 | 0 | delete m_internal; |
23 | 0 | m_internal = nullptr; |
24 | 0 | } |
25 | 8 | } |
26 | | |
27 | | wxMutex::~wxMutex() |
28 | 0 | { |
29 | 0 | delete m_internal; |
30 | 0 | } |
31 | | |
32 | | bool wxMutex::IsOk() const |
33 | 0 | { |
34 | 0 | return m_internal != nullptr; |
35 | 0 | } |
36 | | |
37 | | wxMutexError wxMutex::Lock() |
38 | 8 | { |
39 | 8 | wxCHECK_MSG( m_internal, wxMUTEX_INVALID, |
40 | 8 | wxT("wxMutex::Lock(): not initialized") ); |
41 | | |
42 | 8 | return m_internal->Lock(); |
43 | 8 | } |
44 | | |
45 | | wxMutexError wxMutex::LockTimeout(unsigned long ms) |
46 | 0 | { |
47 | 0 | wxCHECK_MSG( m_internal, wxMUTEX_INVALID, |
48 | 0 | wxT("wxMutex::Lock(): not initialized") ); |
49 | |
|
50 | 0 | return m_internal->Lock(ms); |
51 | 0 | } |
52 | | |
53 | | wxMutexError wxMutex::TryLock() |
54 | 0 | { |
55 | 0 | wxCHECK_MSG( m_internal, wxMUTEX_INVALID, |
56 | 0 | wxT("wxMutex::TryLock(): not initialized") ); |
57 | |
|
58 | 0 | return m_internal->TryLock(); |
59 | 0 | } |
60 | | |
61 | | wxMutexError wxMutex::Unlock() |
62 | 8 | { |
63 | 8 | wxCHECK_MSG( m_internal, wxMUTEX_INVALID, |
64 | 8 | wxT("wxMutex::Unlock(): not initialized") ); |
65 | | |
66 | 8 | return m_internal->Unlock(); |
67 | 8 | } |
68 | | |
69 | | // -------------------------------------------------------------------------- |
70 | | // wxConditionInternal |
71 | | // -------------------------------------------------------------------------- |
72 | | |
73 | | // Win32 doesn't have explicit support for the POSIX condition |
74 | | // variables and its events/event semaphores have quite different semantics, |
75 | | // so we reimplement the conditions from scratch using the mutexes and |
76 | | // semaphores |
77 | | #if defined(__WINDOWS__) |
78 | | |
79 | | class wxConditionInternal |
80 | | { |
81 | | public: |
82 | | wxConditionInternal(wxMutex& mutex); |
83 | | |
84 | | bool IsOk() const { return m_mutex.IsOk() && m_semaphore.IsOk(); } |
85 | | |
86 | | wxCondError Wait(); |
87 | | wxCondError WaitTimeout(unsigned long milliseconds); |
88 | | |
89 | | wxCondError Signal(); |
90 | | wxCondError Broadcast(); |
91 | | |
92 | | private: |
93 | | // the number of threads currently waiting for this condition |
94 | | LONG m_numWaiters; |
95 | | |
96 | | // the critical section protecting m_numWaiters |
97 | | wxCriticalSection m_csWaiters; |
98 | | |
99 | | wxMutex& m_mutex; |
100 | | wxSemaphore m_semaphore; |
101 | | |
102 | | wxDECLARE_NO_COPY_CLASS(wxConditionInternal); |
103 | | }; |
104 | | |
105 | | wxConditionInternal::wxConditionInternal(wxMutex& mutex) |
106 | | : m_mutex(mutex) |
107 | | { |
108 | | // another thread can't access it until we return from ctor, so no need to |
109 | | // protect access to m_numWaiters here |
110 | | m_numWaiters = 0; |
111 | | } |
112 | | |
113 | | wxCondError wxConditionInternal::Wait() |
114 | | { |
115 | | // increment the number of waiters |
116 | | { |
117 | | wxCriticalSectionLocker lock(m_csWaiters); |
118 | | m_numWaiters++; |
119 | | } |
120 | | |
121 | | m_mutex.Unlock(); |
122 | | |
123 | | // after unlocking the mutex other threads may Signal() us, but it is ok |
124 | | // now as we had already incremented m_numWaiters so Signal() will post the |
125 | | // semaphore and decrement m_numWaiters back even if it is called before we |
126 | | // start to Wait() |
127 | | const wxSemaError err = m_semaphore.Wait(); |
128 | | |
129 | | m_mutex.Lock(); |
130 | | |
131 | | if ( err == wxSEMA_NO_ERROR ) |
132 | | { |
133 | | // m_numWaiters was decremented by Signal() |
134 | | return wxCOND_NO_ERROR; |
135 | | } |
136 | | |
137 | | // but in case of an error we need to do it manually |
138 | | { |
139 | | wxCriticalSectionLocker lock(m_csWaiters); |
140 | | m_numWaiters--; |
141 | | } |
142 | | |
143 | | return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR; |
144 | | } |
145 | | |
146 | | wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds) |
147 | | { |
148 | | { |
149 | | wxCriticalSectionLocker lock(m_csWaiters); |
150 | | m_numWaiters++; |
151 | | } |
152 | | |
153 | | m_mutex.Unlock(); |
154 | | |
155 | | wxSemaError err = m_semaphore.WaitTimeout(milliseconds); |
156 | | |
157 | | m_mutex.Lock(); |
158 | | |
159 | | if ( err == wxSEMA_NO_ERROR ) |
160 | | return wxCOND_NO_ERROR; |
161 | | |
162 | | if ( err == wxSEMA_TIMEOUT ) |
163 | | { |
164 | | // a potential race condition exists here: it happens when a waiting |
165 | | // thread times out but doesn't have time to decrement m_numWaiters yet |
166 | | // before Signal() is called in another thread |
167 | | // |
168 | | // to handle this particular case, check the semaphore again after |
169 | | // acquiring m_csWaiters lock -- this will catch the signals missed |
170 | | // during this window |
171 | | wxCriticalSectionLocker lock(m_csWaiters); |
172 | | |
173 | | err = m_semaphore.WaitTimeout(0); |
174 | | if ( err == wxSEMA_NO_ERROR ) |
175 | | return wxCOND_NO_ERROR; |
176 | | |
177 | | // we need to decrement m_numWaiters ourselves as it wasn't done by |
178 | | // Signal() |
179 | | m_numWaiters--; |
180 | | |
181 | | return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR; |
182 | | } |
183 | | |
184 | | // undo m_numWaiters++ above in case of an error |
185 | | { |
186 | | wxCriticalSectionLocker lock(m_csWaiters); |
187 | | m_numWaiters--; |
188 | | } |
189 | | |
190 | | return wxCOND_MISC_ERROR; |
191 | | } |
192 | | |
193 | | wxCondError wxConditionInternal::Signal() |
194 | | { |
195 | | wxCriticalSectionLocker lock(m_csWaiters); |
196 | | |
197 | | if ( m_numWaiters > 0 ) |
198 | | { |
199 | | // increment the semaphore by 1 |
200 | | if ( m_semaphore.Post() != wxSEMA_NO_ERROR ) |
201 | | return wxCOND_MISC_ERROR; |
202 | | |
203 | | m_numWaiters--; |
204 | | } |
205 | | |
206 | | return wxCOND_NO_ERROR; |
207 | | } |
208 | | |
209 | | wxCondError wxConditionInternal::Broadcast() |
210 | | { |
211 | | wxCriticalSectionLocker lock(m_csWaiters); |
212 | | |
213 | | while ( m_numWaiters > 0 ) |
214 | | { |
215 | | if ( m_semaphore.Post() != wxSEMA_NO_ERROR ) |
216 | | return wxCOND_MISC_ERROR; |
217 | | |
218 | | m_numWaiters--; |
219 | | } |
220 | | |
221 | | return wxCOND_NO_ERROR; |
222 | | } |
223 | | |
224 | | #endif // __WINDOWS__ |
225 | | |
226 | | // ---------------------------------------------------------------------------- |
227 | | // wxCondition |
228 | | // ---------------------------------------------------------------------------- |
229 | | |
230 | | wxCondition::wxCondition(wxMutex& mutex) |
231 | 0 | { |
232 | 0 | m_internal = new wxConditionInternal(mutex); |
233 | |
|
234 | 0 | if ( !m_internal->IsOk() ) |
235 | 0 | { |
236 | 0 | delete m_internal; |
237 | 0 | m_internal = nullptr; |
238 | 0 | } |
239 | 0 | } |
240 | | |
241 | | wxCondition::~wxCondition() |
242 | 0 | { |
243 | 0 | delete m_internal; |
244 | 0 | } |
245 | | |
246 | | bool wxCondition::IsOk() const |
247 | 0 | { |
248 | 0 | return m_internal != nullptr; |
249 | 0 | } |
250 | | |
251 | | wxCondError wxCondition::Wait() |
252 | 0 | { |
253 | 0 | wxCHECK_MSG( m_internal, wxCOND_INVALID, |
254 | 0 | wxT("wxCondition::Wait(): not initialized") ); |
255 | |
|
256 | 0 | return m_internal->Wait(); |
257 | 0 | } |
258 | | |
259 | | wxCondError wxCondition::WaitTimeout(unsigned long milliseconds) |
260 | 0 | { |
261 | 0 | wxCHECK_MSG( m_internal, wxCOND_INVALID, |
262 | 0 | wxT("wxCondition::Wait(): not initialized") ); |
263 | |
|
264 | 0 | return m_internal->WaitTimeout(milliseconds); |
265 | 0 | } |
266 | | |
267 | | wxCondError wxCondition::Signal() |
268 | 0 | { |
269 | 0 | wxCHECK_MSG( m_internal, wxCOND_INVALID, |
270 | 0 | wxT("wxCondition::Signal(): not initialized") ); |
271 | |
|
272 | 0 | return m_internal->Signal(); |
273 | 0 | } |
274 | | |
275 | | wxCondError wxCondition::Broadcast() |
276 | 0 | { |
277 | 0 | wxCHECK_MSG( m_internal, wxCOND_INVALID, |
278 | 0 | wxT("wxCondition::Broadcast(): not initialized") ); |
279 | |
|
280 | 0 | return m_internal->Broadcast(); |
281 | 0 | } |
282 | | |
283 | | // -------------------------------------------------------------------------- |
284 | | // wxSemaphore |
285 | | // -------------------------------------------------------------------------- |
286 | | |
287 | | wxSemaphore::wxSemaphore(int initialcount, int maxcount) |
288 | 0 | { |
289 | 0 | m_internal = new wxSemaphoreInternal( initialcount, maxcount ); |
290 | 0 | if ( !m_internal->IsOk() ) |
291 | 0 | { |
292 | 0 | delete m_internal; |
293 | 0 | m_internal = nullptr; |
294 | 0 | } |
295 | 0 | } |
296 | | |
297 | | wxSemaphore::~wxSemaphore() |
298 | 0 | { |
299 | 0 | delete m_internal; |
300 | 0 | } |
301 | | |
302 | | bool wxSemaphore::IsOk() const |
303 | 0 | { |
304 | 0 | return m_internal != nullptr; |
305 | 0 | } |
306 | | |
307 | | wxSemaError wxSemaphore::Wait() |
308 | 0 | { |
309 | 0 | wxCHECK_MSG( m_internal, wxSEMA_INVALID, |
310 | 0 | wxT("wxSemaphore::Wait(): not initialized") ); |
311 | |
|
312 | 0 | return m_internal->Wait(); |
313 | 0 | } |
314 | | |
315 | | wxSemaError wxSemaphore::TryWait() |
316 | 0 | { |
317 | 0 | wxCHECK_MSG( m_internal, wxSEMA_INVALID, |
318 | 0 | wxT("wxSemaphore::TryWait(): not initialized") ); |
319 | |
|
320 | 0 | return m_internal->TryWait(); |
321 | 0 | } |
322 | | |
323 | | wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds) |
324 | 0 | { |
325 | 0 | wxCHECK_MSG( m_internal, wxSEMA_INVALID, |
326 | 0 | wxT("wxSemaphore::WaitTimeout(): not initialized") ); |
327 | |
|
328 | 0 | return m_internal->WaitTimeout(milliseconds); |
329 | 0 | } |
330 | | |
331 | | wxSemaError wxSemaphore::Post() |
332 | 0 | { |
333 | 0 | wxCHECK_MSG( m_internal, wxSEMA_INVALID, |
334 | 0 | wxT("wxSemaphore::Post(): not initialized") ); |
335 | |
|
336 | 0 | return m_internal->Post(); |
337 | 0 | } |
338 | | |
339 | | // ---------------------------------------------------------------------------- |
340 | | // wxThread |
341 | | // ---------------------------------------------------------------------------- |
342 | | |
343 | | #include "wx/utils.h" |
344 | | |
345 | | void wxThread::Sleep(unsigned long milliseconds) |
346 | 0 | { |
347 | 0 | wxMilliSleep(milliseconds); |
348 | 0 | } |