]> git.saurik.com Git - wxWidgets.git/blob - src/osx/carbon/thread.cpp
Added ability to switch off more components of the size page UI
[wxWidgets.git] / src / osx / carbon / thread.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/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 #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
28 #if wxOSX_USE_COCOA_OR_CARBON
29 #include <CoreServices/CoreServices.h>
30 #else
31 #include <Foundation/Foundation.h>
32 #endif
33
34 #include "wx/osx/uma.h"
35
36 // the possible states of the thread:
37 // ("=>" shows all possible transitions from this state)
38 enum 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
52 wxThreadIdType wxThread::ms_idMainThread = kInvalidID;
53
54 // this is the Per-Task Storage for the pointer to the appropriate wxThread
55 TaskStorageIndex gs_tlsForWXThread = 0;
56
57 // if it's false, some secondary thread is holding the GUI lock
58 static 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
63 static wxCriticalSection *gs_critsectGui = NULL;
64
65 // critical section which protects gs_nWaitingForGui variable
66 static wxCriticalSection *gs_critsectWaitingForGui = NULL;
67
68 // number of threads waiting for GUI in wxMutexGuiEnter()
69 static size_t gs_nWaitingForGui = 0;
70
71 // overall number of threads, needed for determining
72 // the sleep value of the main event loop
73 size_t g_numberOfThreads = 0;
74
75
76 #if wxUSE_GUI
77 MPCriticalRegionID 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
109 wxCriticalSection::wxCriticalSection( wxCriticalSectionType WXUNUSED(critSecType) )
110 {
111 MPCreateCriticalRegion( (MPCriticalRegionID*) &m_critRegion );
112 }
113
114 wxCriticalSection::~wxCriticalSection()
115 {
116 MPDeleteCriticalRegion( (MPCriticalRegionID) m_critRegion );
117 }
118
119 void wxCriticalSection::Enter()
120 {
121 MPEnterCriticalRegion( (MPCriticalRegionID) m_critRegion, kDurationForever );
122 }
123
124 bool wxCriticalSection::TryEnter()
125 {
126 return MPEnterCriticalRegion( (MPCriticalRegionID) m_critRegion, kDurationImmediate ) == noErr;
127 }
128
129 void 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
142 #if wxUSE_MAC_CRITICAL_REGION_MUTEX
143
144 class wxMutexInternal
145 {
146 public:
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
157 private:
158 MPCriticalRegionID m_critRegion;
159 bool m_isOk ;
160 };
161
162 wxMutexInternal::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
175 wxMutexInternal::~wxMutexInternal()
176 {
177 if ( m_critRegion != kInvalidID )
178 MPDeleteCriticalRegion( m_critRegion );
179
180 MPYield();
181 }
182
183 wxMutexError 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
205 wxMutexError 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
222 wxMutexError 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
245 class wxSemaphoreInternal
246 {
247 public:
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
269 private:
270 MPSemaphoreID m_semaphore;
271 bool m_isOk;
272 };
273
274 wxSemaphoreInternal::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
291 wxSemaphoreInternal::~wxSemaphoreInternal()
292 {
293 if (m_semaphore != kInvalidID)
294 MPDeleteSemaphore( m_semaphore );
295
296 MPYield();
297 }
298
299 wxSemaError 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
313 wxSemaError 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
327 class wxConditionInternal
328 {
329 public:
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
341 private:
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
351 wxDECLARE_NO_COPY_CLASS(wxConditionInternal);
352 };
353
354 wxConditionInternal::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
362 wxCondError 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
386 wxCondError 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
427 wxCondError 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
443 wxCondError 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 }
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
471 class wxThreadInternal
472 {
473 public:
474 wxThreadInternal()
475 {
476 m_tid = kInvalidID;
477 m_state = STATE_NEW;
478 m_prio = wxPRIORITY_DEFAULT;
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
566 private:
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
601 OSStatus 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
654 bool wxThreadInternal::Create( wxThread *thread, unsigned int stackSize )
655 {
656 wxASSERT_MSG( m_state == STATE_NEW && !m_tid,
657 wxT("Create()ing thread twice?") );
658
659 OSStatus err = noErr;
660 m_thread = thread;
661
662 if ( m_notifyQueueId == kInvalidID )
663 {
664 OSStatus err = MPCreateQueue( &m_notifyQueueId );
665 if (err != noErr)
666 {
667 wxLogSysError( wxT("Can't create the thread event queue") );
668
669 return false;
670 }
671 }
672
673 m_state = STATE_NEW;
674
675 err = MPCreateTask(
676 MacThreadStart, (void*)m_thread, stackSize,
677 m_notifyQueueId, &m_exitcode, 0, 0, &m_tid );
678
679 if (err != noErr)
680 {
681 wxLogSysError( wxT("Can't create thread") );
682
683 return false;
684 }
685
686 if ( m_prio != wxPRIORITY_DEFAULT )
687 SetPriority( m_prio );
688
689 return true;
690 }
691
692 void wxThreadInternal::SetPriority( int priority )
693 {
694 m_prio = priority;
695
696 if (m_tid)
697 {
698 // Mac priorities range from 1 to 10,000, with a default of 100.
699 // wxWidgets priorities range from 0 to 100 with a default of 50.
700 // We can map wxWidgets to Mac priorities easily by assuming
701 // the former uses a logarithmic scale.
702 const unsigned int macPriority = (int)( exp( priority / 25.0 * log( 10.0)) + 0.5);
703
704 MPSetTaskWeight( m_tid, macPriority );
705 }
706 }
707
708 wxThreadError wxThreadInternal::Run()
709 {
710 wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
711 wxT("thread may only be started once after Create()") );
712
713 SetState( STATE_RUNNING );
714
715 // wake up threads waiting for our start
716 SignalRun();
717
718 return wxTHREAD_NO_ERROR;
719 }
720
721 void wxThreadInternal::Wait()
722 {
723 wxCHECK_RET( !m_isDetached, wxT("can't wait for a detached thread") );
724
725 // if the thread we're waiting for is waiting for the GUI mutex, we will
726 // deadlock so make sure we release it temporarily
727 if ( wxThread::IsMain() )
728 {
729 // give the thread we're waiting for chance to do the GUI call
730 // it might be in, we don't do this conditionally as the to be waited on
731 // thread might have to acquire the mutex later but before terminating
732 if ( wxGuiOwnedByMainThread() )
733 wxMutexGuiLeave();
734 }
735
736 {
737 wxCriticalSectionLocker lock(m_csJoinFlag);
738
739 if ( m_shouldBeJoined )
740 {
741 void *param1, *param2, *rc;
742
743 OSStatus err = MPWaitOnQueue(
744 m_notifyQueueId,
745 &param1,
746 &param2,
747 &rc,
748 kDurationForever );
749 if (err != noErr)
750 {
751 wxLogSysError( wxT( "Cannot wait for thread termination."));
752 rc = (void*) -1;
753 }
754
755 // actually param1 would be the address of m_exitcode
756 // but we don't need this here
757 m_exitcode = rc;
758
759 m_shouldBeJoined = false;
760 }
761 }
762 }
763
764 void wxThreadInternal::Pause()
765 {
766 // the state is set from the thread which pauses us first, this function
767 // is called later so the state should have been already set
768 wxCHECK_RET( m_state == STATE_PAUSED,
769 wxT("thread must first be paused with wxThread::Pause().") );
770
771 // wait until the semaphore is Post()ed from Resume()
772 m_semSuspend.Wait();
773 }
774
775 void wxThreadInternal::Resume()
776 {
777 wxCHECK_RET( m_state == STATE_PAUSED,
778 wxT("can't resume thread which is not suspended.") );
779
780 // the thread might be not actually paused yet - if there were no call to
781 // TestDestroy() since the last call to Pause() for example
782 if ( IsReallyPaused() )
783 {
784 // wake up Pause()
785 m_semSuspend.Post();
786
787 // reset the flag
788 SetReallyPaused( false );
789 }
790
791 SetState( STATE_RUNNING );
792 }
793
794 // static functions
795 // ----------------
796
797 wxThread *wxThread::This()
798 {
799 wxThread* thr = (wxThread*) MPGetTaskStorageValue( gs_tlsForWXThread ) ;
800
801 return thr;
802 }
803
804 #ifdef Yield
805 #undef Yield
806 #endif
807
808 void wxThread::Yield()
809 {
810 CFRunLoopRunInMode( kCFRunLoopDefaultMode , 0 , true ) ;
811
812 MPYield();
813 }
814
815 void wxThread::Sleep( unsigned long milliseconds )
816 {
817 AbsoluteTime wakeup = AddDurationToAbsolute( milliseconds, UpTime() );
818 MPDelayUntil( &wakeup );
819 }
820
821 int wxThread::GetCPUCount()
822 {
823 return MPProcessors();
824 }
825
826 unsigned long wxThread::GetCurrentId()
827 {
828 return (unsigned long)MPCurrentTaskID();
829 }
830
831 bool wxThread::SetConcurrency( size_t WXUNUSED(level) )
832 {
833 // Cannot be set in MacOS.
834 return false;
835 }
836
837 wxThread::wxThread( wxThreadKind kind )
838 {
839 g_numberOfThreads++;
840 m_internal = new wxThreadInternal();
841
842 m_isDetached = (kind == wxTHREAD_DETACHED);
843 }
844
845 wxThread::~wxThread()
846 {
847 wxASSERT_MSG( g_numberOfThreads>0 , wxT("More threads deleted than created.") ) ;
848
849 g_numberOfThreads--;
850
851 m_critsect.Enter();
852
853 // check that the thread either exited or couldn't be created
854 if ( m_internal->GetState() != STATE_EXITED &&
855 m_internal->GetState() != STATE_NEW )
856 {
857 wxLogDebug(
858 wxT("The thread %ld is being destroyed although it is still running! The application may crash."),
859 GetId() );
860 }
861
862 m_critsect.Leave();
863
864 wxDELETE( m_internal ) ;
865 }
866
867 wxThreadError wxThread::Create( unsigned int stackSize )
868 {
869 wxCriticalSectionLocker lock(m_critsect);
870
871 if ( m_isDetached )
872 m_internal->Detach() ;
873
874 if ( !m_internal->Create(this, stackSize) )
875 {
876 m_internal->SetState( STATE_EXITED );
877
878 return wxTHREAD_NO_RESOURCE;
879 }
880
881 return wxTHREAD_NO_ERROR;
882 }
883
884 wxThreadError wxThread::Run()
885 {
886 wxCriticalSectionLocker lock(m_critsect);
887
888 wxCHECK_MSG( m_internal->GetId(), wxTHREAD_MISC_ERROR,
889 wxT("must call wxThread::Create() first") );
890
891 return m_internal->Run();
892 }
893
894 // -----------------------------------------------------------------------------
895 // pause/resume
896 // -----------------------------------------------------------------------------
897
898 wxThreadError wxThread::Pause()
899 {
900 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
901 wxT("a thread can't pause itself") );
902
903 wxCriticalSectionLocker lock(m_critsect);
904
905 if ( m_internal->GetState() != STATE_RUNNING )
906 {
907 wxLogDebug( wxT("Can't pause thread which is not running.") );
908
909 return wxTHREAD_NOT_RUNNING;
910 }
911
912 // just set a flag, the thread will be really paused only during the next
913 // call to TestDestroy()
914 m_internal->SetState( STATE_PAUSED );
915
916 return wxTHREAD_NO_ERROR;
917 }
918
919 wxThreadError wxThread::Resume()
920 {
921 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
922 wxT("a thread can't resume itself") );
923
924 wxCriticalSectionLocker lock(m_critsect);
925
926 wxThreadState state = m_internal->GetState();
927
928 switch ( state )
929 {
930 case STATE_PAUSED:
931 m_internal->Resume();
932 return wxTHREAD_NO_ERROR;
933
934 case STATE_EXITED:
935 return wxTHREAD_NO_ERROR;
936
937 default:
938 wxLogDebug( wxT("Attempt to resume a thread which is not paused.") );
939
940 return wxTHREAD_MISC_ERROR;
941 }
942 }
943
944 // -----------------------------------------------------------------------------
945 // exiting thread
946 // -----------------------------------------------------------------------------
947
948 wxThread::ExitCode wxThread::Wait(wxThreadWait WXUNUSED(waitMode))
949 {
950 wxCHECK_MSG( This() != this, (ExitCode)-1,
951 wxT("a thread can't wait for itself") );
952
953 wxCHECK_MSG( !m_isDetached, (ExitCode)-1,
954 wxT("can't wait for detached thread") );
955
956 m_internal->Wait();
957
958 return m_internal->GetExitCode();
959 }
960
961 wxThreadError wxThread::Delete(ExitCode *rc, wxThreadWait WXUNUSED(waitMode))
962 {
963 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
964 wxT("a thread can't delete itself") );
965
966 bool isDetached = m_isDetached;
967
968 m_critsect.Enter();
969 wxThreadState state = m_internal->GetState();
970
971 // ask the thread to stop
972 m_internal->SetCancelFlag();
973
974 m_critsect.Leave();
975
976 switch ( state )
977 {
978 case STATE_NEW:
979 // we need to wake up the thread so that PthreadStart() will
980 // terminate - right now it's blocking on run semaphore in
981 // PthreadStart()
982 m_internal->SignalRun();
983
984 // fall through
985
986 case STATE_EXITED:
987 // nothing to do
988 break;
989
990 case STATE_PAUSED:
991 // resume the thread first
992 m_internal->Resume();
993
994 // fall through
995
996 default:
997 if ( !isDetached )
998 {
999 // wait until the thread stops
1000 m_internal->Wait();
1001
1002 if ( rc )
1003 {
1004 // return the exit code of the thread
1005 *rc = m_internal->GetExitCode();
1006 }
1007 }
1008 }
1009
1010 return wxTHREAD_NO_ERROR;
1011 }
1012
1013 wxThreadError wxThread::Kill()
1014 {
1015 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1016 wxT("a thread can't kill itself") );
1017
1018 switch ( m_internal->GetState() )
1019 {
1020 case STATE_NEW:
1021 case STATE_EXITED:
1022 return wxTHREAD_NOT_RUNNING;
1023
1024 case STATE_PAUSED:
1025 // resume the thread first
1026 Resume();
1027
1028 // fall through
1029
1030 default:
1031 OSStatus err = MPTerminateTask( m_internal->GetId() , -1 ) ;
1032 if (err != noErr)
1033 {
1034 wxLogError( wxT("Failed to terminate a thread.") );
1035
1036 return wxTHREAD_MISC_ERROR;
1037 }
1038
1039 if ( m_isDetached )
1040 {
1041 delete this ;
1042 }
1043 else
1044 {
1045 // this should be retrieved by Wait actually
1046 m_internal->SetExitCode( (void*)-1 );
1047 }
1048
1049 return wxTHREAD_NO_ERROR;
1050 }
1051 }
1052
1053 void wxThread::Exit( ExitCode status )
1054 {
1055 wxASSERT_MSG( This() == this,
1056 wxT("wxThread::Exit() can only be called in the context of the same thread") );
1057
1058 // don't enter m_critsect before calling OnExit() because the user code
1059 // might deadlock if, for example, it signals a condition in OnExit() (a
1060 // common case) while the main thread calls any of functions entering
1061 // m_critsect on us (almost all of them do)
1062 OnExit();
1063
1064 MPTaskID threadid = m_internal->GetId();
1065
1066 if ( IsDetached() )
1067 {
1068 delete this;
1069 }
1070 else // joinable
1071 {
1072 // update the status of the joinable thread
1073 wxCriticalSectionLocker lock( m_critsect );
1074 m_internal->SetState( STATE_EXITED );
1075 }
1076
1077 MPTerminateTask( threadid, (long)status );
1078 }
1079
1080 // also test whether we were paused
1081 bool wxThread::TestDestroy()
1082 {
1083 wxASSERT_MSG( This() == this,
1084 wxT("wxThread::TestDestroy() can only be called in the context of the same thread") );
1085
1086 m_critsect.Enter();
1087
1088 if ( m_internal->GetState() == STATE_PAUSED )
1089 {
1090 m_internal->SetReallyPaused( true );
1091
1092 // leave the crit section or the other threads will stop too if they attempt
1093 // to call any of (seemingly harmless) IsXXX() functions while we sleep
1094 m_critsect.Leave();
1095
1096 m_internal->Pause();
1097 }
1098 else
1099 {
1100 // thread wasn't requested to pause, nothing to do
1101 m_critsect.Leave();
1102 }
1103
1104 return m_internal->WasCancelled();
1105 }
1106
1107 // -----------------------------------------------------------------------------
1108 // priority setting
1109 // -----------------------------------------------------------------------------
1110
1111 void wxThread::SetPriority(unsigned int prio)
1112 {
1113 wxCHECK_RET( wxPRIORITY_MIN <= prio && prio <= wxPRIORITY_MAX,
1114 wxT("invalid thread priority") );
1115
1116 wxCriticalSectionLocker lock(m_critsect);
1117
1118 switch ( m_internal->GetState() )
1119 {
1120 case STATE_RUNNING:
1121 case STATE_PAUSED:
1122 case STATE_NEW:
1123 // thread not yet started, priority will be set when it is
1124 m_internal->SetPriority( prio );
1125 break;
1126
1127 case STATE_EXITED:
1128 default:
1129 wxFAIL_MSG( wxT("impossible to set thread priority in this state") );
1130 }
1131 }
1132
1133 unsigned int wxThread::GetPriority() const
1134 {
1135 wxCriticalSectionLocker lock(const_cast<wxCriticalSection &>(m_critsect));
1136
1137 return m_internal->GetPriority();
1138 }
1139
1140 unsigned long wxThread::GetId() const
1141 {
1142 wxCriticalSectionLocker lock(const_cast<wxCriticalSection &>(m_critsect));
1143
1144 return (unsigned long)m_internal->GetId();
1145 }
1146
1147 // -----------------------------------------------------------------------------
1148 // state tests
1149 // -----------------------------------------------------------------------------
1150
1151 bool wxThread::IsRunning() const
1152 {
1153 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
1154
1155 return m_internal->GetState() == STATE_RUNNING;
1156 }
1157
1158 bool wxThread::IsAlive() const
1159 {
1160 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
1161
1162 switch ( m_internal->GetState() )
1163 {
1164 case STATE_RUNNING:
1165 case STATE_PAUSED:
1166 return true;
1167
1168 default:
1169 return false;
1170 }
1171 }
1172
1173 bool wxThread::IsPaused() const
1174 {
1175 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
1176
1177 return (m_internal->GetState() == STATE_PAUSED);
1178 }
1179
1180 // ----------------------------------------------------------------------------
1181 // Automatic initialization for thread module
1182 // ----------------------------------------------------------------------------
1183
1184 class wxThreadModule : public wxModule
1185 {
1186 public:
1187 virtual bool OnInit();
1188 virtual void OnExit();
1189
1190 private:
1191 DECLARE_DYNAMIC_CLASS(wxThreadModule)
1192 };
1193
1194 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
1195
1196 bool wxThreadModule::OnInit()
1197 {
1198 bool hasThreadManager =
1199 #ifdef __LP64__
1200 true ; // TODO VERIFY IN NEXT BUILD
1201 #else
1202 MPLibraryIsLoaded();
1203 #endif
1204
1205 if ( !hasThreadManager )
1206 {
1207 wxLogError( wxT("MP thread support is not available on this system" ) ) ;
1208
1209 return false;
1210 }
1211
1212 // main thread's This() is NULL
1213 verify_noerr( MPAllocateTaskStorageIndex( &gs_tlsForWXThread ) ) ;
1214 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread, 0 ) ) ;
1215
1216 wxThread::ms_idMainThread = wxThread::GetCurrentId();
1217 gs_critsectWaitingForGui = new wxCriticalSection();
1218
1219 gs_critsectGui = new wxCriticalSection();
1220 gs_critsectGui->Enter();
1221
1222 return true;
1223 }
1224
1225 void wxThreadModule::OnExit()
1226 {
1227 if ( gs_critsectGui )
1228 {
1229 if ( !wxGuiOwnedByMainThread() )
1230 {
1231 gs_critsectGui->Enter();
1232 gs_bGuiOwnedByMainThread = true;
1233 }
1234
1235 gs_critsectGui->Leave();
1236 wxDELETE(gs_critsectGui);
1237 }
1238
1239 wxDELETE(gs_critsectWaitingForGui);
1240 }
1241
1242 // ----------------------------------------------------------------------------
1243 // GUI Serialization copied from MSW implementation
1244 // ----------------------------------------------------------------------------
1245
1246 void wxMutexGuiEnterImpl()
1247 {
1248 // this would dead lock everything...
1249 wxASSERT_MSG( !wxThread::IsMain(),
1250 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
1251
1252 // the order in which we enter the critical sections here is crucial!!
1253
1254 // set the flag telling to the main thread that we want to do some GUI
1255 {
1256 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1257
1258 gs_nWaitingForGui++;
1259 }
1260
1261 wxWakeUpMainThread();
1262
1263 // now we may block here because the main thread will soon let us in
1264 // (during the next iteration of OnIdle())
1265 gs_critsectGui->Enter();
1266 }
1267
1268 void wxMutexGuiLeaveImpl()
1269 {
1270 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1271
1272 if ( wxThread::IsMain() )
1273 {
1274 gs_bGuiOwnedByMainThread = false;
1275 }
1276 else
1277 {
1278 // decrement the number of threads waiting for GUI access now
1279 wxASSERT_MSG( gs_nWaitingForGui > 0,
1280 wxT("calling wxMutexGuiLeave() without entering it first?") );
1281
1282 gs_nWaitingForGui--;
1283
1284 wxWakeUpMainThread();
1285 }
1286
1287 gs_critsectGui->Leave();
1288 }
1289
1290 void WXDLLIMPEXP_BASE wxMutexGuiLeaveOrEnter()
1291 {
1292 wxASSERT_MSG( wxThread::IsMain(),
1293 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1294
1295 if ( !gs_critsectWaitingForGui )
1296 return;
1297
1298 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1299
1300 if ( gs_nWaitingForGui == 0 )
1301 {
1302 // no threads are waiting for GUI - so we may acquire the lock without
1303 // any danger (but only if we don't already have it)
1304 if ( !wxGuiOwnedByMainThread() )
1305 {
1306 gs_critsectGui->Enter();
1307
1308 gs_bGuiOwnedByMainThread = true;
1309 }
1310 //else: already have it, nothing to do
1311 }
1312 else
1313 {
1314 // some threads are waiting, release the GUI lock if we have it
1315 if ( wxGuiOwnedByMainThread() )
1316 wxMutexGuiLeave();
1317 //else: some other worker thread is doing GUI
1318 }
1319 }
1320
1321 bool WXDLLIMPEXP_BASE wxGuiOwnedByMainThread()
1322 {
1323 return gs_bGuiOwnedByMainThread;
1324 }
1325
1326 // wake up the main thread
1327 void WXDLLEXPORT wxWakeUpMainThread()
1328 {
1329 wxMacWakeUp();
1330 }
1331
1332 // ----------------------------------------------------------------------------
1333 // include common implementation code
1334 // ----------------------------------------------------------------------------
1335
1336 #include "wx/thrimpl.cpp"
1337
1338 #endif // wxUSE_THREADS