]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/mpthread.cpp
bf5b9b18fd09b64ca9cd1df7b495e73e318dc0f1
[wxWidgets.git] / src / mac / carbon / mpthread.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: thread.cpp
3 // Purpose: wxThread Implementation
4 // Author: Original from Wolfram Gloger/Guilhem Lavaux/Vadim Zeitlin
5 // Modified by: Aj Lavin, 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 <CoreServices/CoreServices.h>
39 #include "wx/mac/uma.h"
40 #endif
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 MPTaskID gs_idMainThread = 0;
63 static bool gs_waitingForThread = FALSE ;
64 size_t g_numberOfThreads = 0;
65
66 #if wxUSE_GUI
67
68 MPCriticalRegionID gs_guiCritical = 0;
69
70 #endif
71
72 // ============================================================================
73 // MacOS implementation of thread classes
74 // ============================================================================
75
76 class wxMacStCritical
77 {
78 public :
79 wxMacStCritical()
80 {
81 if ( ! s_criticalId)
82 makeCritical();
83
84 MPEnterCriticalRegion( s_criticalId, kDurationForever);
85 }
86 ~wxMacStCritical()
87 {
88 MPExitCriticalRegion( s_criticalId);
89 }
90
91 private:
92
93 void makeCritical()
94 {
95 OSStatus err = MPCreateCriticalRegion( & s_criticalId);
96 if ( err)
97 {
98 wxLogSysError(_("Could not make the static mutex."));
99 }
100 }
101
102 static MPCriticalRegionID s_criticalId;
103 };
104
105 MPCriticalRegionID wxMacStCritical::s_criticalId = 0;
106
107 // ----------------------------------------------------------------------------
108 // wxMutex implementation
109 // ----------------------------------------------------------------------------
110
111 class wxMutexInternal
112 {
113 public:
114 // ALL MUTEXES WILL BE NON-RECURSIVE.
115 wxMutexInternal(wxMutexType WXUNUSED(mutexType))
116 {
117 OSStatus err = MPCreateBinarySemaphore( & m_semaphore);
118 if ( err)
119 wxLogSysError(_("Could not construct mutex."));
120 }
121
122 ~wxMutexInternal()
123 {
124 MPDeleteSemaphore( m_semaphore);
125 }
126
127 bool IsOk() const { return true; }
128
129 wxMutexError Lock() ;
130 wxMutexError TryLock() ;
131 wxMutexError Unlock();
132 public:
133
134 MPSemaphoreID m_semaphore;
135 };
136
137 wxMutexError wxMutexInternal::Lock()
138 {
139 OSStatus err = MPWaitOnSemaphore( m_semaphore, kDurationForever);
140 if ( err)
141 {
142 wxLogSysError(_("Could not lock mutex"));
143 return wxMUTEX_MISC_ERROR;
144 }
145
146 return wxMUTEX_NO_ERROR;
147 }
148
149 wxMutexError wxMutexInternal::TryLock()
150 {
151 OSStatus err = MPWaitOnSemaphore( m_semaphore, kDurationImmediate);
152 if ( err)
153 {
154 if ( err == kMPTimeoutErr)
155 {
156 return wxMUTEX_BUSY;
157 }
158 wxLogSysError(_("Could not try lock mutex"));
159 return wxMUTEX_MISC_ERROR;
160 }
161
162 return wxMUTEX_NO_ERROR;
163 }
164
165 wxMutexError wxMutexInternal::Unlock()
166 {
167 OSStatus err = MPSignalSemaphore( m_semaphore);
168 if ( err)
169 {
170 wxLogSysError(_("Could not unlock mutex"));
171 return wxMUTEX_MISC_ERROR;
172 }
173
174 return wxMUTEX_NO_ERROR;
175 }
176
177 // --------------------------------------------------------------------------
178 // wxSemaphore
179 // --------------------------------------------------------------------------
180
181 class wxSemaphoreInternal
182 {
183 public:
184 wxSemaphoreInternal(int initialcount, int maxcount);
185 ~wxSemaphoreInternal();
186
187 bool IsOk() const { return true ; }
188
189 wxSemaError WaitTimeout(unsigned long milliseconds);
190
191 wxSemaError Wait() { return WaitTimeout( kDurationForever); }
192
193 wxSemaError TryWait() { return WaitTimeout(0); }
194
195 wxSemaError Post();
196
197 private:
198 MPSemaphoreID m_semaphore;
199 };
200
201 wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
202 {
203 if ( maxcount == 0 )
204 {
205 // make it practically infinite
206 maxcount = INT_MAX;
207 }
208 MPCreateSemaphore( maxcount, initialcount, & m_semaphore);
209 }
210
211 wxSemaphoreInternal::~wxSemaphoreInternal()
212 {
213 MPDeleteSemaphore( m_semaphore);
214 }
215
216 wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds)
217 {
218 OSStatus err = MPWaitOnSemaphore( m_semaphore, milliseconds);
219 if ( err)
220 {
221 if ( err == kMPTimeoutErr)
222 {
223 return wxSEMA_TIMEOUT;
224 }
225 return wxSEMA_MISC_ERROR;
226 }
227 return wxSEMA_NO_ERROR;
228 }
229
230 wxSemaError wxSemaphoreInternal::Post()
231 {
232 OSStatus err = MPSignalSemaphore( m_semaphore);
233 if ( err)
234 {
235 return wxSEMA_MISC_ERROR;
236 }
237 return wxSEMA_NO_ERROR;
238 }
239
240 // ----------------------------------------------------------------------------
241 // wxCondition implementation
242 // ----------------------------------------------------------------------------
243
244 class wxConditionInternal
245 {
246 public:
247
248 wxConditionInternal(wxMutex& mutex)
249 : m_mutex( mutex),
250 m_semaphore( 0, 1),
251 m_gate( 1, 1)
252 {
253 m_waiters = 0;
254 m_signals = 0;
255 m_canceled = 0;
256 }
257
258 ~wxConditionInternal()
259 {
260 }
261
262 bool IsOk() const { return m_mutex.IsOk() ; }
263
264 wxCondError Wait()
265 {
266 return WaitTimeout( kDurationForever);
267 }
268
269 wxCondError WaitTimeout(unsigned long msectimeout);
270
271 wxCondError Signal()
272 {
273 return DoSignal( false);
274 }
275
276 wxCondError Broadcast()
277 {
278 return DoSignal( true);
279 }
280
281 private:
282
283 wxCondError DoSignal( bool signalAll);
284
285 wxMutex& m_mutex;
286 wxSemaphoreInternal m_semaphore; // Signals the waiting threads.
287 wxSemaphoreInternal m_gate;
288 wxCriticalSection m_varSection;
289 size_t m_waiters; // Number of threads waiting for a signal.
290 size_t m_signals; // Number of signals to send.
291 size_t m_canceled; // Number of canceled waiters in m_waiters.
292 };
293
294
295 wxCondError wxConditionInternal::WaitTimeout(unsigned long msectimeout)
296 {
297 m_gate.Wait();
298 if ( ++ m_waiters == INT_MAX)
299 {
300 m_varSection.Enter();
301 m_waiters -= m_canceled;
302 m_signals -= m_canceled;
303 m_canceled = 0;
304 m_varSection.Leave();
305 }
306 m_gate.Post();
307
308 m_mutex.Unlock();
309
310 wxSemaError err = m_semaphore.WaitTimeout( msectimeout);
311 wxASSERT( err == wxSEMA_NO_ERROR || err == wxSEMA_TIMEOUT);
312
313 m_varSection.Enter();
314 if ( err != wxSEMA_NO_ERROR)
315 {
316 if ( m_signals > m_canceled)
317 {
318 // A signal is being sent after we timed out.
319
320 if ( m_waiters == m_signals)
321 {
322 // There are no excess waiters to catch the signal, so
323 // we must throw it away.
324
325 wxSemaError err2 = m_semaphore.Wait();
326 if ( err2 != wxSEMA_NO_ERROR)
327 {
328 wxLogSysError(_("Error while waiting on semaphore"));
329 }
330 wxASSERT( err2 == wxSEMA_NO_ERROR);
331 -- m_waiters;
332 if ( -- m_signals == m_canceled)
333 {
334 // This was the last signal. open the gate.
335 wxASSERT( m_waiters == m_canceled);
336 m_gate.Post();
337 }
338 }
339 else
340 {
341 // There are excess waiters to catch the signal, leave
342 // it be.
343 -- m_waiters;
344 }
345 }
346 else
347 {
348 // No signals is being sent.
349 // The gate may be open or closed, so we can't touch m_waiters.
350 ++ m_canceled;
351 ++ m_signals;
352 }
353 }
354 else
355 {
356 // We caught a signal.
357 wxASSERT( m_signals > m_canceled);
358 -- m_waiters;
359 if ( -- m_signals == m_canceled)
360 {
361 // This was the last signal. open the gate.
362 wxASSERT( m_waiters == m_canceled);
363 m_gate.Post();
364 }
365 }
366 m_varSection.Leave();
367
368 m_mutex.Lock();
369
370 if ( err)
371 {
372 return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR;
373 }
374
375 return wxCOND_NO_ERROR;
376 }
377
378
379 wxCondError wxConditionInternal::DoSignal( bool signalAll)
380 {
381 m_gate.Wait();
382 m_varSection.Enter();
383
384 wxASSERT( m_signals == m_canceled);
385
386 if ( m_waiters == m_canceled)
387 {
388 m_varSection.Leave();
389 m_gate.Post();
390 return wxCOND_NO_ERROR;
391 }
392
393 if ( m_canceled > 0)
394 {
395 m_waiters -= m_canceled;
396 m_signals = 0;
397 m_canceled = 0;
398 }
399
400 m_signals = signalAll ? m_waiters : 1;
401 size_t n = m_signals;
402
403 m_varSection.Leave();
404
405 // Let the waiters inherit the gate lock.
406
407 do
408 {
409 wxSemaError err = m_semaphore.Post();
410 wxASSERT( err == wxSEMA_NO_ERROR);
411 } while ( -- n);
412
413 return wxCOND_NO_ERROR;
414 }
415
416
417
418 // ----------------------------------------------------------------------------
419 // wxCriticalSection implementation
420 // ----------------------------------------------------------------------------
421
422 // XXX currently implemented as mutex in headers. Change to critical section.
423
424 // ----------------------------------------------------------------------------
425 // wxThread implementation
426 // ----------------------------------------------------------------------------
427
428 // wxThreadInternal class
429 // ----------------------
430
431 class wxThreadInternal
432 {
433 public:
434 wxThreadInternal()
435 {
436 m_tid = 0;
437 m_state = STATE_NEW;
438 m_priority = WXTHREAD_DEFAULT_PRIORITY;
439 m_notifyQueueId = 0;
440 }
441
442 ~wxThreadInternal()
443 {
444 if ( m_notifyQueueId)
445 MPDeleteQueue( m_notifyQueueId);
446 }
447
448 void Free()
449 {
450 }
451
452 // create a new (suspended) thread (for the given thread object)
453 // stacksize == 0 will give the default stack size of 4 KB.
454 bool Create(wxThread *thread, unsigned int stackSize);
455
456 void Run();
457
458 // suspend/resume/terminate
459 bool Suspend();
460 bool Resume();
461 void Cancel()
462 {
463 wxCriticalSectionLocker lock( m_critical);
464 m_state = STATE_CANCELED;
465 }
466
467 wxThread::ExitCode Wait();
468
469 // thread state
470 void SetState(wxThreadState state)
471 {
472 wxCriticalSectionLocker lock( m_critical);
473 m_state = state;
474 }
475
476 wxThreadState GetState() const
477 {
478 wxCriticalSectionLocker lock( m_critical);
479 return m_state;
480 }
481
482 // thread priority
483 void SetPriority(unsigned int priority);
484 unsigned int GetPriority() const
485 {
486 wxCriticalSectionLocker lock( m_critical);
487 return m_priority;
488 }
489
490 void SetResult( void *res )
491 {
492 wxCriticalSectionLocker lock( m_critical);
493 m_result = res ;
494 }
495
496 void *GetResult()
497 {
498 wxCriticalSectionLocker lock( m_critical);
499 return m_result ;
500 }
501
502 // Get the ID of this thread's underlying MP Services task.
503 MPTaskID GetId() const
504 {
505 wxCriticalSectionLocker lock( m_critical);
506 return m_tid;
507 }
508
509 // thread function
510 static OSStatus MacThreadStart(void* arg);
511
512 private:
513
514 wxThreadState m_state; // state, see wxThreadState enum
515 unsigned int m_priority; // thread priority in "wx" units
516 MPTaskID m_tid; // thread id
517 void* m_result;
518
519 mutable wxCriticalSection m_critical;
520 MPQueueID m_notifyQueueId;
521 unsigned int m_stackSize;
522 wxThread* m_thread;
523 };
524
525 static wxArrayPtrVoid s_threads ;
526
527 OSStatus wxThreadInternal::MacThreadStart(void *parameter)
528 {
529 wxThread* thread = (wxThread*) parameter ;
530 // first of all, check whether we hadn't been cancelled already
531 if ( thread->m_internal->GetState() == STATE_EXITED )
532 {
533 return kMPDeletedErr;
534 }
535
536 thread->Entry();
537
538 thread->m_critsect.Enter();
539 bool wasCancelled = thread->m_internal->GetState() == STATE_CANCELED;
540 thread->m_internal->SetState(STATE_EXITED);
541 thread->m_critsect.Leave();
542
543 thread->OnExit();
544
545 // If the thread was cancelled (from Delete()), then the handle is still
546 // needed there.
547 if ( thread->IsDetached() && !wasCancelled )
548 {
549 delete thread;
550 }
551 //else: the joinable threads handle will be closed when Wait() is done
552
553 return noErr;
554 }
555
556 void wxThreadInternal::SetPriority(unsigned int priority)
557 {
558 wxASSERT_MSG( priority >= 0, _T("Thread priority must be at least 0."));
559 wxASSERT_MSG( priority <= 100, _T("Thread priority must be at most 100."));
560
561 wxCriticalSectionLocker lock(m_critical);
562
563 m_priority = priority;
564
565 if ( m_tid)
566 {
567 // Mac priorities range from 1 to 10,000, with a default of 100.
568 // wxWindows priorities range from 0 to 100 with a default of 50.
569 // We can map wxWindows to Mac priorities easily by assuming
570 // the former uses a logarithmic scale.
571 const unsigned int macPriority = ( int)( exp( priority / 25.0 * log( 10.0)) + 0.5);
572
573 MPSetTaskWeight( m_tid, macPriority);
574 }
575 }
576
577
578 void wxThreadInternal::Run()
579 {
580 OSStatus err;
581
582 m_state = STATE_NEW;
583
584 err = MPCreateTask( MacThreadStart,
585 (void*) m_thread,
586 m_stackSize,
587 m_notifyQueueId,
588 &m_result,
589 0,
590 0,
591 &m_tid);
592
593 if ( err)
594 {
595 wxLogSysError(_("Can't create thread"));
596
597 return;
598 }
599
600 if ( m_priority != WXTHREAD_DEFAULT_PRIORITY )
601 {
602 SetPriority(m_priority);
603 }
604
605 m_state = STATE_RUNNING;
606 }
607
608
609 bool wxThreadInternal::Create(wxThread *thread, unsigned int stackSize)
610 {
611 m_stackSize = stackSize;
612 m_thread = thread;
613
614 if ( ! m_notifyQueueId)
615 {
616 OSStatus err = MPCreateQueue( & m_notifyQueueId);
617 if( err)
618 {
619 wxLogSysError(_("Cant create the thread event queue"));
620 return FALSE;
621 }
622 }
623
624 return true;
625 }
626
627 bool wxThreadInternal::Suspend()
628 {
629 wxCriticalSectionLocker lock(m_critical);
630
631 if ( m_state != STATE_RUNNING )
632 {
633 wxLogSysError(_("Can not suspend thread %x"), m_tid);
634 return FALSE;
635 }
636
637 m_state = STATE_PAUSED;
638
639 OSStatus err = MPThrowException( m_tid, kMPTaskStoppedErr);
640
641 if ( err)
642 {
643 wxLogSysError(_("Can not suspend thread %x"), m_tid);
644 return FALSE;
645 }
646
647 return TRUE;
648 }
649
650 bool wxThreadInternal::Resume()
651 {
652 wxCriticalSectionLocker lock(m_critical);
653
654 if ( m_state != STATE_PAUSED && m_state != STATE_NEW )
655 {
656 wxLogSysError(_("Can not resume thread %x"), m_tid);
657 return FALSE;
658 }
659
660 OSStatus err = MPDisposeTaskException( m_tid, kMPTaskResumeMask);
661 if ( err)
662 {
663 wxLogSysError(_("Cannot resume thread %x"), m_tid);
664 return FALSE;
665 }
666
667 m_state = STATE_RUNNING;
668
669 return TRUE;
670 }
671
672
673 wxThread::ExitCode wxThreadInternal::Wait()
674 {
675 void * param1;
676 void * param2;
677 void * rc;
678
679 OSStatus err = MPWaitOnQueue ( m_notifyQueueId,
680 & param1,
681 & param2,
682 & rc,
683 kDurationForever);
684 if ( err)
685 {
686 wxLogSysError( _( "Cannot wait on thread to exit."));
687 return ( wxThread::ExitCode)-1;
688 }
689
690 m_result = rc;
691
692 return ( wxThread::ExitCode)rc;
693 }
694
695
696 // static functions
697 // ----------------
698 wxThread *wxThread::This()
699 {
700 MPTaskID current = MPCurrentTaskID();
701
702 {
703 wxMacStCritical critical ;
704
705 for ( size_t i = 0 ; i < s_threads.Count() ; ++i )
706 {
707 if ( ( (wxThread*) s_threads[i] )->GetId() == (unsigned long)current )
708 return (wxThread*) s_threads[i] ;
709 }
710 }
711
712 wxLogSysError(_("Couldn't get the current thread pointer"));
713 return NULL;
714 }
715
716 bool wxThread::IsMain()
717 {
718 return MPCurrentTaskID() == gs_idMainThread;
719 }
720
721 #ifdef Yield
722 #undef Yield
723 #endif
724
725 void wxThread::Yield()
726 {
727 #if TARGET_API_MAC_OSX
728 CFRunLoopRunInMode( kCFRunLoopDefaultMode , 0 , true ) ;
729 #endif
730 MPYield();
731 }
732
733
734 void wxThread::Sleep(unsigned long milliseconds)
735 {
736 AbsoluteTime wakeup = AddDurationToAbsolute( milliseconds, UpTime());
737 MPDelayUntil( & wakeup);
738 }
739
740
741 int wxThread::GetCPUCount()
742 {
743 return MPProcessors();
744 }
745
746 unsigned long wxThread::GetCurrentId()
747 {
748 return (unsigned long)MPCurrentTaskID();
749 }
750
751
752 // NOT IMPLEMENTED.
753 bool wxThread::SetConcurrency(size_t level)
754 {
755 return false;
756 }
757
758
759 wxThread::wxThread(wxThreadKind kind)
760 {
761 g_numberOfThreads++;
762 m_internal = new wxThreadInternal();
763
764 m_isDetached = kind == wxTHREAD_DETACHED;
765
766 {
767 wxMacStCritical critical;
768 s_threads.Add( (void*) this) ;
769 }
770 }
771
772 wxThread::~wxThread()
773 {
774 if (g_numberOfThreads>0)
775 {
776 g_numberOfThreads--;
777 }
778 #ifdef __WXDEBUG__
779 else
780 {
781 wxFAIL_MSG(wxT("More threads deleted than created."));
782 }
783 #endif
784
785 {
786 wxMacStCritical critical;
787 s_threads.Remove( (void*) this ) ;
788 }
789
790 if (m_internal != NULL) {
791 delete m_internal;
792 m_internal = NULL;
793 }
794 }
795
796
797 wxThreadError wxThread::Create(unsigned int stackSize)
798 {
799 wxCriticalSectionLocker lock(m_critsect);
800
801 if ( !m_internal->Create(this, stackSize) )
802 return wxTHREAD_NO_RESOURCE;
803
804 return wxTHREAD_NO_ERROR;
805 }
806
807 wxThreadError wxThread::Run()
808 {
809 m_internal->Run();
810
811 return wxTHREAD_NO_ERROR;
812 }
813
814 wxThreadError wxThread::Pause()
815 {
816 wxCriticalSectionLocker lock(m_critsect);
817 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
818 }
819
820 wxThreadError wxThread::Resume()
821 {
822 wxCriticalSectionLocker lock(m_critsect);
823 return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
824 }
825
826
827 wxThread::ExitCode wxThread::Wait()
828 {
829 // although under MacOS we can wait for any thread, it's an error to
830 // wait for a detached one in wxWin API
831 wxCHECK_MSG( !IsDetached(),
832 (ExitCode)-1,
833 _T("can't wait for detached thread") );
834
835 m_internal->Wait();
836
837 ExitCode rc;
838 (void)Delete(&rc);
839
840 m_internal->Free();
841
842 return rc;
843 }
844
845 wxThreadError wxThread::Delete( ExitCode *pRc)
846 {
847 // Delete() is always safe to call, so consider all possible states
848
849 bool shouldResume = FALSE;
850
851 {
852 wxCriticalSectionLocker lock(m_critsect);
853
854 if ( m_internal->GetState() == STATE_NEW )
855 {
856 // MacThreadStart() will see it and terminate immediately
857 m_internal->SetState(STATE_EXITED);
858
859 shouldResume = TRUE;
860 }
861 }
862
863 if ( shouldResume || IsPaused() )
864 Resume();
865
866 if ( IsRunning() )
867 {
868 if ( IsMain() )
869 {
870 {
871 wxMacStCritical critical;
872 gs_waitingForThread = TRUE;
873 }
874 #if wxUSE_GUI
875 wxBeginBusyCursor();
876 #endif // wxUSE_GUI
877 }
878
879 {
880 wxCriticalSectionLocker lock(m_critsect);
881 m_internal->Cancel();
882 }
883
884 while( TestDestroy() )
885 {
886 MPYield() ;
887 }
888
889 if ( IsMain() )
890 {
891 {
892 wxMacStCritical critical;
893 gs_waitingForThread = FALSE;
894 }
895 #if wxUSE_GUI
896 wxEndBusyCursor();
897 #endif // wxUSE_GUI
898 }
899 }
900
901 if ( pRc)
902 * pRc = (ExitCode)m_internal->GetResult();
903
904 if ( IsDetached() )
905 {
906 // If the thread exits normally, this is done in
907 // MachreadStart, but in this case it would have been too
908 // early, so we must do it here.
909 delete this;
910 }
911
912 if ( pRc && * pRc == (ExitCode)-1)
913 return wxTHREAD_MISC_ERROR;
914 return wxTHREAD_NO_ERROR;
915 }
916
917 wxThreadError wxThread::Kill()
918 {
919 if ( !IsRunning() )
920 return wxTHREAD_NOT_RUNNING;
921
922 if ( MPTerminateTask( m_internal->GetId(), -1) )
923 {
924 wxLogSysError(_("Couldn't terminate thread"));
925
926 return wxTHREAD_MISC_ERROR;
927 }
928
929 m_internal->Free();
930
931 if ( IsDetached() )
932 {
933 delete this;
934 }
935
936 return wxTHREAD_NO_ERROR;
937 }
938
939 void wxThread::Exit(ExitCode status)
940 {
941 m_internal->Free();
942
943 if ( IsDetached() )
944 {
945 delete this;
946 }
947 else
948 {
949 m_internal->SetResult( status ) ;
950 }
951 }
952
953 void wxThread::SetPriority(unsigned int prio)
954 {
955 m_internal->SetPriority(prio);
956 }
957
958 unsigned int wxThread::GetPriority() const
959 {
960 return m_internal->GetPriority();
961 }
962
963 unsigned long wxThread::GetId() const
964 {
965 return (unsigned long)m_internal->GetId();
966 }
967
968 bool wxThread::IsRunning() const
969 {
970 return m_internal->GetState() == STATE_RUNNING;
971 }
972
973 bool wxThread::IsAlive() const
974 {
975 return (m_internal->GetState() == STATE_RUNNING) ||
976 (m_internal->GetState() == STATE_PAUSED);
977 }
978
979 bool wxThread::IsPaused() const
980 {
981 return m_internal->GetState() == STATE_PAUSED;
982 }
983
984 bool wxThread::TestDestroy()
985 {
986 return m_internal->GetState() == STATE_CANCELED;
987 }
988
989 // ----------------------------------------------------------------------------
990 // Automatic initialization for thread module
991 // ----------------------------------------------------------------------------
992
993 class wxThreadModule : public wxModule
994 {
995 public:
996 virtual bool OnInit();
997 virtual void OnExit();
998
999 private:
1000 DECLARE_DYNAMIC_CLASS(wxThreadModule)
1001 };
1002
1003 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
1004
1005 bool wxThreadModule::OnInit()
1006 {
1007 bool hasThreadManager ;
1008 hasThreadManager = MPLibraryIsLoaded();
1009
1010 #if !TARGET_CARBON
1011 #if GENERATINGCFM
1012 // verify presence of shared library
1013 hasThreadManager = hasThreadManager && ((Ptr)NewThread != (Ptr)kUnresolvedCFragSymbolAddress);
1014 #endif
1015 #endif
1016 if ( !hasThreadManager )
1017 {
1018 wxMessageBox( "Error" , "Thread Support is not available on this System" , wxOK ) ;
1019 return FALSE ;
1020 }
1021
1022 gs_idMainThread = MPCurrentTaskID();
1023
1024 #if wxUSE_GUI
1025
1026 OSStatus err = MPCreateCriticalRegion( & gs_guiCritical);
1027 if ( err)
1028 {
1029 wxLogSysError(_("Could not make the GUI critical region."));
1030 }
1031
1032 // XXX wxMac never Exits the GUI Mutex.
1033 // XXX MPEnterCriticalRegion( gs_guiCritical, kDurationForever);
1034 #endif
1035
1036 return TRUE;
1037 }
1038
1039 void wxThreadModule::OnExit()
1040 {
1041 #if wxUSE_GUI
1042 MPExitCriticalRegion( gs_guiCritical);
1043
1044 MPDeleteCriticalRegion( gs_guiCritical);
1045 #endif
1046 }
1047
1048
1049 void WXDLLEXPORT wxMutexGuiEnter()
1050 {
1051 #if wxUSE_GUI
1052 MPEnterCriticalRegion( gs_guiCritical, kDurationForever);
1053 #endif
1054 }
1055
1056 void WXDLLEXPORT wxMutexGuiLeave()
1057 {
1058 #if wxUSE_GUI
1059 MPExitCriticalRegion( gs_guiCritical);
1060 #endif
1061 }
1062
1063
1064 // NOT IMPLEMENTED
1065 void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
1066 {
1067 }
1068
1069 // NOT IMPLEMENTED
1070 bool WXDLLEXPORT wxGuiOwnedByMainThread()
1071 {
1072 return true;
1073 }
1074
1075 // wake up the main thread
1076 void WXDLLEXPORT wxWakeUpMainThread()
1077 {
1078 wxMacWakeUp() ;
1079 }
1080
1081 bool WXDLLEXPORT wxIsWaitingForThread()
1082 {
1083 return gs_waitingForThread;
1084 }
1085
1086 #include "wx/thrimpl.cpp"
1087
1088 #endif // wxUSE_THREADS
1089
1090 // vi:sts=4:sw=4:et
1091