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