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