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