]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/mpthread.cpp
replacing OSX only carbon calls by classic ones for CFM build
[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)
10// Licence: wxWindows licence
11/////////////////////////////////////////////////////////////////////////////
12
13#ifdef __GNUG__
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>
43#include <math.h>
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
167d8a88
SC
129#if 0
130
7368be43
SC
131class wxMutexInternal
132{
133public:
167d8a88
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 ;
7368be43
SC
144};
145
167d8a88
SC
146wxMutexInternal::wxMutexInternal(wxMutexType mutexType )
147{
148 m_isOk = false ;
149 m_semaphore = kInvalidID ;
150
151 OSStatus err = noErr ;
152 switch( mutexType )
153 {
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 ;
166 }
167}
168
169wxMutexInternal::~wxMutexInternal()
170{
171 if ( m_semaphore != kInvalidID )
172 MPDeleteSemaphore( m_semaphore);
173}
174
7368be43
SC
175wxMutexError wxMutexInternal::Lock()
176{
167d8a88
SC
177 wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ;
178 OSStatus err = MPWaitOnSemaphore( m_semaphore, kDurationForever);
179 if ( err)
7368be43 180 {
167d8a88
SC
181 wxLogSysError(wxT("Could not lock mutex"));
182 return wxMUTEX_MISC_ERROR;
7368be43
SC
183 }
184
167d8a88 185 return wxMUTEX_NO_ERROR;
7368be43
SC
186}
187
188wxMutexError wxMutexInternal::TryLock()
189{
167d8a88
SC
190 wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ;
191 OSStatus err = MPWaitOnSemaphore( m_semaphore, kDurationImmediate);
192 if ( err)
7368be43 193 {
167d8a88
SC
194 if ( err == kMPTimeoutErr)
195 {
196 return wxMUTEX_BUSY;
197 }
198 wxLogSysError(wxT("Could not try lock mutex"));
199 return wxMUTEX_MISC_ERROR;
7368be43
SC
200 }
201
167d8a88 202 return wxMUTEX_NO_ERROR;
7368be43
SC
203}
204
205wxMutexError wxMutexInternal::Unlock()
206{
167d8a88
SC
207 wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ;
208 OSStatus err = MPSignalSemaphore( m_semaphore);
209 if ( err)
7368be43 210 {
167d8a88
SC
211 wxLogSysError(_("Could not unlock mutex"));
212 return wxMUTEX_MISC_ERROR;
7368be43
SC
213 }
214
167d8a88 215 return wxMUTEX_NO_ERROR;
7368be43
SC
216}
217
167d8a88 218#else
7368be43 219
167d8a88 220class wxMutexInternal
7368be43
SC
221{
222public:
167d8a88
SC
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};
234
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}
7368be43 246
167d8a88
SC
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;
261 }
262
263 return wxMUTEX_NO_ERROR;
264}
7368be43 265
167d8a88
SC
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}
7368be43 282
167d8a88
SC
283wxMutexError wxMutexInternal::Unlock()
284{
285 wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ;
286 OSStatus err = MPExitCriticalRegion( m_critRegion);
287 if ( err)
288 {
289 wxLogSysError(_("Could not unlock mutex"));
290 return wxMUTEX_MISC_ERROR;
291 }
292
293 return wxMUTEX_NO_ERROR;
294}
7368be43 295
167d8a88 296#endif
7368be43 297
167d8a88
SC
298// --------------------------------------------------------------------------
299// wxSemaphore
300// --------------------------------------------------------------------------
7368be43 301
167d8a88
SC
302class wxSemaphoreInternal
303{
304public:
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
7368be43 323private:
167d8a88
SC
324 MPSemaphoreID m_semaphore;
325 bool m_isOk ;
7368be43
SC
326};
327
328wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
329{
167d8a88
SC
330 m_isOk = false ;
331 m_semaphore = kInvalidID ;
332 if ( maxcount == 0 )
7368be43 333 {
167d8a88
SC
334 // make it practically infinite
335 maxcount = INT_MAX;
7368be43 336 }
167d8a88
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") ) ;
7368be43
SC
342}
343
344wxSemaphoreInternal::~wxSemaphoreInternal()
345{
167d8a88
SC
346 if( m_semaphore != kInvalidID )
347 MPDeleteSemaphore( m_semaphore);
7368be43
SC
348}
349
350wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds)
351{
167d8a88
SC
352 OSStatus err = MPWaitOnSemaphore( m_semaphore, milliseconds);
353 if ( err)
7368be43 354 {
167d8a88
SC
355 if ( err == kMPTimeoutErr)
356 {
357 return wxSEMA_TIMEOUT;
358 }
359 return wxSEMA_MISC_ERROR;
7368be43 360 }
167d8a88 361 return wxSEMA_NO_ERROR;
7368be43
SC
362}
363
364wxSemaError wxSemaphoreInternal::Post()
365{
167d8a88
SC
366 OSStatus err = MPSignalSemaphore( m_semaphore);
367 if ( err)
7368be43 368 {
167d8a88 369 return wxSEMA_MISC_ERROR;
7368be43 370 }
167d8a88 371 return wxSEMA_NO_ERROR;
7368be43
SC
372}
373
374// ----------------------------------------------------------------------------
375// wxCondition implementation
376// ----------------------------------------------------------------------------
377
167d8a88
SC
378#if 0
379
7368be43
SC
380class wxConditionInternal
381{
382public:
167d8a88
SC
383
384 wxConditionInternal(wxMutex& mutex)
7368be43 385 : m_mutex( mutex),
167d8a88
SC
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() ; }
7368be43 399
167d8a88
SC
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 }
7368be43
SC
416
417private:
167d8a88
SC
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.
7368be43
SC
428};
429
430
431wxCondError wxConditionInternal::WaitTimeout(unsigned long msectimeout)
432{
167d8a88
SC
433 m_gate.Wait();
434 if ( ++ m_waiters == INT_MAX)
7368be43 435 {
167d8a88
SC
436 m_varSection.Enter();
437 m_waiters -= m_canceled;
438 m_signals -= m_canceled;
439 m_canceled = 0;
440 m_varSection.Leave();
7368be43 441 }
167d8a88
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)
7368be43 451 {
167d8a88 452 if ( m_signals > m_canceled)
7368be43 453 {
167d8a88
SC
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 }
7368be43 481 }
167d8a88 482 else
7368be43 483 {
167d8a88
SC
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;
7368be43 488 }
7368be43 489 }
167d8a88 490 else
7368be43 491 {
167d8a88
SC
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 }
7368be43 501 }
167d8a88
SC
502 m_varSection.Leave();
503
504 m_mutex.Lock();
505
506 if ( err)
7368be43 507 {
167d8a88 508 return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR;
7368be43
SC
509 }
510
167d8a88 511 return wxCOND_NO_ERROR;
7368be43 512}
167d8a88 513
7368be43
SC
514
515wxCondError wxConditionInternal::DoSignal( bool signalAll)
516{
167d8a88
SC
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)
7368be43 530 {
167d8a88
SC
531 m_waiters -= m_canceled;
532 m_signals = 0;
533 m_canceled = 0;
7368be43 534 }
167d8a88
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(); }
7368be43 559
167d8a88
SC
560 wxCondError Wait();
561 wxCondError WaitTimeout(unsigned long milliseconds);
562
563 wxCondError Signal();
564 wxCondError Broadcast();
565
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 )
7368be43 624 {
167d8a88
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 )
642 {
643 m_numWaiters--;
644 }
7368be43
SC
645 }
646
167d8a88 647 m_mutex.Lock();
7368be43 648
167d8a88
SC
649 return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : wxCOND_MISC_ERROR;
650}
7368be43 651
167d8a88
SC
652wxCondError wxConditionInternal::Signal()
653{
654 wxCriticalSectionLocker lock(m_csWaiters);
7368be43 655
167d8a88 656 if ( m_numWaiters > 0 )
7368be43 657 {
167d8a88
SC
658 // increment the semaphore by 1
659 if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
660 return wxCOND_MISC_ERROR;
7368be43 661
167d8a88
SC
662 m_numWaiters--;
663 }
664
665 return wxCOND_NO_ERROR;
7368be43
SC
666}
667
167d8a88
SC
668wxCondError wxConditionInternal::Broadcast()
669{
670 wxCriticalSectionLocker lock(m_csWaiters);
671
672 while ( m_numWaiters > 0 )
673 {
674 if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
675 return wxCOND_MISC_ERROR;
7368be43 676
167d8a88
SC
677 m_numWaiters--;
678 }
679
680 return wxCOND_NO_ERROR;
681}
682#endif
7368be43
SC
683
684// ----------------------------------------------------------------------------
685// wxCriticalSection implementation
686// ----------------------------------------------------------------------------
687
688// XXX currently implemented as mutex in headers. Change to critical section.
689
690// ----------------------------------------------------------------------------
691// wxThread implementation
692// ----------------------------------------------------------------------------
693
694// wxThreadInternal class
695// ----------------------
696
697class wxThreadInternal
698{
699public:
167d8a88
SC
700 wxThreadInternal()
701 {
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;
715 }
716 ~wxThreadInternal()
7368be43 717 {
167d8a88
SC
718 if ( m_notifyQueueId)
719 {
720 MPDeleteQueue( m_notifyQueueId);
721 m_notifyQueueId = kInvalidID ;
722 }
7368be43
SC
723 }
724
167d8a88
SC
725 // thread function
726 static OSStatus MacThreadStart(void* arg);
727
728 // create a new (suspended) thread (for the given thread object)
729 bool Create(wxThread *thread, unsigned int stackSize);
730
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
748 wxThreadState GetState() const { return m_state; }
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; }
753
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; }
759
760 // the pause flag
761 void SetReallyPaused(bool paused) { m_isPaused = paused; }
762 bool IsReallyPaused() const { return m_isPaused; }
763
764 // tell the thread that it is a detached one
765 void Detach()
766 {
767 wxCriticalSectionLocker lock(m_csJoinFlag);
7368be43 768
167d8a88
SC
769 m_shouldBeJoined = FALSE;
770 m_isDetached = TRUE;
771 }
7368be43 772
167d8a88
SC
773private:
774 // the thread we're associated with
775 wxThread * m_thread;
7368be43 776
167d8a88
SC
777 MPTaskID m_tid; // thread id
778 MPQueueID m_notifyQueueId; // its notification queue
7368be43 779
167d8a88
SC
780 wxThreadState m_state; // see wxThreadState enum
781 int m_prio; // in wxWindows units: from 0 to 100
7368be43 782
167d8a88
SC
783 // this flag is set when the thread should terminate
784 bool m_cancelled;
7368be43 785
167d8a88
SC
786 // this flag is set when the thread is blocking on m_semSuspend
787 bool m_isPaused;
7368be43 788
167d8a88
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;
7368be43 792
167d8a88
SC
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;
7368be43 798
167d8a88
SC
799 // this semaphore is posted by Run() and the threads Entry() is not
800 // called before it is done
801 wxSemaphore m_semRun;
7368be43 802
167d8a88
SC
803 // this one is signaled when the thread should resume after having been
804 // Pause()d
805 wxSemaphore m_semSuspend;
806};
7368be43 807
167d8a88 808OSStatus wxThreadInternal::MacThreadStart(void *parameter)
7368be43 809{
167d8a88
SC
810 wxThread* thread = (wxThread*) parameter ;
811 wxThreadInternal *pthread = thread->m_internal;
812
813 // add to TLS so that This() will work
814 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread , (long) thread ) ) ;
7368be43 815
167d8a88
SC
816 // have to declare this before pthread_cleanup_push() which defines a
817 // block!
818 bool dontRunAtAll;
7368be43 819
167d8a88
SC
820 // wait for the semaphore to be posted from Run()
821 pthread->m_semRun.Wait();
7368be43 822
167d8a88
SC
823 // test whether we should run the run at all - may be it was deleted
824 // before it started to Run()?
7368be43 825 {
167d8a88
SC
826 wxCriticalSectionLocker lock(thread->m_critsect);
827
828 dontRunAtAll = pthread->GetState() == STATE_NEW &&
829 pthread->WasCancelled();
7368be43
SC
830 }
831
167d8a88 832 if ( !dontRunAtAll )
7368be43 833 {
167d8a88
SC
834 pthread->m_exitcode = thread->Entry();
835
836 {
837 wxCriticalSectionLocker lock(thread->m_critsect);
838 pthread->SetState(STATE_EXITED);
839 }
7368be43 840 }
167d8a88
SC
841
842 if ( dontRunAtAll )
843 {
844 if ( pthread->m_isDetached )
845 delete thread;
7368be43 846
167d8a88
SC
847 return -1 ;
848 }
849 else
850 {
851 // on mac for the running code the correct thread termination is to
852 // return
7368be43 853
167d8a88
SC
854 // terminate the thread
855 thread->Exit(pthread->m_exitcode);
856
857 return (OSStatus) NULL ; // pthread->m_exitcode;
858 }
859}
7368be43
SC
860
861bool wxThreadInternal::Create(wxThread *thread, unsigned int stackSize)
862{
167d8a88
SC
863 wxASSERT_MSG( m_state == STATE_NEW && !m_tid,
864 _T("Create()ing thread twice?") );
7368be43 865
167d8a88
SC
866 OSStatus err = noErr ;
867 m_thread = thread;
868
869 if ( m_notifyQueueId == kInvalidID )
7368be43 870 {
167d8a88
SC
871 OSStatus err = MPCreateQueue( & m_notifyQueueId);
872 if( err)
873 {
874 wxLogSysError(_("Cant create the thread event queue"));
875 return false;
876 }
7368be43 877 }
167d8a88
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)
891 {
892 wxLogSysError(_("Can't create thread"));
893 return false;
894 }
895
896 if ( m_prio != WXTHREAD_DEFAULT_PRIORITY )
897 {
898 SetPriority(m_prio);
899 }
900
901 return true;
7368be43
SC
902}
903
167d8a88 904void wxThreadInternal::SetPriority( int priority)
7368be43 905{
167d8a88
SC
906 m_prio = priority;
907
908 if ( m_tid)
7368be43 909 {
167d8a88
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);
7368be43 917 }
167d8a88 918}
7368be43 919
167d8a88
SC
920wxThreadError wxThreadInternal::Run()
921{
922 wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
923 wxT("thread may only be started once after Create()") );
7368be43 924
167d8a88 925 SetState(STATE_RUNNING);
7368be43 926
167d8a88
SC
927 // wake up threads waiting for our start
928 SignalRun();
929
930 return wxTHREAD_NO_ERROR;
7368be43
SC
931}
932
167d8a88 933void wxThreadInternal::Wait()
7368be43 934{
167d8a88
SC
935 wxCHECK_RET( !m_isDetached, _T("can't wait for a detached thread") );
936
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();
7368be43 941
7368be43 942 {
167d8a88
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 }
7368be43
SC
968 }
969
167d8a88
SC
970 // reacquire GUI mutex
971 if ( wxThread::IsMain() )
972 wxMutexGuiEnter();
7368be43
SC
973}
974
167d8a88
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().") );
981
982 // wait until the semaphore is Post()ed from Resume()
983 m_semSuspend.Wait();
984}
7368be43 985
167d8a88 986void wxThreadInternal::Resume()
7368be43 987{
167d8a88
SC
988 wxCHECK_RET( m_state == STATE_PAUSED,
989 wxT("can't resume thread which is not suspended.") );
7368be43 990
167d8a88
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() )
7368be43 994 {
167d8a88
SC
995 // wake up Pause()
996 m_semSuspend.Post();
7368be43 997
167d8a88
SC
998 // reset the flag
999 SetReallyPaused(FALSE);
1000 }
7368be43 1001
167d8a88 1002 SetState(STATE_RUNNING);
7368be43
SC
1003}
1004
7368be43
SC
1005// static functions
1006// ----------------
167d8a88 1007
7368be43
SC
1008wxThread *wxThread::This()
1009{
167d8a88
SC
1010 wxThread* thr = (wxThread*) MPGetTaskStorageValue( gs_tlsForWXThread ) ;
1011 return thr;
7368be43
SC
1012}
1013
1014bool wxThread::IsMain()
1015{
167d8a88 1016 return GetCurrentId() == gs_idMainThread;
7368be43
SC
1017}
1018
1019#ifdef Yield
1020#undef Yield
1021#endif
1022
1023void wxThread::Yield()
1024{
1025#if TARGET_API_MAC_OSX
167d8a88 1026 CFRunLoopRunInMode( kCFRunLoopDefaultMode , 0 , true ) ;
7368be43 1027#endif
167d8a88 1028 MPYield();
7368be43
SC
1029}
1030
1031
1032void wxThread::Sleep(unsigned long milliseconds)
1033{
167d8a88
SC
1034 AbsoluteTime wakeup = AddDurationToAbsolute( milliseconds, UpTime());
1035 MPDelayUntil( & wakeup);
7368be43
SC
1036}
1037
1038
1039int wxThread::GetCPUCount()
1040{
167d8a88 1041 return MPProcessors();
7368be43
SC
1042}
1043
1044unsigned long wxThread::GetCurrentId()
1045{
167d8a88 1046 return (unsigned long)MPCurrentTaskID();
7368be43
SC
1047}
1048
1049
7368be43
SC
1050bool wxThread::SetConcurrency(size_t level)
1051{
167d8a88
SC
1052 // Cannot be set in MacOS.
1053 return false;
7368be43
SC
1054}
1055
1056
1057wxThread::wxThread(wxThreadKind kind)
1058{
167d8a88
SC
1059 g_numberOfThreads++;
1060 m_internal = new wxThreadInternal();
1061
1062 m_isDetached = (kind == wxTHREAD_DETACHED);
7368be43
SC
1063}
1064
1065wxThread::~wxThread()
1066{
167d8a88
SC
1067 wxASSERT_MSG( g_numberOfThreads>0 , wxT("More threads deleted than created.") ) ;
1068 g_numberOfThreads--;
1069
7368be43 1070#ifdef __WXDEBUG__
167d8a88
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 )
7368be43 1076 {
167d8a88 1077 wxLogDebug(_T("The thread %ld is being destroyed although it is still running! The application may crash."), GetId());
7368be43 1078 }
7368be43 1079
167d8a88
SC
1080 m_critsect.Leave();
1081#endif // __WXDEBUG__
1082
1083 wxDELETE( m_internal ) ;
7368be43
SC
1084}
1085
1086
1087wxThreadError wxThread::Create(unsigned int stackSize)
1088{
167d8a88
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);
1098 return wxTHREAD_NO_RESOURCE;
1099 }
1100
1101 return wxTHREAD_NO_ERROR;
7368be43
SC
1102}
1103
1104wxThreadError wxThread::Run()
1105{
167d8a88 1106 wxCriticalSectionLocker lock(m_critsect);
7368be43 1107
167d8a88
SC
1108 wxCHECK_MSG( m_internal->GetId(), wxTHREAD_MISC_ERROR,
1109 wxT("must call wxThread::Create() first") );
1110
1111 return m_internal->Run();
7368be43
SC
1112}
1113
167d8a88
SC
1114// -----------------------------------------------------------------------------
1115// pause/resume
1116// -----------------------------------------------------------------------------
1117
7368be43
SC
1118wxThreadError wxThread::Pause()
1119{
167d8a88
SC
1120 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1121 _T("a thread can't pause itself") );
1122
1123 wxCriticalSectionLocker lock(m_critsect);
1124
1125 if ( m_internal->GetState() != STATE_RUNNING )
1126 {
1127 wxLogDebug(wxT("Can't pause thread which is not running."));
1128
1129 return wxTHREAD_NOT_RUNNING;
1130 }
1131
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);
1135
1136 return wxTHREAD_NO_ERROR;
7368be43
SC
1137}
1138
1139wxThreadError wxThread::Resume()
1140{
167d8a88
SC
1141 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1142 _T("a thread can't resume itself") );
7368be43 1143
167d8a88 1144 wxCriticalSectionLocker lock(m_critsect);
7368be43 1145
167d8a88 1146 wxThreadState state = m_internal->GetState();
7368be43 1147
167d8a88
SC
1148 switch ( state )
1149 {
1150 case STATE_PAUSED:
167d8a88 1151 m_internal->Resume();
167d8a88 1152 return wxTHREAD_NO_ERROR;
167d8a88 1153 case STATE_EXITED:
167d8a88 1154 return wxTHREAD_NO_ERROR;
7368be43 1155
167d8a88
SC
1156 default:
1157 wxLogDebug(_T("Attempt to resume a thread which is not paused."));
7368be43 1158
167d8a88
SC
1159 return wxTHREAD_MISC_ERROR;
1160 }
1161}
7368be43 1162
167d8a88
SC
1163// -----------------------------------------------------------------------------
1164// exiting thread
1165// -----------------------------------------------------------------------------
7368be43 1166
167d8a88
SC
1167wxThread::ExitCode wxThread::Wait()
1168{
1169 wxCHECK_MSG( This() != this, (ExitCode)-1,
1170 _T("a thread can't wait for itself") );
7368be43 1171
167d8a88
SC
1172 wxCHECK_MSG( !m_isDetached, (ExitCode)-1,
1173 _T("can't wait for detached thread") );
7368be43 1174
167d8a88 1175 m_internal->Wait();
7368be43 1176
167d8a88
SC
1177 return m_internal->GetExitCode();
1178}
7368be43 1179
167d8a88
SC
1180wxThreadError wxThread::Delete(ExitCode *rc)
1181{
1182 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1183 _T("a thread can't delete itself") );
7368be43 1184
167d8a88 1185 bool isDetached = m_isDetached;
7368be43 1186
167d8a88
SC
1187 m_critsect.Enter();
1188 wxThreadState state = m_internal->GetState();
1189
1190 // ask the thread to stop
1191 m_internal->SetCancelFlag();
7368be43 1192
167d8a88 1193 m_critsect.Leave();
7368be43 1194
167d8a88 1195 switch ( state )
7368be43 1196 {
167d8a88
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
7368be43
SC
1228 }
1229
167d8a88 1230 return wxTHREAD_NO_ERROR;
7368be43
SC
1231}
1232
1233wxThreadError wxThread::Kill()
1234{
167d8a88
SC
1235 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1236 _T("a thread can't kill itself") );
7368be43 1237
167d8a88 1238 switch ( m_internal->GetState() )
7368be43 1239 {
167d8a88
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;
7368be43 1270 }
167d8a88
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") );
7368be43 1277
167d8a88
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();
7368be43 1283
167d8a88
SC
1284 MPTerminateTask( m_internal->GetId() , (long) status) ;
1285
1286 if ( IsDetached() )
7368be43 1287 {
167d8a88
SC
1288 delete this;
1289 }
1290 else // joinable
1291 {
1292 // update the status of the joinable thread
1293 wxCriticalSectionLocker lock(m_critsect);
1294 m_internal->SetState(STATE_EXITED);
7368be43 1295 }
7368be43
SC
1296}
1297
167d8a88
SC
1298// also test whether we were paused
1299bool wxThread::TestDestroy()
7368be43 1300{
167d8a88
SC
1301 wxASSERT_MSG( This() == this,
1302 _T("wxThread::TestDestroy() can only be called in the context of the same thread") );
1303
1304 m_critsect.Enter();
7368be43 1305
167d8a88 1306 if ( m_internal->GetState() == STATE_PAUSED )
7368be43 1307 {
167d8a88
SC
1308 m_internal->SetReallyPaused(TRUE);
1309
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();
1314
1315 m_internal->Pause();
7368be43 1316 }
167d8a88 1317 else
7368be43 1318 {
167d8a88
SC
1319 // thread wasn't requested to pause, nothing to do
1320 m_critsect.Leave();
7368be43 1321 }
167d8a88
SC
1322
1323 return m_internal->WasCancelled();
7368be43
SC
1324}
1325
167d8a88
SC
1326// -----------------------------------------------------------------------------
1327// priority setting
1328// -----------------------------------------------------------------------------
1329
7368be43
SC
1330void wxThread::SetPriority(unsigned int prio)
1331{
167d8a88
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 }
7368be43
SC
1351}
1352
1353unsigned int wxThread::GetPriority() const
1354{
167d8a88
SC
1355 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
1356
1357 return m_internal->GetPriority();
7368be43
SC
1358}
1359
1360unsigned long wxThread::GetId() const
1361{
167d8a88
SC
1362 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
1363
1364 return (unsigned long)m_internal->GetId();
7368be43
SC
1365}
1366
167d8a88
SC
1367// -----------------------------------------------------------------------------
1368// state tests
1369// -----------------------------------------------------------------------------
1370
7368be43
SC
1371bool wxThread::IsRunning() const
1372{
167d8a88
SC
1373 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
1374
1375 return m_internal->GetState() == STATE_RUNNING;
7368be43
SC
1376}
1377
1378bool wxThread::IsAlive() const
1379{
167d8a88
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 }
7368be43
SC
1391}
1392
1393bool wxThread::IsPaused() const
1394{
167d8a88 1395 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
7368be43 1396
167d8a88 1397 return (m_internal->GetState() == STATE_PAUSED);
7368be43
SC
1398}
1399
1400// ----------------------------------------------------------------------------
1401// Automatic initialization for thread module
1402// ----------------------------------------------------------------------------
1403
1404class wxThreadModule : public wxModule
1405{
1406public:
167d8a88
SC
1407 virtual bool OnInit();
1408 virtual void OnExit();
1409
7368be43 1410private:
167d8a88
SC
1411 DECLARE_DYNAMIC_CLASS(wxThreadModule)
1412};
7368be43
SC
1413
1414IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
1415
167d8a88 1416bool wxThreadModule::OnInit()
7368be43 1417{
167d8a88
SC
1418 bool hasThreadManager = false ;
1419 hasThreadManager = MPLibraryIsLoaded();
7368be43 1420
167d8a88 1421 if ( !hasThreadManager )
7368be43 1422 {
d9d14984 1423 wxMessageBox( wxT("Error") , wxT("MP Thread Support is not available on this System" ), wxOK ) ;
167d8a88 1424 return FALSE ;
7368be43 1425 }
167d8a88
SC
1426
1427 verify_noerr( MPAllocateTaskStorageIndex( &gs_tlsForWXThread ) ) ;
1428 // main thread's This() is NULL
1429 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread , NULL ) ) ;
7368be43 1430
167d8a88
SC
1431 gs_idMainThread = wxThread::GetCurrentId() ;
1432
1433 gs_critsectWaitingForGui = new wxCriticalSection();
7368be43 1434
167d8a88
SC
1435 gs_critsectGui = new wxCriticalSection();
1436 gs_critsectGui->Enter();
1437
1438 return TRUE;
1439}
7368be43 1440
167d8a88
SC
1441void wxThreadModule::OnExit()
1442{
1443 if ( gs_critsectGui )
7368be43 1444 {
167d8a88
SC
1445 gs_critsectGui->Leave();
1446 delete gs_critsectGui;
1447 gs_critsectGui = NULL;
7368be43 1448 }
7368be43 1449
167d8a88
SC
1450 delete gs_critsectWaitingForGui;
1451 gs_critsectWaitingForGui = NULL;
7368be43
SC
1452}
1453
167d8a88
SC
1454// ----------------------------------------------------------------------------
1455// GUI Serialization copied from MSW implementation
1456// ----------------------------------------------------------------------------
1457
1458void WXDLLIMPEXP_BASE wxMutexGuiEnter()
7368be43 1459{
167d8a88
SC
1460 // this would dead lock everything...
1461 wxASSERT_MSG( !wxThread::IsMain(),
1462 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
7368be43 1463
167d8a88 1464 // the order in which we enter the critical sections here is crucial!!
7368be43 1465
167d8a88
SC
1466 // set the flag telling to the main thread that we want to do some GUI
1467 {
1468 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
7368be43 1469
167d8a88
SC
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();
7368be43
SC
1478}
1479
167d8a88 1480void WXDLLIMPEXP_BASE wxMutexGuiLeave()
7368be43 1481{
167d8a88
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 }
7368be43 1498
167d8a88
SC
1499 gs_critsectGui->Leave();
1500}
7368be43 1501
167d8a88 1502void WXDLLIMPEXP_BASE wxMutexGuiLeaveOrEnter()
7368be43 1503{
167d8a88
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 }
7368be43
SC
1530}
1531
167d8a88 1532bool WXDLLIMPEXP_BASE wxGuiOwnedByMainThread()
7368be43 1533{
167d8a88 1534 return gs_bGuiOwnedByMainThread;
7368be43
SC
1535}
1536
1537// wake up the main thread
1538void WXDLLEXPORT wxWakeUpMainThread()
1539{
167d8a88 1540 wxMacWakeUp() ;
7368be43
SC
1541}
1542
167d8a88
SC
1543// ----------------------------------------------------------------------------
1544// include common implementation code
1545// ----------------------------------------------------------------------------
7368be43
SC
1546
1547#include "wx/thrimpl.cpp"
1548
1549#endif // wxUSE_THREADS