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