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