]> git.saurik.com Git - wxWidgets.git/blob - src/os2/thread.cpp
gdk_window_copy_area(drawable,gc,x,y,source_drawable,source_x,source_y,width,height) ->
[wxWidgets.git] / src / os2 / thread.cpp
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)
42 enum 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()
57 static ULONG s_ulIdMainThread = 1;
58 wxMutex* p_wxMainMutex;
59
60 // OS2 substitute for Tls pointer the current parent thread object
61 wxThread* m_pThread; // pointer to the wxWidgets thread object
62
63 // if it's false, some secondary thread is holding the GUI lock
64 static 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
69 static wxCriticalSection *gs_pCritsectGui = NULL;
70
71 // critical section which protects s_nWaitingForGui variable
72 static wxCriticalSection *gs_pCritsectWaitingForGui = NULL;
73
74 // number of threads waiting for GUI in wxMutexGuiEnter()
75 static size_t gs_nWaitingForGui = 0;
76
77 // are we waiting for a thread termination?
78 static bool gs_bWaitingForThread = false;
79
80 // ============================================================================
81 // OS/2 implementation of thread and related classes
82 // ============================================================================
83
84 // ----------------------------------------------------------------------------
85 // wxMutex implementation
86 // ----------------------------------------------------------------------------
87 class wxMutexInternal
88 {
89 public:
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
99 private:
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.)
108 wxMutexInternal::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
118 wxMutexInternal::~wxMutexInternal()
119 {
120 if (m_vMutex)
121 {
122 if (::DosCloseMutexSem(m_vMutex))
123 wxLogLastError(_T("DosCloseMutexSem(mutex)"));
124 }
125 }
126
127 wxMutexError 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
156 wxMutexError 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
174 class wxSemaphoreInternal
175 {
176 public:
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
188 private:
189 HEV m_vEvent;
190 HMTX m_vMutex;
191 int m_count;
192 int m_maxcount;
193 };
194
195 wxSemaphoreInternal::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
226 wxSemaphoreInternal::~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
243 wxSemaError 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
302 wxSemaError 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
335 class wxThreadInternal
336 {
337 public:
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
375 private:
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
384 void 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
432 void 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
467 bool 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
493 bool 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
507 bool 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
531 wxThread *wxThread::This()
532 {
533 wxThread* pThread = m_pThread;
534 return pThread;
535 }
536
537 bool 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
554 void wxThread::Yield()
555 {
556 ::DosSleep(0);
557 }
558
559 void wxThread::Sleep(
560 unsigned long ulMilliseconds
561 )
562 {
563 ::DosSleep(ulMilliseconds);
564 }
565
566 int 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
579 unsigned 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
588 bool 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
603 wxThread::wxThread(wxThreadKind kind)
604 {
605 m_internal = new wxThreadInternal();
606
607 m_isDetached = kind == wxTHREAD_DETACHED;
608 }
609
610 wxThread::~wxThread()
611 {
612 delete m_internal;
613 }
614
615 // create/start thread
616 // -------------------
617
618 wxThreadError 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
630 wxThreadError 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
645 wxThreadError wxThread::Pause()
646 {
647 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
648
649 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
650 }
651
652 wxThreadError 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
669 wxThread::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
680 wxThreadError 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
839 wxThreadError 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
852 void wxThread::Exit(ExitCode WXUNUSED(pStatus))
853 {
854 delete this;
855 _endthread();
856 wxFAIL_MSG(wxT("Couldn't return from DosExit()!"));
857 }
858
859 void wxThread::SetPriority(
860 unsigned int nPrio
861 )
862 {
863 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
864
865 m_internal->SetPriority(nPrio);
866 }
867
868 unsigned int wxThread::GetPriority() const
869 {
870 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
871
872 return m_internal->GetPriority();
873 }
874
875 unsigned long wxThread::GetId() const
876 {
877 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
878
879 return (unsigned long)m_internal->GetId();
880 }
881
882 bool wxThread::IsRunning() const
883 {
884 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
885
886 return(m_internal->GetState() == STATE_RUNNING);
887 }
888
889 bool 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
897 bool wxThread::IsPaused() const
898 {
899 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
900
901 return (m_internal->GetState() == STATE_PAUSED);
902 }
903
904 bool 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
915 class wxThreadModule : public wxModule
916 {
917 public:
918 virtual bool OnInit();
919 virtual void OnExit();
920
921 private:
922 DECLARE_DYNAMIC_CLASS(wxThreadModule)
923 };
924
925 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
926
927 bool 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
943 void 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()
964 void 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
975 void 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
997 void 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
1019 void 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
1049 bool WXDLLEXPORT wxGuiOwnedByMainThread()
1050 {
1051 return gs_bGuiOwnedByMainThread;
1052 }
1053
1054 bool 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