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