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