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