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