]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/os2/thread.cpp
whoever added mdig.cpp forgot to update the makefiles
[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// ----------------------------------------------------------------------------
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)
37enum 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()
52static ULONG s_ulIdMainThread = 0;
53wxMutex* p_wxMainMutex;
54
55// OS2 substitute for Tls pointer the current parent thread object
56wxThread* m_pThread; // pointer to the wxWindows thread object
57
58// if it's FALSE, some secondary thread is holding the GUI lock
59static 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
64static wxCriticalSection *gs_pCritsectGui = NULL;
65
66// critical section which protects s_nWaitingForGui variable
67static wxCriticalSection *gs_pCritsectWaitingForGui = NULL;
68
69// number of threads waiting for GUI in wxMutexGuiEnter()
70static size_t gs_nWaitingForGui = 0;
71
72// are we waiting for a thread termination?
73static bool gs_bWaitingForThread = FALSE;
74
75// ============================================================================
76// OS/2 implementation of thread classes
77// ============================================================================
78
79// ----------------------------------------------------------------------------
80// wxMutex implementation
81// ----------------------------------------------------------------------------
82class wxMutexInternal
83{
84public:
85 HMTX m_vMutex;
86};
87
88wxMutex::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
102wxMutex::~wxMutex()
103{
104 ::DosCloseMutexSem(m_internal->m_vMutex);
105 m_internal->m_vMutex = NULL;
106}
107
108wxMutexError 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
136wxMutexError 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
147wxMutexError 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
164class wxConditionInternal
165{
166public:
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
208wxCondition::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
224wxCondition::~wxCondition()
225{
226 ::DosCloseEventSem(m_internal->m_vEvent);
227 delete m_internal;
228 m_internal = NULL;
229}
230
231wxCondError 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
248wxCondError 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
267wxCondError 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
282wxCondError 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
311wxCriticalSection::wxCriticalSection()
312{
313}
314
315wxCriticalSection::~wxCriticalSection()
316{
317}
318
319void wxCriticalSection::Enter()
320{
321 ::DosEnterCritSec();
322}
323
324void wxCriticalSection::Leave()
325{
326 ::DosExitCritSec();
327}
328
329// ----------------------------------------------------------------------------
330// wxThread implementation
331// ----------------------------------------------------------------------------
332
333// wxThreadInternal class
334// ----------------------
335
336class wxThreadInternal
337{
338public:
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
385private:
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
394ULONG 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
423void 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
459bool 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
485bool 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
498bool 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
514wxThread *wxThread::This()
515{
516 wxThread* pThread = m_pThread;
517 return pThread;
518}
519
520bool 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
536void wxThread::Yield()
537{
538 ::DosSleep(0);
539}
540
541void wxThread::Sleep(
542 unsigned long ulMilliseconds
543)
544{
545 ::DosSleep(ulMilliseconds);
546}
547
548// ctor and dtor
549// -------------
550
551wxThread::wxThread(wxThreadKind kind)
552{
553 m_internal = new wxThreadInternal();
554
555 m_isDetached = kind == wxTHREAD_DETACHED;
556}
557
558wxThread::~wxThread()
559{
560 delete m_internal;
561}
562
563// create/start thread
564// -------------------
565
566wxThreadError 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
576wxThreadError 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
591wxThreadError wxThread::Pause()
592{
593 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
594
595 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
596}
597
598wxThreadError 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
608wxThread::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
620wxThreadError 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
685wxThreadError 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
699void 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
709void wxThread::SetPriority(
710 unsigned int nPrio
711)
712{
713 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
714
715 m_internal->SetPriority(nPrio);
716}
717
718unsigned int wxThread::GetPriority() const
719{
720 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
721
722 return m_internal->GetPriority();
723}
724
725unsigned long wxThread::GetId() const
726{
727 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
728
729 return (unsigned long)m_internal->GetId();
730}
731
732bool wxThread::IsRunning() const
733{
734 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
735
736 return(m_internal->GetState() == STATE_RUNNING);
737}
738
739bool 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
747bool wxThread::IsPaused() const
748{
749 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
750
751 return (m_internal->GetState() == STATE_PAUSED);
752}
753
754bool 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
765class wxThreadModule : public wxModule
766{
767public:
768 virtual bool OnInit();
769 virtual void OnExit();
770
771private:
772 DECLARE_DYNAMIC_CLASS(wxThreadModule)
773};
774
775IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
776
777bool 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
793void 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]
814void WXDLLEXPORT wxWakeUpMainThread()
815{
816}
817
818void 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
840void 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
870bool WXDLLEXPORT wxGuiOwnedByMainThread()
871{
872 return gs_bGuiOwnedByMainThread;
873}
874
875bool WXDLLEXPORT wxIsWaitingForThread()
876{
877 return gs_bWaitingForThread;
878}
879
880#endif
881 // wxUSE_THREADS