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