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