]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/os2/thread.cpp
minor cleanup; remove focus patch scaffolding
[wxWidgets.git] / src / os2 / thread.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/os2/thread.cpp
3// Purpose: wxThread Implementation
4// Author: Original from Wolfram Gloger/Guilhem Lavaux/David Webster
5// Modified by: Stefan Neis
6// Created: 04/22/98
7// RCS-ID: $Id$
8// Copyright: (c) Stefan Neis (2003)
9//
10// Licence: wxWindows licence
11/////////////////////////////////////////////////////////////////////////////
12
13// ----------------------------------------------------------------------------
14// headers
15// ----------------------------------------------------------------------------
16
17// For compilers that support precompilation, includes "wx.h".
18#include "wx/wxprec.h"
19
20#if wxUSE_THREADS
21
22#include <stdio.h>
23
24#include "wx/app.h"
25#include "wx/apptrait.h"
26#include "wx/module.h"
27#include "wx/intl.h"
28#include "wx/utils.h"
29#include "wx/log.h"
30#include "wx/thread.h"
31
32#define INCL_DOSSEMAPHORES
33#define INCL_DOSPROCESS
34#define INCL_DOSMISC
35#define INCL_ERRORS
36#include <os2.h>
37#ifndef __EMX__
38#include <bseerr.h>
39#endif
40// the possible states of the thread ("=>" shows all possible transitions from
41// this state)
42enum wxThreadState
43{
44 STATE_NEW, // didn't start execution yet (=> RUNNING)
45 STATE_RUNNING, // thread is running (=> PAUSED, CANCELED)
46 STATE_PAUSED, // thread is temporarily suspended (=> RUNNING)
47 STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED)
48 STATE_EXITED // thread is terminating
49};
50
51// ----------------------------------------------------------------------------
52// this module's globals
53// ----------------------------------------------------------------------------
54
55// id of the main thread - the one which can call GUI functions without first
56// calling wxMutexGuiEnter()
57static ULONG s_ulIdMainThread = 1;
58wxMutex* p_wxMainMutex;
59
60// OS2 substitute for Tls pointer the current parent thread object
61wxThread* m_pThread; // pointer to the wxWidgets thread object
62
63// if it's false, some secondary thread is holding the GUI lock
64static bool gs_bGuiOwnedByMainThread = true;
65
66// critical section which controls access to all GUI functions: any secondary
67// thread (i.e. except the main one) must enter this crit section before doing
68// any GUI calls
69static wxCriticalSection *gs_pCritsectGui = NULL;
70
71// critical section which protects s_nWaitingForGui variable
72static wxCriticalSection *gs_pCritsectWaitingForGui = NULL;
73
74// number of threads waiting for GUI in wxMutexGuiEnter()
75static size_t gs_nWaitingForGui = 0;
76
77// are we waiting for a thread termination?
78static bool gs_bWaitingForThread = false;
79
80// ============================================================================
81// OS/2 implementation of thread and related classes
82// ============================================================================
83
84// ----------------------------------------------------------------------------
85// wxMutex implementation
86// ----------------------------------------------------------------------------
87class wxMutexInternal
88{
89public:
90 wxMutexInternal(wxMutexType mutexType);
91 ~wxMutexInternal();
92
93 bool IsOk() const { return m_vMutex != NULL; }
94
95 wxMutexError Lock() { return LockTimeout(SEM_INDEFINITE_WAIT); }
96 wxMutexError TryLock() { return LockTimeout(SEM_IMMEDIATE_RETURN); }
97 wxMutexError Unlock();
98
99private:
100 wxMutexError LockTimeout(ULONG ulMilliseconds);
101 HMTX m_vMutex;
102};
103
104// all mutexes are "pseudo-"recursive under OS2 so we don't use mutexType
105// (Calls to DosRequestMutexSem and DosReleaseMutexSem can be nested, but
106// the request count for a semaphore cannot exceed 65535. If an attempt is
107// made to exceed this number, ERROR_TOO_MANY_SEM_REQUESTS is returned.)
108wxMutexInternal::wxMutexInternal(wxMutexType WXUNUSED(eMutexType))
109{
110 APIRET ulrc = ::DosCreateMutexSem(NULL, &m_vMutex, 0L, FALSE);
111 if (ulrc != 0)
112 {
113 wxLogSysError(_("Can not create mutex."));
114 m_vMutex = NULL;
115 }
116}
117
118wxMutexInternal::~wxMutexInternal()
119{
120 if (m_vMutex)
121 {
122 if (::DosCloseMutexSem(m_vMutex))
123 wxLogLastError(_T("DosCloseMutexSem(mutex)"));
124 }
125}
126
127wxMutexError wxMutexInternal::LockTimeout(ULONG ulMilliseconds)
128{
129 APIRET ulrc;
130
131 ulrc = ::DosRequestMutexSem(m_vMutex, ulMilliseconds);
132
133 switch (ulrc)
134 {
135 case ERROR_TIMEOUT:
136 case ERROR_TOO_MANY_SEM_REQUESTS:
137 return wxMUTEX_BUSY;
138
139 case NO_ERROR:
140 // ok
141 break;
142
143 case ERROR_INVALID_HANDLE:
144 case ERROR_INTERRUPT:
145 case ERROR_SEM_OWNER_DIED:
146 wxLogSysError(_("Couldn't acquire a mutex lock"));
147 return wxMUTEX_MISC_ERROR;
148
149 default:
150 wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
151 return wxMUTEX_MISC_ERROR;
152 }
153 return wxMUTEX_NO_ERROR;
154}
155
156wxMutexError wxMutexInternal::Unlock()
157{
158 APIRET ulrc;
159
160 ulrc = ::DosReleaseMutexSem(m_vMutex);
161 if (ulrc != 0)
162 {
163 wxLogSysError(_("Couldn't release a mutex"));
164 return wxMUTEX_MISC_ERROR;
165 }
166 return wxMUTEX_NO_ERROR;
167}
168
169// --------------------------------------------------------------------------
170// wxSemaphore
171// --------------------------------------------------------------------------
172
173// a trivial wrapper around OS2 event semaphore
174class wxSemaphoreInternal
175{
176public:
177 wxSemaphoreInternal(int initialcount, int maxcount);
178 ~wxSemaphoreInternal();
179
180 bool IsOk() const { return m_vEvent != NULL; }
181
182 wxSemaError Wait() { return WaitTimeout(SEM_INDEFINITE_WAIT); }
183 wxSemaError TryWait() { return WaitTimeout(SEM_IMMEDIATE_RETURN); }
184 wxSemaError WaitTimeout(unsigned long milliseconds);
185
186 wxSemaError Post();
187
188private:
189 HEV m_vEvent;
190 HMTX m_vMutex;
191 int m_count;
192 int m_maxcount;
193};
194
195wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
196{
197 APIRET ulrc;
198 if ( maxcount == 0 )
199 {
200 // make it practically infinite
201 maxcount = INT_MAX;
202 }
203
204 m_count = initialcount;
205 m_maxcount = maxcount;
206 ulrc = ::DosCreateMutexSem(NULL, &m_vMutex, 0L, FALSE);
207 if (ulrc != 0)
208 {
209 wxLogLastError(_T("DosCreateMutexSem()"));
210 m_vMutex = NULL;
211 m_vEvent = NULL;
212 return;
213 }
214 ulrc = ::DosCreateEventSem(NULL, &m_vEvent, 0L, FALSE);
215 if ( ulrc != 0)
216 {
217 wxLogLastError(_T("DosCreateEventSem()"));
218 ::DosCloseMutexSem(m_vMutex);
219 m_vMutex = NULL;
220 m_vEvent = NULL;
221 }
222 if (initialcount)
223 ::DosPostEventSem(m_vEvent);
224}
225
226wxSemaphoreInternal::~wxSemaphoreInternal()
227{
228 if ( m_vEvent )
229 {
230 if ( ::DosCloseEventSem(m_vEvent) )
231 {
232 wxLogLastError(_T("DosCloseEventSem(semaphore)"));
233 }
234 if ( ::DosCloseMutexSem(m_vMutex) )
235 {
236 wxLogLastError(_T("DosCloseMutexSem(semaphore)"));
237 }
238 else
239 m_vEvent = NULL;
240 }
241}
242
243wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long ulMilliseconds)
244{
245 APIRET ulrc;
246 do {
247 ulrc = ::DosWaitEventSem(m_vEvent, ulMilliseconds );
248 switch ( ulrc )
249 {
250 case NO_ERROR:
251 break;
252
253 case ERROR_TIMEOUT:
254 if (ulMilliseconds == SEM_IMMEDIATE_RETURN)
255 return wxSEMA_BUSY;
256 else
257 return wxSEMA_TIMEOUT;
258
259 default:
260 wxLogLastError(_T("DosWaitEventSem(semaphore)"));
261 return wxSEMA_MISC_ERROR;
262 }
263 ulrc = :: DosRequestMutexSem(m_vMutex, ulMilliseconds);
264 switch ( ulrc )
265 {
266 case NO_ERROR:
267 // ok
268 break;
269
270 case ERROR_TIMEOUT:
271 case ERROR_TOO_MANY_SEM_REQUESTS:
272 if (ulMilliseconds == SEM_IMMEDIATE_RETURN)
273 return wxSEMA_BUSY;
274 else
275 return wxSEMA_TIMEOUT;
276
277 default:
278 wxFAIL_MSG(wxT("DosRequestMutexSem(mutex)"));
279 return wxSEMA_MISC_ERROR;
280 }
281 bool OK = false;
282 if (m_count > 0)
283 {
284 m_count--;
285 OK = true;
286 }
287 else
288 {
289 ULONG ulPostCount;
290 ::DosResetEventSem(m_vEvent, &ulPostCount);
291 }
292 ::DosReleaseMutexSem(m_vMutex);
293 if (OK)
294 return wxSEMA_NO_ERROR;
295 } while (ulMilliseconds == SEM_INDEFINITE_WAIT);
296
297 if (ulMilliseconds == SEM_IMMEDIATE_RETURN)
298 return wxSEMA_BUSY;
299 return wxSEMA_TIMEOUT;
300}
301
302wxSemaError wxSemaphoreInternal::Post()
303{
304 APIRET ulrc;
305 ulrc = ::DosRequestMutexSem(m_vMutex, SEM_INDEFINITE_WAIT);
306 if (ulrc != NO_ERROR)
307 return wxSEMA_MISC_ERROR;
308 bool OK = false;
309 if (m_count < m_maxcount)
310 {
311 m_count++;
312 ulrc = ::DosPostEventSem(m_vEvent);
313 OK = true;
314 }
315 ::DosReleaseMutexSem(m_vMutex);
316 if (!OK)
317 return wxSEMA_OVERFLOW;
318 if ( ulrc != NO_ERROR && ulrc != ERROR_ALREADY_POSTED )
319 {
320 wxLogLastError(_T("DosPostEventSem(semaphore)"));
321
322 return wxSEMA_MISC_ERROR;
323 }
324
325 return wxSEMA_NO_ERROR;
326}
327
328// ----------------------------------------------------------------------------
329// wxThread implementation
330// ----------------------------------------------------------------------------
331
332// wxThreadInternal class
333// ----------------------
334
335class wxThreadInternal
336{
337public:
338 inline wxThreadInternal()
339 {
340 m_hThread = 0;
341 m_eState = STATE_NEW;
342 m_nPriority = WXTHREAD_DEFAULT_PRIORITY;
343 }
344
345 ~wxThreadInternal()
346 {
347 m_hThread = 0;
348 }
349
350 // create a new (suspended) thread (for the given thread object)
351 bool Create( wxThread* pThread
352 ,unsigned int uStackSize
353 );
354
355 // suspend/resume/terminate
356 bool Suspend();
357 bool Resume();
358 inline void Cancel() { m_eState = STATE_CANCELED; }
359
360 // thread state
361 inline void SetState(wxThreadState eState) { m_eState = eState; }
362 inline wxThreadState GetState() const { return m_eState; }
363
364 // thread priority
365 void SetPriority(unsigned int nPriority);
366 inline unsigned int GetPriority() const { return m_nPriority; }
367
368 // thread handle and id
369 inline TID GetHandle() const { return m_hThread; }
370 TID GetId() const { return m_hThread; }
371
372 // thread function
373 static void OS2ThreadStart(void* pParam);
374
375private:
376 // Threads in OS/2 have only an ID, so m_hThread is both it's handle and ID
377 // PM also has no real Tls mechanism to index pointers by so we'll just
378 // keep track of the wxWidgets parent object here.
379 TID m_hThread; // handle and ID of the thread
380 wxThreadState m_eState; // state, see wxThreadState enum
381 unsigned int m_nPriority; // thread priority in "wx" units
382};
383
384void wxThreadInternal::OS2ThreadStart( void * pParam )
385{
386 DWORD dwRet;
387 bool bWasCancelled;
388
389 wxThread *pThread = (wxThread *)pParam;
390
391 // first of all, wait for the thread to be started.
392 pThread->m_critsect.Enter();
393 pThread->m_critsect.Leave();
394 // Now check whether we hadn't been cancelled already and don't
395 // start the user code at all in this case.
396 if ( pThread->m_internal->GetState() == STATE_EXITED )
397 {
398 dwRet = (DWORD)-1;
399 bWasCancelled = true;
400 }
401 else // do run thread
402 {
403 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
404 unsigned long ulHab;
405 if (traits)
406 traits->InitializeGui(ulHab);
407 dwRet = (DWORD)pThread->Entry();
408 if (traits)
409 traits->TerminateGui(ulHab);
410
411 // enter m_critsect before changing the thread state
412 pThread->m_critsect.Enter();
413
414 bWasCancelled = pThread->m_internal->GetState() == STATE_CANCELED;
415
416 pThread->m_internal->SetState(STATE_EXITED);
417 pThread->m_critsect.Leave();
418 }
419 pThread->OnExit();
420
421 // if the thread was cancelled (from Delete()), then it the handle is still
422 // needed there
423 if (pThread->IsDetached() && !bWasCancelled)
424 {
425 // auto delete
426 delete pThread;
427 }
428 //else: the joinable threads handle will be closed when Wait() is done
429 return;
430}
431
432void wxThreadInternal::SetPriority(
433 unsigned int nPriority
434)
435{
436 // translate wxWidgets priority to the PM one
437 ULONG ulOS2_PriorityClass;
438 ULONG ulOS2_SubPriority;
439 ULONG ulrc;
440
441 m_nPriority = nPriority;
442 if (m_nPriority <= 25)
443 ulOS2_PriorityClass = PRTYC_IDLETIME;
444 else if (m_nPriority <= 50)
445 ulOS2_PriorityClass = PRTYC_REGULAR;
446 else if (m_nPriority <= 75)
447 ulOS2_PriorityClass = PRTYC_TIMECRITICAL;
448 else if (m_nPriority <= 100)
449 ulOS2_PriorityClass = PRTYC_FOREGROUNDSERVER;
450 else
451 {
452 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
453 ulOS2_PriorityClass = PRTYC_REGULAR;
454 }
455 ulOS2_SubPriority = (ULONG) (((m_nPriority - 1) % 25 + 1) * 31.0 / 25);
456 ulrc = ::DosSetPriority( PRTYS_THREAD
457 ,ulOS2_PriorityClass
458 ,ulOS2_SubPriority
459 ,(ULONG)m_hThread
460 );
461 if (ulrc != 0)
462 {
463 wxLogSysError(_("Can't set thread priority"));
464 }
465}
466
467bool wxThreadInternal::Create( wxThread* pThread,
468 unsigned int uStackSize)
469{
470 int tid;
471
472 if (!uStackSize)
473 uStackSize = 131072;
474
475 pThread->m_critsect.Enter();
476 tid = _beginthread(wxThreadInternal::OS2ThreadStart,
477 NULL, uStackSize, pThread);
478 if(tid == -1)
479 {
480 wxLogSysError(_("Can't create thread"));
481
482 return false;
483 }
484 m_hThread = tid;
485 if (m_nPriority != WXTHREAD_DEFAULT_PRIORITY)
486 {
487 SetPriority(m_nPriority);
488 }
489
490 return true;
491}
492
493bool wxThreadInternal::Suspend()
494{
495 ULONG ulrc = ::DosSuspendThread(m_hThread);
496
497 if (ulrc != 0)
498 {
499 wxLogSysError(_("Can not suspend thread %lu"), m_hThread);
500 return false;
501 }
502 m_eState = STATE_PAUSED;
503
504 return true;
505}
506
507bool wxThreadInternal::Resume()
508{
509 ULONG ulrc = ::DosResumeThread(m_hThread);
510
511 if (ulrc != 0)
512 {
513 wxLogSysError(_("Can not resume thread %lu"), m_hThread);
514 return false;
515 }
516
517 // don't change the state from STATE_EXITED because it's special and means
518 // we are going to terminate without running any user code - if we did it,
519 // the codei n Delete() wouldn't work
520 if ( m_eState != STATE_EXITED )
521 {
522 m_eState = STATE_RUNNING;
523 }
524
525 return true;
526}
527
528// static functions
529// ----------------
530
531wxThread *wxThread::This()
532{
533 wxThread* pThread = m_pThread;
534 return pThread;
535}
536
537bool wxThread::IsMain()
538{
539 PTIB ptib;
540 PPIB ppib;
541
542 ::DosGetInfoBlocks(&ptib, &ppib);
543
544 if (ptib->tib_ptib2->tib2_ultid == s_ulIdMainThread)
545 return true;
546
547 return false;
548}
549
550#ifdef Yield
551 #undef Yield
552#endif
553
554void wxThread::Yield()
555{
556 ::DosSleep(0);
557}
558
559void wxThread::Sleep(
560 unsigned long ulMilliseconds
561)
562{
563 ::DosSleep(ulMilliseconds);
564}
565
566int wxThread::GetCPUCount()
567{
568 ULONG CPUCount;
569 APIRET ulrc;
570 ulrc = ::DosQuerySysInfo(26, 26, (void *)&CPUCount, sizeof(ULONG));
571 // QSV_NUMPROCESSORS(26) is typically not defined in header files
572
573 if (ulrc != 0)
574 CPUCount = 1;
575
576 return CPUCount;
577}
578
579unsigned long wxThread::GetCurrentId()
580{
581 PTIB ptib;
582 PPIB ppib;
583
584 ::DosGetInfoBlocks(&ptib, &ppib);
585 return (unsigned long) ptib->tib_ptib2->tib2_ultid;
586}
587
588bool wxThread::SetConcurrency(size_t level)
589{
590 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
591
592 // ok only for the default one
593 if ( level == 0 )
594 return 0;
595
596 // Don't know how to realize this on OS/2.
597 return level == 1;
598}
599
600// ctor and dtor
601// -------------
602
603wxThread::wxThread(wxThreadKind kind)
604{
605 m_internal = new wxThreadInternal();
606
607 m_isDetached = kind == wxTHREAD_DETACHED;
608}
609
610wxThread::~wxThread()
611{
612 delete m_internal;
613}
614
615// create/start thread
616// -------------------
617
618wxThreadError wxThread::Create(
619 unsigned int uStackSize
620)
621{
622 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
623
624 if ( !m_internal->Create(this, uStackSize) )
625 return wxTHREAD_NO_RESOURCE;
626
627 return wxTHREAD_NO_ERROR;
628}
629
630wxThreadError wxThread::Run()
631{
632 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
633
634 if ( m_internal->GetState() != STATE_NEW )
635 {
636 // actually, it may be almost any state at all, not only STATE_RUNNING
637 return wxTHREAD_RUNNING;
638 }
639 return Resume();
640}
641
642// suspend/resume thread
643// ---------------------
644
645wxThreadError wxThread::Pause()
646{
647 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
648
649 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
650}
651
652wxThreadError wxThread::Resume()
653{
654 if (m_internal->GetState() == STATE_NEW)
655 {
656 m_internal->SetState(STATE_RUNNING);
657 m_critsect.Leave();
658 return wxTHREAD_NO_ERROR;
659 }
660
661 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
662
663 return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
664}
665
666// stopping thread
667// ---------------
668
669wxThread::ExitCode wxThread::Wait()
670{
671 // although under Windows we can wait for any thread, it's an error to
672 // wait for a detached one in wxWin API
673 wxCHECK_MSG( !IsDetached(), (ExitCode)-1,
674 _T("can't wait for detached thread") );
675 ExitCode rc = (ExitCode)-1;
676 (void)Delete(&rc);
677 return(rc);
678}
679
680wxThreadError wxThread::Delete(ExitCode *pRc)
681{
682 ExitCode rc = 0;
683
684 // Delete() is always safe to call, so consider all possible states
685
686 // we might need to resume the thread, but we might also not need to cancel
687 // it if it doesn't run yet
688 bool shouldResume = false,
689 shouldCancel = true,
690 isRunning = false;
691
692 // check if the thread already started to run
693 {
694 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
695
696 if ( m_internal->GetState() == STATE_NEW )
697 {
698 // WinThreadStart() will see it and terminate immediately, no need
699 // to cancel the thread - but we still need to resume it to let it
700 // run
701 m_internal->SetState(STATE_EXITED);
702
703 Resume(); // it knows about STATE_EXITED special case
704
705 shouldCancel = false;
706 isRunning = true;
707
708 // shouldResume is correctly set to false here
709 }
710 else
711 {
712 shouldResume = IsPaused();
713 }
714 }
715
716 // resume the thread if it is paused
717 if ( shouldResume )
718 Resume();
719
720 TID hThread = m_internal->GetHandle();
721
722 if ( isRunning || IsRunning())
723 {
724 if (IsMain())
725 {
726 // set flag for wxIsWaitingForThread()
727 gs_bWaitingForThread = true;
728 }
729
730 // ask the thread to terminate
731 if ( shouldCancel )
732 {
733 wxCriticalSectionLocker lock(m_critsect);
734
735 m_internal->Cancel();
736 }
737
738#if 0
739 // we can't just wait for the thread to terminate because it might be
740 // calling some GUI functions and so it will never terminate before we
741 // process the Windows messages that result from these functions
742 DWORD result = 0; // suppress warnings from broken compilers
743 do
744 {
745 if ( IsMain() )
746 {
747 // give the thread we're waiting for chance to do the GUI call
748 // it might be in
749 if ( (gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
750 {
751 wxMutexGuiLeave();
752 }
753 }
754
755 result = ::DosWaitThread(&hThread, DCWW_NOWAIT);
756 // FIXME: We ought to have a message processing loop here!!
757
758 switch ( result )
759 {
760 case ERROR_INTERRUPT:
761 case ERROR_THREAD_NOT_TERMINATED:
762 break;
763 case ERROR_INVALID_THREADID:
764 case NO_ERROR:
765 // thread we're waiting for just terminated
766 // or even does not exist any more.
767 result = NO_ERROR;
768 break;
769 default:
770 wxFAIL_MSG(wxT("unexpected result of DosWaitThread"));
771 }
772 if ( IsMain() )
773 {
774 // event processing - needed if we are the main thread
775 // to give other threads a chance to do remaining GUI
776 // processing and terminate cleanly.
777 wxTheApp->HandleSockets();
778 if (wxTheApp->Pending())
779 if ( !wxTheApp->DoMessage() )
780 {
781 // WM_QUIT received: kill the thread
782 Kill();
783
784 return wxTHREAD_KILLED;
785 }
786 else
787 wxUsleep(10);
788 }
789 else
790 wxUsleep(10);
791 } while ( result != NO_ERROR );
792#else // !wxUSE_GUI
793 // simply wait for the thread to terminate
794 //
795 // OTOH, even console apps create windows (in wxExecute, for WinSock
796 // &c), so may be use MsgWaitForMultipleObject() too here?
797 if ( ::DosWaitThread(&hThread, DCWW_WAIT) != NO_ERROR )
798 {
799 wxFAIL_MSG(wxT("unexpected result of DosWaitThread"));
800 }
801#endif // wxUSE_GUI/!wxUSE_GUI
802
803 if ( IsMain() )
804 {
805 gs_bWaitingForThread = false;
806 }
807 }
808
809#if 0
810 // although the thread might be already in the EXITED state it might not
811 // have terminated yet and so we are not sure that it has actually
812 // terminated if the "if" above hadn't been taken
813 do
814 {
815 if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
816 {
817 wxLogLastError(wxT("GetExitCodeThread"));
818
819 rc = (ExitCode)-1;
820 }
821 } while ( (DWORD)rc == STILL_ACTIVE );
822#endif
823
824 if ( IsDetached() )
825 {
826 // if the thread exits normally, this is done in WinThreadStart, but in
827 // this case it would have been too early because
828 // MsgWaitForMultipleObject() would fail if the thread handle was
829 // closed while we were waiting on it, so we must do it here
830 delete this;
831 }
832
833 if ( pRc )
834 *pRc = rc;
835
836 return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR;
837}
838
839wxThreadError wxThread::Kill()
840{
841 if (!IsRunning())
842 return wxTHREAD_NOT_RUNNING;
843
844 ::DosKillThread(m_internal->GetHandle());
845 if (IsDetached())
846 {
847 delete this;
848 }
849 return wxTHREAD_NO_ERROR;
850}
851
852void wxThread::Exit(ExitCode WXUNUSED(pStatus))
853{
854 delete this;
855 _endthread();
856 wxFAIL_MSG(wxT("Couldn't return from DosExit()!"));
857}
858
859void wxThread::SetPriority(
860 unsigned int nPrio
861)
862{
863 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
864
865 m_internal->SetPriority(nPrio);
866}
867
868unsigned int wxThread::GetPriority() const
869{
870 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
871
872 return m_internal->GetPriority();
873}
874
875unsigned long wxThread::GetId() const
876{
877 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
878
879 return (unsigned long)m_internal->GetId();
880}
881
882bool wxThread::IsRunning() const
883{
884 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
885
886 return(m_internal->GetState() == STATE_RUNNING);
887}
888
889bool wxThread::IsAlive() const
890{
891 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
892
893 return (m_internal->GetState() == STATE_RUNNING) ||
894 (m_internal->GetState() == STATE_PAUSED);
895}
896
897bool wxThread::IsPaused() const
898{
899 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
900
901 return (m_internal->GetState() == STATE_PAUSED);
902}
903
904bool wxThread::TestDestroy()
905{
906 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
907
908 return m_internal->GetState() == STATE_CANCELED;
909}
910
911// ----------------------------------------------------------------------------
912// Automatic initialization for thread module
913// ----------------------------------------------------------------------------
914
915class wxThreadModule : public wxModule
916{
917public:
918 virtual bool OnInit();
919 virtual void OnExit();
920
921private:
922 DECLARE_DYNAMIC_CLASS(wxThreadModule)
923};
924
925IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
926
927bool wxThreadModule::OnInit()
928{
929 gs_pCritsectWaitingForGui = new wxCriticalSection();
930
931 gs_pCritsectGui = new wxCriticalSection();
932 gs_pCritsectGui->Enter();
933
934 PTIB ptib;
935 PPIB ppib;
936
937 ::DosGetInfoBlocks(&ptib, &ppib);
938
939 s_ulIdMainThread = ptib->tib_ptib2->tib2_ultid;
940 return true;
941}
942
943void wxThreadModule::OnExit()
944{
945 if (gs_pCritsectGui)
946 {
947 gs_pCritsectGui->Leave();
948#if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
949 delete gs_pCritsectGui;
950#endif
951 gs_pCritsectGui = NULL;
952 }
953
954#if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
955 wxDELETE(gs_pCritsectWaitingForGui);
956#endif
957}
958
959// ----------------------------------------------------------------------------
960// Helper functions
961// ----------------------------------------------------------------------------
962
963// wake up the main thread if it's in ::GetMessage()
964void WXDLLEXPORT wxWakeUpMainThread()
965{
966#if 0
967 if ( !::WinPostQueueMsg(wxTheApp->m_hMq, WM_NULL, 0, 0) )
968 {
969 // should never happen
970 wxLogLastError(wxT("WinPostMessage(WM_NULL)"));
971 }
972#endif
973}
974
975void WXDLLEXPORT wxMutexGuiEnter()
976{
977 // this would dead lock everything...
978 wxASSERT_MSG( !wxThread::IsMain(),
979 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
980
981 // the order in which we enter the critical sections here is crucial!!
982
983 // set the flag telling to the main thread that we want to do some GUI
984 {
985 wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui);
986
987 gs_nWaitingForGui++;
988 }
989
990 wxWakeUpMainThread();
991
992 // now we may block here because the main thread will soon let us in
993 // (during the next iteration of OnIdle())
994 gs_pCritsectGui->Enter();
995}
996
997void WXDLLEXPORT wxMutexGuiLeave()
998{
999 wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui);
1000
1001 if ( wxThread::IsMain() )
1002 {
1003 gs_bGuiOwnedByMainThread = false;
1004 }
1005 else
1006 {
1007 // decrement the number of waiters now
1008 wxASSERT_MSG(gs_nWaitingForGui > 0,
1009 wxT("calling wxMutexGuiLeave() without entering it first?") );
1010
1011 gs_nWaitingForGui--;
1012
1013 wxWakeUpMainThread();
1014 }
1015
1016 gs_pCritsectGui->Leave();
1017}
1018
1019void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
1020{
1021 wxASSERT_MSG( wxThread::IsMain(),
1022 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1023
1024 wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui);
1025
1026 if (gs_nWaitingForGui == 0)
1027 {
1028 // no threads are waiting for GUI - so we may acquire the lock without
1029 // any danger (but only if we don't already have it)
1030 if (!wxGuiOwnedByMainThread())
1031 {
1032 gs_pCritsectGui->Enter();
1033
1034 gs_bGuiOwnedByMainThread = true;
1035 }
1036 //else: already have it, nothing to do
1037 }
1038 else
1039 {
1040 // some threads are waiting, release the GUI lock if we have it
1041 if (wxGuiOwnedByMainThread())
1042 {
1043 wxMutexGuiLeave();
1044 }
1045 //else: some other worker thread is doing GUI
1046 }
1047}
1048
1049bool WXDLLEXPORT wxGuiOwnedByMainThread()
1050{
1051 return gs_bGuiOwnedByMainThread;
1052}
1053
1054bool WXDLLEXPORT wxIsWaitingForThread()
1055{
1056 return gs_bWaitingForThread;
1057}
1058
1059// ----------------------------------------------------------------------------
1060// include common implementation code
1061// ----------------------------------------------------------------------------
1062
1063#include "wx/thrimpl.cpp"
1064
1065#endif
1066 // wxUSE_THREADS