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