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