]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/os2/thread.cpp
Applied patch [ 677730 ] Menus with radio items (wxUniv)
[wxWidgets.git] / src / os2 / thread.cpp
... / ...
CommitLineData
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)
42enum 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()
57static ULONG s_ulIdMainThread = 0;
58wxMutex* p_wxMainMutex;
59
60// OS2 substitute for Tls pointer the current parent thread object
61wxThread* m_pThread; // pointer to the wxWindows thread object
62
63// if it's FALSE, some secondary thread is holding the GUI lock
64static 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
69static wxCriticalSection *gs_pCritsectGui = NULL;
70
71// critical section which protects s_nWaitingForGui variable
72static wxCriticalSection *gs_pCritsectWaitingForGui = NULL;
73
74// number of threads waiting for GUI in wxMutexGuiEnter()
75static size_t gs_nWaitingForGui = 0;
76
77// are we waiting for a thread termination?
78static bool gs_bWaitingForThread = FALSE;
79
80// ============================================================================
81// OS/2 implementation of thread classes
82// ============================================================================
83
84// ----------------------------------------------------------------------------
85// wxMutex implementation
86// ----------------------------------------------------------------------------
87class wxMutexInternal
88{
89public:
90 HMTX m_vMutex;
91};
92
93wxMutex::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
107wxMutex::~wxMutex()
108{
109 ::DosCloseMutexSem(m_internal->m_vMutex);
110 m_internal->m_vMutex = NULL;
111}
112
113wxMutexError 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
141wxMutexError 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
152wxMutexError 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
169class wxConditionInternal
170{
171public:
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
213wxCondition::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
229wxCondition::~wxCondition()
230{
231 ::DosCloseEventSem(m_internal->m_vEvent);
232 delete m_internal;
233 m_internal = NULL;
234}
235
236wxCondError 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
253wxCondError 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
272wxCondError 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
287wxCondError 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
316wxCriticalSection::wxCriticalSection()
317{
318}
319
320wxCriticalSection::~wxCriticalSection()
321{
322}
323
324void wxCriticalSection::Enter()
325{
326 ::DosEnterCritSec();
327}
328
329void wxCriticalSection::Leave()
330{
331 ::DosExitCritSec();
332}
333
334// ----------------------------------------------------------------------------
335// wxThread implementation
336// ----------------------------------------------------------------------------
337
338// wxThreadInternal class
339// ----------------------
340
341class wxThreadInternal
342{
343public:
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
390private:
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
399ULONG 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
428void 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
464bool 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
490bool 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
503bool 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
519wxThread *wxThread::This()
520{
521 wxThread* pThread = m_pThread;
522 return pThread;
523}
524
525bool 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
541void wxThread::Yield()
542{
543 ::DosSleep(0);
544}
545
546void wxThread::Sleep(
547 unsigned long ulMilliseconds
548)
549{
550 ::DosSleep(ulMilliseconds);
551}
552
553// ctor and dtor
554// -------------
555
556wxThread::wxThread(wxThreadKind kind)
557{
558 m_internal = new wxThreadInternal();
559
560 m_isDetached = kind == wxTHREAD_DETACHED;
561}
562
563wxThread::~wxThread()
564{
565 delete m_internal;
566}
567
568// create/start thread
569// -------------------
570
571wxThreadError 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
581wxThreadError 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
596wxThreadError wxThread::Pause()
597{
598 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
599
600 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
601}
602
603wxThreadError 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
613wxThread::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
625wxThreadError 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
690wxThreadError 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
704void 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
714void wxThread::SetPriority(
715 unsigned int nPrio
716)
717{
718 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
719
720 m_internal->SetPriority(nPrio);
721}
722
723unsigned int wxThread::GetPriority() const
724{
725 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
726
727 return m_internal->GetPriority();
728}
729
730unsigned long wxThread::GetId() const
731{
732 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
733
734 return (unsigned long)m_internal->GetId();
735}
736
737bool wxThread::IsRunning() const
738{
739 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
740
741 return(m_internal->GetState() == STATE_RUNNING);
742}
743
744bool 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
752bool wxThread::IsPaused() const
753{
754 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
755
756 return (m_internal->GetState() == STATE_PAUSED);
757}
758
759bool 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
770class wxThreadModule : public wxModule
771{
772public:
773 virtual bool OnInit();
774 virtual void OnExit();
775
776private:
777 DECLARE_DYNAMIC_CLASS(wxThreadModule)
778};
779
780IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
781
782bool 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
798void 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]
819void WXDLLEXPORT wxWakeUpMainThread()
820{
821}
822
823void 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
845void 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
875bool WXDLLEXPORT wxGuiOwnedByMainThread()
876{
877 return gs_bGuiOwnedByMainThread;
878}
879
880bool WXDLLEXPORT wxIsWaitingForThread()
881{
882 return gs_bWaitingForThread;
883}
884
885#endif
886 // wxUSE_THREADS