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