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