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