]> git.saurik.com Git - wxWidgets.git/blob - src/mac/classic/thread.cpp
catching errors
[wxWidgets.git] / src / mac / classic / thread.cpp
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)
53 enum 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
66 static ThreadID gs_idMainThread = kNoThreadID ;
67 static bool gs_waitingForThread = FALSE ;
68 size_t g_numberOfThreads = 0;
69
70 // ============================================================================
71 // MacOS implementation of thread classes
72 // ============================================================================
73
74 class wxMacStCritical
75 {
76 public :
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
99 class wxMutexInternal
100 {
101 public:
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();
121 public:
122 ThreadID m_owner ;
123 wxArrayLong m_waiters ;
124 long m_locked ;
125 };
126
127 wxMutexError 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
151 wxMutexError 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
169 wxMutexError 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
214 class wxSemaphoreInternal
215 {
216 public:
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
228 private:
229 };
230
231 wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
232 {
233 if ( maxcount == 0 )
234 {
235 // make it practically infinite
236 maxcount = INT_MAX;
237 }
238 }
239
240 wxSemaphoreInternal::~wxSemaphoreInternal()
241 {
242 }
243
244 wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds)
245 {
246 return wxSEMA_MISC_ERROR;
247 }
248
249 wxSemaError wxSemaphoreInternal::Post()
250 {
251 return wxSEMA_MISC_ERROR;
252 }
253
254 // ----------------------------------------------------------------------------
255 // wxCondition implementation
256 // ----------------------------------------------------------------------------
257
258 // TODO this is not yet completed
259
260 class wxConditionInternal
261 {
262 public:
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
335 class wxThreadInternal
336 {
337 public:
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
378 private:
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
386 static wxArrayPtrVoid s_threads ;
387
388 ThreadEntryUPP wxThreadInternal::s_threadEntry = NULL ;
389 pascal 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 }
418 void wxThreadInternal::SetPriority(unsigned int priority)
419 {
420 // Priorities don't exist on Mac
421 }
422
423 bool 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
453 bool 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
475 bool 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 // ----------------
506 wxThread *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
525 bool 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
538 void wxThread::Yield()
539 {
540 ::YieldToAnyThread() ;
541 }
542
543 void 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
561 int wxThread::GetCPUCount()
562 {
563 // we will use whatever MP API will be used for the new MP Macs
564 return 1;
565 }
566
567 unsigned long wxThread::GetCurrentId()
568 {
569 ThreadID current ;
570 MacGetCurrentThread( &current ) ;
571 return (unsigned long)current;
572 }
573
574 bool 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
596 wxThread::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
605 wxThread::~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
628 wxThreadError 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
638 wxThreadError 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
655 wxThreadError wxThread::Pause()
656 {
657 wxCriticalSectionLocker lock(m_critsect);
658
659 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
660 }
661
662 wxThreadError 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
672 wxThread::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
688 wxThreadError 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
772 wxThreadError 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
794 void 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
820 void wxThread::SetPriority(unsigned int prio)
821 {
822 m_internal->SetPriority(prio);
823 }
824
825 unsigned int wxThread::GetPriority() const
826 {
827 return m_internal->GetPriority();
828 }
829
830 unsigned long wxThread::GetId() const
831 {
832 return (unsigned long)m_internal->GetId();
833 }
834
835 bool wxThread::IsRunning() const
836 {
837 return m_internal->GetState() == STATE_RUNNING;
838 }
839
840 bool wxThread::IsAlive() const
841 {
842 return (m_internal->GetState() == STATE_RUNNING) ||
843 (m_internal->GetState() == STATE_PAUSED);
844 }
845
846 bool wxThread::IsPaused() const
847 {
848 return m_internal->GetState() == STATE_PAUSED;
849 }
850
851 bool wxThread::TestDestroy()
852 {
853 return m_internal->GetState() == STATE_CANCELED;
854 }
855
856 // ----------------------------------------------------------------------------
857 // Automatic initialization for thread module
858 // ----------------------------------------------------------------------------
859
860 class wxThreadModule : public wxModule
861 {
862 public:
863 virtual bool OnInit();
864 virtual void OnExit();
865
866 private:
867 DECLARE_DYNAMIC_CLASS(wxThreadModule)
868 };
869
870 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
871
872 bool 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
895 void 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
904 void WXDLLEXPORT wxMutexGuiEnter()
905 {
906 }
907
908 void WXDLLEXPORT wxMutexGuiLeave()
909 {
910 }
911
912 void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
913 {
914 }
915
916 bool WXDLLEXPORT wxGuiOwnedByMainThread()
917 {
918 return false ;
919 }
920
921 // wake up the main thread
922 void WXDLLEXPORT wxWakeUpMainThread()
923 {
924 wxMacWakeUp() ;
925 }
926
927 bool WXDLLEXPORT wxIsWaitingForThread()
928 {
929 return false ;
930 }
931
932 #include "wx/thrimpl.cpp"
933
934 #endif // wxUSE_THREADS