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