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