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