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