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