]> git.saurik.com Git - wxWidgets.git/blob - src/os2/thread.cpp
XRC spec: relax requirements on some commonly omitted properties.
[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 // 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)
44 enum 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()
59 wxThreadIdType wxThread::ms_idMainThread = 0;
60 wxMutex* p_wxMainMutex;
61
62 // OS2 substitute for Tls pointer the current parent thread object
63 wxThread* m_pThread; // pointer to the wxWidgets thread object
64
65 // if it's false, some secondary thread is holding the GUI lock
66 static 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
71 static wxCriticalSection *gs_pCritsectGui = NULL;
72
73 // critical section which protects s_nWaitingForGui variable
74 static wxCriticalSection *gs_pCritsectWaitingForGui = NULL;
75
76 // number of threads waiting for GUI in wxMutexGuiEnter()
77 static size_t gs_nWaitingForGui = 0;
78
79 // are we waiting for a thread termination?
80 static bool gs_bWaitingForThread = false;
81
82 // ============================================================================
83 // OS/2 implementation of thread and related classes
84 // ============================================================================
85
86 // ----------------------------------------------------------------------------
87 // wxMutex implementation
88 // ----------------------------------------------------------------------------
89 class wxMutexInternal
90 {
91 public:
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
102 private:
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.)
111 wxMutexInternal::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
121 wxMutexInternal::~wxMutexInternal()
122 {
123 if (m_vMutex)
124 {
125 if (::DosCloseMutexSem(m_vMutex))
126 {
127 wxLogLastError(wxT("DosCloseMutexSem(mutex)"));
128 }
129 }
130 }
131
132 wxMutexError 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
140 wxMutexError 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
170 wxMutexError 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
188 class wxSemaphoreInternal
189 {
190 public:
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
202 private:
203 HEV m_vEvent;
204 HMTX m_vMutex;
205 int m_count;
206 int m_maxcount;
207 };
208
209 wxSemaphoreInternal::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
240 wxSemaphoreInternal::~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
257 wxSemaError 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
316 wxSemaError 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
349 class wxThreadInternal
350 {
351 public:
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
389 private:
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
398 void 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->CallEntry();
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
446 void 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
481 bool 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
507 bool 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
521 bool 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
545 wxThread *wxThread::This()
546 {
547 wxThread* pThread = m_pThread;
548 return pThread;
549 }
550
551 #ifdef Yield
552 #undef Yield
553 #endif
554
555 void wxThread::Yield()
556 {
557 ::DosSleep(0);
558 }
559
560 int 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
573 wxThreadIdType wxThread::GetCurrentId()
574 {
575 PTIB ptib;
576 PPIB ppib;
577
578 ::DosGetInfoBlocks(&ptib, &ppib);
579 return (wxThreadIdType) ptib->tib_ptib2->tib2_ultid;
580 }
581
582 bool 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
597 wxThread::wxThread(wxThreadKind kind)
598 {
599 m_internal = new wxThreadInternal();
600
601 m_isDetached = kind == wxTHREAD_DETACHED;
602 }
603
604 wxThread::~wxThread()
605 {
606 delete m_internal;
607 }
608
609 // create/start thread
610 // -------------------
611
612 wxThreadError 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
624 wxThreadError 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
647 wxThreadError wxThread::Pause()
648 {
649 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
650
651 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
652 }
653
654 wxThreadError 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
671 wxThread::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
682 wxThreadError 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
841 wxThreadError 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
854 void wxThread::Exit(ExitCode WXUNUSED(pStatus))
855 {
856 delete this;
857 _endthread();
858 wxFAIL_MSG(wxT("Couldn't return from DosExit()!"));
859 }
860
861 void wxThread::SetPriority(
862 unsigned int nPrio
863 )
864 {
865 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
866
867 m_internal->SetPriority(nPrio);
868 }
869
870 unsigned int wxThread::GetPriority() const
871 {
872 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
873
874 return m_internal->GetPriority();
875 }
876
877 unsigned long wxThread::GetId() const
878 {
879 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
880
881 return (unsigned long)m_internal->GetId();
882 }
883
884 bool wxThread::IsRunning() const
885 {
886 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
887
888 return(m_internal->GetState() == STATE_RUNNING);
889 }
890
891 bool 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
899 bool wxThread::IsPaused() const
900 {
901 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
902
903 return (m_internal->GetState() == STATE_PAUSED);
904 }
905
906 bool 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
917 class wxThreadModule : public wxModule
918 {
919 public:
920 virtual bool OnInit();
921 virtual void OnExit();
922
923 private:
924 DECLARE_DYNAMIC_CLASS(wxThreadModule)
925 };
926
927 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
928
929 bool 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
941 void 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()
962 void 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
973 void 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
995 void 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
1017 void 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
1047 bool WXDLLEXPORT wxGuiOwnedByMainThread()
1048 {
1049 return gs_bGuiOwnedByMainThread;
1050 }
1051
1052 bool 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