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