]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/thread.cpp
fixes for mouse handling on 10.2 systems
[wxWidgets.git] / src / mac / carbon / thread.cpp
CommitLineData
e9576ca5 1/////////////////////////////////////////////////////////////////////////////
68ba3b21
SC
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)
65571936 10// Licence: wxWindows licence
e9576ca5
SC
11/////////////////////////////////////////////////////////////////////////////
12
13#ifdef __GNUG__
68ba3b21 14#pragma implementation "thread.h"
e9576ca5
SC
15#endif
16
e7549107
SC
17// ----------------------------------------------------------------------------
18// headers
19// ----------------------------------------------------------------------------
20
21// For compilers that support precompilation, includes "wx.h".
22#include "wx/wxprec.h"
23
24#if defined(__BORLANDC__)
68ba3b21 25#pragma hdrstop
e7549107
SC
26#endif
27
28#ifndef WX_PRECOMP
68ba3b21 29#include "wx/wx.h"
e7549107
SC
30#endif
31
32#if wxUSE_THREADS
33
e9576ca5
SC
34#include "wx/module.h"
35#include "wx/thread.h"
e9576ca5 36
76a5e5d2 37#ifdef __WXMAC__
68ba3b21
SC
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
9c152f80 45#include "wx/mac/uma.h"
76a5e5d2
SC
46#endif
47
9e1eb0ed
JS
48#include "wx/mac/macnotfy.h"
49
a959b088
SC
50// ----------------------------------------------------------------------------
51// constants
52// ----------------------------------------------------------------------------
53
e7549107
SC
54// the possible states of the thread ("=>" shows all possible transitions from
55// this state)
56enum wxThreadState
57{
68ba3b21
SC
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
e9576ca5
SC
63};
64
e7549107 65// ----------------------------------------------------------------------------
a959b088 66// this module globals
e7549107 67// ----------------------------------------------------------------------------
169935ad 68
68ba3b21
SC
69
70// the task ID of the main thread
71static wxThreadIdType gs_idMainThread = kInvalidID;
72
73// this is the Per-Task Storage for the pointer to the appropriate wxThread
74TaskStorageIndex gs_tlsForWXThread = 0 ;
75
76// if it's false, some secondary thread is holding the GUI lock
77static 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
82static wxCriticalSection *gs_critsectGui = NULL;
83
84// critical section which protects gs_nWaitingForGui variable
85static wxCriticalSection *gs_critsectWaitingForGui = NULL;
86
87// number of threads waiting for GUI in wxMutexGuiEnter()
88static size_t gs_nWaitingForGui = 0;
89
90// overall number of threads, needed for determining the sleep value of the main
91// event loop
e64313ba 92size_t g_numberOfThreads = 0;
e9576ca5 93
68ba3b21
SC
94
95
96#if wxUSE_GUI
97
98MPCriticalRegionID gs_guiCritical = kInvalidID;
99
100#endif
101
e7549107 102// ============================================================================
a959b088 103// MacOS implementation of thread classes
e7549107
SC
104// ============================================================================
105
68ba3b21
SC
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*/
a959b088 126
e7549107
SC
127// ----------------------------------------------------------------------------
128// wxMutex implementation
129// ----------------------------------------------------------------------------
a959b088 130
881b5a06
SC
131#if TARGET_API_MAC_OSX
132#define wxUSE_MAC_SEMAPHORE_MUTEX 0
ed197fcf
SC
133#define wxUSE_MAC_CRITICAL_REGION_MUTEX 1
134#define wxUSE_MAC_PTHREADS_MUTEX 0
881b5a06
SC
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
145class wxMutexInternal
146{
147public:
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
157private:
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)
168extern "C" int pthread_mutexattr_settype(pthread_mutexattr_t *, int);
169#endif
170
171wxMutexInternal::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
219wxMutexInternal::~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
231wxMutexError 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
256wxMutexError 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
280wxMutexError 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
68ba3b21 307
e7549107
SC
308class wxMutexInternal
309{
e9576ca5 310public:
68ba3b21
SC
311 wxMutexInternal(wxMutexType mutexType) ;
312 ~wxMutexInternal() ;
313 bool IsOk() const { return m_isOk; }
314
315 wxMutexError Lock() ;
316 wxMutexError TryLock() ;
317 wxMutexError Unlock();
318private:
319 MPSemaphoreID m_semaphore;
320 bool m_isOk ;
321};
a959b088 322
68ba3b21
SC
323wxMutexInternal::wxMutexInternal(wxMutexType mutexType )
324{
325 m_isOk = false ;
326 m_semaphore = kInvalidID ;
327
328 OSStatus err = noErr ;
329 switch( mutexType )
a959b088 330 {
68ba3b21
SC
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 ;
a959b088 343 }
68ba3b21 344}
a959b088 345
68ba3b21
SC
346wxMutexInternal::~wxMutexInternal()
347{
348 if ( m_semaphore != kInvalidID )
349 MPDeleteSemaphore( m_semaphore);
ed197fcf 350 MPYield() ;
68ba3b21 351}
e9576ca5 352
ad816ba5 353wxMutexError wxMutexInternal::Lock()
e9576ca5 354{
68ba3b21
SC
355 wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ;
356 OSStatus err = MPWaitOnSemaphore( m_semaphore, kDurationForever);
357 if ( err)
6fe73788 358 {
68ba3b21
SC
359 wxLogSysError(wxT("Could not lock mutex"));
360 return wxMUTEX_MISC_ERROR;
6fe73788 361 }
68ba3b21
SC
362
363 return wxMUTEX_NO_ERROR;
e9576ca5
SC
364}
365
ad816ba5 366wxMutexError wxMutexInternal::TryLock()
e9576ca5 367{
68ba3b21
SC
368 wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ;
369 OSStatus err = MPWaitOnSemaphore( m_semaphore, kDurationImmediate);
370 if ( err)
ea736fec 371 {
68ba3b21
SC
372 if ( err == kMPTimeoutErr)
373 {
374 return wxMUTEX_BUSY;
375 }
376 wxLogSysError(wxT("Could not try lock mutex"));
377 return wxMUTEX_MISC_ERROR;
9c152f80 378 }
68ba3b21
SC
379
380 return wxMUTEX_NO_ERROR;
e9576ca5
SC
381}
382
ad816ba5 383wxMutexError wxMutexInternal::Unlock()
e9576ca5 384{
68ba3b21
SC
385 wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ;
386 OSStatus err = MPSignalSemaphore( m_semaphore);
ed197fcf 387 MPYield() ;
68ba3b21 388 if ( err)
ea736fec 389 {
68ba3b21
SC
390 wxLogSysError(_("Could not unlock mutex"));
391 return wxMUTEX_MISC_ERROR;
392 }
68ba3b21
SC
393 return wxMUTEX_NO_ERROR;
394}
ea736fec 395
881b5a06
SC
396#endif
397
398#if wxUSE_MAC_CRITICAL_REGION_MUTEX
9c152f80 399
68ba3b21
SC
400class wxMutexInternal
401{
402public:
403 wxMutexInternal(wxMutexType mutexType) ;
404 ~wxMutexInternal() ;
405 bool IsOk() const { return m_isOk; }
406
407 wxMutexError Lock() ;
408 wxMutexError TryLock() ;
409 wxMutexError Unlock();
410private:
411 MPCriticalRegionID m_critRegion ;
412 bool m_isOk ;
413};
9c152f80 414
68ba3b21
SC
415wxMutexInternal::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
427wxMutexInternal::~wxMutexInternal()
428{
429 if ( m_critRegion != kInvalidID )
430 MPDeleteCriticalRegion( m_critRegion);
ed197fcf 431 MPYield() ;
68ba3b21
SC
432}
433
434wxMutexError 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;
9c152f80 442 }
68ba3b21
SC
443
444 return wxMUTEX_NO_ERROR;
445}
446
447wxMutexError 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
464wxMutexError wxMutexInternal::Unlock()
465{
466 wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ;
467 OSStatus err = MPExitCriticalRegion( m_critRegion);
ed197fcf 468 MPYield() ;
68ba3b21 469 if ( err)
6fe73788 470 {
68ba3b21
SC
471 wxLogSysError(_("Could not unlock mutex"));
472 return wxMUTEX_MISC_ERROR;
6fe73788 473 }
68ba3b21
SC
474
475 return wxMUTEX_NO_ERROR;
e9576ca5
SC
476}
477
68ba3b21
SC
478#endif
479
ad816ba5
SC
480// --------------------------------------------------------------------------
481// wxSemaphore
482// --------------------------------------------------------------------------
483
ad816ba5
SC
484class wxSemaphoreInternal
485{
486public:
68ba3b21
SC
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
ad816ba5 505private:
68ba3b21
SC
506 MPSemaphoreID m_semaphore;
507 bool m_isOk ;
ad816ba5
SC
508};
509
510wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
511{
68ba3b21
SC
512 m_isOk = false ;
513 m_semaphore = kInvalidID ;
514 if ( maxcount == 0 )
ad816ba5 515 {
68ba3b21
SC
516 // make it practically infinite
517 maxcount = INT_MAX;
ad816ba5 518 }
68ba3b21
SC
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") ) ;
ad816ba5
SC
524}
525
526wxSemaphoreInternal::~wxSemaphoreInternal()
527{
68ba3b21
SC
528 if( m_semaphore != kInvalidID )
529 MPDeleteSemaphore( m_semaphore);
ed197fcf 530 MPYield() ;
ad816ba5
SC
531}
532
533wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds)
534{
68ba3b21
SC
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;
ad816ba5
SC
545}
546
547wxSemaError wxSemaphoreInternal::Post()
548{
68ba3b21 549 OSStatus err = MPSignalSemaphore( m_semaphore);
ed197fcf 550 MPYield() ;
68ba3b21
SC
551 if ( err)
552 {
553 return wxSEMA_MISC_ERROR;
554 }
555 return wxSEMA_NO_ERROR;
ad816ba5
SC
556}
557
e7549107
SC
558// ----------------------------------------------------------------------------
559// wxCondition implementation
560// ----------------------------------------------------------------------------
561
68ba3b21 562#if 0
ad816ba5 563
e7549107
SC
564class wxConditionInternal
565{
e9576ca5 566public:
68ba3b21
SC
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
601private:
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
615wxCondError wxConditionInternal::WaitTimeout(unsigned long msectimeout)
616{
617 m_gate.Wait();
618 if ( ++ m_waiters == INT_MAX)
a959b088 619 {
68ba3b21
SC
620 m_varSection.Enter();
621 m_waiters -= m_canceled;
622 m_signals -= m_canceled;
623 m_canceled = 0;
624 m_varSection.Leave();
a959b088 625 }
68ba3b21
SC
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)
a959b088 635 {
68ba3b21
SC
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 }
a959b088 673 }
68ba3b21
SC
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}
e9576ca5 697
2dbc444a 698
68ba3b21
SC
699wxCondError 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)
ad816ba5 714 {
68ba3b21
SC
715 m_waiters -= m_canceled;
716 m_signals = 0;
717 m_canceled = 0;
ad816ba5 718 }
68ba3b21
SC
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
737class wxConditionInternal
738{
739public:
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();
2dbc444a 749
68ba3b21
SC
750private:
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
763wxConditionInternal::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
771wxCondError 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
795wxCondError 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 )
e7549107 808 {
68ba3b21
SC
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 )
6fe73788 826 {
68ba3b21 827 m_numWaiters--;
6fe73788 828 }
68ba3b21 829 }
a959b088 830
68ba3b21 831 m_mutex.Lock();
a959b088 832
68ba3b21
SC
833 return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : wxCOND_MISC_ERROR;
834}
a959b088 835
68ba3b21
SC
836wxCondError wxConditionInternal::Signal()
837{
838 wxCriticalSectionLocker lock(m_csWaiters);
839
840 if ( m_numWaiters > 0 )
6fe73788 841 {
68ba3b21
SC
842 // increment the semaphore by 1
843 if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
844 return wxCOND_MISC_ERROR;
845
846 m_numWaiters--;
6fe73788 847 }
a959b088 848
68ba3b21
SC
849 return wxCOND_NO_ERROR;
850}
851
852wxCondError wxConditionInternal::Broadcast()
853{
854 wxCriticalSectionLocker lock(m_csWaiters);
855
856 while ( m_numWaiters > 0 )
ad816ba5 857 {
68ba3b21
SC
858 if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
859 return wxCOND_MISC_ERROR;
860
861 m_numWaiters--;
2dbc444a 862 }
ad816ba5 863
68ba3b21
SC
864 return wxCOND_NO_ERROR;
865}
866#endif
e7549107 867
e7549107
SC
868// ----------------------------------------------------------------------------
869// wxCriticalSection implementation
870// ----------------------------------------------------------------------------
871
68ba3b21 872// XXX currently implemented as mutex in headers. Change to critical section.
e7549107
SC
873
874// ----------------------------------------------------------------------------
875// wxThread implementation
876// ----------------------------------------------------------------------------
877
878// wxThreadInternal class
879// ----------------------
880
e7549107
SC
881class wxThreadInternal
882{
883public:
884 wxThreadInternal()
885 {
68ba3b21
SC
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;
e7549107 899 }
a959b088
SC
900 ~wxThreadInternal()
901 {
68ba3b21
SC
902 if ( m_notifyQueueId)
903 {
904 MPDeleteQueue( m_notifyQueueId);
905 m_notifyQueueId = kInvalidID ;
906 }
a959b088
SC
907 }
908
68ba3b21
SC
909 // thread function
910 static OSStatus MacThreadStart(void* arg);
a959b088 911
e7549107 912 // create a new (suspended) thread (for the given thread object)
6fe73788 913 bool Create(wxThread *thread, unsigned int stackSize);
e7549107 914
68ba3b21
SC
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
e7549107 932 wxThreadState GetState() const { return m_state; }
68ba3b21
SC
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; }
e7549107 937
68ba3b21
SC
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; }
ea736fec 943
68ba3b21
SC
944 // the pause flag
945 void SetReallyPaused(bool paused) { m_isPaused = paused; }
946 bool IsReallyPaused() const { return m_isPaused; }
e7549107 947
68ba3b21
SC
948 // tell the thread that it is a detached one
949 void Detach()
950 {
951 wxCriticalSectionLocker lock(m_csJoinFlag);
e7549107 952
68ba3b21
SC
953 m_shouldBeJoined = FALSE;
954 m_isDetached = TRUE;
955 }
e7549107
SC
956
957private:
68ba3b21
SC
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
77ffb593 965 int m_prio; // in wxWidgets units: from 0 to 100
68ba3b21
SC
966
967 // this flag is set when the thread should terminate
968 bool m_cancelled;
e7549107 969
68ba3b21
SC
970 // this flag is set when the thread is blocking on m_semSuspend
971 bool m_isPaused;
a959b088 972
68ba3b21
SC
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
992OSStatus wxThreadInternal::MacThreadStart(void *parameter)
e7549107 993{
68ba3b21
SC
994 wxThread* thread = (wxThread*) parameter ;
995 wxThreadInternal *pthread = thread->m_internal;
e7549107 996
68ba3b21
SC
997 // add to TLS so that This() will work
998 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread , (long) thread ) ) ;
a959b088 999
68ba3b21
SC
1000 // have to declare this before pthread_cleanup_push() which defines a
1001 // block!
1002 bool dontRunAtAll;
a959b088 1003
68ba3b21
SC
1004 // wait for the semaphore to be posted from Run()
1005 pthread->m_semRun.Wait();
e7549107 1006
68ba3b21
SC
1007 // test whether we should run the run at all - may be it was deleted
1008 // before it started to Run()?
a959b088 1009 {
68ba3b21
SC
1010 wxCriticalSectionLocker lock(thread->m_critsect);
1011
1012 dontRunAtAll = pthread->GetState() == STATE_NEW &&
1013 pthread->WasCancelled();
a959b088 1014 }
e7549107 1015
68ba3b21
SC
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 }
e7549107
SC
1043}
1044
6fe73788 1045bool wxThreadInternal::Create(wxThread *thread, unsigned int stackSize)
e7549107 1046{
68ba3b21
SC
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 )
6fe73788 1054 {
68ba3b21
SC
1055 OSStatus err = MPCreateQueue( & m_notifyQueueId);
1056 if( err)
1057 {
1058 wxLogSysError(_("Cant create the thread event queue"));
1059 return false;
1060 }
6fe73788 1061 }
68ba3b21
SC
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)
e7549107 1075 {
68ba3b21
SC
1076 wxLogSysError(_("Can't create thread"));
1077 return false;
e7549107 1078 }
68ba3b21
SC
1079
1080 if ( m_prio != WXTHREAD_DEFAULT_PRIORITY )
1081 {
1082 SetPriority(m_prio);
1083 }
1084
1085 return true;
1086}
e7549107 1087
68ba3b21
SC
1088void wxThreadInternal::SetPriority( int priority)
1089{
1090 m_prio = priority;
1091
1092 if ( m_tid)
e7549107 1093 {
68ba3b21 1094 // Mac priorities range from 1 to 10,000, with a default of 100.
77ffb593
JS
1095 // wxWidgets priorities range from 0 to 100 with a default of 50.
1096 // We can map wxWidgets to Mac priorities easily by assuming
68ba3b21
SC
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);
e7549107 1101 }
68ba3b21
SC
1102}
1103
1104wxThreadError 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);
e7549107 1110
68ba3b21
SC
1111 // wake up threads waiting for our start
1112 SignalRun();
1dfc3cda 1113
68ba3b21 1114 return wxTHREAD_NO_ERROR;
e7549107
SC
1115}
1116
68ba3b21 1117void wxThreadInternal::Wait()
e7549107 1118{
68ba3b21 1119 wxCHECK_RET( !m_isDetached, _T("can't wait for a detached thread") );
ea736fec 1120
68ba3b21
SC
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() )
93b14e80
SC
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 }
e7549107 1133
a959b088 1134 {
68ba3b21
SC
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 }
e7549107 1160 }
68ba3b21 1161}
e7549107 1162
68ba3b21
SC
1163void 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().") );
a959b088 1169
68ba3b21
SC
1170 // wait until the semaphore is Post()ed from Resume()
1171 m_semSuspend.Wait();
e7549107
SC
1172}
1173
68ba3b21 1174void wxThreadInternal::Resume()
e7549107 1175{
68ba3b21
SC
1176 wxCHECK_RET( m_state == STATE_PAUSED,
1177 wxT("can't resume thread which is not suspended.") );
ea736fec 1178
68ba3b21
SC
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() )
6fe73788 1182 {
68ba3b21
SC
1183 // wake up Pause()
1184 m_semSuspend.Post();
ea736fec 1185
68ba3b21
SC
1186 // reset the flag
1187 SetReallyPaused(FALSE);
6fe73788 1188 }
ea736fec 1189
68ba3b21 1190 SetState(STATE_RUNNING);
e7549107
SC
1191}
1192
1193// static functions
1194// ----------------
68ba3b21 1195
e7549107
SC
1196wxThread *wxThread::This()
1197{
68ba3b21
SC
1198 wxThread* thr = (wxThread*) MPGetTaskStorageValue( gs_tlsForWXThread ) ;
1199 return thr;
e7549107
SC
1200}
1201
1202bool wxThread::IsMain()
1203{
93b14e80 1204 return GetCurrentId() == gs_idMainThread || gs_idMainThread == kInvalidID ;
e7549107
SC
1205}
1206
1207#ifdef Yield
a959b088 1208#undef Yield
e7549107
SC
1209#endif
1210
1211void wxThread::Yield()
1212{
39fbbfda 1213#if TARGET_API_MAC_OSX
68ba3b21 1214 CFRunLoopRunInMode( kCFRunLoopDefaultMode , 0 , true ) ;
39fbbfda 1215#endif
68ba3b21 1216 MPYield();
e7549107
SC
1217}
1218
68ba3b21 1219
e7549107
SC
1220void wxThread::Sleep(unsigned long milliseconds)
1221{
68ba3b21
SC
1222 AbsoluteTime wakeup = AddDurationToAbsolute( milliseconds, UpTime());
1223 MPDelayUntil( & wakeup);
a959b088
SC
1224}
1225
68ba3b21 1226
a959b088
SC
1227int wxThread::GetCPUCount()
1228{
68ba3b21 1229 return MPProcessors();
a959b088
SC
1230}
1231
ea736fec
RD
1232unsigned long wxThread::GetCurrentId()
1233{
68ba3b21 1234 return (unsigned long)MPCurrentTaskID();
ea736fec
RD
1235}
1236
68ba3b21 1237
a959b088
SC
1238bool wxThread::SetConcurrency(size_t level)
1239{
68ba3b21
SC
1240 // Cannot be set in MacOS.
1241 return false;
a959b088
SC
1242}
1243
a959b088
SC
1244
1245wxThread::wxThread(wxThreadKind kind)
1246{
68ba3b21
SC
1247 g_numberOfThreads++;
1248 m_internal = new wxThreadInternal();
1249
1250 m_isDetached = (kind == wxTHREAD_DETACHED);
a959b088
SC
1251}
1252
1253wxThread::~wxThread()
1254{
68ba3b21
SC
1255 wxASSERT_MSG( g_numberOfThreads>0 , wxT("More threads deleted than created.") ) ;
1256 g_numberOfThreads--;
1257
e64313ba 1258#ifdef __WXDEBUG__
68ba3b21
SC
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 )
e64313ba 1264 {
68ba3b21 1265 wxLogDebug(_T("The thread %ld is being destroyed although it is still running! The application may crash."), GetId());
e64313ba 1266 }
e64313ba 1267
68ba3b21
SC
1268 m_critsect.Leave();
1269#endif // __WXDEBUG__
1270
1271 wxDELETE( m_internal ) ;
e7549107
SC
1272}
1273
e7549107 1274
6fe73788 1275wxThreadError wxThread::Create(unsigned int stackSize)
e9576ca5 1276{
68ba3b21
SC
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);
e7549107 1286 return wxTHREAD_NO_RESOURCE;
68ba3b21
SC
1287 }
1288
1289 return wxTHREAD_NO_ERROR;
e9576ca5
SC
1290}
1291
e7549107 1292wxThreadError wxThread::Run()
e9576ca5 1293{
e7549107
SC
1294 wxCriticalSectionLocker lock(m_critsect);
1295
68ba3b21
SC
1296 wxCHECK_MSG( m_internal->GetId(), wxTHREAD_MISC_ERROR,
1297 wxT("must call wxThread::Create() first") );
e7549107 1298
68ba3b21 1299 return m_internal->Run();
e9576ca5
SC
1300}
1301
68ba3b21
SC
1302// -----------------------------------------------------------------------------
1303// pause/resume
1304// -----------------------------------------------------------------------------
e7549107 1305
e9576ca5
SC
1306wxThreadError wxThread::Pause()
1307{
68ba3b21
SC
1308 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1309 _T("a thread can't pause itself") );
e9576ca5 1310
e7549107 1311 wxCriticalSectionLocker lock(m_critsect);
e9576ca5 1312
68ba3b21
SC
1313 if ( m_internal->GetState() != STATE_RUNNING )
1314 {
1315 wxLogDebug(wxT("Can't pause thread which is not running."));
a959b088 1316
68ba3b21
SC
1317 return wxTHREAD_NOT_RUNNING;
1318 }
a959b088 1319
68ba3b21
SC
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);
a959b088 1323
68ba3b21 1324 return wxTHREAD_NO_ERROR;
a959b088
SC
1325}
1326
68ba3b21 1327wxThreadError wxThread::Resume()
e9576ca5 1328{
68ba3b21
SC
1329 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1330 _T("a thread can't resume itself") );
e7549107 1331
68ba3b21 1332 wxCriticalSectionLocker lock(m_critsect);
a959b088 1333
68ba3b21 1334 wxThreadState state = m_internal->GetState();
a959b088 1335
68ba3b21 1336 switch ( state )
a959b088 1337 {
68ba3b21
SC
1338 case STATE_PAUSED:
1339 m_internal->Resume();
1340 return wxTHREAD_NO_ERROR;
1341 case STATE_EXITED:
1342 return wxTHREAD_NO_ERROR;
a959b088 1343
68ba3b21
SC
1344 default:
1345 wxLogDebug(_T("Attempt to resume a thread which is not paused."));
a959b088 1346
68ba3b21 1347 return wxTHREAD_MISC_ERROR;
a959b088 1348 }
68ba3b21 1349}
a959b088 1350
68ba3b21
SC
1351// -----------------------------------------------------------------------------
1352// exiting thread
1353// -----------------------------------------------------------------------------
e7549107 1354
68ba3b21
SC
1355wxThread::ExitCode wxThread::Wait()
1356{
1357 wxCHECK_MSG( This() != this, (ExitCode)-1,
1358 _T("a thread can't wait for itself") );
e7549107 1359
68ba3b21
SC
1360 wxCHECK_MSG( !m_isDetached, (ExitCode)-1,
1361 _T("can't wait for detached thread") );
e7549107 1362
68ba3b21 1363 m_internal->Wait();
e7549107 1364
68ba3b21
SC
1365 return m_internal->GetExitCode();
1366}
e7549107 1367
68ba3b21
SC
1368wxThreadError wxThread::Delete(ExitCode *rc)
1369{
1370 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1371 _T("a thread can't delete itself") );
e7549107 1372
68ba3b21 1373 bool isDetached = m_isDetached;
e7549107 1374
68ba3b21
SC
1375 m_critsect.Enter();
1376 wxThreadState state = m_internal->GetState();
e7549107 1377
68ba3b21
SC
1378 // ask the thread to stop
1379 m_internal->SetCancelFlag();
1380
1381 m_critsect.Leave();
1382
1383 switch ( state )
a959b088 1384 {
68ba3b21
SC
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 }
e7549107
SC
1415 }
1416
68ba3b21 1417 return wxTHREAD_NO_ERROR;
e9576ca5
SC
1418}
1419
e7549107 1420wxThreadError wxThread::Kill()
e9576ca5 1421{
68ba3b21
SC
1422 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1423 _T("a thread can't kill itself") );
e7549107 1424
68ba3b21 1425 switch ( m_internal->GetState() )
e7549107 1426 {
68ba3b21
SC
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;
e7549107 1457 }
68ba3b21
SC
1458}
1459
1460void 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") );
e7549107 1464
68ba3b21
SC
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();
a959b088 1470
5efd525f 1471 MPTaskID threadid = m_internal->GetId() ;
68ba3b21 1472
a959b088
SC
1473 if ( IsDetached() )
1474 {
1475 delete this;
1476 }
68ba3b21
SC
1477 else // joinable
1478 {
1479 // update the status of the joinable thread
1480 wxCriticalSectionLocker lock(m_critsect);
1481 m_internal->SetState(STATE_EXITED);
1482 }
5efd525f 1483 MPTerminateTask( threadid , (long) status) ;
e9576ca5
SC
1484}
1485
68ba3b21
SC
1486// also test whether we were paused
1487bool wxThread::TestDestroy()
e9576ca5 1488{
68ba3b21
SC
1489 wxASSERT_MSG( This() == this,
1490 _T("wxThread::TestDestroy() can only be called in the context of the same thread") );
e7549107 1491
68ba3b21
SC
1492 m_critsect.Enter();
1493
1494 if ( m_internal->GetState() == STATE_PAUSED )
a959b088 1495 {
68ba3b21 1496 m_internal->SetReallyPaused(TRUE);
e7549107 1497
68ba3b21
SC
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();
a959b088 1502
68ba3b21
SC
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();
e9576ca5
SC
1512}
1513
68ba3b21 1514// -----------------------------------------------------------------------------
a959b088 1515// priority setting
68ba3b21 1516// -----------------------------------------------------------------------------
a959b088 1517
e7549107 1518void wxThread::SetPriority(unsigned int prio)
e9576ca5 1519{
68ba3b21
SC
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 }
e9576ca5
SC
1539}
1540
e7549107 1541unsigned int wxThread::GetPriority() const
e9576ca5 1542{
68ba3b21
SC
1543 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
1544
a959b088 1545 return m_internal->GetPriority();
e9576ca5
SC
1546}
1547
a959b088 1548unsigned long wxThread::GetId() const
e9576ca5 1549{
68ba3b21
SC
1550 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
1551
a959b088 1552 return (unsigned long)m_internal->GetId();
e9576ca5
SC
1553}
1554
68ba3b21
SC
1555// -----------------------------------------------------------------------------
1556// state tests
1557// -----------------------------------------------------------------------------
1558
e7549107 1559bool wxThread::IsRunning() const
e9576ca5 1560{
68ba3b21
SC
1561 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
1562
a959b088 1563 return m_internal->GetState() == STATE_RUNNING;
e9576ca5 1564}
e9576ca5
SC
1565
1566bool wxThread::IsAlive() const
1567{
68ba3b21
SC
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 }
e9576ca5
SC
1579}
1580
e7549107 1581bool wxThread::IsPaused() const
e9576ca5 1582{
68ba3b21 1583 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
e9576ca5 1584
68ba3b21 1585 return (m_internal->GetState() == STATE_PAUSED);
e9576ca5
SC
1586}
1587
e7549107
SC
1588// ----------------------------------------------------------------------------
1589// Automatic initialization for thread module
1590// ----------------------------------------------------------------------------
e9576ca5 1591
e7549107
SC
1592class wxThreadModule : public wxModule
1593{
e9576ca5 1594public:
68ba3b21
SC
1595 virtual bool OnInit();
1596 virtual void OnExit();
1597
e7549107 1598private:
68ba3b21 1599 DECLARE_DYNAMIC_CLASS(wxThreadModule)
e9576ca5
SC
1600};
1601
1602IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
1603
e7549107
SC
1604bool wxThreadModule::OnInit()
1605{
68ba3b21
SC
1606 bool hasThreadManager = false ;
1607 hasThreadManager = MPLibraryIsLoaded();
1608
1609 if ( !hasThreadManager )
6fe73788 1610 {
c3e8a84f 1611 wxLogError( _("MP Thread Support is not available on this System" ) ) ;
68ba3b21 1612 return FALSE ;
6fe73788 1613 }
68ba3b21
SC
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;
e7549107
SC
1627}
1628
1629void wxThreadModule::OnExit()
1630{
68ba3b21
SC
1631 if ( gs_critsectGui )
1632 {
bd241606
SC
1633 if ( !wxGuiOwnedByMainThread() )
1634 {
1635 gs_critsectGui->Enter();
1636 gs_bGuiOwnedByMainThread = true;
1637 }
68ba3b21
SC
1638 gs_critsectGui->Leave();
1639 delete gs_critsectGui;
1640 gs_critsectGui = NULL;
1641 }
1642
1643 delete gs_critsectWaitingForGui;
1644 gs_critsectWaitingForGui = NULL;
e7549107
SC
1645}
1646
1647// ----------------------------------------------------------------------------
68ba3b21 1648// GUI Serialization copied from MSW implementation
e7549107
SC
1649// ----------------------------------------------------------------------------
1650
68ba3b21 1651void WXDLLIMPEXP_BASE wxMutexGuiEnter()
e7549107 1652{
68ba3b21
SC
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();
e7549107
SC
1671}
1672
68ba3b21 1673void WXDLLIMPEXP_BASE wxMutexGuiLeave()
e7549107 1674{
68ba3b21
SC
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();
e7549107
SC
1693}
1694
68ba3b21 1695void WXDLLIMPEXP_BASE wxMutexGuiLeaveOrEnter()
e7549107 1696{
68ba3b21
SC
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 }
e7549107
SC
1723}
1724
68ba3b21 1725bool WXDLLIMPEXP_BASE wxGuiOwnedByMainThread()
e7549107 1726{
68ba3b21 1727 return gs_bGuiOwnedByMainThread;
e7549107
SC
1728}
1729
ea736fec 1730// wake up the main thread
e7549107
SC
1731void WXDLLEXPORT wxWakeUpMainThread()
1732{
68ba3b21 1733 wxMacWakeUp() ;
e7549107
SC
1734}
1735
68ba3b21
SC
1736// ----------------------------------------------------------------------------
1737// include common implementation code
1738// ----------------------------------------------------------------------------
e7549107 1739
ad816ba5
SC
1740#include "wx/thrimpl.cpp"
1741
e7549107 1742#endif // wxUSE_THREADS