]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/mac/classic/thread.cpp
Doc tweaks
[wxWidgets.git] / src / mac / classic / thread.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: thread.cpp
3// Purpose: wxThread Implementation
4// Author: Original from Wolfram Gloger/Guilhem Lavaux/Vadim Zeitlin
5// Modified by: Stefan Csomor
6// Created: 04/22/98
7// RCS-ID: $Id$
8// Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998),
9// Vadim Zeitlin (1999) , Stefan Csomor (2000)
10// Licence: wxWindows licence
11/////////////////////////////////////////////////////////////////////////////
12
13#ifdef __GNUG__
14 #pragma implementation "thread.h"
15#endif
16
17// ----------------------------------------------------------------------------
18// headers
19// ----------------------------------------------------------------------------
20
21// For compilers that support precompilation, includes "wx.h".
22#include "wx/wxprec.h"
23
24#if defined(__BORLANDC__)
25 #pragma hdrstop
26#endif
27
28#ifndef WX_PRECOMP
29 #include "wx/wx.h"
30#endif
31
32#if wxUSE_THREADS
33
34#include "wx/module.h"
35#include "wx/thread.h"
36
37#ifdef __WXMAC__
38#include <Threads.h>
39#include "wx/mac/uma.h"
40#include "wx/mac/macnotfy.h"
41#include <Timer.h>
42#endif
43
44#define INFINITE 0xFFFFFFFF
45
46
47// ----------------------------------------------------------------------------
48// constants
49// ----------------------------------------------------------------------------
50
51// the possible states of the thread ("=>" shows all possible transitions from
52// this state)
53enum wxThreadState
54{
55 STATE_NEW, // didn't start execution yet (=> RUNNING)
56 STATE_RUNNING, // thread is running (=> PAUSED, CANCELED)
57 STATE_PAUSED, // thread is temporarily suspended (=> RUNNING)
58 STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED)
59 STATE_EXITED // thread is terminating
60};
61
62// ----------------------------------------------------------------------------
63// this module globals
64// ----------------------------------------------------------------------------
65
66static ThreadID gs_idMainThread = kNoThreadID ;
67static bool gs_waitingForThread = FALSE ;
68size_t g_numberOfThreads = 0;
69
70// ============================================================================
71// MacOS implementation of thread classes
72// ============================================================================
73
74class wxMacStCritical
75{
76public :
77 wxMacStCritical()
78 {
79 if ( UMASystemIsInitialized() )
80 {
81 OSErr err = ThreadBeginCritical() ;
82 wxASSERT( err == noErr ) ;
83 }
84 }
85 ~wxMacStCritical()
86 {
87 if ( UMASystemIsInitialized() )
88 {
89 OSErr err = ThreadEndCritical() ;
90 wxASSERT( err == noErr ) ;
91 }
92 }
93};
94
95// ----------------------------------------------------------------------------
96// wxMutex implementation
97// ----------------------------------------------------------------------------
98
99class wxMutexInternal
100{
101public:
102 wxMutexInternal(wxMutexType WXUNUSED(mutexType))
103 {
104 m_owner = kNoThreadID ;
105 m_locked = 0;
106 }
107
108 ~wxMutexInternal()
109 {
110 if ( m_locked > 0 )
111 {
112 wxLogDebug(_T("Warning: freeing a locked mutex (%ld locks)."), m_locked);
113 }
114 }
115
116 bool IsOk() const { return true; }
117
118 wxMutexError Lock() ;
119 wxMutexError TryLock() ;
120 wxMutexError Unlock();
121public:
122 ThreadID m_owner ;
123 wxArrayLong m_waiters ;
124 long m_locked ;
125};
126
127wxMutexError wxMutexInternal::Lock()
128{
129 wxMacStCritical critical ;
130 if ( UMASystemIsInitialized() )
131 {
132 OSErr err ;
133 ThreadID current = kNoThreadID;
134 err = ::MacGetCurrentThread(&current);
135 // if we are not the owner, add this thread to the list of waiting threads, stop this thread
136 // and invoke the scheduler to continue executing the owner's thread
137 while ( m_owner != kNoThreadID && m_owner != current)
138 {
139 m_waiters.Add(current);
140 err = ::SetThreadStateEndCritical(kCurrentThreadID, kStoppedThreadState, m_owner);
141 err = ::ThreadBeginCritical();
142 wxASSERT( err == noErr ) ;
143 }
144 m_owner = current;
145 }
146 m_locked++;
147
148 return wxMUTEX_NO_ERROR;
149}
150
151wxMutexError wxMutexInternal::TryLock()
152{
153 wxMacStCritical critical ;
154 if ( UMASystemIsInitialized() )
155 {
156 ThreadID current = kNoThreadID;
157 ::MacGetCurrentThread(&current);
158 // if we are not the owner, give an error back
159 if ( m_owner != kNoThreadID && m_owner != current )
160 return wxMUTEX_BUSY;
161
162 m_owner = current;
163 }
164 m_locked++;
165
166 return wxMUTEX_NO_ERROR;
167}
168
169wxMutexError wxMutexInternal::Unlock()
170{
171 if ( UMASystemIsInitialized() )
172 {
173 OSErr err;
174 err = ::ThreadBeginCritical();
175 wxASSERT( err == noErr ) ;
176
177 if (m_locked > 0)
178 m_locked--;
179
180 // this mutex is not owned by anybody anmore
181 m_owner = kNoThreadID;
182
183 // now pass on to the first waiting thread
184 ThreadID firstWaiting = kNoThreadID;
185 bool found = false;
186 while (!m_waiters.IsEmpty() && !found)
187 {
188 firstWaiting = m_waiters[0];
189 err = ::SetThreadState(firstWaiting, kReadyThreadState, kNoThreadID);
190 // in case this was not successful (dead thread), we just loop on and reset the id
191 found = (err != threadNotFoundErr);
192 if ( !found )
193 firstWaiting = kNoThreadID ;
194 m_waiters.RemoveAt(0) ;
195 }
196 // now we have a valid firstWaiting thread, which has been scheduled to run next, just end the
197 // critical section and invoke the scheduler
198 err = ::SetThreadStateEndCritical(kCurrentThreadID, kReadyThreadState, firstWaiting);
199 }
200 else
201 {
202 if (m_locked > 0)
203 m_locked--;
204 }
205 return wxMUTEX_NO_ERROR;
206}
207
208// --------------------------------------------------------------------------
209// wxSemaphore
210// --------------------------------------------------------------------------
211
212// TODO not yet implemented
213
214class wxSemaphoreInternal
215{
216public:
217 wxSemaphoreInternal(int initialcount, int maxcount);
218 ~wxSemaphoreInternal();
219
220 bool IsOk() const { return true ; }
221
222 wxSemaError Wait() { return WaitTimeout(INFINITE); }
223 wxSemaError TryWait() { return WaitTimeout(0); }
224 wxSemaError WaitTimeout(unsigned long milliseconds);
225
226 wxSemaError Post();
227
228private:
229};
230
231wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
232{
233 if ( maxcount == 0 )
234 {
235 // make it practically infinite
236 maxcount = INT_MAX;
237 }
238}
239
240wxSemaphoreInternal::~wxSemaphoreInternal()
241{
242}
243
244wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds)
245{
246 return wxSEMA_MISC_ERROR;
247}
248
249wxSemaError wxSemaphoreInternal::Post()
250{
251 return wxSEMA_MISC_ERROR;
252}
253
254// ----------------------------------------------------------------------------
255// wxCondition implementation
256// ----------------------------------------------------------------------------
257
258// TODO this is not yet completed
259
260class wxConditionInternal
261{
262public:
263 wxConditionInternal(wxMutex& mutex) : m_mutex(mutex)
264 {
265 m_excessSignals = 0 ;
266 }
267 ~wxConditionInternal()
268 {
269 }
270
271 bool IsOk() const { return m_mutex.IsOk() ; }
272
273 wxCondError Wait()
274 {
275 return WaitTimeout(0xFFFFFFFF );
276 }
277
278 wxCondError WaitTimeout(unsigned long msectimeout)
279 {
280 wxMacStCritical critical ;
281 if ( m_excessSignals > 0 )
282 {
283 --m_excessSignals ;
284 return wxCOND_NO_ERROR ;
285 }
286 else if ( msectimeout == 0 )
287 {
288 return wxCOND_MISC_ERROR ;
289 }
290 else
291 {
292 }
293 /*
294 waiters++;
295
296 // FIXME this should be MsgWaitForMultipleObjects() as well probably
297 DWORD rc = ::WaitForSingleObject(event, timeout);
298
299 waiters--;
300
301 return rc != WAIT_TIMEOUT;
302 */
303 return wxCOND_NO_ERROR ;
304 }
305 wxCondError Signal()
306 {
307 wxMacStCritical critical ;
308 return wxCOND_NO_ERROR;
309 }
310
311 wxCondError Broadcast()
312 {
313 wxMacStCritical critical ;
314 return wxCOND_NO_ERROR;
315 }
316
317 wxArrayLong m_waiters ;
318 wxInt32 m_excessSignals ;
319 wxMutex& m_mutex;
320};
321
322// ----------------------------------------------------------------------------
323// wxCriticalSection implementation
324// ----------------------------------------------------------------------------
325
326// it's implemented as a mutex on mac os, so it is defined in the headers
327
328// ----------------------------------------------------------------------------
329// wxThread implementation
330// ----------------------------------------------------------------------------
331
332// wxThreadInternal class
333// ----------------------
334
335class wxThreadInternal
336{
337public:
338 wxThreadInternal()
339 {
340 m_tid = kNoThreadID ;
341 m_state = STATE_NEW;
342 m_priority = WXTHREAD_DEFAULT_PRIORITY;
343 }
344
345 ~wxThreadInternal()
346 {
347 }
348
349 void Free()
350 {
351 }
352
353 // create a new (suspended) thread (for the given thread object)
354 bool Create(wxThread *thread, unsigned int stackSize);
355
356 // suspend/resume/terminate
357 bool Suspend();
358 bool Resume();
359 void Cancel() { m_state = STATE_CANCELED; }
360
361 // thread state
362 void SetState(wxThreadState state) { m_state = state; }
363 wxThreadState GetState() const { return m_state; }
364
365 // thread priority
366 void SetPriority(unsigned int priority);
367 unsigned int GetPriority() const { return m_priority; }
368
369 void SetResult( void *res ) { m_result = res ; }
370 void *GetResult() { return m_result ; }
371
372 // thread handle and id
373 ThreadID GetId() const { return m_tid; }
374
375 // thread function
376 static pascal void* MacThreadStart(wxThread* arg);
377
378private:
379 wxThreadState m_state; // state, see wxThreadState enum
380 unsigned int m_priority; // thread priority in "wx" units
381 ThreadID m_tid; // thread id
382 void* m_result;
383 static ThreadEntryUPP s_threadEntry ;
384};
385
386static wxArrayPtrVoid s_threads ;
387
388ThreadEntryUPP wxThreadInternal::s_threadEntry = NULL ;
389pascal void* wxThreadInternal::MacThreadStart(wxThread *thread)
390{
391 // first of all, check whether we hadn't been cancelled already
392 if ( thread->m_internal->GetState() == STATE_EXITED )
393 {
394 return (void*)-1;
395 }
396
397 void* rc = thread->Entry();
398
399 // enter m_critsect before changing the thread state
400 thread->m_critsect.Enter();
401 bool wasCancelled = thread->m_internal->GetState() == STATE_CANCELED;
402 thread->m_internal->SetState(STATE_EXITED);
403 thread->m_critsect.Leave();
404
405 thread->OnExit();
406
407 // if the thread was cancelled (from Delete()), then it the handle is still
408 // needed there
409 if ( thread->IsDetached() && !wasCancelled )
410 {
411 // auto delete
412 delete thread;
413 }
414 //else: the joinable threads handle will be closed when Wait() is done
415
416 return rc;
417}
418void wxThreadInternal::SetPriority(unsigned int priority)
419{
420 // Priorities don't exist on Mac
421}
422
423bool wxThreadInternal::Create(wxThread *thread, unsigned int stackSize)
424{
425 if ( s_threadEntry == NULL )
426 {
427 s_threadEntry = NewThreadEntryUPP( (ThreadEntryProcPtr) MacThreadStart ) ;
428 }
429 OSErr err = NewThread( kCooperativeThread,
430 s_threadEntry,
431 (void*) thread,
432 stackSize,
433 kNewSuspend,
434 &m_result,
435 &m_tid );
436
437 if ( err != noErr )
438 {
439 wxLogSysError(_("Can't create thread"));
440 return FALSE;
441 }
442
443 if ( m_priority != WXTHREAD_DEFAULT_PRIORITY )
444 {
445 SetPriority(m_priority);
446 }
447
448 m_state = STATE_NEW;
449
450 return TRUE;
451}
452
453bool wxThreadInternal::Suspend()
454{
455 OSErr err ;
456
457 err = ::ThreadBeginCritical();
458 wxASSERT( err == noErr ) ;
459
460 if ( m_state != STATE_RUNNING )
461 {
462 err = ::ThreadEndCritical() ;
463 wxASSERT( err == noErr ) ;
464 wxLogSysError(_("Can not suspend thread %x"), m_tid);
465 return FALSE;
466 }
467
468 m_state = STATE_PAUSED;
469
470 err = ::SetThreadStateEndCritical(m_tid, kStoppedThreadState, kNoThreadID);
471
472 return TRUE;
473}
474
475bool wxThreadInternal::Resume()
476{
477 ThreadID current ;
478 OSErr err ;
479 err = MacGetCurrentThread( &current ) ;
480
481 wxASSERT( err == noErr ) ;
482 wxASSERT( current != m_tid ) ;
483
484 err = ::ThreadBeginCritical();
485 wxASSERT( err == noErr ) ;
486
487 if ( m_state != STATE_PAUSED && m_state != STATE_NEW )
488 {
489 err = ::ThreadEndCritical() ;
490 wxASSERT( err == noErr ) ;
491 wxLogSysError(_("Can not resume thread %x"), m_tid);
492 return FALSE;
493
494 }
495 err = ::SetThreadStateEndCritical(m_tid, kReadyThreadState, kNoThreadID);
496
497 m_state = STATE_RUNNING;
498 err = ::ThreadEndCritical() ;
499 wxASSERT( err == noErr ) ;
500 ::YieldToAnyThread() ;
501 return TRUE;
502}
503
504// static functions
505// ----------------
506wxThread *wxThread::This()
507{
508 wxMacStCritical critical ;
509
510 ThreadID current ;
511 OSErr err ;
512
513 err = MacGetCurrentThread( &current ) ;
514
515 for ( size_t i = 0 ; i < s_threads.Count() ; ++i )
516 {
517 if ( ( (wxThread*) s_threads[i] )->GetId() == current )
518 return (wxThread*) s_threads[i] ;
519 }
520
521 wxLogSysError(_("Couldn't get the current thread pointer"));
522 return NULL;
523}
524
525bool wxThread::IsMain()
526{
527 ThreadID current ;
528 OSErr err ;
529
530 err = MacGetCurrentThread( &current ) ;
531 return current == gs_idMainThread;
532}
533
534#ifdef Yield
535#undef Yield
536#endif
537
538void wxThread::Yield()
539{
540 ::YieldToAnyThread() ;
541}
542
543void wxThread::Sleep(unsigned long milliseconds)
544{
545 UnsignedWide start, now;
546
547 Microseconds(&start);
548
549 double mssleep = milliseconds * 1000 ;
550 double msstart, msnow ;
551 msstart = (start.hi * 4294967296.0 + start.lo) ;
552
553 do
554 {
555 YieldToAnyThread();
556 Microseconds(&now);
557 msnow = (now.hi * 4294967296.0 + now.lo) ;
558 } while( msnow - msstart < mssleep );
559}
560
561int wxThread::GetCPUCount()
562{
563 // we will use whatever MP API will be used for the new MP Macs
564 return 1;
565}
566
567unsigned long wxThread::GetCurrentId()
568{
569 ThreadID current ;
570 MacGetCurrentThread( &current ) ;
571 return (unsigned long)current;
572}
573
574bool wxThread::SetConcurrency(size_t level)
575{
576 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
577
578 // ok only for the default one
579 if ( level == 0 )
580 return 0;
581
582 // how many CPUs have we got?
583 if ( GetCPUCount() == 1 )
584 {
585 // don't bother with all this complicated stuff - on a single
586 // processor system it doesn't make much sense anyhow
587 return level == 1;
588 }
589
590 return TRUE ;
591}
592
593// ctor and dtor
594// -------------
595
596wxThread::wxThread(wxThreadKind kind)
597{
598 g_numberOfThreads++;
599 m_internal = new wxThreadInternal();
600
601 m_isDetached = kind == wxTHREAD_DETACHED;
602 s_threads.Add( (void*) this ) ;
603}
604
605wxThread::~wxThread()
606{
607 if (g_numberOfThreads>0)
608 {
609 g_numberOfThreads--;
610 }
611#ifdef __WXDEBUG__
612 else
613 {
614 wxFAIL_MSG(wxT("More threads deleted than created."));
615 }
616#endif
617
618 s_threads.Remove( (void*) this ) ;
619 if (m_internal != NULL) {
620 delete m_internal;
621 m_internal = NULL;
622 }
623}
624
625// create/start thread
626// -------------------
627
628wxThreadError wxThread::Create(unsigned int stackSize)
629{
630 wxCriticalSectionLocker lock(m_critsect);
631
632 if ( !m_internal->Create(this, stackSize) )
633 return wxTHREAD_NO_RESOURCE;
634
635 return wxTHREAD_NO_ERROR;
636}
637
638wxThreadError wxThread::Run()
639{
640 wxCriticalSectionLocker lock(m_critsect);
641
642 if ( m_internal->GetState() != STATE_NEW )
643 {
644 // actually, it may be almost any state at all, not only STATE_RUNNING
645 return wxTHREAD_RUNNING;
646 }
647
648 // the thread has just been created and is still suspended - let it run
649 return Resume();
650}
651
652// suspend/resume thread
653// ---------------------
654
655wxThreadError wxThread::Pause()
656{
657 wxCriticalSectionLocker lock(m_critsect);
658
659 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
660}
661
662wxThreadError wxThread::Resume()
663{
664 wxCriticalSectionLocker lock(m_critsect);
665
666 return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
667}
668
669// stopping thread
670// ---------------
671
672wxThread::ExitCode wxThread::Wait()
673{
674 // although under MacOS we can wait for any thread, it's an error to
675 // wait for a detached one in wxWin API
676 wxCHECK_MSG( !IsDetached(), (ExitCode)-1,
677 _T("can't wait for detached thread") );
678
679 ExitCode rc = (ExitCode)-1;
680
681 (void)Delete(&rc);
682
683 m_internal->Free();
684
685 return rc;
686}
687
688wxThreadError wxThread::Delete(ExitCode *pRc)
689{
690 ExitCode rc = 0;
691
692 // Delete() is always safe to call, so consider all possible states
693
694 // has the thread started to run?
695 bool shouldResume = FALSE;
696
697 {
698 wxCriticalSectionLocker lock(m_critsect);
699
700 if ( m_internal->GetState() == STATE_NEW )
701 {
702 // WinThreadStart() will see it and terminate immediately
703 m_internal->SetState(STATE_EXITED);
704
705 shouldResume = TRUE;
706 }
707 }
708
709 // is the thread paused?
710 if ( shouldResume || IsPaused() )
711 Resume();
712
713 // does is still run?
714 if ( IsRunning() )
715 {
716 if ( IsMain() )
717 {
718 // set flag for wxIsWaitingForThread()
719 gs_waitingForThread = TRUE;
720
721#if wxUSE_GUI
722 wxBeginBusyCursor();
723#endif // wxUSE_GUI
724 }
725
726 // ask the thread to terminate
727 {
728 wxCriticalSectionLocker lock(m_critsect);
729
730 m_internal->Cancel();
731 }
732
733#if wxUSE_GUI
734 // simply wait for the thread to terminate
735 while( TestDestroy() )
736 {
737 ::YieldToAnyThread() ;
738 }
739#else // !wxUSE_GUI
740 // simply wait for the thread to terminate
741 while( TestDestroy() )
742 {
743 ::YieldToAnyThread() ;
744 }
745#endif // wxUSE_GUI/!wxUSE_GUI
746
747 if ( IsMain() )
748 {
749 gs_waitingForThread = FALSE;
750
751#if wxUSE_GUI
752 wxEndBusyCursor();
753#endif // wxUSE_GUI
754 }
755 }
756
757 if ( IsDetached() )
758 {
759 // if the thread exits normally, this is done in WinThreadStart, but in
760 // this case it would have been too early because
761 // MsgWaitForMultipleObject() would fail if the therad handle was
762 // closed while we were waiting on it, so we must do it here
763 delete this;
764 }
765
766 if ( pRc )
767 *pRc = rc;
768
769 return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR;
770}
771
772wxThreadError wxThread::Kill()
773{
774 if ( !IsRunning() )
775 return wxTHREAD_NOT_RUNNING;
776
777// if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
778 {
779 wxLogSysError(_("Couldn't terminate thread"));
780
781 return wxTHREAD_MISC_ERROR;
782 }
783
784 m_internal->Free();
785
786 if ( IsDetached() )
787 {
788 delete this;
789 }
790
791 return wxTHREAD_NO_ERROR;
792}
793
794void wxThread::Exit(ExitCode status)
795{
796 m_internal->Free();
797
798 if ( IsDetached() )
799 {
800 delete this;
801 }
802
803 m_internal->SetResult( status ) ;
804
805/*
806#if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
807 _endthreadex((unsigned)status);
808#else // !VC++
809 ::ExitThread((DWORD)status);
810#endif // VC++/!VC++
811*/
812 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
813}
814
815// priority setting
816// ----------------
817
818// since all these calls are execute cooperatively we don't have to use the critical section
819
820void wxThread::SetPriority(unsigned int prio)
821{
822 m_internal->SetPriority(prio);
823}
824
825unsigned int wxThread::GetPriority() const
826{
827 return m_internal->GetPriority();
828}
829
830unsigned long wxThread::GetId() const
831{
832 return (unsigned long)m_internal->GetId();
833}
834
835bool wxThread::IsRunning() const
836{
837 return m_internal->GetState() == STATE_RUNNING;
838}
839
840bool wxThread::IsAlive() const
841{
842 return (m_internal->GetState() == STATE_RUNNING) ||
843 (m_internal->GetState() == STATE_PAUSED);
844}
845
846bool wxThread::IsPaused() const
847{
848 return m_internal->GetState() == STATE_PAUSED;
849}
850
851bool wxThread::TestDestroy()
852{
853 return m_internal->GetState() == STATE_CANCELED;
854}
855
856// ----------------------------------------------------------------------------
857// Automatic initialization for thread module
858// ----------------------------------------------------------------------------
859
860class wxThreadModule : public wxModule
861{
862public:
863 virtual bool OnInit();
864 virtual void OnExit();
865
866private:
867 DECLARE_DYNAMIC_CLASS(wxThreadModule)
868};
869
870IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
871
872bool wxThreadModule::OnInit()
873{
874 long response;
875 bool hasThreadManager ;
876 hasThreadManager = Gestalt( gestaltThreadMgrAttr, &response) == noErr && response & 1;
877#if !TARGET_CARBON
878#if GENERATINGCFM
879 // verify presence of shared library
880 hasThreadManager = hasThreadManager && ((Ptr)NewThread != (Ptr)kUnresolvedCFragSymbolAddress);
881#endif
882#endif
883 if ( !hasThreadManager )
884 {
885 wxLogSysError( wxT("Thread Support is not available on this System") );
886 return FALSE ;
887 }
888
889 // no error return for GetCurrentThreadId()
890 MacGetCurrentThread( &gs_idMainThread ) ;
891
892 return TRUE;
893}
894
895void wxThreadModule::OnExit()
896{
897}
898
899// ----------------------------------------------------------------------------
900// under MacOS we don't have currently preemptive threads, so any thread may access
901// the GUI at any time
902// ----------------------------------------------------------------------------
903
904void WXDLLEXPORT wxMutexGuiEnter()
905{
906}
907
908void WXDLLEXPORT wxMutexGuiLeave()
909{
910}
911
912void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
913{
914}
915
916bool WXDLLEXPORT wxGuiOwnedByMainThread()
917{
918 return false ;
919}
920
921// wake up the main thread
922void WXDLLEXPORT wxWakeUpMainThread()
923{
924 wxMacWakeUp() ;
925}
926
927bool WXDLLEXPORT wxIsWaitingForThread()
928{
929 return false ;
930}
931
932#include "wx/thrimpl.cpp"
933
934#endif // wxUSE_THREADS