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