]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/osx/carbon/thread.cpp
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / src / osx / carbon / thread.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/osx/carbon/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// Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998),
8// Vadim Zeitlin (1999), Stefan Csomor (2000)
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
13
14#if defined(__BORLANDC__)
15 #pragma hdrstop
16#endif
17
18#ifndef WX_PRECOMP
19 #include "wx/wx.h"
20 #include "wx/module.h"
21#endif
22
23#if wxUSE_THREADS
24
25#include "wx/thread.h"
26
27#if wxOSX_USE_COCOA_OR_CARBON
28#include <CoreServices/CoreServices.h>
29#else
30#include <Foundation/Foundation.h>
31#endif
32
33#include "wx/osx/uma.h"
34
35// the possible states of the thread:
36// ("=>" shows all possible transitions from this state)
37enum wxThreadState
38{
39 STATE_NEW, // didn't start execution yet (=> RUNNING)
40 STATE_RUNNING, // thread is running (=> PAUSED, CANCELED)
41 STATE_PAUSED, // thread is temporarily suspended (=> RUNNING)
42 STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED)
43 STATE_EXITED // thread is terminating
44};
45
46// ----------------------------------------------------------------------------
47// globals
48// ----------------------------------------------------------------------------
49
50// the task ID of the main thread
51wxThreadIdType wxThread::ms_idMainThread = kInvalidID;
52
53// this is the Per-Task Storage for the pointer to the appropriate wxThread
54TaskStorageIndex gs_tlsForWXThread = 0;
55
56// if it's false, some secondary thread is holding the GUI lock
57static bool gs_bGuiOwnedByMainThread = true;
58
59// critical section which controls access to all GUI functions: any secondary
60// thread (i.e. except the main one) must enter this crit section before doing
61// any GUI calls
62static wxCriticalSection *gs_critsectGui = NULL;
63
64// critical section which protects gs_nWaitingForGui variable
65static wxCriticalSection *gs_critsectWaitingForGui = NULL;
66
67// number of threads waiting for GUI in wxMutexGuiEnter()
68static size_t gs_nWaitingForGui = 0;
69
70// overall number of threads, needed for determining
71// the sleep value of the main event loop
72size_t g_numberOfThreads = 0;
73
74
75#if wxUSE_GUI
76MPCriticalRegionID gs_guiCritical = kInvalidID;
77#endif
78
79// ============================================================================
80// MacOS implementation of thread classes
81// ============================================================================
82
83/*
84 Notes :
85
86 The implementation is very close to the phtreads implementation, the reason for
87 using MPServices is the fact that these are also available under OS 9. Thus allowing
88 for one common API for all current builds.
89
90 As soon as wxThreads are on a 64 bit address space, the TLS must be extended
91 to use two indices one for each 32 bit part as the MP implementation is limited
92 to longs.
93
94 I have three implementations for mutexes :
95 version A based on a binary semaphore, problem - not reentrant, version B based
96 on a critical region, allows for reentrancy, performance implications not
97 yet tested, and third a plain pthreads implementation
98
99 The same for condition internal, one implementation by Aj Lavin and the other one
100 copied from the thrimpl.cpp which I assume has been more broadly tested, I've just
101 replaced the interlock increment with the appropriate PPC calls
102*/
103
104// ----------------------------------------------------------------------------
105// wxCriticalSection
106// ----------------------------------------------------------------------------
107
108wxCriticalSection::wxCriticalSection( wxCriticalSectionType WXUNUSED(critSecType) )
109{
110 MPCreateCriticalRegion( (MPCriticalRegionID*) &m_critRegion );
111}
112
113wxCriticalSection::~wxCriticalSection()
114{
115 MPDeleteCriticalRegion( (MPCriticalRegionID) m_critRegion );
116}
117
118void wxCriticalSection::Enter()
119{
120 MPEnterCriticalRegion( (MPCriticalRegionID) m_critRegion, kDurationForever );
121}
122
123bool wxCriticalSection::TryEnter()
124{
125 return MPEnterCriticalRegion( (MPCriticalRegionID) m_critRegion, kDurationImmediate ) == noErr;
126}
127
128void wxCriticalSection::Leave()
129{
130 MPExitCriticalRegion( (MPCriticalRegionID) m_critRegion );
131}
132
133// ----------------------------------------------------------------------------
134// wxMutex implementation
135// ----------------------------------------------------------------------------
136
137#define wxUSE_MAC_SEMAPHORE_MUTEX 0
138#define wxUSE_MAC_CRITICAL_REGION_MUTEX 1
139#define wxUSE_MAC_PTHREADS_MUTEX 0
140
141#if wxUSE_MAC_CRITICAL_REGION_MUTEX
142
143class wxMutexInternal
144{
145public:
146 wxMutexInternal( wxMutexType mutexType );
147 virtual ~wxMutexInternal();
148
149 bool IsOk() const { return m_isOk; }
150
151 wxMutexError Lock() { return Lock(kDurationForever); }
152 wxMutexError Lock(unsigned long ms);
153 wxMutexError TryLock();
154 wxMutexError Unlock();
155
156private:
157 MPCriticalRegionID m_critRegion;
158 bool m_isOk ;
159};
160
161wxMutexInternal::wxMutexInternal( wxMutexType WXUNUSED(mutexType) )
162{
163 m_isOk = false;
164 m_critRegion = kInvalidID;
165
166 verify_noerr( MPCreateCriticalRegion( &m_critRegion ) );
167 m_isOk = ( m_critRegion != kInvalidID );
168 if ( !IsOk() )
169 {
170 wxFAIL_MSG( wxT("Error when creating mutex") );
171 }
172}
173
174wxMutexInternal::~wxMutexInternal()
175{
176 if ( m_critRegion != kInvalidID )
177 MPDeleteCriticalRegion( m_critRegion );
178
179 MPYield();
180}
181
182wxMutexError wxMutexInternal::Lock(unsigned long ms)
183{
184 wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") );
185
186 OSStatus err = MPEnterCriticalRegion( m_critRegion, ms );
187 switch ( err )
188 {
189 case noErr:
190 break;
191
192 case kMPTimeoutErr:
193 wxASSERT_MSG( ms != kDurationForever, wxT("unexpected timeout") );
194 return wxMUTEX_TIMEOUT;
195
196 default:
197 wxLogSysError(wxT("Could not lock mutex"));
198 return wxMUTEX_MISC_ERROR;
199 }
200
201 return wxMUTEX_NO_ERROR;
202}
203
204wxMutexError wxMutexInternal::TryLock()
205{
206 wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ;
207
208 OSStatus err = MPEnterCriticalRegion( m_critRegion, kDurationImmediate);
209 if (err != noErr)
210 {
211 if ( err == kMPTimeoutErr)
212 return wxMUTEX_BUSY;
213
214 wxLogSysError( wxT("Could not try lock mutex") );
215 return wxMUTEX_MISC_ERROR;
216 }
217
218 return wxMUTEX_NO_ERROR;
219}
220
221wxMutexError wxMutexInternal::Unlock()
222{
223 wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ;
224
225 OSStatus err = MPExitCriticalRegion( m_critRegion );
226 MPYield() ;
227
228 if (err != noErr)
229 {
230 wxLogSysError( wxT("Could not unlock mutex") );
231
232 return wxMUTEX_MISC_ERROR;
233 }
234
235 return wxMUTEX_NO_ERROR;
236}
237
238#endif
239
240// --------------------------------------------------------------------------
241// wxSemaphore
242// --------------------------------------------------------------------------
243
244class wxSemaphoreInternal
245{
246public:
247 wxSemaphoreInternal( int initialcount, int maxcount );
248 virtual ~wxSemaphoreInternal();
249
250 bool IsOk() const
251 { return m_isOk; }
252
253 wxSemaError Post();
254 wxSemaError WaitTimeout( unsigned long milliseconds );
255
256 wxSemaError Wait()
257 { return WaitTimeout( kDurationForever); }
258
259 wxSemaError TryWait()
260 {
261 wxSemaError err = WaitTimeout( kDurationImmediate );
262 if (err == wxSEMA_TIMEOUT)
263 err = wxSEMA_BUSY;
264
265 return err;
266 }
267
268private:
269 MPSemaphoreID m_semaphore;
270 bool m_isOk;
271};
272
273wxSemaphoreInternal::wxSemaphoreInternal( int initialcount, int maxcount)
274{
275 m_isOk = false;
276 m_semaphore = kInvalidID;
277 if ( maxcount == 0 )
278 // make it practically infinite
279 maxcount = INT_MAX;
280
281 verify_noerr( MPCreateSemaphore( maxcount, initialcount, &m_semaphore ) );
282 m_isOk = ( m_semaphore != kInvalidID );
283
284 if ( !IsOk() )
285 {
286 wxFAIL_MSG( wxT("Error when creating semaphore") );
287 }
288}
289
290wxSemaphoreInternal::~wxSemaphoreInternal()
291{
292 if (m_semaphore != kInvalidID)
293 MPDeleteSemaphore( m_semaphore );
294
295 MPYield();
296}
297
298wxSemaError wxSemaphoreInternal::WaitTimeout( unsigned long milliseconds )
299{
300 OSStatus err = MPWaitOnSemaphore( m_semaphore, milliseconds );
301 if (err != noErr)
302 {
303 if (err == kMPTimeoutErr)
304 return wxSEMA_TIMEOUT;
305
306 return wxSEMA_MISC_ERROR;
307 }
308
309 return wxSEMA_NO_ERROR;
310}
311
312wxSemaError wxSemaphoreInternal::Post()
313{
314 OSStatus err = MPSignalSemaphore( m_semaphore );
315 MPYield();
316 if (err != noErr)
317 return wxSEMA_MISC_ERROR;
318
319 return wxSEMA_NO_ERROR;
320}
321
322// ----------------------------------------------------------------------------
323// wxCondition implementation
324// ----------------------------------------------------------------------------
325
326class wxConditionInternal
327{
328public:
329 wxConditionInternal( wxMutex& mutex );
330
331 bool IsOk() const
332 { return m_mutex.IsOk() && m_semaphore.IsOk(); }
333
334 wxCondError Wait();
335 wxCondError WaitTimeout( unsigned long milliseconds );
336
337 wxCondError Signal();
338 wxCondError Broadcast();
339
340private:
341 // the number of threads currently waiting for this condition
342 SInt32 m_numWaiters;
343
344 // the critical section protecting m_numWaiters
345 wxCriticalSection m_csWaiters;
346
347 wxMutex& m_mutex;
348 wxSemaphore m_semaphore;
349
350 wxDECLARE_NO_COPY_CLASS(wxConditionInternal);
351};
352
353wxConditionInternal::wxConditionInternal( wxMutex& mutex )
354 : m_mutex(mutex)
355{
356 // another thread can't access it until we return from ctor, so no need to
357 // protect access to m_numWaiters here
358 m_numWaiters = 0;
359}
360
361wxCondError wxConditionInternal::Wait()
362{
363 // increment the number of waiters
364 IncrementAtomic( &m_numWaiters );
365
366 m_mutex.Unlock();
367
368 // a potential race condition can occur here
369 //
370 // after a thread increments nwaiters, and unlocks the mutex and before the
371 // semaphore.Wait() is called, if another thread can cause a signal to be
372 // generated
373 //
374 // this race condition is handled by using a semaphore and incrementing the
375 // semaphore only if 'nwaiters' is greater that zero since the semaphore,
376 // can 'remember' signals the race condition will not occur
377
378 // wait ( if necessary ) and decrement semaphore
379 wxSemaError err = m_semaphore.Wait();
380 m_mutex.Lock();
381
382 return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : wxCOND_MISC_ERROR;
383}
384
385wxCondError wxConditionInternal::WaitTimeout( unsigned long milliseconds )
386{
387 IncrementAtomic( &m_numWaiters );
388
389 m_mutex.Unlock();
390
391 // a race condition can occur at this point in the code
392 //
393 // please see the comments in Wait(), for details
394
395 wxSemaError err = m_semaphore.WaitTimeout(milliseconds);
396
397 if ( err == wxSEMA_TIMEOUT )
398 {
399 // another potential race condition exists here it is caused when a
400 // 'waiting' thread timesout, and returns from WaitForSingleObject, but
401 // has not yet decremented 'nwaiters'.
402 //
403 // at this point if another thread calls signal() then the semaphore
404 // will be incremented, but the waiting thread will miss it.
405 //
406 // to handle this particular case, the waiting thread calls
407 // WaitForSingleObject again with a timeout of 0, after locking
408 // 'nwaiters_mutex'. this call does not block because of the zero
409 // timeout, but will allow the waiting thread to catch the missed
410 // signals.
411 wxCriticalSectionLocker lock(m_csWaiters);
412
413 err = m_semaphore.WaitTimeout(0);
414
415 if ( err != wxSEMA_NO_ERROR )
416 {
417 m_numWaiters--;
418 }
419 }
420
421 m_mutex.Lock();
422
423 return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : wxCOND_MISC_ERROR;
424}
425
426wxCondError wxConditionInternal::Signal()
427{
428 wxCriticalSectionLocker lock(m_csWaiters);
429
430 if ( m_numWaiters > 0 )
431 {
432 // increment the semaphore by 1
433 if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
434 return wxCOND_MISC_ERROR;
435
436 m_numWaiters--;
437 }
438
439 return wxCOND_NO_ERROR;
440}
441
442wxCondError wxConditionInternal::Broadcast()
443{
444 wxCriticalSectionLocker lock(m_csWaiters);
445
446 while ( m_numWaiters > 0 )
447 {
448 if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
449 return wxCOND_MISC_ERROR;
450
451 m_numWaiters--;
452 }
453
454 return wxCOND_NO_ERROR;
455}
456
457// ----------------------------------------------------------------------------
458// wxCriticalSection implementation
459// ----------------------------------------------------------------------------
460
461// XXX currently implemented as mutex in headers. Change to critical section.
462
463// ----------------------------------------------------------------------------
464// wxThread implementation
465// ----------------------------------------------------------------------------
466
467// wxThreadInternal class
468// ----------------------
469
470class wxThreadInternal
471{
472public:
473 wxThreadInternal()
474 {
475 m_tid = kInvalidID;
476 m_state = STATE_NEW;
477 m_prio = wxPRIORITY_DEFAULT;
478 m_notifyQueueId = kInvalidID;
479 m_exitcode = 0;
480 m_cancelled = false ;
481
482 // set to true only when the thread starts waiting on m_semSuspend
483 m_isPaused = false;
484
485 // defaults for joinable threads
486 m_shouldBeJoined = true;
487 m_isDetached = false;
488 }
489
490 virtual ~wxThreadInternal()
491 {
492 if ( m_notifyQueueId)
493 {
494 MPDeleteQueue( m_notifyQueueId );
495 m_notifyQueueId = kInvalidID ;
496 }
497 }
498
499 // thread function
500 static OSStatus MacThreadStart(void* arg);
501
502 // create a new (suspended) thread (for the given thread object)
503 bool Create(wxThread *thread, unsigned int stackSize);
504
505 // thread actions
506
507 // start the thread
508 wxThreadError Run();
509
510 // unblock the thread allowing it to run
511 void SignalRun() { m_semRun.Post(); }
512
513 // ask the thread to terminate
514 void Wait();
515
516 // go to sleep until Resume() is called
517 void Pause();
518
519 // resume the thread
520 void Resume();
521
522 // accessors
523 // priority
524 int GetPriority() const
525 { return m_prio; }
526 void SetPriority(int prio);
527
528 // state
529 wxThreadState GetState() const
530 { return m_state; }
531 void SetState(wxThreadState state)
532 { m_state = state; }
533
534 // Get the ID of this thread's underlying MP Services task.
535 MPTaskID GetId() const
536 { return m_tid; }
537
538 void SetCancelFlag()
539 { m_cancelled = true; }
540
541 bool WasCancelled() const
542 { return m_cancelled; }
543
544 // exit code
545 void SetExitCode(wxThread::ExitCode exitcode)
546 { m_exitcode = exitcode; }
547 wxThread::ExitCode GetExitCode() const
548 { return m_exitcode; }
549
550 // the pause flag
551 void SetReallyPaused(bool paused)
552 { m_isPaused = paused; }
553 bool IsReallyPaused() const
554 { return m_isPaused; }
555
556 // tell the thread that it is a detached one
557 void Detach()
558 {
559 wxCriticalSectionLocker lock(m_csJoinFlag);
560
561 m_shouldBeJoined = false;
562 m_isDetached = true;
563 }
564
565private:
566 // the thread we're associated with
567 wxThread * m_thread;
568
569 MPTaskID m_tid; // thread id
570 MPQueueID m_notifyQueueId; // its notification queue
571
572 wxThreadState m_state; // see wxThreadState enum
573 int m_prio; // in wxWidgets units: from 0 to 100
574
575 // this flag is set when the thread should terminate
576 bool m_cancelled;
577
578 // this flag is set when the thread is blocking on m_semSuspend
579 bool m_isPaused;
580
581 // the thread exit code - only used for joinable (!detached) threads and
582 // is only valid after the thread termination
583 wxThread::ExitCode m_exitcode;
584
585 // many threads may call Wait(), but only one of them should call
586 // pthread_join(), so we have to keep track of this
587 wxCriticalSection m_csJoinFlag;
588 bool m_shouldBeJoined;
589 bool m_isDetached;
590
591 // this semaphore is posted by Run() and the threads Entry() is not
592 // called before it is done
593 wxSemaphore m_semRun;
594
595 // this one is signaled when the thread should resume after having been
596 // Pause()d
597 wxSemaphore m_semSuspend;
598};
599
600OSStatus wxThreadInternal::MacThreadStart(void *parameter)
601{
602 wxThread* thread = (wxThread*) parameter ;
603 wxThreadInternal *pthread = thread->m_internal;
604
605 // add to TLS so that This() will work
606 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread , (TaskStorageValue) thread ) ) ;
607
608 // have to declare this before pthread_cleanup_push() which defines a
609 // block!
610 bool dontRunAtAll;
611
612 // wait for the semaphore to be posted from Run()
613 pthread->m_semRun.Wait();
614
615 // test whether we should run the run at all - may be it was deleted
616 // before it started to Run()?
617 {
618 wxCriticalSectionLocker lock(thread->m_critsect);
619
620 dontRunAtAll = pthread->GetState() == STATE_NEW &&
621 pthread->WasCancelled();
622 }
623
624 if ( !dontRunAtAll )
625 {
626 pthread->m_exitcode = thread->CallEntry();
627
628 {
629 wxCriticalSectionLocker lock(thread->m_critsect);
630 pthread->SetState( STATE_EXITED );
631 }
632 }
633
634 if ( dontRunAtAll )
635 {
636 if ( pthread->m_isDetached )
637 delete thread;
638
639 return -1;
640 }
641 else
642 {
643 // on Mac for the running code,
644 // the correct thread termination is to return
645
646 // terminate the thread
647 thread->Exit( pthread->m_exitcode );
648
649 return (OSStatus) NULL; // pthread->m_exitcode;
650 }
651}
652
653bool wxThreadInternal::Create( wxThread *thread, unsigned int stackSize )
654{
655 wxASSERT_MSG( m_state == STATE_NEW && !m_tid,
656 wxT("Create()ing thread twice?") );
657
658 if ( thread->IsDetached() )
659 Detach();
660
661 OSStatus err = noErr;
662 m_thread = thread;
663
664 if ( m_notifyQueueId == kInvalidID )
665 {
666 OSStatus err = MPCreateQueue( &m_notifyQueueId );
667 if (err != noErr)
668 {
669 wxLogSysError( wxT("Can't create the thread event queue") );
670
671 return false;
672 }
673 }
674
675 m_state = STATE_NEW;
676
677 err = MPCreateTask(
678 MacThreadStart, (void*)m_thread, stackSize,
679 m_notifyQueueId, &m_exitcode, 0, 0, &m_tid );
680
681 if (err != noErr)
682 {
683 wxLogSysError( wxT("Can't create thread") );
684
685 return false;
686 }
687
688 if ( m_prio != wxPRIORITY_DEFAULT )
689 SetPriority( m_prio );
690
691 return true;
692}
693
694void wxThreadInternal::SetPriority( int priority )
695{
696 m_prio = priority;
697
698 if (m_tid)
699 {
700 // Mac priorities range from 1 to 10,000, with a default of 100.
701 // wxWidgets priorities range from 0 to 100 with a default of 50.
702 // We can map wxWidgets to Mac priorities easily by assuming
703 // the former uses a logarithmic scale.
704 const unsigned int macPriority = (int)( exp( priority / 25.0 * log( 10.0)) + 0.5);
705
706 MPSetTaskWeight( m_tid, macPriority );
707 }
708}
709
710wxThreadError wxThreadInternal::Run()
711{
712 wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
713 wxT("thread may only be started once after Create()") );
714
715 SetState( STATE_RUNNING );
716
717 // wake up threads waiting for our start
718 SignalRun();
719
720 return wxTHREAD_NO_ERROR;
721}
722
723void wxThreadInternal::Wait()
724{
725 wxCHECK_RET( !m_isDetached, wxT("can't wait for a detached thread") );
726
727 // if the thread we're waiting for is waiting for the GUI mutex, we will
728 // deadlock so make sure we release it temporarily
729 if ( wxThread::IsMain() )
730 {
731 // give the thread we're waiting for chance to do the GUI call
732 // it might be in, we don't do this conditionally as the to be waited on
733 // thread might have to acquire the mutex later but before terminating
734 if ( wxGuiOwnedByMainThread() )
735 wxMutexGuiLeave();
736 }
737
738 {
739 wxCriticalSectionLocker lock(m_csJoinFlag);
740
741 if ( m_shouldBeJoined )
742 {
743 void *param1, *param2, *rc;
744
745 OSStatus err = MPWaitOnQueue(
746 m_notifyQueueId,
747 &param1,
748 &param2,
749 &rc,
750 kDurationForever );
751 if (err != noErr)
752 {
753 wxLogSysError( wxT( "Cannot wait for thread termination."));
754 rc = (void*) -1;
755 }
756
757 // actually param1 would be the address of m_exitcode
758 // but we don't need this here
759 m_exitcode = rc;
760
761 m_shouldBeJoined = false;
762 }
763 }
764}
765
766void wxThreadInternal::Pause()
767{
768 // the state is set from the thread which pauses us first, this function
769 // is called later so the state should have been already set
770 wxCHECK_RET( m_state == STATE_PAUSED,
771 wxT("thread must first be paused with wxThread::Pause().") );
772
773 // wait until the semaphore is Post()ed from Resume()
774 m_semSuspend.Wait();
775}
776
777void wxThreadInternal::Resume()
778{
779 wxCHECK_RET( m_state == STATE_PAUSED,
780 wxT("can't resume thread which is not suspended.") );
781
782 // the thread might be not actually paused yet - if there were no call to
783 // TestDestroy() since the last call to Pause() for example
784 if ( IsReallyPaused() )
785 {
786 // wake up Pause()
787 m_semSuspend.Post();
788
789 // reset the flag
790 SetReallyPaused( false );
791 }
792
793 SetState( STATE_RUNNING );
794}
795
796// static functions
797// ----------------
798
799wxThread *wxThread::This()
800{
801 wxThread* thr = (wxThread*) MPGetTaskStorageValue( gs_tlsForWXThread ) ;
802
803 return thr;
804}
805
806#ifdef Yield
807#undef Yield
808#endif
809
810void wxThread::Yield()
811{
812 CFRunLoopRunInMode( kCFRunLoopDefaultMode , 0 , true ) ;
813
814 MPYield();
815}
816
817void wxThread::Sleep( unsigned long milliseconds )
818{
819 AbsoluteTime wakeup = AddDurationToAbsolute( milliseconds, UpTime() );
820 MPDelayUntil( &wakeup );
821}
822
823int wxThread::GetCPUCount()
824{
825 return MPProcessors();
826}
827
828unsigned long wxThread::GetCurrentId()
829{
830 return (unsigned long)MPCurrentTaskID();
831}
832
833bool wxThread::SetConcurrency( size_t WXUNUSED(level) )
834{
835 // Cannot be set in MacOS.
836 return false;
837}
838
839wxThread::wxThread( wxThreadKind kind )
840{
841 g_numberOfThreads++;
842 m_internal = new wxThreadInternal();
843
844 m_isDetached = (kind == wxTHREAD_DETACHED);
845}
846
847wxThread::~wxThread()
848{
849 wxASSERT_MSG( g_numberOfThreads>0 , wxT("More threads deleted than created.") ) ;
850
851 g_numberOfThreads--;
852
853 m_critsect.Enter();
854
855 // check that the thread either exited or couldn't be created
856 if ( m_internal->GetState() != STATE_EXITED &&
857 m_internal->GetState() != STATE_NEW )
858 {
859 wxLogDebug(
860 wxT("The thread %ld is being destroyed although it is still running! The application may crash."),
861 GetId() );
862 }
863
864 m_critsect.Leave();
865
866 wxDELETE( m_internal ) ;
867}
868
869wxThreadError wxThread::Create( unsigned int stackSize )
870{
871 wxCriticalSectionLocker lock(m_critsect);
872
873 if ( !m_internal->Create(this, stackSize) )
874 {
875 m_internal->SetState( STATE_EXITED );
876 return wxTHREAD_NO_RESOURCE;
877 }
878
879 return wxTHREAD_NO_ERROR;
880}
881
882wxThreadError wxThread::Run()
883{
884 wxCriticalSectionLocker lock(m_critsect);
885
886 // Create the thread if it wasn't created yet with an explicit
887 // Create() call:
888 if ( m_internal->GetId() == kInvalidID )
889 {
890 if ( !m_internal->Create(this, stackSize) )
891 {
892 m_internal->SetState( STATE_EXITED );
893 return wxTHREAD_NO_RESOURCE;
894 }
895 }
896
897 wxCHECK_MSG( m_internal->GetId(), wxTHREAD_MISC_ERROR,
898 wxT("must call wxThread::Create() first") );
899
900 return m_internal->Run();
901}
902
903// -----------------------------------------------------------------------------
904// pause/resume
905// -----------------------------------------------------------------------------
906
907wxThreadError wxThread::Pause()
908{
909 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
910 wxT("a thread can't pause itself") );
911
912 wxCriticalSectionLocker lock(m_critsect);
913
914 if ( m_internal->GetState() != STATE_RUNNING )
915 {
916 wxLogDebug( wxT("Can't pause thread which is not running.") );
917
918 return wxTHREAD_NOT_RUNNING;
919 }
920
921 // just set a flag, the thread will be really paused only during the next
922 // call to TestDestroy()
923 m_internal->SetState( STATE_PAUSED );
924
925 return wxTHREAD_NO_ERROR;
926}
927
928wxThreadError wxThread::Resume()
929{
930 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
931 wxT("a thread can't resume itself") );
932
933 wxCriticalSectionLocker lock(m_critsect);
934
935 wxThreadState state = m_internal->GetState();
936
937 switch ( state )
938 {
939 case STATE_PAUSED:
940 m_internal->Resume();
941 return wxTHREAD_NO_ERROR;
942
943 case STATE_EXITED:
944 return wxTHREAD_NO_ERROR;
945
946 default:
947 wxLogDebug( wxT("Attempt to resume a thread which is not paused.") );
948
949 return wxTHREAD_MISC_ERROR;
950 }
951}
952
953// -----------------------------------------------------------------------------
954// exiting thread
955// -----------------------------------------------------------------------------
956
957wxThread::ExitCode wxThread::Wait(wxThreadWait WXUNUSED(waitMode))
958{
959 wxCHECK_MSG( This() != this, (ExitCode)-1,
960 wxT("a thread can't wait for itself") );
961
962 wxCHECK_MSG( !m_isDetached, (ExitCode)-1,
963 wxT("can't wait for detached thread") );
964
965 m_internal->Wait();
966
967 return m_internal->GetExitCode();
968}
969
970wxThreadError wxThread::Delete(ExitCode *rc, wxThreadWait WXUNUSED(waitMode))
971{
972 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
973 wxT("a thread can't delete itself") );
974
975 bool isDetached = m_isDetached;
976
977 m_critsect.Enter();
978 wxThreadState state = m_internal->GetState();
979
980 // ask the thread to stop
981 m_internal->SetCancelFlag();
982
983 m_critsect.Leave();
984
985 switch ( state )
986 {
987 case STATE_NEW:
988 // we need to wake up the thread so that PthreadStart() will
989 // terminate - right now it's blocking on run semaphore in
990 // PthreadStart()
991 m_internal->SignalRun();
992
993 // fall through
994
995 case STATE_EXITED:
996 // nothing to do
997 break;
998
999 case STATE_PAUSED:
1000 // resume the thread first
1001 m_internal->Resume();
1002
1003 // fall through
1004
1005 default:
1006 if ( !isDetached )
1007 {
1008 // wait until the thread stops
1009 m_internal->Wait();
1010
1011 if ( rc )
1012 {
1013 // return the exit code of the thread
1014 *rc = m_internal->GetExitCode();
1015 }
1016 }
1017 }
1018
1019 return wxTHREAD_NO_ERROR;
1020}
1021
1022wxThreadError wxThread::Kill()
1023{
1024 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1025 wxT("a thread can't kill itself") );
1026
1027 switch ( m_internal->GetState() )
1028 {
1029 case STATE_NEW:
1030 case STATE_EXITED:
1031 return wxTHREAD_NOT_RUNNING;
1032
1033 case STATE_PAUSED:
1034 // resume the thread first
1035 Resume();
1036
1037 // fall through
1038
1039 default:
1040 OSStatus err = MPTerminateTask( m_internal->GetId() , -1 ) ;
1041 if (err != noErr)
1042 {
1043 wxLogError( wxT("Failed to terminate a thread.") );
1044
1045 return wxTHREAD_MISC_ERROR;
1046 }
1047
1048 if ( m_isDetached )
1049 {
1050 delete this ;
1051 }
1052 else
1053 {
1054 // this should be retrieved by Wait actually
1055 m_internal->SetExitCode( (void*)-1 );
1056 }
1057
1058 return wxTHREAD_NO_ERROR;
1059 }
1060}
1061
1062void wxThread::Exit( ExitCode status )
1063{
1064 wxASSERT_MSG( This() == this,
1065 wxT("wxThread::Exit() can only be called in the context of the same thread") );
1066
1067 // don't enter m_critsect before calling OnExit() because the user code
1068 // might deadlock if, for example, it signals a condition in OnExit() (a
1069 // common case) while the main thread calls any of functions entering
1070 // m_critsect on us (almost all of them do)
1071 OnExit();
1072
1073 MPTaskID threadid = m_internal->GetId();
1074
1075 if ( IsDetached() )
1076 {
1077 delete this;
1078 }
1079 else // joinable
1080 {
1081 // update the status of the joinable thread
1082 wxCriticalSectionLocker lock( m_critsect );
1083 m_internal->SetState( STATE_EXITED );
1084 }
1085
1086 MPTerminateTask( threadid, (long)status );
1087}
1088
1089// also test whether we were paused
1090bool wxThread::TestDestroy()
1091{
1092 wxASSERT_MSG( This() == this,
1093 wxT("wxThread::TestDestroy() can only be called in the context of the same thread") );
1094
1095 m_critsect.Enter();
1096
1097 if ( m_internal->GetState() == STATE_PAUSED )
1098 {
1099 m_internal->SetReallyPaused( true );
1100
1101 // leave the crit section or the other threads will stop too if they attempt
1102 // to call any of (seemingly harmless) IsXXX() functions while we sleep
1103 m_critsect.Leave();
1104
1105 m_internal->Pause();
1106 }
1107 else
1108 {
1109 // thread wasn't requested to pause, nothing to do
1110 m_critsect.Leave();
1111 }
1112
1113 return m_internal->WasCancelled();
1114}
1115
1116// -----------------------------------------------------------------------------
1117// priority setting
1118// -----------------------------------------------------------------------------
1119
1120void wxThread::SetPriority(unsigned int prio)
1121{
1122 wxCHECK_RET( wxPRIORITY_MIN <= prio && prio <= wxPRIORITY_MAX,
1123 wxT("invalid thread priority") );
1124
1125 wxCriticalSectionLocker lock(m_critsect);
1126
1127 switch ( m_internal->GetState() )
1128 {
1129 case STATE_RUNNING:
1130 case STATE_PAUSED:
1131 case STATE_NEW:
1132 // thread not yet started, priority will be set when it is
1133 m_internal->SetPriority( prio );
1134 break;
1135
1136 case STATE_EXITED:
1137 default:
1138 wxFAIL_MSG( wxT("impossible to set thread priority in this state") );
1139 }
1140}
1141
1142unsigned int wxThread::GetPriority() const
1143{
1144 wxCriticalSectionLocker lock(const_cast<wxCriticalSection &>(m_critsect));
1145
1146 return m_internal->GetPriority();
1147}
1148
1149unsigned long wxThread::GetId() const
1150{
1151 wxCriticalSectionLocker lock(const_cast<wxCriticalSection &>(m_critsect));
1152
1153 return (unsigned long)m_internal->GetId();
1154}
1155
1156// -----------------------------------------------------------------------------
1157// state tests
1158// -----------------------------------------------------------------------------
1159
1160bool wxThread::IsRunning() const
1161{
1162 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
1163
1164 return m_internal->GetState() == STATE_RUNNING;
1165}
1166
1167bool wxThread::IsAlive() const
1168{
1169 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
1170
1171 switch ( m_internal->GetState() )
1172 {
1173 case STATE_RUNNING:
1174 case STATE_PAUSED:
1175 return true;
1176
1177 default:
1178 return false;
1179 }
1180}
1181
1182bool wxThread::IsPaused() const
1183{
1184 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
1185
1186 return (m_internal->GetState() == STATE_PAUSED);
1187}
1188
1189// ----------------------------------------------------------------------------
1190// Automatic initialization for thread module
1191// ----------------------------------------------------------------------------
1192
1193class wxThreadModule : public wxModule
1194{
1195public:
1196 virtual bool OnInit();
1197 virtual void OnExit();
1198
1199private:
1200 DECLARE_DYNAMIC_CLASS(wxThreadModule)
1201};
1202
1203IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
1204
1205bool wxThreadModule::OnInit()
1206{
1207 bool hasThreadManager =
1208#ifdef __LP64__
1209 true ; // TODO VERIFY IN NEXT BUILD
1210#else
1211 MPLibraryIsLoaded();
1212#endif
1213
1214 if ( !hasThreadManager )
1215 {
1216 wxLogError( wxT("MP thread support is not available on this system" ) ) ;
1217
1218 return false;
1219 }
1220
1221 // main thread's This() is NULL
1222 verify_noerr( MPAllocateTaskStorageIndex( &gs_tlsForWXThread ) ) ;
1223 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread, 0 ) ) ;
1224
1225 wxThread::ms_idMainThread = wxThread::GetCurrentId();
1226 gs_critsectWaitingForGui = new wxCriticalSection();
1227
1228 gs_critsectGui = new wxCriticalSection();
1229 gs_critsectGui->Enter();
1230
1231 return true;
1232}
1233
1234void wxThreadModule::OnExit()
1235{
1236 if ( gs_critsectGui )
1237 {
1238 if ( !wxGuiOwnedByMainThread() )
1239 {
1240 gs_critsectGui->Enter();
1241 gs_bGuiOwnedByMainThread = true;
1242 }
1243
1244 gs_critsectGui->Leave();
1245 wxDELETE(gs_critsectGui);
1246 }
1247
1248 wxDELETE(gs_critsectWaitingForGui);
1249}
1250
1251// ----------------------------------------------------------------------------
1252// GUI Serialization copied from MSW implementation
1253// ----------------------------------------------------------------------------
1254
1255void wxMutexGuiEnterImpl()
1256{
1257 // this would dead lock everything...
1258 wxASSERT_MSG( !wxThread::IsMain(),
1259 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
1260
1261 // the order in which we enter the critical sections here is crucial!!
1262
1263 // set the flag telling to the main thread that we want to do some GUI
1264 {
1265 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1266
1267 gs_nWaitingForGui++;
1268 }
1269
1270 wxWakeUpMainThread();
1271
1272 // now we may block here because the main thread will soon let us in
1273 // (during the next iteration of OnIdle())
1274 gs_critsectGui->Enter();
1275}
1276
1277void wxMutexGuiLeaveImpl()
1278{
1279 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1280
1281 if ( wxThread::IsMain() )
1282 {
1283 gs_bGuiOwnedByMainThread = false;
1284 }
1285 else
1286 {
1287 // decrement the number of threads waiting for GUI access now
1288 wxASSERT_MSG( gs_nWaitingForGui > 0,
1289 wxT("calling wxMutexGuiLeave() without entering it first?") );
1290
1291 gs_nWaitingForGui--;
1292
1293 wxWakeUpMainThread();
1294 }
1295
1296 gs_critsectGui->Leave();
1297}
1298
1299void WXDLLIMPEXP_BASE wxMutexGuiLeaveOrEnter()
1300{
1301 wxASSERT_MSG( wxThread::IsMain(),
1302 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1303
1304 if ( !gs_critsectWaitingForGui )
1305 return;
1306
1307 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1308
1309 if ( gs_nWaitingForGui == 0 )
1310 {
1311 // no threads are waiting for GUI - so we may acquire the lock without
1312 // any danger (but only if we don't already have it)
1313 if ( !wxGuiOwnedByMainThread() )
1314 {
1315 gs_critsectGui->Enter();
1316
1317 gs_bGuiOwnedByMainThread = true;
1318 }
1319 //else: already have it, nothing to do
1320 }
1321 else
1322 {
1323 // some threads are waiting, release the GUI lock if we have it
1324 if ( wxGuiOwnedByMainThread() )
1325 wxMutexGuiLeave();
1326 //else: some other worker thread is doing GUI
1327 }
1328}
1329
1330bool WXDLLIMPEXP_BASE wxGuiOwnedByMainThread()
1331{
1332 return gs_bGuiOwnedByMainThread;
1333}
1334
1335// wake up the main thread
1336void WXDLLEXPORT wxWakeUpMainThread()
1337{
1338 wxMacWakeUp();
1339}
1340
1341// ----------------------------------------------------------------------------
1342// include common implementation code
1343// ----------------------------------------------------------------------------
1344
1345#include "wx/thrimpl.cpp"
1346
1347#endif // wxUSE_THREADS