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