]> git.saurik.com Git - wxWidgets.git/blob - src/os2/thread.cpp
Under Cygwin, in platform.h default to wxMSW unless otherwise specified.
[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 return(TRUE);
488 }
489
490 bool wxThreadInternal::Suspend()
491 {
492 ULONG ulrc = ::DosSuspendThread(m_hThread);
493
494 if (ulrc != 0)
495 {
496 wxLogSysError(_("Can not suspend thread %lu"), m_hThread);
497 return FALSE;
498 }
499 m_eState = STATE_PAUSED;
500 return TRUE;
501 }
502
503 bool wxThreadInternal::Resume()
504 {
505 ULONG ulrc = ::DosResumeThread(m_hThread);
506
507 if (ulrc != 0)
508 {
509 wxLogSysError(_("Can not suspend thread %lu"), m_hThread);
510 return FALSE;
511 }
512 m_eState = STATE_PAUSED;
513 return TRUE;
514 }
515
516 // static functions
517 // ----------------
518
519 wxThread *wxThread::This()
520 {
521 wxThread* pThread = m_pThread;
522 return pThread;
523 }
524
525 bool wxThread::IsMain()
526 {
527 PTIB ptib;
528 PPIB ppib;
529
530 ::DosGetInfoBlocks(&ptib, &ppib);
531
532 if (ptib->tib_ptib2->tib2_ultid == s_ulIdMainThread)
533 return TRUE;
534 return FALSE;
535 }
536
537 #ifdef Yield
538 #undef Yield
539 #endif
540
541 void wxThread::Yield()
542 {
543 ::DosSleep(0);
544 }
545
546 void wxThread::Sleep(
547 unsigned long ulMilliseconds
548 )
549 {
550 ::DosSleep(ulMilliseconds);
551 }
552
553 // ctor and dtor
554 // -------------
555
556 wxThread::wxThread(wxThreadKind kind)
557 {
558 m_internal = new wxThreadInternal();
559
560 m_isDetached = kind == wxTHREAD_DETACHED;
561 }
562
563 wxThread::~wxThread()
564 {
565 delete m_internal;
566 }
567
568 // create/start thread
569 // -------------------
570
571 wxThreadError wxThread::Create(
572 unsigned int uStackSize
573 )
574 {
575 if ( !m_internal->Create(this, uStackSize) )
576 return wxTHREAD_NO_RESOURCE;
577
578 return wxTHREAD_NO_ERROR;
579 }
580
581 wxThreadError wxThread::Run()
582 {
583 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
584
585 if ( m_internal->GetState() != STATE_NEW )
586 {
587 // actually, it may be almost any state at all, not only STATE_RUNNING
588 return wxTHREAD_RUNNING;
589 }
590 return Resume();
591 }
592
593 // suspend/resume thread
594 // ---------------------
595
596 wxThreadError wxThread::Pause()
597 {
598 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
599
600 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
601 }
602
603 wxThreadError wxThread::Resume()
604 {
605 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
606
607 return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
608 }
609
610 // stopping thread
611 // ---------------
612
613 wxThread::ExitCode wxThread::Wait()
614 {
615 // although under Windows we can wait for any thread, it's an error to
616 // wait for a detached one in wxWin API
617 wxCHECK_MSG( !IsDetached(), (ExitCode)-1,
618 _T("can't wait for detached thread") );
619 ExitCode rc = (ExitCode)-1;
620 (void)Delete(&rc);
621 m_internal->Free();
622 return(rc);
623 }
624
625 wxThreadError wxThread::Delete(ExitCode *pRc)
626 {
627 ExitCode rc = 0;
628
629 // Delete() is always safe to call, so consider all possible states
630 if (IsPaused())
631 Resume();
632
633 TID hThread = m_internal->GetHandle();
634
635 if (IsRunning())
636 {
637 if (IsMain())
638 {
639 // set flag for wxIsWaitingForThread()
640 gs_bWaitingForThread = TRUE;
641
642 #if wxUSE_GUI
643 wxBeginBusyCursor();
644 #endif // wxUSE_GUI
645 }
646
647 // ask the thread to terminate
648 {
649 wxCriticalSectionLocker lock(m_critsect);
650 m_internal->Cancel();
651 }
652
653 #if wxUSE_GUI
654 // need a way to finish GUI processing before killing the thread
655 // until then we just exit
656
657 if ((gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread())
658 {
659 wxMutexGuiLeave();
660 }
661 #else // !wxUSE_GUI
662
663 // can't wait for yourself to end under OS/2 so just quit
664
665 #endif // wxUSE_GUI/!wxUSE_GUI
666
667 if ( IsMain() )
668 {
669 gs_bWaitingForThread = FALSE;
670
671 #if wxUSE_GUI
672 wxEndBusyCursor();
673 #endif // wxUSE_GUI
674 }
675 }
676
677 ::DosExit(0, 0);
678 // probably won't get this far, but
679 if (IsDetached())
680 {
681 delete this;
682 }
683
684 if ( pRc )
685 *pRc = rc;
686
687 return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR;
688 }
689
690 wxThreadError wxThread::Kill()
691 {
692 if (!IsRunning())
693 return wxTHREAD_NOT_RUNNING;
694
695 ::DosKillThread(m_internal->GetHandle());
696 m_internal->Free();
697 if (IsDetached())
698 {
699 delete this;
700 }
701 return wxTHREAD_NO_ERROR;
702 }
703
704 void wxThread::Exit(
705 ExitCode pStatus
706 )
707 {
708 m_internal->Free();
709 delete this;
710 ::DosExit(EXIT_THREAD, ULONG(pStatus));
711 wxFAIL_MSG(wxT("Couldn't return from DosExit()!"));
712 }
713
714 void wxThread::SetPriority(
715 unsigned int nPrio
716 )
717 {
718 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
719
720 m_internal->SetPriority(nPrio);
721 }
722
723 unsigned int wxThread::GetPriority() const
724 {
725 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
726
727 return m_internal->GetPriority();
728 }
729
730 unsigned long wxThread::GetId() const
731 {
732 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
733
734 return (unsigned long)m_internal->GetId();
735 }
736
737 bool wxThread::IsRunning() const
738 {
739 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
740
741 return(m_internal->GetState() == STATE_RUNNING);
742 }
743
744 bool wxThread::IsAlive() const
745 {
746 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
747
748 return (m_internal->GetState() == STATE_RUNNING) ||
749 (m_internal->GetState() == STATE_PAUSED);
750 }
751
752 bool wxThread::IsPaused() const
753 {
754 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
755
756 return (m_internal->GetState() == STATE_PAUSED);
757 }
758
759 bool wxThread::TestDestroy()
760 {
761 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
762
763 return m_internal->GetState() == STATE_CANCELED;
764 }
765
766 // ----------------------------------------------------------------------------
767 // Automatic initialization for thread module
768 // ----------------------------------------------------------------------------
769
770 class wxThreadModule : public wxModule
771 {
772 public:
773 virtual bool OnInit();
774 virtual void OnExit();
775
776 private:
777 DECLARE_DYNAMIC_CLASS(wxThreadModule)
778 };
779
780 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
781
782 bool wxThreadModule::OnInit()
783 {
784 gs_pCritsectWaitingForGui = new wxCriticalSection();
785
786 gs_pCritsectGui = new wxCriticalSection();
787 gs_pCritsectGui->Enter();
788
789 PTIB ptib;
790 PPIB ppib;
791
792 ::DosGetInfoBlocks(&ptib, &ppib);
793
794 s_ulIdMainThread = ptib->tib_ptib2->tib2_ultid;
795 return TRUE;
796 }
797
798 void wxThreadModule::OnExit()
799 {
800 if (gs_pCritsectGui)
801 {
802 gs_pCritsectGui->Leave();
803 #if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
804 delete gs_pCritsectGui;
805 #endif
806 gs_pCritsectGui = NULL;
807 }
808
809 #if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
810 wxDELETE(gs_pCritsectWaitingForGui);
811 #endif
812 }
813
814 // ----------------------------------------------------------------------------
815 // Helper functions
816 // ----------------------------------------------------------------------------
817
818 // Does nothing under OS/2 [for now]
819 void WXDLLEXPORT wxWakeUpMainThread()
820 {
821 }
822
823 void WXDLLEXPORT wxMutexGuiLeave()
824 {
825 wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui);
826
827 if ( wxThread::IsMain() )
828 {
829 gs_bGuiOwnedByMainThread = FALSE;
830 }
831 else
832 {
833 // decrement the number of waiters now
834 wxASSERT_MSG(gs_nWaitingForGui > 0,
835 wxT("calling wxMutexGuiLeave() without entering it first?") );
836
837 gs_nWaitingForGui--;
838
839 wxWakeUpMainThread();
840 }
841
842 gs_pCritsectGui->Leave();
843 }
844
845 void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
846 {
847 wxASSERT_MSG( wxThread::IsMain(),
848 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
849
850 wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui);
851
852 if (gs_nWaitingForGui == 0)
853 {
854 // no threads are waiting for GUI - so we may acquire the lock without
855 // any danger (but only if we don't already have it)
856 if (!wxGuiOwnedByMainThread())
857 {
858 gs_pCritsectGui->Enter();
859
860 gs_bGuiOwnedByMainThread = TRUE;
861 }
862 //else: already have it, nothing to do
863 }
864 else
865 {
866 // some threads are waiting, release the GUI lock if we have it
867 if (wxGuiOwnedByMainThread())
868 {
869 wxMutexGuiLeave();
870 }
871 //else: some other worker thread is doing GUI
872 }
873 }
874
875 bool WXDLLEXPORT wxGuiOwnedByMainThread()
876 {
877 return gs_bGuiOwnedByMainThread;
878 }
879
880 bool WXDLLEXPORT wxIsWaitingForThread()
881 {
882 return gs_bWaitingForThread;
883 }
884
885 #endif
886 // wxUSE_THREADS