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