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