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