]>
Commit | Line | Data |
---|---|---|
0e320a79 DW |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: thread.cpp | |
3 | // Purpose: wxThread Implementation. For Unix ports, see e.g. src/gtk | |
4 | // Author: Original from Wolfram Gloger/Guilhem Lavaux | |
d90895ac | 5 | // Modified by: David Webster |
0e320a79 DW |
6 | // Created: 04/22/98 |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998) | |
9 | // Licence: wxWindows licence | |
10 | ///////////////////////////////////////////////////////////////////////////// | |
11 | ||
d90895ac DW |
12 | // ---------------------------------------------------------------------------- |
13 | // headers | |
14 | // ---------------------------------------------------------------------------- | |
0e320a79 | 15 | |
d90895ac DW |
16 | // For compilers that support precompilation, includes "wx.h". |
17 | #include "wx/wxprec.h" | |
0e320a79 DW |
18 | |
19 | #if wxUSE_THREADS | |
20 | ||
d90895ac DW |
21 | #include <stdio.h> |
22 | ||
d90895ac DW |
23 | #include "wx/module.h" |
24 | #include "wx/thread.h" | |
25 | ||
c5fb56c0 DW |
26 | #define INCL_DOSSEMAPHORES |
27 | #define INCL_DOSPROCESS | |
28 | #define INCL_ERRORS | |
29 | #include <os2.h> | |
30 | #include <bseerr.h> | |
31 | ||
d90895ac DW |
32 | // the possible states of the thread ("=>" shows all possible transitions from |
33 | // this state) | |
34 | enum wxThreadState | |
35 | { | |
36 | STATE_NEW, // didn't start execution yet (=> RUNNING) | |
37 | STATE_RUNNING, // thread is running (=> PAUSED, CANCELED) | |
38 | STATE_PAUSED, // thread is temporarily suspended (=> RUNNING) | |
39 | STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED) | |
40 | STATE_EXITED // thread is terminating | |
0e320a79 DW |
41 | }; |
42 | ||
d90895ac DW |
43 | // ---------------------------------------------------------------------------- |
44 | // static variables | |
45 | // ---------------------------------------------------------------------------- | |
0e320a79 | 46 | |
d90895ac DW |
47 | // id of the main thread - the one which can call GUI functions without first |
48 | // calling wxMutexGuiEnter() | |
c5fb56c0 DW |
49 | static ULONG s_ulIdMainThread = 0; |
50 | wxMutex* p_wxMainMutex; | |
51 | ||
52 | // OS2 substitute for Tls pointer the current parent thread object | |
53 | wxThread* m_pThread; // pointer to the wxWindows thread object | |
d90895ac DW |
54 | |
55 | // if it's FALSE, some secondary thread is holding the GUI lock | |
56 | static bool s_bGuiOwnedByMainThread = TRUE; | |
0e320a79 | 57 | |
d90895ac DW |
58 | // critical section which controls access to all GUI functions: any secondary |
59 | // thread (i.e. except the main one) must enter this crit section before doing | |
60 | // any GUI calls | |
c5fb56c0 | 61 | static wxCriticalSection *s_pCritsectGui = NULL; |
d90895ac DW |
62 | |
63 | // critical section which protects s_nWaitingForGui variable | |
c5fb56c0 | 64 | static wxCriticalSection *s_pCritsectWaitingForGui = NULL; |
d90895ac DW |
65 | |
66 | // number of threads waiting for GUI in wxMutexGuiEnter() | |
67 | static size_t s_nWaitingForGui = 0; | |
68 | ||
69 | // are we waiting for a thread termination? | |
c5fb56c0 | 70 | static bool s_bWaitingForThread = FALSE; |
d90895ac DW |
71 | |
72 | // ============================================================================ | |
c5fb56c0 | 73 | // OS/2 implementation of thread classes |
d90895ac DW |
74 | // ============================================================================ |
75 | ||
76 | // ---------------------------------------------------------------------------- | |
77 | // wxMutex implementation | |
78 | // ---------------------------------------------------------------------------- | |
79 | class wxMutexInternal | |
80 | { | |
0e320a79 | 81 | public: |
c5fb56c0 | 82 | HMTX m_vMutex; |
0e320a79 DW |
83 | }; |
84 | ||
85 | wxMutex::wxMutex() | |
86 | { | |
c5fb56c0 DW |
87 | APIRET ulrc; |
88 | ||
0e320a79 | 89 | p_internal = new wxMutexInternal; |
c5fb56c0 DW |
90 | ulrc = ::DosCreateMutexSem(NULL, &p_internal->m_vMutex, 0L, FALSE); |
91 | if (ulrc != 0) | |
d90895ac DW |
92 | { |
93 | wxLogSysError(_("Can not create mutex.")); | |
94 | } | |
0e320a79 DW |
95 | m_locked = 0; |
96 | } | |
97 | ||
98 | wxMutex::~wxMutex() | |
99 | { | |
100 | if (m_locked > 0) | |
d90895ac | 101 | wxLogDebug(wxT("Warning: freeing a locked mutex (%d locks)."), m_locked); |
c5fb56c0 DW |
102 | ::DosCloseMutexSem(p_internal->m_vMutex); |
103 | delete p_internal; | |
104 | p_internal = NULL; | |
0e320a79 DW |
105 | } |
106 | ||
107 | wxMutexError wxMutex::Lock() | |
108 | { | |
c5fb56c0 DW |
109 | APIRET ulrc; |
110 | ||
111 | ulrc = ::DosRequestMutexSem(p_internal->m_vMutex, SEM_INDEFINITE_WAIT); | |
d90895ac | 112 | |
c5fb56c0 | 113 | switch (ulrc) |
d90895ac | 114 | { |
c5fb56c0 | 115 | case ERROR_TOO_MANY_SEM_REQUESTS: |
d90895ac DW |
116 | return wxMUTEX_BUSY; |
117 | ||
c5fb56c0 | 118 | case NO_ERROR: |
d90895ac DW |
119 | // ok |
120 | break; | |
121 | ||
c5fb56c0 DW |
122 | case ERROR_INVALID_HANDLE: |
123 | case ERROR_INTERRUPT: | |
124 | case ERROR_SEM_OWNER_DIED: | |
d90895ac DW |
125 | wxLogSysError(_("Couldn't acquire a mutex lock")); |
126 | return wxMUTEX_MISC_ERROR; | |
127 | ||
c5fb56c0 | 128 | case ERROR_TIMEOUT: |
d90895ac DW |
129 | default: |
130 | wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock")); | |
131 | } | |
0e320a79 DW |
132 | m_locked++; |
133 | return wxMUTEX_NO_ERROR; | |
134 | } | |
135 | ||
136 | wxMutexError wxMutex::TryLock() | |
137 | { | |
c5fb56c0 | 138 | ULONG ulrc; |
d90895ac | 139 | |
c5fb56c0 DW |
140 | ulrc = ::DosRequestMutexSem(p_internal->m_vMutex, SEM_IMMEDIATE_RETURN /*0L*/); |
141 | if (ulrc == ERROR_TIMEOUT || ulrc == ERROR_TOO_MANY_SEM_REQUESTS) | |
d90895ac DW |
142 | return wxMUTEX_BUSY; |
143 | ||
0e320a79 DW |
144 | m_locked++; |
145 | return wxMUTEX_NO_ERROR; | |
146 | } | |
147 | ||
148 | wxMutexError wxMutex::Unlock() | |
149 | { | |
c5fb56c0 DW |
150 | APIRET ulrc; |
151 | ||
0e320a79 DW |
152 | if (m_locked > 0) |
153 | m_locked--; | |
154 | ||
c5fb56c0 DW |
155 | ulrc = ::DosReleaseMutexSem(p_internal->m_vMutex); |
156 | if (ulrc != 0) | |
d90895ac DW |
157 | { |
158 | wxLogSysError(_("Couldn't release a mutex")); | |
159 | return wxMUTEX_MISC_ERROR; | |
160 | } | |
0e320a79 DW |
161 | return wxMUTEX_NO_ERROR; |
162 | } | |
163 | ||
d90895ac DW |
164 | // ---------------------------------------------------------------------------- |
165 | // wxCondition implementation | |
166 | // ---------------------------------------------------------------------------- | |
167 | ||
168 | class wxConditionInternal | |
169 | { | |
0e320a79 | 170 | public: |
c5fb56c0 DW |
171 | HEV m_vEvent; |
172 | int m_nWaiters; | |
0e320a79 DW |
173 | }; |
174 | ||
175 | wxCondition::wxCondition() | |
176 | { | |
c5fb56c0 DW |
177 | APIRET ulrc; |
178 | ULONG ulCount; | |
179 | ||
0e320a79 | 180 | p_internal = new wxConditionInternal; |
c5fb56c0 DW |
181 | ulrc = ::DosCreateEventSem(NULL, &p_internal->m_vEvent, 0L, FALSE); |
182 | if (ulrc != 0) | |
d90895ac DW |
183 | { |
184 | wxLogSysError(_("Can not create event object.")); | |
185 | } | |
c5fb56c0 DW |
186 | p_internal->m_nWaiters = 0; |
187 | // ?? just for good measure? | |
188 | ::DosResetEventSem(p_internal->m_vEvent, &ulCount); | |
0e320a79 DW |
189 | } |
190 | ||
191 | wxCondition::~wxCondition() | |
192 | { | |
c5fb56c0 DW |
193 | ::DosCloseEventSem(p_internal->m_vEvent); |
194 | delete p_internal; | |
195 | p_internal = NULL; | |
0e320a79 DW |
196 | } |
197 | ||
c5fb56c0 DW |
198 | void wxCondition::Wait( |
199 | wxMutex& rMutex | |
200 | ) | |
0e320a79 | 201 | { |
c5fb56c0 DW |
202 | rMutex.Unlock(); |
203 | p_internal->m_nWaiters++; | |
204 | ::DosWaitEventSem(p_internal->m_vEvent, SEM_INDEFINITE_WAIT); | |
205 | p_internal->m_nWaiters--; | |
206 | rMutex.Lock(); | |
0e320a79 DW |
207 | } |
208 | ||
c5fb56c0 DW |
209 | bool wxCondition::Wait( |
210 | wxMutex& rMutex | |
211 | , unsigned long ulSec | |
212 | , unsigned long ulMillisec) | |
0e320a79 | 213 | { |
c5fb56c0 | 214 | APIRET ulrc; |
d90895ac | 215 | |
c5fb56c0 DW |
216 | rMutex.Unlock(); |
217 | p_internal->m_nWaiters++; | |
218 | ulrc = ::DosWaitEventSem(p_internal->m_vEvent, ULONG((ulSec * 1000L) + ulMillisec)); | |
219 | p_internal->m_nWaiters--; | |
220 | rMutex.Lock(); | |
0e320a79 | 221 | |
c5fb56c0 | 222 | return (ulrc != ERROR_TIMEOUT); |
0e320a79 DW |
223 | } |
224 | ||
225 | void wxCondition::Signal() | |
226 | { | |
c5fb56c0 | 227 | ::DosPostEventSem(p_internal->m_vEvent); |
0e320a79 DW |
228 | } |
229 | ||
230 | void wxCondition::Broadcast() | |
231 | { | |
c5fb56c0 | 232 | int i; |
d90895ac | 233 | |
c5fb56c0 | 234 | for (i = 0; i < p_internal->m_nWaiters; i++) |
d90895ac | 235 | { |
c5fb56c0 | 236 | if (::DosPostEventSem(p_internal->m_vEvent) != 0) |
d90895ac DW |
237 | { |
238 | wxLogSysError(_("Couldn't change the state of event object.")); | |
239 | } | |
240 | } | |
0e320a79 DW |
241 | } |
242 | ||
d90895ac DW |
243 | // ---------------------------------------------------------------------------- |
244 | // wxCriticalSection implementation | |
245 | // ---------------------------------------------------------------------------- | |
d90895ac DW |
246 | |
247 | void wxCriticalSection::Enter() | |
248 | { | |
c5fb56c0 | 249 | ::DosEnterCritSec(); |
d90895ac DW |
250 | } |
251 | ||
252 | void wxCriticalSection::Leave() | |
253 | { | |
c5fb56c0 | 254 | ::DosExitCritSec(); |
d90895ac DW |
255 | } |
256 | ||
257 | // ---------------------------------------------------------------------------- | |
258 | // wxThread implementation | |
259 | // ---------------------------------------------------------------------------- | |
260 | ||
261 | // wxThreadInternal class | |
262 | // ---------------------- | |
263 | ||
264 | class wxThreadInternal | |
265 | { | |
266 | public: | |
c5fb56c0 | 267 | inline wxThreadInternal() |
d90895ac DW |
268 | { |
269 | m_hThread = 0; | |
c5fb56c0 DW |
270 | m_eState = STATE_NEW; |
271 | m_nPriority = 0; | |
d90895ac DW |
272 | } |
273 | ||
274 | // create a new (suspended) thread (for the given thread object) | |
c5fb56c0 | 275 | bool Create(wxThread* pThread); |
d90895ac DW |
276 | |
277 | // suspend/resume/terminate | |
278 | bool Suspend(); | |
279 | bool Resume(); | |
c5fb56c0 | 280 | inline void Cancel() { m_eState = STATE_CANCELED; } |
d90895ac DW |
281 | |
282 | // thread state | |
c5fb56c0 DW |
283 | inline void SetState(wxThreadState eState) { m_eState = eState; } |
284 | inline wxThreadState GetState() const { return m_eState; } | |
d90895ac DW |
285 | |
286 | // thread priority | |
c5fb56c0 DW |
287 | inline void SetPriority(unsigned int nPriority) { m_nPriority = nPriority; } |
288 | inline unsigned int GetPriority() const { return m_nPriority; } | |
d90895ac DW |
289 | |
290 | // thread handle and id | |
c5fb56c0 DW |
291 | inline TID GetHandle() const { return m_hThread; } |
292 | TID GetId() const { return m_hThread; } | |
d90895ac DW |
293 | |
294 | // thread function | |
295 | static DWORD OS2ThreadStart(wxThread *thread); | |
296 | ||
297 | private: | |
c5fb56c0 DW |
298 | // Threads in OS/2 have only an ID, so m_hThread is both it's handle and ID |
299 | // PM also has no real Tls mechanism to index pointers by so we'll just | |
300 | // keep track of the wxWindows parent object here. | |
301 | TID m_hThread; // handle and ID of the thread | |
302 | wxThreadState m_eState; // state, see wxThreadState enum | |
303 | unsigned int m_nPriority; // thread priority in "wx" units | |
d90895ac DW |
304 | }; |
305 | ||
c5fb56c0 DW |
306 | ULONG wxThreadInternal::OS2ThreadStart( |
307 | wxThread* pThread | |
308 | ) | |
d90895ac | 309 | { |
c5fb56c0 | 310 | m_pThread = pThread; |
d90895ac | 311 | |
c5fb56c0 | 312 | DWORD dwRet = (DWORD)pThread->Entry(); |
d90895ac | 313 | |
c5fb56c0 DW |
314 | pThread->p_internal->SetState(STATE_EXITED); |
315 | pThread->OnExit(); | |
d90895ac | 316 | |
c5fb56c0 DW |
317 | delete pThread; |
318 | m_pThread = NULL; | |
319 | return dwRet; | |
d90895ac DW |
320 | } |
321 | ||
c5fb56c0 DW |
322 | bool wxThreadInternal::Create( |
323 | wxThread* pThread | |
324 | ) | |
d90895ac | 325 | { |
c5fb56c0 | 326 | APIRET ulrc; |
d90895ac | 327 | |
c5fb56c0 DW |
328 | ulrc = ::DosCreateThread( &m_hThread |
329 | ,(PFNTHREAD)wxThreadInternal::OS2ThreadStart | |
330 | ,(ULONG)pThread | |
331 | ,CREATE_SUSPENDED | STACK_SPARSE | |
332 | ,8192L | |
333 | ); | |
334 | if(ulrc != 0) | |
d90895ac DW |
335 | { |
336 | wxLogSysError(_("Can't create thread")); | |
337 | ||
338 | return FALSE; | |
339 | } | |
340 | ||
c5fb56c0 DW |
341 | // translate wxWindows priority to the PM one |
342 | ULONG ulOS2_Priority; | |
343 | ||
344 | if (m_nPriority <= 20) | |
345 | ulOS2_Priority = PRTYC_NOCHANGE; | |
346 | else if (m_nPriority <= 40) | |
347 | ulOS2_Priority = PRTYC_IDLETIME; | |
348 | else if (m_nPriority <= 60) | |
349 | ulOS2_Priority = PRTYC_REGULAR; | |
350 | else if (m_nPriority <= 80) | |
351 | ulOS2_Priority = PRTYC_TIMECRITICAL; | |
352 | else if (m_nPriority <= 100) | |
353 | ulOS2_Priority = PRTYC_FOREGROUNDSERVER; | |
d90895ac DW |
354 | else |
355 | { | |
356 | wxFAIL_MSG(wxT("invalid value of thread priority parameter")); | |
c5fb56c0 | 357 | ulOS2_Priority = PRTYC_REGULAR; |
d90895ac | 358 | } |
c5fb56c0 DW |
359 | ulrc = ::DosSetPriority( PRTYS_THREAD |
360 | ,ulOS2_Priority | |
361 | ,0 | |
362 | ,(ULONG)m_hThread | |
363 | ); | |
364 | if (ulrc != 0) | |
d90895ac DW |
365 | { |
366 | wxLogSysError(_("Can't set thread priority")); | |
367 | } | |
c5fb56c0 | 368 | return TRUE; |
d90895ac DW |
369 | } |
370 | ||
371 | bool wxThreadInternal::Suspend() | |
372 | { | |
c5fb56c0 | 373 | ULONG ulrc = ::DosSuspendThread(m_hThread); |
d90895ac | 374 | |
c5fb56c0 DW |
375 | if (ulrc != 0) |
376 | { | |
377 | wxLogSysError(_("Can not suspend thread %lu"), m_hThread); | |
d90895ac DW |
378 | return FALSE; |
379 | } | |
c5fb56c0 DW |
380 | m_eState = STATE_PAUSED; |
381 | return TRUE; | |
d90895ac DW |
382 | } |
383 | ||
384 | bool wxThreadInternal::Resume() | |
385 | { | |
c5fb56c0 | 386 | ULONG ulrc = ::DosResumeThread(m_hThread); |
d90895ac | 387 | |
c5fb56c0 DW |
388 | if (ulrc != 0) |
389 | { | |
390 | wxLogSysError(_("Can not suspend thread %lu"), m_hThread); | |
d90895ac DW |
391 | return FALSE; |
392 | } | |
c5fb56c0 DW |
393 | m_eState = STATE_PAUSED; |
394 | return TRUE; | |
d90895ac DW |
395 | } |
396 | ||
397 | // static functions | |
398 | // ---------------- | |
399 | ||
400 | wxThread *wxThread::This() | |
401 | { | |
c5fb56c0 DW |
402 | wxThread* pThread = m_pThread; |
403 | return pThread; | |
d90895ac DW |
404 | } |
405 | ||
406 | bool wxThread::IsMain() | |
407 | { | |
c5fb56c0 DW |
408 | PTIB ptib; |
409 | PPIB ppib; | |
410 | ||
411 | ::DosGetInfoBlocks(&ptib, &ppib); | |
412 | ||
413 | if (ptib->tib_ptib2->tib2_ultid == s_ulIdMainThread) | |
414 | return TRUE; | |
d90895ac DW |
415 | return FALSE; |
416 | } | |
417 | ||
418 | #ifdef Yield | |
419 | #undef Yield | |
420 | #endif | |
421 | ||
422 | void wxThread::Yield() | |
423 | { | |
d90895ac DW |
424 | ::DosSleep(0); |
425 | } | |
426 | ||
c5fb56c0 DW |
427 | void wxThread::Sleep( |
428 | unsigned long ulMilliseconds | |
429 | ) | |
d90895ac | 430 | { |
c5fb56c0 | 431 | ::DosSleep(ulMilliseconds); |
d90895ac DW |
432 | } |
433 | ||
434 | // create/start thread | |
435 | // ------------------- | |
436 | ||
0e320a79 DW |
437 | wxThreadError wxThread::Create() |
438 | { | |
d90895ac DW |
439 | if ( !p_internal->Create(this) ) |
440 | return wxTHREAD_NO_RESOURCE; | |
441 | ||
0e320a79 DW |
442 | return wxTHREAD_NO_ERROR; |
443 | } | |
444 | ||
d90895ac | 445 | wxThreadError wxThread::Run() |
0e320a79 | 446 | { |
c5fb56c0 | 447 | wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); |
d90895ac DW |
448 | |
449 | if ( p_internal->GetState() != STATE_NEW ) | |
450 | { | |
451 | // actually, it may be almost any state at all, not only STATE_RUNNING | |
452 | return wxTHREAD_RUNNING; | |
453 | } | |
d90895ac | 454 | return Resume(); |
0e320a79 DW |
455 | } |
456 | ||
d90895ac DW |
457 | // suspend/resume thread |
458 | // --------------------- | |
459 | ||
0e320a79 DW |
460 | wxThreadError wxThread::Pause() |
461 | { | |
c5fb56c0 | 462 | wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); |
d90895ac DW |
463 | |
464 | return p_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR; | |
0e320a79 DW |
465 | } |
466 | ||
467 | wxThreadError wxThread::Resume() | |
468 | { | |
c5fb56c0 | 469 | wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); |
0e320a79 | 470 | |
d90895ac | 471 | return p_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR; |
0e320a79 DW |
472 | } |
473 | ||
d90895ac DW |
474 | // stopping thread |
475 | // --------------- | |
476 | ||
477 | wxThread::ExitCode wxThread::Delete() | |
0e320a79 | 478 | { |
c5fb56c0 DW |
479 | ExitCode rc = 0; |
480 | ULONG ulrc; | |
d90895ac DW |
481 | |
482 | // Delete() is always safe to call, so consider all possible states | |
c5fb56c0 | 483 | if (IsPaused()) |
d90895ac DW |
484 | Resume(); |
485 | ||
c5fb56c0 | 486 | if (IsRunning()) |
d90895ac | 487 | { |
c5fb56c0 | 488 | if (IsMain()) |
d90895ac DW |
489 | { |
490 | // set flag for wxIsWaitingForThread() | |
c5fb56c0 | 491 | s_bWaitingForThread = TRUE; |
d90895ac DW |
492 | wxBeginBusyCursor(); |
493 | } | |
494 | ||
c5fb56c0 DW |
495 | TID hThread; |
496 | ||
d90895ac | 497 | { |
c5fb56c0 | 498 | wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); |
d90895ac DW |
499 | |
500 | p_internal->Cancel(); | |
501 | hThread = p_internal->GetHandle(); | |
502 | } | |
503 | ||
504 | // we can't just wait for the thread to terminate because it might be | |
505 | // calling some GUI functions and so it will never terminate before we | |
506 | // process the Windows messages that result from these functions | |
c5fb56c0 | 507 | |
d90895ac DW |
508 | do |
509 | { | |
c5fb56c0 DW |
510 | ulrc = ::DosWaitThread( &hThread |
511 | ,DCWW_NOWAIT | |
512 | ); | |
513 | switch (ulrc) | |
d90895ac | 514 | { |
c5fb56c0 DW |
515 | case ERROR_INTERRUPT: |
516 | case ERROR_INVALID_THREADID: | |
d90895ac DW |
517 | // error |
518 | wxLogSysError(_("Can not wait for thread termination")); | |
519 | Kill(); | |
520 | return (ExitCode)-1; | |
521 | ||
c5fb56c0 | 522 | case 0: |
d90895ac DW |
523 | // thread we're waiting for terminated |
524 | break; | |
525 | ||
c5fb56c0 | 526 | case ERROR_THREAD_NOT_TERMINATED: |
d90895ac | 527 | // new message arrived, process it |
c5fb56c0 | 528 | if (!wxTheApp->DoMessage()) |
d90895ac DW |
529 | { |
530 | // WM_QUIT received: kill the thread | |
531 | Kill(); | |
d90895ac DW |
532 | return (ExitCode)-1; |
533 | } | |
c5fb56c0 | 534 | if (IsMain()) |
d90895ac DW |
535 | { |
536 | // give the thread we're waiting for chance to exit | |
537 | // from the GUI call it might have been in | |
c5fb56c0 | 538 | if ((s_nWaitingForGui > 0) && wxGuiOwnedByMainThread()) |
d90895ac DW |
539 | { |
540 | wxMutexGuiLeave(); | |
541 | } | |
542 | } | |
d90895ac DW |
543 | break; |
544 | ||
545 | default: | |
c5fb56c0 | 546 | wxFAIL_MSG(wxT("unexpected result of DosWatiThread")); |
d90895ac | 547 | } |
c5fb56c0 | 548 | } while (ulrc != 0); |
d90895ac | 549 | |
c5fb56c0 | 550 | if (IsMain()) |
d90895ac | 551 | { |
c5fb56c0 DW |
552 | s_bWaitingForThread = FALSE; |
553 | wxEndBusyCursor(); | |
d90895ac DW |
554 | } |
555 | ||
c5fb56c0 | 556 | ::DosExit(EXIT_THREAD, ulrc); |
d90895ac | 557 | } |
c5fb56c0 | 558 | rc = (ExitCode)ulrc; |
d90895ac | 559 | return rc; |
0e320a79 DW |
560 | } |
561 | ||
d90895ac | 562 | wxThreadError wxThread::Kill() |
0e320a79 | 563 | { |
c5fb56c0 | 564 | if (!IsRunning()) |
d90895ac DW |
565 | return wxTHREAD_NOT_RUNNING; |
566 | ||
c5fb56c0 | 567 | ::DosKillThread(p_internal->GetHandle()); |
d90895ac | 568 | delete this; |
d90895ac | 569 | return wxTHREAD_NO_ERROR; |
0e320a79 DW |
570 | } |
571 | ||
c5fb56c0 DW |
572 | void wxThread::Exit( |
573 | void* pStatus | |
574 | ) | |
0e320a79 | 575 | { |
d90895ac | 576 | delete this; |
c5fb56c0 DW |
577 | ::DosExit(EXIT_THREAD, ULONG(pStatus)); |
578 | wxFAIL_MSG(wxT("Couldn't return from DosExit()!")); | |
0e320a79 DW |
579 | } |
580 | ||
c5fb56c0 DW |
581 | void wxThread::SetPriority( |
582 | unsigned int nPrio | |
583 | ) | |
0e320a79 | 584 | { |
c5fb56c0 | 585 | wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); |
d90895ac | 586 | |
c5fb56c0 | 587 | p_internal->SetPriority(nPrio); |
0e320a79 DW |
588 | } |
589 | ||
d90895ac | 590 | unsigned int wxThread::GetPriority() const |
0e320a79 | 591 | { |
c5fb56c0 | 592 | wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); |
d90895ac DW |
593 | |
594 | return p_internal->GetPriority(); | |
0e320a79 DW |
595 | } |
596 | ||
597 | unsigned long wxThread::GetID() const | |
598 | { | |
c5fb56c0 | 599 | wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); |
d90895ac DW |
600 | |
601 | return (unsigned long)p_internal->GetId(); | |
0e320a79 DW |
602 | } |
603 | ||
d90895ac | 604 | bool wxThread::IsRunning() const |
0e320a79 | 605 | { |
c5fb56c0 | 606 | wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); |
d90895ac DW |
607 | |
608 | return p_internal->GetState() == STATE_RUNNING; | |
0e320a79 | 609 | } |
0e320a79 DW |
610 | |
611 | bool wxThread::IsAlive() const | |
612 | { | |
c5fb56c0 | 613 | wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); |
d90895ac DW |
614 | |
615 | return (p_internal->GetState() == STATE_RUNNING) || | |
616 | (p_internal->GetState() == STATE_PAUSED); | |
0e320a79 DW |
617 | } |
618 | ||
d90895ac | 619 | bool wxThread::IsPaused() const |
0e320a79 | 620 | { |
c5fb56c0 | 621 | wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); |
d90895ac DW |
622 | |
623 | return (p_internal->GetState() == STATE_PAUSED); | |
0e320a79 DW |
624 | } |
625 | ||
d90895ac | 626 | bool wxThread::TestDestroy() |
0e320a79 | 627 | { |
c5fb56c0 | 628 | wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); |
d90895ac DW |
629 | |
630 | return p_internal->GetState() == STATE_CANCELED; | |
0e320a79 DW |
631 | } |
632 | ||
633 | wxThread::wxThread() | |
634 | { | |
635 | p_internal = new wxThreadInternal(); | |
0e320a79 DW |
636 | } |
637 | ||
638 | wxThread::~wxThread() | |
639 | { | |
0e320a79 DW |
640 | delete p_internal; |
641 | } | |
642 | ||
d90895ac DW |
643 | // ---------------------------------------------------------------------------- |
644 | // Automatic initialization for thread module | |
645 | // ---------------------------------------------------------------------------- | |
0e320a79 | 646 | |
d90895ac DW |
647 | class wxThreadModule : public wxModule |
648 | { | |
0e320a79 | 649 | public: |
d90895ac DW |
650 | virtual bool OnInit(); |
651 | virtual void OnExit(); | |
0e320a79 | 652 | |
d90895ac DW |
653 | private: |
654 | DECLARE_DYNAMIC_CLASS(wxThreadModule) | |
0e320a79 DW |
655 | }; |
656 | ||
657 | IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule) | |
658 | ||
d90895ac DW |
659 | bool wxThreadModule::OnInit() |
660 | { | |
c5fb56c0 | 661 | s_pCritsectWaitingForGui = new wxCriticalSection(); |
d90895ac | 662 | |
c5fb56c0 DW |
663 | s_pCritsectGui = new wxCriticalSection(); |
664 | s_pCritsectGui->Enter(); | |
d90895ac | 665 | |
c5fb56c0 DW |
666 | PTIB ptib; |
667 | PPIB ppib; | |
d90895ac | 668 | |
c5fb56c0 | 669 | ::DosGetInfoBlocks(&ptib, &ppib); |
d90895ac | 670 | |
c5fb56c0 | 671 | s_ulIdMainThread = ptib->tib_ptib2->tib2_ultid; |
d90895ac DW |
672 | return TRUE; |
673 | } | |
674 | ||
675 | void wxThreadModule::OnExit() | |
676 | { | |
c5fb56c0 | 677 | if (s_pCritsectGui) |
d90895ac | 678 | { |
c5fb56c0 DW |
679 | s_pCritsectGui->Leave(); |
680 | delete s_pCritsectGui; | |
681 | s_pCritsectGui = NULL; | |
d90895ac DW |
682 | } |
683 | ||
c5fb56c0 | 684 | wxDELETE(s_pCritsectWaitingForGui); |
d90895ac DW |
685 | } |
686 | ||
687 | // ---------------------------------------------------------------------------- | |
c5fb56c0 | 688 | // Helper functions |
d90895ac DW |
689 | // ---------------------------------------------------------------------------- |
690 | ||
c5fb56c0 DW |
691 | // Does nothing under OS/2 [for now] |
692 | void WXDLLEXPORT wxWakeUpMainThread() | |
d90895ac | 693 | { |
d90895ac DW |
694 | } |
695 | ||
696 | void WXDLLEXPORT wxMutexGuiLeave() | |
697 | { | |
c5fb56c0 | 698 | wxCriticalSectionLocker enter(*s_pCritsectWaitingForGui); |
d90895ac DW |
699 | |
700 | if ( wxThread::IsMain() ) | |
701 | { | |
702 | s_bGuiOwnedByMainThread = FALSE; | |
703 | } | |
704 | else | |
705 | { | |
706 | // decrement the number of waiters now | |
707 | wxASSERT_MSG( s_nWaitingForGui > 0, | |
708 | wxT("calling wxMutexGuiLeave() without entering it first?") ); | |
709 | ||
710 | s_nWaitingForGui--; | |
711 | ||
712 | wxWakeUpMainThread(); | |
713 | } | |
714 | ||
c5fb56c0 | 715 | s_pCritsectGui->Leave(); |
d90895ac DW |
716 | } |
717 | ||
718 | void WXDLLEXPORT wxMutexGuiLeaveOrEnter() | |
719 | { | |
720 | wxASSERT_MSG( wxThread::IsMain(), | |
721 | wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") ); | |
722 | ||
c5fb56c0 | 723 | wxCriticalSectionLocker enter(*s_pCritsectWaitingForGui); |
d90895ac DW |
724 | |
725 | if ( s_nWaitingForGui == 0 ) | |
726 | { | |
727 | // no threads are waiting for GUI - so we may acquire the lock without | |
728 | // any danger (but only if we don't already have it) | |
c5fb56c0 | 729 | if (!wxGuiOwnedByMainThread()) |
d90895ac | 730 | { |
c5fb56c0 | 731 | s_pCritsectGui->Enter(); |
d90895ac DW |
732 | |
733 | s_bGuiOwnedByMainThread = TRUE; | |
734 | } | |
735 | //else: already have it, nothing to do | |
736 | } | |
737 | else | |
738 | { | |
739 | // some threads are waiting, release the GUI lock if we have it | |
c5fb56c0 | 740 | if (wxGuiOwnedByMainThread()) |
d90895ac DW |
741 | { |
742 | wxMutexGuiLeave(); | |
743 | } | |
744 | //else: some other worker thread is doing GUI | |
745 | } | |
746 | } | |
747 | ||
748 | bool WXDLLEXPORT wxGuiOwnedByMainThread() | |
749 | { | |
750 | return s_bGuiOwnedByMainThread; | |
751 | } | |
752 | ||
0e320a79 DW |
753 | #endif |
754 | // wxUSE_THREADS |