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