]> git.saurik.com Git - wxWidgets.git/blob - src/mac/classic/thread.cpp
Fix for always failing assert in GetValue. Save the same value that
[wxWidgets.git] / src / mac / classic / thread.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/classic/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 // ----------------------------------------------------------------------------
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 #include "wx/module.h"
27 #endif
28
29 #if wxUSE_THREADS
30
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)
49 enum 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
62 static ThreadID gs_idMainThread = kNoThreadID ;
63 static bool gs_waitingForThread = false ;
64 size_t g_numberOfThreads = 0;
65
66 // ============================================================================
67 // MacOS implementation of thread classes
68 // ============================================================================
69
70 class wxMacStCritical
71 {
72 public :
73 wxMacStCritical()
74 {
75 if ( UMASystemIsInitialized() )
76 {
77 OSErr err = ThreadBeginCritical() ;
78 wxASSERT( err == noErr ) ;
79 }
80 }
81 ~wxMacStCritical()
82 {
83 if ( UMASystemIsInitialized() )
84 {
85 OSErr err = ThreadEndCritical() ;
86 wxASSERT( err == noErr ) ;
87 }
88 }
89 };
90
91 // ----------------------------------------------------------------------------
92 // wxMutex implementation
93 // ----------------------------------------------------------------------------
94
95 class wxMutexInternal
96 {
97 public:
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();
117 public:
118 ThreadID m_owner ;
119 wxArrayLong m_waiters ;
120 long m_locked ;
121 };
122
123 wxMutexError 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();
138 wxASSERT( err == noErr ) ;
139 }
140 m_owner = current;
141 }
142 m_locked++;
143
144 return wxMUTEX_NO_ERROR;
145 }
146
147 wxMutexError 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
165 wxMutexError wxMutexInternal::Unlock()
166 {
167 if ( UMASystemIsInitialized() )
168 {
169 OSErr err;
170 err = ::ThreadBeginCritical();
171 wxASSERT( err == noErr ) ;
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
210 class wxSemaphoreInternal
211 {
212 public:
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
224 private:
225 };
226
227 wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
228 {
229 if ( maxcount == 0 )
230 {
231 // make it practically infinite
232 maxcount = INT_MAX;
233 }
234 }
235
236 wxSemaphoreInternal::~wxSemaphoreInternal()
237 {
238 }
239
240 wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds)
241 {
242 return wxSEMA_MISC_ERROR;
243 }
244
245 wxSemaError wxSemaphoreInternal::Post()
246 {
247 return wxSEMA_MISC_ERROR;
248 }
249
250 // ----------------------------------------------------------------------------
251 // wxCondition implementation
252 // ----------------------------------------------------------------------------
253
254 // TODO this is not yet completed
255
256 class wxConditionInternal
257 {
258 public:
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
331 class wxThreadInternal
332 {
333 public:
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
374 private:
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
382 static wxArrayPtrVoid s_threads ;
383
384 ThreadEntryUPP wxThreadInternal::s_threadEntry = NULL ;
385 pascal 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 }
414 void wxThreadInternal::SetPriority(unsigned int priority)
415 {
416 // Priorities don't exist on Mac
417 }
418
419 bool 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
449 bool wxThreadInternal::Suspend()
450 {
451 OSErr err ;
452
453 err = ::ThreadBeginCritical();
454 wxASSERT( err == noErr ) ;
455
456 if ( m_state != STATE_RUNNING )
457 {
458 err = ::ThreadEndCritical() ;
459 wxASSERT( err == noErr ) ;
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
471 bool wxThreadInternal::Resume()
472 {
473 ThreadID current ;
474 OSErr err ;
475 err = MacGetCurrentThread( &current ) ;
476
477 wxASSERT( err == noErr ) ;
478 wxASSERT( current != m_tid ) ;
479
480 err = ::ThreadBeginCritical();
481 wxASSERT( err == noErr ) ;
482
483 if ( m_state != STATE_PAUSED && m_state != STATE_NEW )
484 {
485 err = ::ThreadEndCritical() ;
486 wxASSERT( err == noErr ) ;
487 wxLogSysError(_("Can not resume thread %x"), m_tid);
488 return false;
489
490 }
491 err = ::SetThreadStateEndCritical(m_tid, kReadyThreadState, kNoThreadID);
492
493 m_state = STATE_RUNNING;
494 err = ::ThreadEndCritical() ;
495 wxASSERT( err == noErr ) ;
496 ::YieldToAnyThread() ;
497 return true;
498 }
499
500 // static functions
501 // ----------------
502 wxThread *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
521 bool 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
534 void wxThread::Yield()
535 {
536 ::YieldToAnyThread() ;
537 }
538
539 void 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
557 int wxThread::GetCPUCount()
558 {
559 // we will use whatever MP API will be used for the new MP Macs
560 return 1;
561 }
562
563 unsigned long wxThread::GetCurrentId()
564 {
565 ThreadID current ;
566 MacGetCurrentThread( &current ) ;
567 return (unsigned long)current;
568 }
569
570 bool 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
592 wxThread::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
601 wxThread::~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
624 wxThreadError 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
634 wxThreadError 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
651 wxThreadError wxThread::Pause()
652 {
653 wxCriticalSectionLocker lock(m_critsect);
654
655 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
656 }
657
658 wxThreadError 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
668 wxThread::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
684 wxThreadError 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
768 wxThreadError 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
790 void 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
816 void wxThread::SetPriority(unsigned int prio)
817 {
818 m_internal->SetPriority(prio);
819 }
820
821 unsigned int wxThread::GetPriority() const
822 {
823 return m_internal->GetPriority();
824 }
825
826 unsigned long wxThread::GetId() const
827 {
828 return (unsigned long)m_internal->GetId();
829 }
830
831 bool wxThread::IsRunning() const
832 {
833 return m_internal->GetState() == STATE_RUNNING;
834 }
835
836 bool wxThread::IsAlive() const
837 {
838 return (m_internal->GetState() == STATE_RUNNING) ||
839 (m_internal->GetState() == STATE_PAUSED);
840 }
841
842 bool wxThread::IsPaused() const
843 {
844 return m_internal->GetState() == STATE_PAUSED;
845 }
846
847 bool wxThread::TestDestroy()
848 {
849 return m_internal->GetState() == STATE_CANCELED;
850 }
851
852 // ----------------------------------------------------------------------------
853 // Automatic initialization for thread module
854 // ----------------------------------------------------------------------------
855
856 class wxThreadModule : public wxModule
857 {
858 public:
859 virtual bool OnInit();
860 virtual void OnExit();
861
862 private:
863 DECLARE_DYNAMIC_CLASS(wxThreadModule)
864 };
865
866 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
867
868 bool 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
891 void 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
900 void WXDLLEXPORT wxMutexGuiEnter()
901 {
902 }
903
904 void WXDLLEXPORT wxMutexGuiLeave()
905 {
906 }
907
908 void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
909 {
910 }
911
912 bool WXDLLEXPORT wxGuiOwnedByMainThread()
913 {
914 return false ;
915 }
916
917 // wake up the main thread
918 void WXDLLEXPORT wxWakeUpMainThread()
919 {
920 wxMacWakeUp() ;
921 }
922
923 bool WXDLLEXPORT wxIsWaitingForThread()
924 {
925 return false ;
926 }
927
928 #include "wx/thrimpl.cpp"
929
930 #endif // wxUSE_THREADS