]> git.saurik.com Git - wxWidgets.git/blame - src/mac/thread.cpp
Applied patch [ 874495 ] wxMSW: Flat buttons
[wxWidgets.git] / src / mac / thread.cpp
CommitLineData
e9576ca5
SC
1/////////////////////////////////////////////////////////////////////////////
2// Name: thread.cpp
e7549107 3// Purpose: wxThread Implementation
a959b088
SC
4// Author: Original from Wolfram Gloger/Guilhem Lavaux/Vadim Zeitlin
5// Modified by: Stefan Csomor
e9576ca5
SC
6// Created: 04/22/98
7// RCS-ID: $Id$
e7549107 8// Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998),
a959b088 9// Vadim Zeitlin (1999) , Stefan Csomor (2000)
e9576ca5
SC
10// Licence: wxWindows licence
11/////////////////////////////////////////////////////////////////////////////
12
13#ifdef __GNUG__
e7549107 14 #pragma implementation "thread.h"
e9576ca5
SC
15#endif
16
e7549107
SC
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
e9576ca5
SC
34#include "wx/module.h"
35#include "wx/thread.h"
e9576ca5 36
76a5e5d2 37#ifdef __WXMAC__
66a09d47 38#include <Threads.h>
9c152f80 39#include "wx/mac/uma.h"
2dbc444a 40#include "wx/mac/macnotfy.h"
76a5e5d2
SC
41#endif
42
ad816ba5
SC
43#define INFINITE 0xFFFFFFFF
44
2dbc444a 45
a959b088
SC
46// ----------------------------------------------------------------------------
47// constants
48// ----------------------------------------------------------------------------
49
e7549107
SC
50// the possible states of the thread ("=>" shows all possible transitions from
51// this state)
52enum wxThreadState
53{
54 STATE_NEW, // didn't start execution yet (=> RUNNING)
55 STATE_RUNNING, // thread is running (=> PAUSED, CANCELED)
56 STATE_PAUSED, // thread is temporarily suspended (=> RUNNING)
57 STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED)
58 STATE_EXITED // thread is terminating
e9576ca5
SC
59};
60
e7549107 61// ----------------------------------------------------------------------------
a959b088 62// this module globals
e7549107 63// ----------------------------------------------------------------------------
169935ad 64
a959b088
SC
65static ThreadID gs_idMainThread = kNoThreadID ;
66static bool gs_waitingForThread = FALSE ;
e64313ba 67size_t g_numberOfThreads = 0;
e9576ca5 68
e7549107 69// ============================================================================
a959b088 70// MacOS implementation of thread classes
e7549107
SC
71// ============================================================================
72
a959b088
SC
73class wxMacStCritical
74{
75public :
ea736fec 76 wxMacStCritical()
6fe73788 77 {
9c152f80
SC
78 if ( UMASystemIsInitialized() )
79 ThreadBeginCritical() ;
6fe73788
RL
80 }
81 ~wxMacStCritical()
82 {
9c152f80
SC
83 if ( UMASystemIsInitialized() )
84 ThreadEndCritical() ;
6fe73788
RL
85 }
86};
a959b088 87
e7549107
SC
88// ----------------------------------------------------------------------------
89// wxMutex implementation
90// ----------------------------------------------------------------------------
a959b088 91
e7549107
SC
92class wxMutexInternal
93{
e9576ca5 94public:
ad816ba5 95 wxMutexInternal(wxMutexType WXUNUSED(mutexType))
a959b088 96 {
6fe73788 97 m_owner = kNoThreadID ;
ad816ba5 98 m_locked = 0;
a959b088
SC
99 }
100
ea736fec 101 ~wxMutexInternal()
a959b088 102 {
ad816ba5
SC
103 if ( m_locked > 0 )
104 {
f5bb2251 105 wxLogDebug(_T("Warning: freeing a locked mutex (%ld locks)."), m_locked);
ad816ba5 106 }
a959b088
SC
107 }
108
ad816ba5
SC
109 bool IsOk() const { return true; }
110
111 wxMutexError Lock() ;
112 wxMutexError TryLock() ;
113 wxMutexError Unlock();
a959b088
SC
114public:
115 ThreadID m_owner ;
116 wxArrayLong m_waiters ;
ad816ba5 117 long m_locked ;
e9576ca5
SC
118};
119
ad816ba5 120wxMutexError wxMutexInternal::Lock()
e9576ca5 121{
6fe73788 122 wxMacStCritical critical ;
9c152f80 123 if ( UMASystemIsInitialized() )
6fe73788 124 {
9c152f80
SC
125 OSErr err ;
126 ThreadID current = kNoThreadID;
127 err = ::MacGetCurrentThread(&current);
128 // if we are not the owner, add this thread to the list of waiting threads, stop this thread
129 // and invoke the scheduler to continue executing the owner's thread
ad816ba5 130 while ( m_owner != kNoThreadID && m_owner != current)
9c152f80 131 {
ad816ba5
SC
132 m_waiters.Add(current);
133 err = ::SetThreadStateEndCritical(kCurrentThreadID, kStoppedThreadState, m_owner);
9c152f80
SC
134 err = ::ThreadBeginCritical();
135 }
ad816ba5 136 m_owner = current;
6fe73788 137 }
e9576ca5 138 m_locked++;
a959b088 139
e9576ca5
SC
140 return wxMUTEX_NO_ERROR;
141}
142
ad816ba5 143wxMutexError wxMutexInternal::TryLock()
e9576ca5 144{
6fe73788 145 wxMacStCritical critical ;
9c152f80 146 if ( UMASystemIsInitialized() )
ea736fec 147 {
9c152f80
SC
148 ThreadID current = kNoThreadID;
149 ::MacGetCurrentThread(&current);
150 // if we are not the owner, give an error back
ad816ba5 151 if ( m_owner != kNoThreadID && m_owner != current )
9c152f80 152 return wxMUTEX_BUSY;
ea736fec 153
ad816ba5 154 m_owner = current;
9c152f80 155 }
e9576ca5 156 m_locked++;
a959b088
SC
157
158 return wxMUTEX_NO_ERROR;
e9576ca5
SC
159}
160
ad816ba5 161wxMutexError wxMutexInternal::Unlock()
e9576ca5 162{
9c152f80 163 if ( UMASystemIsInitialized() )
ea736fec 164 {
9c152f80
SC
165 OSErr err;
166 err = ::ThreadBeginCritical();
ea736fec 167
9c152f80
SC
168 if (m_locked > 0)
169 m_locked--;
170
171 // this mutex is not owned by anybody anmore
ad816ba5 172 m_owner = kNoThreadID;
9c152f80
SC
173
174 // now pass on to the first waiting thread
175 ThreadID firstWaiting = kNoThreadID;
176 bool found = false;
ad816ba5 177 while (!m_waiters.IsEmpty() && !found)
9c152f80 178 {
ad816ba5 179 firstWaiting = m_waiters[0];
9c152f80
SC
180 err = ::SetThreadState(firstWaiting, kReadyThreadState, kNoThreadID);
181 // in case this was not successful (dead thread), we just loop on and reset the id
ea736fec 182 found = (err != threadNotFoundErr);
9c152f80
SC
183 if ( !found )
184 firstWaiting = kNoThreadID ;
ad816ba5 185 m_waiters.RemoveAt(0) ;
9c152f80
SC
186 }
187 // now we have a valid firstWaiting thread, which has been scheduled to run next, just end the
188 // critical section and invoke the scheduler
189 err = ::SetThreadStateEndCritical(kCurrentThreadID, kReadyThreadState, firstWaiting);
190 }
191 else
6fe73788 192 {
9c152f80
SC
193 if (m_locked > 0)
194 m_locked--;
6fe73788 195 }
e9576ca5
SC
196 return wxMUTEX_NO_ERROR;
197}
198
ad816ba5
SC
199// --------------------------------------------------------------------------
200// wxSemaphore
201// --------------------------------------------------------------------------
202
203// TODO not yet implemented
204
205class wxSemaphoreInternal
206{
207public:
208 wxSemaphoreInternal(int initialcount, int maxcount);
209 ~wxSemaphoreInternal();
210
211 bool IsOk() const { return true ; }
212
213 wxSemaError Wait() { return WaitTimeout(INFINITE); }
214 wxSemaError TryWait() { return WaitTimeout(0); }
215 wxSemaError WaitTimeout(unsigned long milliseconds);
216
217 wxSemaError Post();
218
219private:
220};
221
222wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
223{
224 if ( maxcount == 0 )
225 {
226 // make it practically infinite
227 maxcount = INT_MAX;
228 }
229}
230
231wxSemaphoreInternal::~wxSemaphoreInternal()
232{
233}
234
235wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds)
236{
237 return wxSEMA_MISC_ERROR;
238}
239
240wxSemaError wxSemaphoreInternal::Post()
241{
242 return wxSEMA_MISC_ERROR;
243}
244
e7549107
SC
245// ----------------------------------------------------------------------------
246// wxCondition implementation
247// ----------------------------------------------------------------------------
248
ad816ba5
SC
249// TODO this is not yet completed
250
e7549107
SC
251class wxConditionInternal
252{
e9576ca5 253public:
71110b40 254 wxConditionInternal(wxMutex& mutex) : m_mutex(mutex)
a959b088 255 {
6fe73788 256 m_excessSignals = 0 ;
a959b088
SC
257 }
258 ~wxConditionInternal()
259 {
260 }
e9576ca5 261
ad816ba5 262 bool IsOk() const { return m_mutex.IsOk() ; }
2dbc444a 263
ad816ba5
SC
264 wxCondError Wait()
265 {
266 return WaitTimeout(0xFFFFFFFF );
267 }
2dbc444a 268
ad816ba5 269 wxCondError WaitTimeout(unsigned long msectimeout)
e7549107 270 {
6fe73788
RL
271 wxMacStCritical critical ;
272 if ( m_excessSignals > 0 )
273 {
274 --m_excessSignals ;
ad816ba5 275 return wxCOND_NO_ERROR ;
6fe73788
RL
276 }
277 else if ( msectimeout == 0 )
278 {
ad816ba5 279 return wxCOND_MISC_ERROR ;
6fe73788
RL
280 }
281 else
282 {
283 }
284 /*
a959b088
SC
285 waiters++;
286
287 // FIXME this should be MsgWaitForMultipleObjects() as well probably
288 DWORD rc = ::WaitForSingleObject(event, timeout);
289
290 waiters--;
291
292 return rc != WAIT_TIMEOUT;
293 */
ad816ba5 294 return wxCOND_NO_ERROR ;
e7549107 295 }
ad816ba5 296 wxCondError Signal()
6fe73788
RL
297 {
298 wxMacStCritical critical ;
ad816ba5 299 return wxCOND_NO_ERROR;
6fe73788 300 }
a959b088 301
ad816ba5
SC
302 wxCondError Broadcast()
303 {
304 wxMacStCritical critical ;
305 return wxCOND_NO_ERROR;
2dbc444a 306 }
ad816ba5 307
a959b088 308 wxArrayLong m_waiters ;
6fe73788 309 wxInt32 m_excessSignals ;
71110b40 310 wxMutex& m_mutex;
a959b088 311};
e7549107 312
e7549107
SC
313// ----------------------------------------------------------------------------
314// wxCriticalSection implementation
315// ----------------------------------------------------------------------------
316
a959b088 317// it's implemented as a mutex on mac os, so it is defined in the headers
e7549107
SC
318
319// ----------------------------------------------------------------------------
320// wxThread implementation
321// ----------------------------------------------------------------------------
322
323// wxThreadInternal class
324// ----------------------
325
e7549107
SC
326class wxThreadInternal
327{
328public:
329 wxThreadInternal()
330 {
a959b088 331 m_tid = kNoThreadID ;
e7549107
SC
332 m_state = STATE_NEW;
333 m_priority = WXTHREAD_DEFAULT_PRIORITY;
334 }
335
a959b088
SC
336 ~wxThreadInternal()
337 {
338 }
339
340 void Free()
341 {
342 }
343
e7549107 344 // create a new (suspended) thread (for the given thread object)
6fe73788 345 bool Create(wxThread *thread, unsigned int stackSize);
e7549107
SC
346
347 // suspend/resume/terminate
348 bool Suspend();
349 bool Resume();
350 void Cancel() { m_state = STATE_CANCELED; }
351
352 // thread state
353 void SetState(wxThreadState state) { m_state = state; }
354 wxThreadState GetState() const { return m_state; }
355
356 // thread priority
a959b088 357 void SetPriority(unsigned int priority);
e7549107 358 unsigned int GetPriority() const { return m_priority; }
ea736fec 359
a959b088
SC
360 void SetResult( void *res ) { m_result = res ; }
361 void *GetResult() { return m_result ; }
e7549107
SC
362
363 // thread handle and id
a959b088 364 ThreadID GetId() const { return m_tid; }
e7549107
SC
365
366 // thread function
6fe73788 367 static pascal void* MacThreadStart(wxThread* arg);
e7549107
SC
368
369private:
6fe73788
RL
370 wxThreadState m_state; // state, see wxThreadState enum
371 unsigned int m_priority; // thread priority in "wx" units
372 ThreadID m_tid; // thread id
373 void* m_result;
374 static ThreadEntryUPP s_threadEntry ;
e7549107
SC
375};
376
a959b088
SC
377static wxArrayPtrVoid s_threads ;
378
379ThreadEntryUPP wxThreadInternal::s_threadEntry = NULL ;
380pascal void* wxThreadInternal::MacThreadStart(wxThread *thread)
e7549107 381{
a959b088
SC
382 // first of all, check whether we hadn't been cancelled already
383 if ( thread->m_internal->GetState() == STATE_EXITED )
e7549107 384 {
a959b088 385 return (void*)-1;
e7549107
SC
386 }
387
a959b088
SC
388 void* rc = thread->Entry();
389
390 // enter m_critsect before changing the thread state
391 thread->m_critsect.Enter();
392 bool wasCancelled = thread->m_internal->GetState() == STATE_CANCELED;
393 thread->m_internal->SetState(STATE_EXITED);
394 thread->m_critsect.Leave();
395
e7549107
SC
396 thread->OnExit();
397
a959b088
SC
398 // if the thread was cancelled (from Delete()), then it the handle is still
399 // needed there
400 if ( thread->IsDetached() && !wasCancelled )
401 {
402 // auto delete
403 delete thread;
404 }
405 //else: the joinable threads handle will be closed when Wait() is done
e7549107 406
a959b088
SC
407 return rc;
408}
409void wxThreadInternal::SetPriority(unsigned int priority)
410{
6fe73788 411 // Priorities don't exist on Mac
e7549107
SC
412}
413
6fe73788 414bool wxThreadInternal::Create(wxThread *thread, unsigned int stackSize)
e7549107 415{
6fe73788
RL
416 if ( s_threadEntry == NULL )
417 {
418 s_threadEntry = NewThreadEntryUPP( (ThreadEntryProcPtr) MacThreadStart ) ;
419 }
420 OSErr err = NewThread( kCooperativeThread,
421 s_threadEntry,
422 (void*) thread,
423 stackSize,
424 kNewSuspend,
425 &m_result,
426 &m_tid );
a959b088
SC
427
428 if ( err != noErr )
e7549107
SC
429 {
430 wxLogSysError(_("Can't create thread"));
e7549107
SC
431 return FALSE;
432 }
433
a959b088 434 if ( m_priority != WXTHREAD_DEFAULT_PRIORITY )
e7549107 435 {
a959b088 436 SetPriority(m_priority);
e7549107
SC
437 }
438
1dfc3cda
JS
439 m_state = STATE_NEW;
440
e7549107
SC
441 return TRUE;
442}
443
444bool wxThreadInternal::Suspend()
445{
6fe73788 446 OSErr err ;
ea736fec 447
6fe73788 448 ::ThreadBeginCritical();
e7549107 449
6fe73788 450 if ( m_state != STATE_RUNNING )
a959b088 451 {
6fe73788 452 ::ThreadEndCritical() ;
a959b088 453 wxLogSysError(_("Can not suspend thread %x"), m_tid);
e7549107
SC
454 return FALSE;
455 }
456
457 m_state = STATE_PAUSED;
458
6fe73788 459 err = ::SetThreadStateEndCritical(m_tid, kStoppedThreadState, kNoThreadID);
a959b088 460
e7549107
SC
461 return TRUE;
462}
463
464bool wxThreadInternal::Resume()
465{
6fe73788
RL
466 ThreadID current ;
467 OSErr err ;
468 err = MacGetCurrentThread( &current ) ;
469
470 wxASSERT( err == noErr ) ;
471 wxASSERT( current != m_tid ) ;
ea736fec 472
6fe73788
RL
473 ::ThreadBeginCritical();
474 if ( m_state != STATE_PAUSED && m_state != STATE_NEW )
475 {
476 ::ThreadEndCritical() ;
a959b088 477 wxLogSysError(_("Can not resume thread %x"), m_tid);
e7549107 478 return FALSE;
ea736fec 479
6fe73788
RL
480 }
481 err = ::SetThreadStateEndCritical(m_tid, kReadyThreadState, kNoThreadID);
482 wxASSERT( err == noErr ) ;
ea736fec 483
e7549107 484 m_state = STATE_RUNNING;
6fe73788
RL
485 ::ThreadEndCritical() ;
486 ::YieldToAnyThread() ;
e7549107
SC
487 return TRUE;
488}
489
490// static functions
491// ----------------
e7549107
SC
492wxThread *wxThread::This()
493{
6fe73788 494 wxMacStCritical critical ;
ea736fec 495
6fe73788
RL
496 ThreadID current ;
497 OSErr err ;
ea736fec 498
6fe73788 499 err = MacGetCurrentThread( &current ) ;
ea736fec 500
d84afea9 501 for ( size_t i = 0 ; i < s_threads.Count() ; ++i )
6fe73788
RL
502 {
503 if ( ( (wxThread*) s_threads[i] )->GetId() == current )
504 return (wxThread*) s_threads[i] ;
505 }
e7549107 506
a959b088
SC
507 wxLogSysError(_("Couldn't get the current thread pointer"));
508 return NULL;
e7549107
SC
509}
510
511bool wxThread::IsMain()
512{
6fe73788
RL
513 ThreadID current ;
514 OSErr err ;
ea736fec 515
6fe73788 516 err = MacGetCurrentThread( &current ) ;
a959b088 517 return current == gs_idMainThread;
e7549107
SC
518}
519
520#ifdef Yield
a959b088 521#undef Yield
e7549107
SC
522#endif
523
524void wxThread::Yield()
525{
6fe73788 526 ::YieldToAnyThread() ;
e7549107
SC
527}
528
529void wxThread::Sleep(unsigned long milliseconds)
530{
7f19fc8c
JS
531 clock_t start = clock();
532 do
533 {
534 YieldToAnyThread();
e64313ba 535 } while( clock() - start < milliseconds * CLOCKS_PER_SEC / 1000.0 ) ;
a959b088
SC
536}
537
538int wxThread::GetCPUCount()
539{
6fe73788 540 // we will use whatever MP API will be used for the new MP Macs
a959b088
SC
541 return 1;
542}
543
ea736fec
RD
544unsigned long wxThread::GetCurrentId()
545{
546 ThreadID current ;
547 MacGetCurrentThread( &current ) ;
548 return (unsigned long)current;
549}
550
a959b088
SC
551bool wxThread::SetConcurrency(size_t level)
552{
553 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
554
555 // ok only for the default one
556 if ( level == 0 )
557 return 0;
558
559 // how many CPUs have we got?
560 if ( GetCPUCount() == 1 )
561 {
562 // don't bother with all this complicated stuff - on a single
563 // processor system it doesn't make much sense anyhow
564 return level == 1;
565 }
ea736fec 566
a959b088
SC
567 return TRUE ;
568}
569
570// ctor and dtor
571// -------------
572
573wxThread::wxThread(wxThreadKind kind)
574{
e64313ba 575 g_numberOfThreads++;
a959b088
SC
576 m_internal = new wxThreadInternal();
577
578 m_isDetached = kind == wxTHREAD_DETACHED;
579 s_threads.Add( (void*) this ) ;
580}
581
582wxThread::~wxThread()
583{
e64313ba
DS
584 if (g_numberOfThreads>0)
585 {
586 g_numberOfThreads--;
587 }
588#ifdef __WXDEBUG__
589 else
590 {
591 wxFAIL_MSG(wxT("More threads deleted than created."));
592 }
593#endif
594
6fe73788 595 s_threads.Remove( (void*) this ) ;
f5bb2251
GD
596 if (m_internal != NULL) {
597 delete m_internal;
598 m_internal = NULL;
599 }
e7549107
SC
600}
601
602// create/start thread
603// -------------------
604
6fe73788 605wxThreadError wxThread::Create(unsigned int stackSize)
e9576ca5 606{
a959b088
SC
607 wxCriticalSectionLocker lock(m_critsect);
608
6fe73788 609 if ( !m_internal->Create(this, stackSize) )
e7549107
SC
610 return wxTHREAD_NO_RESOURCE;
611
e9576ca5
SC
612 return wxTHREAD_NO_ERROR;
613}
614
e7549107 615wxThreadError wxThread::Run()
e9576ca5 616{
e7549107
SC
617 wxCriticalSectionLocker lock(m_critsect);
618
a959b088 619 if ( m_internal->GetState() != STATE_NEW )
e7549107
SC
620 {
621 // actually, it may be almost any state at all, not only STATE_RUNNING
622 return wxTHREAD_RUNNING;
623 }
624
a959b088 625 // the thread has just been created and is still suspended - let it run
e7549107 626 return Resume();
e9576ca5
SC
627}
628
e7549107
SC
629// suspend/resume thread
630// ---------------------
631
e9576ca5
SC
632wxThreadError wxThread::Pause()
633{
e7549107
SC
634 wxCriticalSectionLocker lock(m_critsect);
635
a959b088 636 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
e9576ca5
SC
637}
638
639wxThreadError wxThread::Resume()
640{
e7549107 641 wxCriticalSectionLocker lock(m_critsect);
e9576ca5 642
a959b088 643 return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
e9576ca5
SC
644}
645
e7549107
SC
646// stopping thread
647// ---------------
648
a959b088
SC
649wxThread::ExitCode wxThread::Wait()
650{
651 // although under MacOS we can wait for any thread, it's an error to
652 // wait for a detached one in wxWin API
653 wxCHECK_MSG( !IsDetached(), (ExitCode)-1,
654 _T("can't wait for detached thread") );
655
656 ExitCode rc = (ExitCode)-1;
657
658 (void)Delete(&rc);
659
660 m_internal->Free();
661
662 return rc;
663}
664
665wxThreadError wxThread::Delete(ExitCode *pRc)
e9576ca5 666{
e7549107
SC
667 ExitCode rc = 0;
668
669 // Delete() is always safe to call, so consider all possible states
a959b088
SC
670
671 // has the thread started to run?
672 bool shouldResume = FALSE;
673
674 {
675 wxCriticalSectionLocker lock(m_critsect);
676
677 if ( m_internal->GetState() == STATE_NEW )
678 {
679 // WinThreadStart() will see it and terminate immediately
680 m_internal->SetState(STATE_EXITED);
681
682 shouldResume = TRUE;
683 }
684 }
685
686 // is the thread paused?
687 if ( shouldResume || IsPaused() )
e7549107
SC
688 Resume();
689
a959b088 690 // does is still run?
e7549107
SC
691 if ( IsRunning() )
692 {
693 if ( IsMain() )
694 {
695 // set flag for wxIsWaitingForThread()
a959b088 696 gs_waitingForThread = TRUE;
e7549107 697
a959b088 698#if wxUSE_GUI
e7549107 699 wxBeginBusyCursor();
a959b088 700#endif // wxUSE_GUI
e7549107
SC
701 }
702
a959b088 703 // ask the thread to terminate
e7549107
SC
704 {
705 wxCriticalSectionLocker lock(m_critsect);
706
a959b088 707 m_internal->Cancel();
e7549107
SC
708 }
709
a959b088
SC
710#if wxUSE_GUI
711 // simply wait for the thread to terminate
6fe73788
RL
712 while( TestDestroy() )
713 {
714 ::YieldToAnyThread() ;
715 }
a959b088
SC
716#else // !wxUSE_GUI
717 // simply wait for the thread to terminate
6fe73788
RL
718 while( TestDestroy() )
719 {
720 ::YieldToAnyThread() ;
721 }
a959b088 722#endif // wxUSE_GUI/!wxUSE_GUI
e7549107
SC
723
724 if ( IsMain() )
725 {
a959b088 726 gs_waitingForThread = FALSE;
e7549107 727
a959b088 728#if wxUSE_GUI
e7549107 729 wxEndBusyCursor();
a959b088 730#endif // wxUSE_GUI
e7549107 731 }
a959b088 732 }
e7549107 733
a959b088
SC
734 if ( IsDetached() )
735 {
736 // if the thread exits normally, this is done in WinThreadStart, but in
737 // this case it would have been too early because
738 // MsgWaitForMultipleObject() would fail if the therad handle was
739 // closed while we were waiting on it, so we must do it here
740 delete this;
e7549107
SC
741 }
742
a959b088
SC
743 if ( pRc )
744 *pRc = rc;
745
746 return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR;
e9576ca5
SC
747}
748
e7549107 749wxThreadError wxThread::Kill()
e9576ca5 750{
e7549107
SC
751 if ( !IsRunning() )
752 return wxTHREAD_NOT_RUNNING;
753
a959b088 754// if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
e7549107
SC
755 {
756 wxLogSysError(_("Couldn't terminate thread"));
757
758 return wxTHREAD_MISC_ERROR;
759 }
760
a959b088
SC
761 m_internal->Free();
762
763 if ( IsDetached() )
764 {
765 delete this;
766 }
e7549107
SC
767
768 return wxTHREAD_NO_ERROR;
e9576ca5
SC
769}
770
a959b088 771void wxThread::Exit(ExitCode status)
e9576ca5 772{
a959b088 773 m_internal->Free();
e7549107 774
a959b088
SC
775 if ( IsDetached() )
776 {
777 delete this;
778 }
e7549107 779
6fe73788 780 m_internal->SetResult( status ) ;
a959b088 781
ea736fec 782/*
a959b088
SC
783#if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
784 _endthreadex((unsigned)status);
785#else // !VC++
786 ::ExitThread((DWORD)status);
787#endif // VC++/!VC++
788*/
e7549107 789 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
e9576ca5
SC
790}
791
a959b088
SC
792// priority setting
793// ----------------
794
795// since all these calls are execute cooperatively we don't have to use the critical section
796
e7549107 797void wxThread::SetPriority(unsigned int prio)
e9576ca5 798{
a959b088 799 m_internal->SetPriority(prio);
e9576ca5
SC
800}
801
e7549107 802unsigned int wxThread::GetPriority() const
e9576ca5 803{
a959b088 804 return m_internal->GetPriority();
e9576ca5
SC
805}
806
a959b088 807unsigned long wxThread::GetId() const
e9576ca5 808{
a959b088 809 return (unsigned long)m_internal->GetId();
e9576ca5
SC
810}
811
e7549107 812bool wxThread::IsRunning() const
e9576ca5 813{
a959b088 814 return m_internal->GetState() == STATE_RUNNING;
e9576ca5 815}
e9576ca5
SC
816
817bool wxThread::IsAlive() const
818{
a959b088
SC
819 return (m_internal->GetState() == STATE_RUNNING) ||
820 (m_internal->GetState() == STATE_PAUSED);
e9576ca5
SC
821}
822
e7549107 823bool wxThread::IsPaused() const
e9576ca5 824{
a959b088 825 return m_internal->GetState() == STATE_PAUSED;
e9576ca5
SC
826}
827
e7549107 828bool wxThread::TestDestroy()
e9576ca5 829{
a959b088 830 return m_internal->GetState() == STATE_CANCELED;
e9576ca5
SC
831}
832
e7549107
SC
833// ----------------------------------------------------------------------------
834// Automatic initialization for thread module
835// ----------------------------------------------------------------------------
e9576ca5 836
e7549107
SC
837class wxThreadModule : public wxModule
838{
e9576ca5 839public:
e7549107
SC
840 virtual bool OnInit();
841 virtual void OnExit();
e9576ca5 842
e7549107
SC
843private:
844 DECLARE_DYNAMIC_CLASS(wxThreadModule)
e9576ca5
SC
845};
846
847IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
848
e7549107
SC
849bool wxThreadModule::OnInit()
850{
6fe73788
RL
851 long response;
852 bool hasThreadManager ;
853 hasThreadManager = Gestalt( gestaltThreadMgrAttr, &response) == noErr && response & 1;
5b781a67
SC
854#if !TARGET_CARBON
855#if GENERATINGCFM
6fe73788
RL
856 // verify presence of shared library
857 hasThreadManager = hasThreadManager && ((Ptr)NewThread != (Ptr)kUnresolvedCFragSymbolAddress);
5b781a67 858#endif
a959b088 859#endif
6fe73788
RL
860 if ( !hasThreadManager )
861 {
2dbc444a 862 wxLogSysError( wxT("Thread Support is not available on this System") );
6fe73788
RL
863 return FALSE ;
864 }
e7549107
SC
865
866 // no error return for GetCurrentThreadId()
a959b088 867 MacGetCurrentThread( &gs_idMainThread ) ;
e7549107
SC
868
869 return TRUE;
870}
871
872void wxThreadModule::OnExit()
873{
e7549107
SC
874}
875
876// ----------------------------------------------------------------------------
a959b088
SC
877// under MacOS we don't have currently preemptive threads, so any thread may access
878// the GUI at any time
e7549107
SC
879// ----------------------------------------------------------------------------
880
881void WXDLLEXPORT wxMutexGuiEnter()
882{
e7549107
SC
883}
884
885void WXDLLEXPORT wxMutexGuiLeave()
886{
e7549107
SC
887}
888
889void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
890{
e7549107
SC
891}
892
893bool WXDLLEXPORT wxGuiOwnedByMainThread()
894{
a959b088 895 return false ;
e7549107
SC
896}
897
ea736fec 898// wake up the main thread
e7549107
SC
899void WXDLLEXPORT wxWakeUpMainThread()
900{
6fe73788 901 wxMacWakeUp() ;
e7549107
SC
902}
903
904bool WXDLLEXPORT wxIsWaitingForThread()
905{
a959b088 906 return false ;
e7549107 907}
e7549107 908
ad816ba5
SC
909#include "wx/thrimpl.cpp"
910
e7549107 911#endif // wxUSE_THREADS