]> git.saurik.com Git - wxWidgets.git/blob - src/osx/carbon/thread.cpp
fixing 64 bit value transfer
[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 static wxThreadIdType gs_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 void wxCriticalSection::Leave()
125 {
126 MPExitCriticalRegion( (MPCriticalRegionID) m_critRegion );
127 }
128
129 // ----------------------------------------------------------------------------
130 // wxMutex implementation
131 // ----------------------------------------------------------------------------
132
133 #define wxUSE_MAC_SEMAPHORE_MUTEX 0
134 #define wxUSE_MAC_CRITICAL_REGION_MUTEX 1
135 #define wxUSE_MAC_PTHREADS_MUTEX 0
136
137 #if wxUSE_MAC_CRITICAL_REGION_MUTEX
138
139 class wxMutexInternal
140 {
141 public:
142 wxMutexInternal( wxMutexType mutexType );
143 virtual ~wxMutexInternal();
144
145 bool IsOk() const { return m_isOk; }
146
147 wxMutexError Lock() { return Lock(kDurationForever); }
148 wxMutexError Lock(unsigned long ms);
149 wxMutexError TryLock();
150 wxMutexError Unlock();
151
152 private:
153 MPCriticalRegionID m_critRegion;
154 bool m_isOk ;
155 };
156
157 wxMutexInternal::wxMutexInternal( wxMutexType WXUNUSED(mutexType) )
158 {
159 m_isOk = false;
160 m_critRegion = kInvalidID;
161
162 verify_noerr( MPCreateCriticalRegion( &m_critRegion ) );
163 m_isOk = ( m_critRegion != kInvalidID );
164 if ( !IsOk() )
165 {
166 wxFAIL_MSG( wxT("Error when creating mutex") );
167 }
168 }
169
170 wxMutexInternal::~wxMutexInternal()
171 {
172 if ( m_critRegion != kInvalidID )
173 MPDeleteCriticalRegion( m_critRegion );
174
175 MPYield();
176 }
177
178 wxMutexError wxMutexInternal::Lock(unsigned long ms)
179 {
180 wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") );
181
182 OSStatus err = MPEnterCriticalRegion( m_critRegion, ms );
183 switch ( err )
184 {
185 case noErr:
186 break;
187
188 case kMPTimeoutErr:
189 wxASSERT_MSG( ms != kDurationForever, wxT("unexpected timeout") );
190 return wxMUTEX_TIMEOUT;
191
192 default:
193 wxLogSysError(wxT("Could not lock mutex"));
194 return wxMUTEX_MISC_ERROR;
195 }
196
197 return wxMUTEX_NO_ERROR;
198 }
199
200 wxMutexError wxMutexInternal::TryLock()
201 {
202 wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ;
203
204 OSStatus err = MPEnterCriticalRegion( m_critRegion, kDurationImmediate);
205 if (err != noErr)
206 {
207 if ( err == kMPTimeoutErr)
208 return wxMUTEX_BUSY;
209
210 wxLogSysError( wxT("Could not try lock mutex") );
211 return wxMUTEX_MISC_ERROR;
212 }
213
214 return wxMUTEX_NO_ERROR;
215 }
216
217 wxMutexError wxMutexInternal::Unlock()
218 {
219 wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ;
220
221 OSStatus err = MPExitCriticalRegion( m_critRegion );
222 MPYield() ;
223
224 if (err != noErr)
225 {
226 wxLogSysError( wxT("Could not unlock mutex") );
227
228 return wxMUTEX_MISC_ERROR;
229 }
230
231 return wxMUTEX_NO_ERROR;
232 }
233
234 #endif
235
236 // --------------------------------------------------------------------------
237 // wxSemaphore
238 // --------------------------------------------------------------------------
239
240 class wxSemaphoreInternal
241 {
242 public:
243 wxSemaphoreInternal( int initialcount, int maxcount );
244 virtual ~wxSemaphoreInternal();
245
246 bool IsOk() const
247 { return m_isOk; }
248
249 wxSemaError Post();
250 wxSemaError WaitTimeout( unsigned long milliseconds );
251
252 wxSemaError Wait()
253 { return WaitTimeout( kDurationForever); }
254
255 wxSemaError TryWait()
256 {
257 wxSemaError err = WaitTimeout( kDurationImmediate );
258 if (err == wxSEMA_TIMEOUT)
259 err = wxSEMA_BUSY;
260
261 return err;
262 }
263
264 private:
265 MPSemaphoreID m_semaphore;
266 bool m_isOk;
267 };
268
269 wxSemaphoreInternal::wxSemaphoreInternal( int initialcount, int maxcount)
270 {
271 m_isOk = false;
272 m_semaphore = kInvalidID;
273 if ( maxcount == 0 )
274 // make it practically infinite
275 maxcount = INT_MAX;
276
277 verify_noerr( MPCreateSemaphore( maxcount, initialcount, &m_semaphore ) );
278 m_isOk = ( m_semaphore != kInvalidID );
279
280 if ( !IsOk() )
281 {
282 wxFAIL_MSG( wxT("Error when creating semaphore") );
283 }
284 }
285
286 wxSemaphoreInternal::~wxSemaphoreInternal()
287 {
288 if (m_semaphore != kInvalidID)
289 MPDeleteSemaphore( m_semaphore );
290
291 MPYield();
292 }
293
294 wxSemaError wxSemaphoreInternal::WaitTimeout( unsigned long milliseconds )
295 {
296 OSStatus err = MPWaitOnSemaphore( m_semaphore, milliseconds );
297 if (err != noErr)
298 {
299 if (err == kMPTimeoutErr)
300 return wxSEMA_TIMEOUT;
301
302 return wxSEMA_MISC_ERROR;
303 }
304
305 return wxSEMA_NO_ERROR;
306 }
307
308 wxSemaError wxSemaphoreInternal::Post()
309 {
310 OSStatus err = MPSignalSemaphore( m_semaphore );
311 MPYield();
312 if (err != noErr)
313 return wxSEMA_MISC_ERROR;
314
315 return wxSEMA_NO_ERROR;
316 }
317
318 // ----------------------------------------------------------------------------
319 // wxCondition implementation
320 // ----------------------------------------------------------------------------
321
322 class wxConditionInternal
323 {
324 public:
325 wxConditionInternal( wxMutex& mutex );
326
327 bool IsOk() const
328 { return m_mutex.IsOk() && m_semaphore.IsOk(); }
329
330 wxCondError Wait();
331 wxCondError WaitTimeout( unsigned long milliseconds );
332
333 wxCondError Signal();
334 wxCondError Broadcast();
335
336 private:
337 // the number of threads currently waiting for this condition
338 SInt32 m_numWaiters;
339
340 // the critical section protecting m_numWaiters
341 wxCriticalSection m_csWaiters;
342
343 wxMutex& m_mutex;
344 wxSemaphore m_semaphore;
345
346 wxDECLARE_NO_COPY_CLASS(wxConditionInternal);
347 };
348
349 wxConditionInternal::wxConditionInternal( wxMutex& mutex )
350 : m_mutex(mutex)
351 {
352 // another thread can't access it until we return from ctor, so no need to
353 // protect access to m_numWaiters here
354 m_numWaiters = 0;
355 }
356
357 wxCondError wxConditionInternal::Wait()
358 {
359 // increment the number of waiters
360 IncrementAtomic( &m_numWaiters );
361
362 m_mutex.Unlock();
363
364 // a potential race condition can occur here
365 //
366 // after a thread increments nwaiters, and unlocks the mutex and before the
367 // semaphore.Wait() is called, if another thread can cause a signal to be
368 // generated
369 //
370 // this race condition is handled by using a semaphore and incrementing the
371 // semaphore only if 'nwaiters' is greater that zero since the semaphore,
372 // can 'remember' signals the race condition will not occur
373
374 // wait ( if necessary ) and decrement semaphore
375 wxSemaError err = m_semaphore.Wait();
376 m_mutex.Lock();
377
378 return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : wxCOND_MISC_ERROR;
379 }
380
381 wxCondError wxConditionInternal::WaitTimeout( unsigned long milliseconds )
382 {
383 IncrementAtomic( &m_numWaiters );
384
385 m_mutex.Unlock();
386
387 // a race condition can occur at this point in the code
388 //
389 // please see the comments in Wait(), for details
390
391 wxSemaError err = m_semaphore.WaitTimeout(milliseconds);
392
393 if ( err == wxSEMA_TIMEOUT )
394 {
395 // another potential race condition exists here it is caused when a
396 // 'waiting' thread timesout, and returns from WaitForSingleObject, but
397 // has not yet decremented 'nwaiters'.
398 //
399 // at this point if another thread calls signal() then the semaphore
400 // will be incremented, but the waiting thread will miss it.
401 //
402 // to handle this particular case, the waiting thread calls
403 // WaitForSingleObject again with a timeout of 0, after locking
404 // 'nwaiters_mutex'. this call does not block because of the zero
405 // timeout, but will allow the waiting thread to catch the missed
406 // signals.
407 wxCriticalSectionLocker lock(m_csWaiters);
408
409 err = m_semaphore.WaitTimeout(0);
410
411 if ( err != wxSEMA_NO_ERROR )
412 {
413 m_numWaiters--;
414 }
415 }
416
417 m_mutex.Lock();
418
419 return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : wxCOND_MISC_ERROR;
420 }
421
422 wxCondError wxConditionInternal::Signal()
423 {
424 wxCriticalSectionLocker lock(m_csWaiters);
425
426 if ( m_numWaiters > 0 )
427 {
428 // increment the semaphore by 1
429 if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
430 return wxCOND_MISC_ERROR;
431
432 m_numWaiters--;
433 }
434
435 return wxCOND_NO_ERROR;
436 }
437
438 wxCondError wxConditionInternal::Broadcast()
439 {
440 wxCriticalSectionLocker lock(m_csWaiters);
441
442 while ( m_numWaiters > 0 )
443 {
444 if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
445 return wxCOND_MISC_ERROR;
446
447 m_numWaiters--;
448 }
449
450 return wxCOND_NO_ERROR;
451 }
452
453 // ----------------------------------------------------------------------------
454 // wxCriticalSection implementation
455 // ----------------------------------------------------------------------------
456
457 // XXX currently implemented as mutex in headers. Change to critical section.
458
459 // ----------------------------------------------------------------------------
460 // wxThread implementation
461 // ----------------------------------------------------------------------------
462
463 // wxThreadInternal class
464 // ----------------------
465
466 class wxThreadInternal
467 {
468 public:
469 wxThreadInternal()
470 {
471 m_tid = kInvalidID;
472 m_state = STATE_NEW;
473 m_prio = WXTHREAD_DEFAULT_PRIORITY;
474 m_notifyQueueId = kInvalidID;
475 m_exitcode = 0;
476 m_cancelled = false ;
477
478 // set to true only when the thread starts waiting on m_semSuspend
479 m_isPaused = false;
480
481 // defaults for joinable threads
482 m_shouldBeJoined = true;
483 m_isDetached = false;
484 }
485
486 virtual ~wxThreadInternal()
487 {
488 if ( m_notifyQueueId)
489 {
490 MPDeleteQueue( m_notifyQueueId );
491 m_notifyQueueId = kInvalidID ;
492 }
493 }
494
495 // thread function
496 static OSStatus MacThreadStart(void* arg);
497
498 // create a new (suspended) thread (for the given thread object)
499 bool Create(wxThread *thread, unsigned int stackSize);
500
501 // thread actions
502
503 // start the thread
504 wxThreadError Run();
505
506 // unblock the thread allowing it to run
507 void SignalRun() { m_semRun.Post(); }
508
509 // ask the thread to terminate
510 void Wait();
511
512 // go to sleep until Resume() is called
513 void Pause();
514
515 // resume the thread
516 void Resume();
517
518 // accessors
519 // priority
520 int GetPriority() const
521 { return m_prio; }
522 void SetPriority(int prio);
523
524 // state
525 wxThreadState GetState() const
526 { return m_state; }
527 void SetState(wxThreadState state)
528 { m_state = state; }
529
530 // Get the ID of this thread's underlying MP Services task.
531 MPTaskID GetId() const
532 { return m_tid; }
533
534 void SetCancelFlag()
535 { m_cancelled = true; }
536
537 bool WasCancelled() const
538 { return m_cancelled; }
539
540 // exit code
541 void SetExitCode(wxThread::ExitCode exitcode)
542 { m_exitcode = exitcode; }
543 wxThread::ExitCode GetExitCode() const
544 { return m_exitcode; }
545
546 // the pause flag
547 void SetReallyPaused(bool paused)
548 { m_isPaused = paused; }
549 bool IsReallyPaused() const
550 { return m_isPaused; }
551
552 // tell the thread that it is a detached one
553 void Detach()
554 {
555 wxCriticalSectionLocker lock(m_csJoinFlag);
556
557 m_shouldBeJoined = false;
558 m_isDetached = true;
559 }
560
561 private:
562 // the thread we're associated with
563 wxThread * m_thread;
564
565 MPTaskID m_tid; // thread id
566 MPQueueID m_notifyQueueId; // its notification queue
567
568 wxThreadState m_state; // see wxThreadState enum
569 int m_prio; // in wxWidgets units: from 0 to 100
570
571 // this flag is set when the thread should terminate
572 bool m_cancelled;
573
574 // this flag is set when the thread is blocking on m_semSuspend
575 bool m_isPaused;
576
577 // the thread exit code - only used for joinable (!detached) threads and
578 // is only valid after the thread termination
579 wxThread::ExitCode m_exitcode;
580
581 // many threads may call Wait(), but only one of them should call
582 // pthread_join(), so we have to keep track of this
583 wxCriticalSection m_csJoinFlag;
584 bool m_shouldBeJoined;
585 bool m_isDetached;
586
587 // this semaphore is posted by Run() and the threads Entry() is not
588 // called before it is done
589 wxSemaphore m_semRun;
590
591 // this one is signaled when the thread should resume after having been
592 // Pause()d
593 wxSemaphore m_semSuspend;
594 };
595
596 OSStatus wxThreadInternal::MacThreadStart(void *parameter)
597 {
598 wxThread* thread = (wxThread*) parameter ;
599 wxThreadInternal *pthread = thread->m_internal;
600
601 // add to TLS so that This() will work
602 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread , (TaskStorageValue) thread ) ) ;
603
604 // have to declare this before pthread_cleanup_push() which defines a
605 // block!
606 bool dontRunAtAll;
607
608 // wait for the semaphore to be posted from Run()
609 pthread->m_semRun.Wait();
610
611 // test whether we should run the run at all - may be it was deleted
612 // before it started to Run()?
613 {
614 wxCriticalSectionLocker lock(thread->m_critsect);
615
616 dontRunAtAll = pthread->GetState() == STATE_NEW &&
617 pthread->WasCancelled();
618 }
619
620 if ( !dontRunAtAll )
621 {
622 pthread->m_exitcode = thread->Entry();
623
624 {
625 wxCriticalSectionLocker lock(thread->m_critsect);
626 pthread->SetState( STATE_EXITED );
627 }
628 }
629
630 if ( dontRunAtAll )
631 {
632 if ( pthread->m_isDetached )
633 delete thread;
634
635 return -1;
636 }
637 else
638 {
639 // on Mac for the running code,
640 // the correct thread termination is to return
641
642 // terminate the thread
643 thread->Exit( pthread->m_exitcode );
644
645 return (OSStatus) NULL; // pthread->m_exitcode;
646 }
647 }
648
649 bool wxThreadInternal::Create( wxThread *thread, unsigned int stackSize )
650 {
651 wxASSERT_MSG( m_state == STATE_NEW && !m_tid,
652 wxT("Create()ing thread twice?") );
653
654 OSStatus err = noErr;
655 m_thread = thread;
656
657 if ( m_notifyQueueId == kInvalidID )
658 {
659 OSStatus err = MPCreateQueue( &m_notifyQueueId );
660 if (err != noErr)
661 {
662 wxLogSysError( wxT("Cant create the thread event queue") );
663
664 return false;
665 }
666 }
667
668 m_state = STATE_NEW;
669
670 err = MPCreateTask(
671 MacThreadStart, (void*)m_thread, stackSize,
672 m_notifyQueueId, &m_exitcode, 0, 0, &m_tid );
673
674 if (err != noErr)
675 {
676 wxLogSysError( wxT("Can't create thread") );
677
678 return false;
679 }
680
681 if ( m_prio != WXTHREAD_DEFAULT_PRIORITY )
682 SetPriority( m_prio );
683
684 return true;
685 }
686
687 void wxThreadInternal::SetPriority( int priority )
688 {
689 m_prio = priority;
690
691 if (m_tid)
692 {
693 // Mac priorities range from 1 to 10,000, with a default of 100.
694 // wxWidgets priorities range from 0 to 100 with a default of 50.
695 // We can map wxWidgets to Mac priorities easily by assuming
696 // the former uses a logarithmic scale.
697 const unsigned int macPriority = (int)( exp( priority / 25.0 * log( 10.0)) + 0.5);
698
699 MPSetTaskWeight( m_tid, macPriority );
700 }
701 }
702
703 wxThreadError wxThreadInternal::Run()
704 {
705 wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
706 wxT("thread may only be started once after Create()") );
707
708 SetState( STATE_RUNNING );
709
710 // wake up threads waiting for our start
711 SignalRun();
712
713 return wxTHREAD_NO_ERROR;
714 }
715
716 void wxThreadInternal::Wait()
717 {
718 wxCHECK_RET( !m_isDetached, wxT("can't wait for a detached thread") );
719
720 // if the thread we're waiting for is waiting for the GUI mutex, we will
721 // deadlock so make sure we release it temporarily
722 if ( wxThread::IsMain() )
723 {
724 // give the thread we're waiting for chance to do the GUI call
725 // it might be in, we don't do this conditionally as the to be waited on
726 // thread might have to acquire the mutex later but before terminating
727 if ( wxGuiOwnedByMainThread() )
728 wxMutexGuiLeave();
729 }
730
731 {
732 wxCriticalSectionLocker lock(m_csJoinFlag);
733
734 if ( m_shouldBeJoined )
735 {
736 void *param1, *param2, *rc;
737
738 OSStatus err = MPWaitOnQueue(
739 m_notifyQueueId,
740 &param1,
741 &param2,
742 &rc,
743 kDurationForever );
744 if (err != noErr)
745 {
746 wxLogSysError( wxT( "Cannot wait for thread termination."));
747 rc = (void*) -1;
748 }
749
750 // actually param1 would be the address of m_exitcode
751 // but we don't need this here
752 m_exitcode = rc;
753
754 m_shouldBeJoined = false;
755 }
756 }
757 }
758
759 void wxThreadInternal::Pause()
760 {
761 // the state is set from the thread which pauses us first, this function
762 // is called later so the state should have been already set
763 wxCHECK_RET( m_state == STATE_PAUSED,
764 wxT("thread must first be paused with wxThread::Pause().") );
765
766 // wait until the semaphore is Post()ed from Resume()
767 m_semSuspend.Wait();
768 }
769
770 void wxThreadInternal::Resume()
771 {
772 wxCHECK_RET( m_state == STATE_PAUSED,
773 wxT("can't resume thread which is not suspended.") );
774
775 // the thread might be not actually paused yet - if there were no call to
776 // TestDestroy() since the last call to Pause() for example
777 if ( IsReallyPaused() )
778 {
779 // wake up Pause()
780 m_semSuspend.Post();
781
782 // reset the flag
783 SetReallyPaused( false );
784 }
785
786 SetState( STATE_RUNNING );
787 }
788
789 // static functions
790 // ----------------
791
792 wxThread *wxThread::This()
793 {
794 wxThread* thr = (wxThread*) MPGetTaskStorageValue( gs_tlsForWXThread ) ;
795
796 return thr;
797 }
798
799 bool wxThread::IsMain()
800 {
801 return GetCurrentId() == gs_idMainThread || gs_idMainThread == kInvalidID ;
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 _T("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()
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)
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( ((int)WXTHREAD_MIN_PRIORITY <= (int)prio) &&
1114 ((int)prio <= (int)WXTHREAD_MAX_PRIORITY),
1115 wxT("invalid thread priority") );
1116
1117 wxCriticalSectionLocker lock(m_critsect);
1118
1119 switch ( m_internal->GetState() )
1120 {
1121 case STATE_RUNNING:
1122 case STATE_PAUSED:
1123 case STATE_NEW:
1124 // thread not yet started, priority will be set when it is
1125 m_internal->SetPriority( prio );
1126 break;
1127
1128 case STATE_EXITED:
1129 default:
1130 wxFAIL_MSG( wxT("impossible to set thread priority in this state") );
1131 }
1132 }
1133
1134 unsigned int wxThread::GetPriority() const
1135 {
1136 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
1137
1138 return m_internal->GetPriority();
1139 }
1140
1141 unsigned long wxThread::GetId() const
1142 {
1143 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
1144
1145 return (unsigned long)m_internal->GetId();
1146 }
1147
1148 // -----------------------------------------------------------------------------
1149 // state tests
1150 // -----------------------------------------------------------------------------
1151
1152 bool wxThread::IsRunning() const
1153 {
1154 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
1155
1156 return m_internal->GetState() == STATE_RUNNING;
1157 }
1158
1159 bool wxThread::IsAlive() const
1160 {
1161 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
1162
1163 switch ( m_internal->GetState() )
1164 {
1165 case STATE_RUNNING:
1166 case STATE_PAUSED:
1167 return true;
1168
1169 default:
1170 return false;
1171 }
1172 }
1173
1174 bool wxThread::IsPaused() const
1175 {
1176 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
1177
1178 return (m_internal->GetState() == STATE_PAUSED);
1179 }
1180
1181 // ----------------------------------------------------------------------------
1182 // Automatic initialization for thread module
1183 // ----------------------------------------------------------------------------
1184
1185 class wxThreadModule : public wxModule
1186 {
1187 public:
1188 virtual bool OnInit();
1189 virtual void OnExit();
1190
1191 private:
1192 DECLARE_DYNAMIC_CLASS(wxThreadModule)
1193 };
1194
1195 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
1196
1197 bool wxThreadModule::OnInit()
1198 {
1199 bool hasThreadManager =
1200 #ifdef __LP64__
1201 true ; // TODO VERIFY IN NEXT BUILD
1202 #else
1203 MPLibraryIsLoaded();
1204 #endif
1205
1206 if ( !hasThreadManager )
1207 {
1208 wxLogError( wxT("MP thread support is not available on this system" ) ) ;
1209
1210 return false;
1211 }
1212
1213 // main thread's This() is NULL
1214 verify_noerr( MPAllocateTaskStorageIndex( &gs_tlsForWXThread ) ) ;
1215 verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread, 0 ) ) ;
1216
1217 gs_idMainThread = wxThread::GetCurrentId();
1218 gs_critsectWaitingForGui = new wxCriticalSection();
1219
1220 gs_critsectGui = new wxCriticalSection();
1221 gs_critsectGui->Enter();
1222
1223 return true;
1224 }
1225
1226 void wxThreadModule::OnExit()
1227 {
1228 if ( gs_critsectGui )
1229 {
1230 if ( !wxGuiOwnedByMainThread() )
1231 {
1232 gs_critsectGui->Enter();
1233 gs_bGuiOwnedByMainThread = true;
1234 }
1235
1236 gs_critsectGui->Leave();
1237 delete gs_critsectGui;
1238 gs_critsectGui = NULL;
1239 }
1240
1241 delete gs_critsectWaitingForGui;
1242 gs_critsectWaitingForGui = NULL;
1243 }
1244
1245 // ----------------------------------------------------------------------------
1246 // GUI Serialization copied from MSW implementation
1247 // ----------------------------------------------------------------------------
1248
1249 void wxMutexGuiEnterImpl()
1250 {
1251 // this would dead lock everything...
1252 wxASSERT_MSG( !wxThread::IsMain(),
1253 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
1254
1255 // the order in which we enter the critical sections here is crucial!!
1256
1257 // set the flag telling to the main thread that we want to do some GUI
1258 {
1259 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1260
1261 gs_nWaitingForGui++;
1262 }
1263
1264 wxWakeUpMainThread();
1265
1266 // now we may block here because the main thread will soon let us in
1267 // (during the next iteration of OnIdle())
1268 gs_critsectGui->Enter();
1269 }
1270
1271 void wxMutexGuiLeaveImpl()
1272 {
1273 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1274
1275 if ( wxThread::IsMain() )
1276 {
1277 gs_bGuiOwnedByMainThread = false;
1278 }
1279 else
1280 {
1281 // decrement the number of threads waiting for GUI access now
1282 wxASSERT_MSG( gs_nWaitingForGui > 0,
1283 wxT("calling wxMutexGuiLeave() without entering it first?") );
1284
1285 gs_nWaitingForGui--;
1286
1287 wxWakeUpMainThread();
1288 }
1289
1290 gs_critsectGui->Leave();
1291 }
1292
1293 void WXDLLIMPEXP_BASE wxMutexGuiLeaveOrEnter()
1294 {
1295 wxASSERT_MSG( wxThread::IsMain(),
1296 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1297
1298 if ( !gs_critsectWaitingForGui )
1299 return;
1300
1301 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1302
1303 if ( gs_nWaitingForGui == 0 )
1304 {
1305 // no threads are waiting for GUI - so we may acquire the lock without
1306 // any danger (but only if we don't already have it)
1307 if ( !wxGuiOwnedByMainThread() )
1308 {
1309 gs_critsectGui->Enter();
1310
1311 gs_bGuiOwnedByMainThread = true;
1312 }
1313 //else: already have it, nothing to do
1314 }
1315 else
1316 {
1317 // some threads are waiting, release the GUI lock if we have it
1318 if ( wxGuiOwnedByMainThread() )
1319 wxMutexGuiLeave();
1320 //else: some other worker thread is doing GUI
1321 }
1322 }
1323
1324 bool WXDLLIMPEXP_BASE wxGuiOwnedByMainThread()
1325 {
1326 return gs_bGuiOwnedByMainThread;
1327 }
1328
1329 // wake up the main thread
1330 void WXDLLEXPORT wxWakeUpMainThread()
1331 {
1332 wxMacWakeUp();
1333 }
1334
1335 // ----------------------------------------------------------------------------
1336 // include common implementation code
1337 // ----------------------------------------------------------------------------
1338
1339 #include "wx/thrimpl.cpp"
1340
1341 #endif // wxUSE_THREADS