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