]> git.saurik.com Git - wxWidgets.git/blame - src/osx/carbon/thread.cpp
move notebook event definition to common code
[wxWidgets.git] / src / osx / carbon / thread.cpp
CommitLineData
489468fe
SC
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/mac/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// 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
52static wxThreadIdType gs_idMainThread = kInvalidID;
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
109wxCriticalSection::wxCriticalSection()
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
346 DECLARE_NO_COPY_CLASS(wxConditionInternal)
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
799bool wxThread::IsMain()
800{
801 return GetCurrentId() == gs_idMainThread || gs_idMainThread == kInvalidID ;
802}
803
804#ifdef Yield
805#undef Yield
806#endif
807
808void wxThread::Yield()
809{
810 CFRunLoopRunInMode( kCFRunLoopDefaultMode , 0 , true ) ;
811
812 MPYield();
813}
814
815void wxThread::Sleep( unsigned long milliseconds )
816{
817 AbsoluteTime wakeup = AddDurationToAbsolute( milliseconds, UpTime() );
818 MPDelayUntil( &wakeup );
819}
820
821int wxThread::GetCPUCount()
822{
823 return MPProcessors();
824}
825
826unsigned long wxThread::GetCurrentId()
827{
828 return (unsigned long)MPCurrentTaskID();
829}
830
831bool wxThread::SetConcurrency( size_t WXUNUSED(level) )
832{
833 // Cannot be set in MacOS.
834 return false;
835}
836
837wxThread::wxThread( wxThreadKind kind )
838{
839 g_numberOfThreads++;
840 m_internal = new wxThreadInternal();
841
842 m_isDetached = (kind == wxTHREAD_DETACHED);
843}
844
845wxThread::~wxThread()
846{
847 wxASSERT_MSG( g_numberOfThreads>0 , wxT("More threads deleted than created.") ) ;
848
849 g_numberOfThreads--;
850
851#ifdef __WXDEBUG__
852 m_critsect.Enter();
853
854 // check that the thread either exited or couldn't be created
855 if ( m_internal->GetState() != STATE_EXITED &&
856 m_internal->GetState() != STATE_NEW )
857 {
858 wxLogDebug(
859 wxT("The thread %ld is being destroyed although it is still running! The application may crash."),
860 GetId() );
861 }
862
863 m_critsect.Leave();
864#endif
865
866 wxDELETE( m_internal ) ;
867}
868
869wxThreadError wxThread::Create( unsigned int stackSize )
870{
871 wxCriticalSectionLocker lock(m_critsect);
872
873 if ( m_isDetached )
874 m_internal->Detach() ;
875
876 if ( !m_internal->Create(this, stackSize) )
877 {
878 m_internal->SetState( STATE_EXITED );
879
880 return wxTHREAD_NO_RESOURCE;
881 }
882
883 return wxTHREAD_NO_ERROR;
884}
885
886wxThreadError wxThread::Run()
887{
888 wxCriticalSectionLocker lock(m_critsect);
889
890 wxCHECK_MSG( m_internal->GetId(), wxTHREAD_MISC_ERROR,
891 wxT("must call wxThread::Create() first") );
892
893 return m_internal->Run();
894}
895
896// -----------------------------------------------------------------------------
897// pause/resume
898// -----------------------------------------------------------------------------
899
900wxThreadError wxThread::Pause()
901{
902 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
903 _T("a thread can't pause itself") );
904
905 wxCriticalSectionLocker lock(m_critsect);
906
907 if ( m_internal->GetState() != STATE_RUNNING )
908 {
909 wxLogDebug( wxT("Can't pause thread which is not running.") );
910
911 return wxTHREAD_NOT_RUNNING;
912 }
913
914 // just set a flag, the thread will be really paused only during the next
915 // call to TestDestroy()
916 m_internal->SetState( STATE_PAUSED );
917
918 return wxTHREAD_NO_ERROR;
919}
920
921wxThreadError wxThread::Resume()
922{
923 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
924 wxT("a thread can't resume itself") );
925
926 wxCriticalSectionLocker lock(m_critsect);
927
928 wxThreadState state = m_internal->GetState();
929
930 switch ( state )
931 {
932 case STATE_PAUSED:
933 m_internal->Resume();
934 return wxTHREAD_NO_ERROR;
935
936 case STATE_EXITED:
937 return wxTHREAD_NO_ERROR;
938
939 default:
940 wxLogDebug( wxT("Attempt to resume a thread which is not paused.") );
941
942 return wxTHREAD_MISC_ERROR;
943 }
944}
945
946// -----------------------------------------------------------------------------
947// exiting thread
948// -----------------------------------------------------------------------------
949
950wxThread::ExitCode wxThread::Wait()
951{
952 wxCHECK_MSG( This() != this, (ExitCode)-1,
953 wxT("a thread can't wait for itself") );
954
955 wxCHECK_MSG( !m_isDetached, (ExitCode)-1,
956 wxT("can't wait for detached thread") );
957
958 m_internal->Wait();
959
960 return m_internal->GetExitCode();
961}
962
963wxThreadError wxThread::Delete(ExitCode *rc)
964{
965 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
966 wxT("a thread can't delete itself") );
967
968 bool isDetached = m_isDetached;
969
970 m_critsect.Enter();
971 wxThreadState state = m_internal->GetState();
972
973 // ask the thread to stop
974 m_internal->SetCancelFlag();
975
976 m_critsect.Leave();
977
978 switch ( state )
979 {
980 case STATE_NEW:
981 // we need to wake up the thread so that PthreadStart() will
982 // terminate - right now it's blocking on run semaphore in
983 // PthreadStart()
984 m_internal->SignalRun();
985
986 // fall through
987
988 case STATE_EXITED:
989 // nothing to do
990 break;
991
992 case STATE_PAUSED:
993 // resume the thread first
994 m_internal->Resume();
995
996 // fall through
997
998 default:
999 if ( !isDetached )
1000 {
1001 // wait until the thread stops
1002 m_internal->Wait();
1003
1004 if ( rc )
1005 {
1006 // return the exit code of the thread
1007 *rc = m_internal->GetExitCode();
1008 }
1009 }
1010 }
1011
1012 return wxTHREAD_NO_ERROR;
1013}
1014
1015wxThreadError wxThread::Kill()
1016{
1017 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1018 wxT("a thread can't kill itself") );
1019
1020 switch ( m_internal->GetState() )
1021 {
1022 case STATE_NEW:
1023 case STATE_EXITED:
1024 return wxTHREAD_NOT_RUNNING;
1025
1026 case STATE_PAUSED:
1027 // resume the thread first
1028 Resume();
1029
1030 // fall through
1031
1032 default:
1033 OSStatus err = MPTerminateTask( m_internal->GetId() , -1 ) ;
1034 if (err != noErr)
1035 {
1036 wxLogError( wxT("Failed to terminate a thread.") );
1037
1038 return wxTHREAD_MISC_ERROR;
1039 }
1040
1041 if ( m_isDetached )
1042 {
1043 delete this ;
1044 }
1045 else
1046 {
1047 // this should be retrieved by Wait actually
1048 m_internal->SetExitCode( (void*)-1 );
1049 }
1050
1051 return wxTHREAD_NO_ERROR;
1052 }
1053}
1054
1055void wxThread::Exit( ExitCode status )
1056{
1057 wxASSERT_MSG( This() == this,
1058 wxT("wxThread::Exit() can only be called in the context of the same thread") );
1059
1060 // don't enter m_critsect before calling OnExit() because the user code
1061 // might deadlock if, for example, it signals a condition in OnExit() (a
1062 // common case) while the main thread calls any of functions entering
1063 // m_critsect on us (almost all of them do)
1064 OnExit();
1065
1066 MPTaskID threadid = m_internal->GetId();
1067
1068 if ( IsDetached() )
1069 {
1070 delete this;
1071 }
1072 else // joinable
1073 {
1074 // update the status of the joinable thread
1075 wxCriticalSectionLocker lock( m_critsect );
1076 m_internal->SetState( STATE_EXITED );
1077 }
1078
1079 MPTerminateTask( threadid, (long)status );
1080}
1081
1082// also test whether we were paused
1083bool wxThread::TestDestroy()
1084{
1085 wxASSERT_MSG( This() == this,
1086 wxT("wxThread::TestDestroy() can only be called in the context of the same thread") );
1087
1088 m_critsect.Enter();
1089
1090 if ( m_internal->GetState() == STATE_PAUSED )
1091 {
1092 m_internal->SetReallyPaused( true );
1093
1094 // leave the crit section or the other threads will stop too if they attempt
1095 // to call any of (seemingly harmless) IsXXX() functions while we sleep
1096 m_critsect.Leave();
1097
1098 m_internal->Pause();
1099 }
1100 else
1101 {
1102 // thread wasn't requested to pause, nothing to do
1103 m_critsect.Leave();
1104 }
1105
1106 return m_internal->WasCancelled();
1107}
1108
1109// -----------------------------------------------------------------------------
1110// priority setting
1111// -----------------------------------------------------------------------------
1112
1113void wxThread::SetPriority(unsigned int prio)
1114{
1115 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY <= (int)prio) &&
1116 ((int)prio <= (int)WXTHREAD_MAX_PRIORITY),
1117 wxT("invalid thread priority") );
1118
1119 wxCriticalSectionLocker lock(m_critsect);
1120
1121 switch ( m_internal->GetState() )
1122 {
1123 case STATE_RUNNING:
1124 case STATE_PAUSED:
1125 case STATE_NEW:
1126 // thread not yet started, priority will be set when it is
1127 m_internal->SetPriority( prio );
1128 break;
1129
1130 case STATE_EXITED:
1131 default:
1132 wxFAIL_MSG( wxT("impossible to set thread priority in this state") );
1133 }
1134}
1135
1136unsigned int wxThread::GetPriority() const
1137{
1138 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
1139
1140 return m_internal->GetPriority();
1141}
1142
1143unsigned long wxThread::GetId() const
1144{
1145 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
1146
1147 return (unsigned long)m_internal->GetId();
1148}
1149
1150// -----------------------------------------------------------------------------
1151// state tests
1152// -----------------------------------------------------------------------------
1153
1154bool wxThread::IsRunning() const
1155{
1156 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
1157
1158 return m_internal->GetState() == STATE_RUNNING;
1159}
1160
1161bool wxThread::IsAlive() const
1162{
1163 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
1164
1165 switch ( m_internal->GetState() )
1166 {
1167 case STATE_RUNNING:
1168 case STATE_PAUSED:
1169 return true;
1170
1171 default:
1172 return false;
1173 }
1174}
1175
1176bool wxThread::IsPaused() const
1177{
1178 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
1179
1180 return (m_internal->GetState() == STATE_PAUSED);
1181}
1182
1183// ----------------------------------------------------------------------------
1184// Automatic initialization for thread module
1185// ----------------------------------------------------------------------------
1186
1187class wxThreadModule : public wxModule
1188{
1189public:
1190 virtual bool OnInit();
1191 virtual void OnExit();
1192
1193private:
1194 DECLARE_DYNAMIC_CLASS(wxThreadModule)
1195};
1196
1197IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
1198
1199bool wxThreadModule::OnInit()
1200{
1201 bool hasThreadManager =
1202#ifdef __LP64__
1203 true ; // TODO VERIFY IN NEXT BUILD
1204#else
1205 MPLibraryIsLoaded();
1206#endif
1207
1208 if ( !hasThreadManager )
1209 {
1210 wxLogError( wxT("MP thread support is not available on this system" ) ) ;
1211
1212 return false;
1213 }
1214
1215 // main thread's This() is NULL
1216 verify_noerr( MPAllocateTaskStorageIndex( &gs_tlsForWXThread ) ) ;
1217 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread, 0 ) ) ;
1218
1219 gs_idMainThread = wxThread::GetCurrentId();
1220 gs_critsectWaitingForGui = new wxCriticalSection();
1221
1222 gs_critsectGui = new wxCriticalSection();
1223 gs_critsectGui->Enter();
1224
1225 return true;
1226}
1227
1228void wxThreadModule::OnExit()
1229{
1230 if ( gs_critsectGui )
1231 {
1232 if ( !wxGuiOwnedByMainThread() )
1233 {
1234 gs_critsectGui->Enter();
1235 gs_bGuiOwnedByMainThread = true;
1236 }
1237
1238 gs_critsectGui->Leave();
1239 delete gs_critsectGui;
1240 gs_critsectGui = NULL;
1241 }
1242
1243 delete gs_critsectWaitingForGui;
1244 gs_critsectWaitingForGui = NULL;
1245}
1246
1247// ----------------------------------------------------------------------------
1248// GUI Serialization copied from MSW implementation
1249// ----------------------------------------------------------------------------
1250
1251void wxMutexGuiEnterImpl()
1252{
1253 // this would dead lock everything...
1254 wxASSERT_MSG( !wxThread::IsMain(),
1255 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
1256
1257 // the order in which we enter the critical sections here is crucial!!
1258
1259 // set the flag telling to the main thread that we want to do some GUI
1260 {
1261 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1262
1263 gs_nWaitingForGui++;
1264 }
1265
1266 wxWakeUpMainThread();
1267
1268 // now we may block here because the main thread will soon let us in
1269 // (during the next iteration of OnIdle())
1270 gs_critsectGui->Enter();
1271}
1272
1273void wxMutexGuiLeaveImpl()
1274{
1275 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1276
1277 if ( wxThread::IsMain() )
1278 {
1279 gs_bGuiOwnedByMainThread = false;
1280 }
1281 else
1282 {
1283 // decrement the number of threads waiting for GUI access now
1284 wxASSERT_MSG( gs_nWaitingForGui > 0,
1285 wxT("calling wxMutexGuiLeave() without entering it first?") );
1286
1287 gs_nWaitingForGui--;
1288
1289 wxWakeUpMainThread();
1290 }
1291
1292 gs_critsectGui->Leave();
1293}
1294
1295void WXDLLIMPEXP_BASE wxMutexGuiLeaveOrEnter()
1296{
1297 wxASSERT_MSG( wxThread::IsMain(),
1298 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1299
1300 if ( !gs_critsectWaitingForGui )
1301 return;
1302
1303 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1304
1305 if ( gs_nWaitingForGui == 0 )
1306 {
1307 // no threads are waiting for GUI - so we may acquire the lock without
1308 // any danger (but only if we don't already have it)
1309 if ( !wxGuiOwnedByMainThread() )
1310 {
1311 gs_critsectGui->Enter();
1312
1313 gs_bGuiOwnedByMainThread = true;
1314 }
1315 //else: already have it, nothing to do
1316 }
1317 else
1318 {
1319 // some threads are waiting, release the GUI lock if we have it
1320 if ( wxGuiOwnedByMainThread() )
1321 wxMutexGuiLeave();
1322 //else: some other worker thread is doing GUI
1323 }
1324}
1325
1326bool WXDLLIMPEXP_BASE wxGuiOwnedByMainThread()
1327{
1328 return gs_bGuiOwnedByMainThread;
1329}
1330
1331// wake up the main thread
1332void WXDLLEXPORT wxWakeUpMainThread()
1333{
1334 wxMacWakeUp();
1335}
1336
1337// ----------------------------------------------------------------------------
1338// include common implementation code
1339// ----------------------------------------------------------------------------
1340
1341#include "wx/thrimpl.cpp"
1342
1343#endif // wxUSE_THREADS