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