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