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