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