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