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