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