]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/mac/thread.cpp
Visualage C++ V4.0 duplicate symbol fixes
[wxWidgets.git] / src / mac / thread.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: thread.cpp
3// Purpose: wxThread Implementation
4// Author: Original from Wolfram Gloger/Guilhem Lavaux
5// Modified by: Vadim Zeitlin to make it work :-)
6// Created: 04/22/98
7// RCS-ID: $Id$
8// Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998),
9// Vadim Zeitlin (1999)
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 <stdio.h>
35
36#include <windows.h>
37
38#include "wx/module.h"
39#include "wx/thread.h"
40
41// the possible states of the thread ("=>" shows all possible transitions from
42// this state)
43enum wxThreadState
44{
45 STATE_NEW, // didn't start execution yet (=> RUNNING)
46 STATE_RUNNING, // thread is running (=> PAUSED, CANCELED)
47 STATE_PAUSED, // thread is temporarily suspended (=> RUNNING)
48 STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED)
49 STATE_EXITED // thread is terminating
50};
51
52// ----------------------------------------------------------------------------
53// static variables
54// ----------------------------------------------------------------------------
55
56// if it's FALSE, some secondary thread is holding the GUI lock
57static bool s_bGuiOwnedByMainThread = TRUE;
58
59// critical section which controls access to all GUI functions: any secondary
60// thread (i.e. except the main one) must enter this crit section before doing
61// any GUI calls
62static wxCriticalSection *s_critsectGui = NULL;
63
64// critical section which protects s_nWaitingForGui variable
65static wxCriticalSection *s_critsectWaitingForGui = NULL;
66
67// number of threads waiting for GUI in wxMutexGuiEnter()
68static size_t s_nWaitingForGui = 0;
69
70// are we waiting for a thread termination?
71static bool s_waitingForThread = FALSE;
72
73// ============================================================================
74// Windows implementation of thread classes
75// ============================================================================
76
77// ----------------------------------------------------------------------------
78// wxMutex implementation
79// ----------------------------------------------------------------------------
80class wxMutexInternal
81{
82public:
83 Handle p_mutex;
84};
85
86wxMutex::wxMutex()
87{
88 p_internal = new wxMutexInternal;
89// p_internal->p_mutex = CreateMutex(NULL, FALSE, NULL);
90 if ( !p_internal->p_mutex )
91 {
92 wxLogSysError(_("Can not create mutex."));
93 }
94
95 m_locked = 0;
96}
97
98wxMutex::~wxMutex()
99{
100 if (m_locked > 0)
101 wxLogDebug(wxT("Warning: freeing a locked mutex (%d locks)."), m_locked);
102// CloseHandle(p_internal->p_mutex);
103}
104
105wxMutexError wxMutex::Lock()
106{
107/*
108 DWORD ret;
109
110 ret = WaitForSingleObject(p_internal->p_mutex, INFINITE);
111 switch ( ret )
112 {
113 case WAIT_ABANDONED:
114 return wxMUTEX_BUSY;
115
116 case WAIT_OBJECT_0:
117 // ok
118 break;
119
120 case WAIT_FAILED:
121 wxLogSysError(_("Couldn't acquire a mutex lock"));
122 return wxMUTEX_MISC_ERROR;
123
124 case WAIT_TIMEOUT:
125 default:
126 wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
127 }
128*/
129 m_locked++;
130 return wxMUTEX_NO_ERROR;
131}
132
133wxMutexError wxMutex::TryLock()
134{
135/*
136 DWORD ret;
137
138 ret = WaitForSingleObject(p_internal->p_mutex, 0);
139 if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
140 return wxMUTEX_BUSY;
141
142 m_locked++;
143*/
144 return wxMUTEX_NO_ERROR;
145}
146
147wxMutexError wxMutex::Unlock()
148{
149 if (m_locked > 0)
150 m_locked--;
151/*
152 BOOL ret = ReleaseMutex(p_internal->p_mutex);
153 if ( ret == 0 )
154 {
155 wxLogSysError(_("Couldn't release a mutex"));
156 return wxMUTEX_MISC_ERROR;
157 }
158*/
159 return wxMUTEX_NO_ERROR;
160}
161
162// ----------------------------------------------------------------------------
163// wxCondition implementation
164// ----------------------------------------------------------------------------
165
166class wxConditionInternal
167{
168public:
169 Handle event;
170 int waiters;
171};
172
173wxCondition::wxCondition()
174{
175 p_internal = new wxConditionInternal;
176// p_internal->event = CreateEvent(NULL, FALSE, FALSE, NULL);
177 if ( !p_internal->event )
178 {
179 wxLogSysError(_("Can not create event object."));
180 }
181
182 p_internal->waiters = 0;
183}
184
185wxCondition::~wxCondition()
186{
187// CloseHandle(p_internal->event);
188}
189
190void wxCondition::Wait(wxMutex& mutex)
191{
192 mutex.Unlock();
193 p_internal->waiters++;
194// WaitForSingleObject(p_internal->event, INFINITE);
195 p_internal->waiters--;
196 mutex.Lock();
197}
198
199bool wxCondition::Wait(wxMutex& mutex,
200 unsigned long sec,
201 unsigned long nsec)
202{
203// DWORD ret;
204
205 mutex.Unlock();
206 p_internal->waiters++;
207 // ret = WaitForSingleObject(p_internal->event, (sec*1000)+(nsec/1000000));
208 p_internal->waiters--;
209 mutex.Lock();
210
211 return TRUE; // false for timeout
212}
213
214void wxCondition::Signal()
215{
216// SetEvent(p_internal->event);
217}
218
219void wxCondition::Broadcast()
220{
221 int i;
222
223 for (i=0;i<p_internal->waiters;i++)
224 {
225// if ( SetEvent(p_internal->event) == 0 )
226 {
227 wxLogSysError(_("Couldn't change the state of event object."));
228 }
229 }
230}
231
232// ----------------------------------------------------------------------------
233// wxCriticalSection implementation
234// ----------------------------------------------------------------------------
235
236class wxCriticalSectionInternal
237{
238public:
239 // init the critical section object
240 wxCriticalSectionInternal()
241 { /* ::InitializeCriticalSection(&m_data);*/ }
242
243 // implicit cast to the associated data
244 operator Handle *() { return &m_data; }
245
246 // free the associated ressources
247 ~wxCriticalSectionInternal()
248 { /* ::DeleteCriticalSection(&m_data); */}
249
250private:
251 Handle m_data;
252};
253
254wxCriticalSection::wxCriticalSection()
255{
256 m_critsect = new wxCriticalSectionInternal;
257}
258
259wxCriticalSection::~wxCriticalSection()
260{
261 delete m_critsect;
262}
263
264void wxCriticalSection::Enter()
265{
266// ::EnterCriticalSection(*m_critsect);
267}
268
269void wxCriticalSection::Leave()
270{
271// ::LeaveCriticalSection(*m_critsect);
272}
273
274// ----------------------------------------------------------------------------
275// wxThread implementation
276// ----------------------------------------------------------------------------
277
278// wxThreadInternal class
279// ----------------------
280
281/*
282class wxThreadInternal
283{
284public:
285 wxThreadInternal()
286 {
287 m_hThread = 0;
288 m_state = STATE_NEW;
289 m_priority = WXTHREAD_DEFAULT_PRIORITY;
290 }
291
292 // create a new (suspended) thread (for the given thread object)
293 bool Create(wxThread *thread);
294
295 // suspend/resume/terminate
296 bool Suspend();
297 bool Resume();
298 void Cancel() { m_state = STATE_CANCELED; }
299
300 // thread state
301 void SetState(wxThreadState state) { m_state = state; }
302 wxThreadState GetState() const { return m_state; }
303
304 // thread priority
305 void SetPriority(unsigned int priority) { m_priority = priority; }
306 unsigned int GetPriority() const { return m_priority; }
307
308 // thread handle and id
309 HANDLE GetHandle() const { return m_hThread; }
310 DWORD GetId() const { return m_tid; }
311
312 // thread function
313 static DWORD WinThreadStart(wxThread *thread);
314
315private:
316 Handle m_hThread; // handle of the thread
317 wxThreadState m_state; // state, see wxThreadState enum
318 unsigned int m_priority; // thread priority in "wx" units
319 ThreadId m_tid; // thread id
320};
321
322DWORD wxThreadInternal::WinThreadStart(wxThread *thread)
323{
324 // store the thread object in the TLS
325 if ( !::TlsSetValue(s_tlsThisThread, thread) )
326 {
327 wxLogSysError(_("Can not start thread: error writing TLS."));
328
329 return (DWORD)-1;
330 }
331
332 DWORD ret = (DWORD)thread->Entry();
333 thread->p_internal->SetState(STATE_EXITED);
334 thread->OnExit();
335
336 delete thread;
337
338 return ret;
339}
340
341bool wxThreadInternal::Create(wxThread *thread)
342{
343 m_hThread = ::CreateThread
344 (
345 NULL, // default security
346 0, // default stack size
347 (LPTHREAD_START_ROUTINE) // thread entry point
348 wxThreadInternal::WinThreadStart, //
349 (LPVOID)thread, // parameter
350 CREATE_SUSPENDED, // flags
351 &m_tid // [out] thread id
352 );
353
354 if ( m_hThread == NULL )
355 {
356 wxLogSysError(_("Can't create thread"));
357
358 return FALSE;
359 }
360
361 // translate wxWindows priority to the Windows one
362 int win_priority;
363 if (m_priority <= 20)
364 win_priority = THREAD_PRIORITY_LOWEST;
365 else if (m_priority <= 40)
366 win_priority = THREAD_PRIORITY_BELOW_NORMAL;
367 else if (m_priority <= 60)
368 win_priority = THREAD_PRIORITY_NORMAL;
369 else if (m_priority <= 80)
370 win_priority = THREAD_PRIORITY_ABOVE_NORMAL;
371 else if (m_priority <= 100)
372 win_priority = THREAD_PRIORITY_HIGHEST;
373 else
374 {
375 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
376 win_priority = THREAD_PRIORITY_NORMAL;
377 }
378
379 if ( ::SetThreadPriority(m_hThread, win_priority) == 0 )
380 {
381 wxLogSysError(_("Can't set thread priority"));
382 }
383
384 return TRUE;
385}
386
387bool wxThreadInternal::Suspend()
388{
389 DWORD nSuspendCount = ::SuspendThread(m_hThread);
390 if ( nSuspendCount == (DWORD)-1 )
391 {
392 wxLogSysError(_("Can not suspend thread %x"), m_hThread);
393
394 return FALSE;
395 }
396
397 m_state = STATE_PAUSED;
398
399 return TRUE;
400}
401
402bool wxThreadInternal::Resume()
403{
404 DWORD nSuspendCount = ::ResumeThread(m_hThread);
405 if ( nSuspendCount == (DWORD)-1 )
406 {
407 wxLogSysError(_("Can not resume thread %x"), m_hThread);
408
409 return FALSE;
410 }
411
412 m_state = STATE_RUNNING;
413
414 return TRUE;
415}
416
417// static functions
418// ----------------
419
420wxThread *wxThread::This()
421{
422 wxThread *thread = (wxThread *)::TlsGetValue(s_tlsThisThread);
423
424 // be careful, 0 may be a valid return value as well
425 if ( !thread && (::GetLastError() != NO_ERROR) )
426 {
427 wxLogSysError(_("Couldn't get the current thread pointer"));
428
429 // return NULL...
430 }
431
432 return thread;
433}
434
435bool wxThread::IsMain()
436{
437 return ::GetCurrentThreadId() == s_idMainThread;
438}
439
440#ifdef Yield
441 #undef Yield
442#endif
443
444void wxThread::Yield()
445{
446 // 0 argument to Sleep() is special
447 ::Sleep(0);
448}
449
450void wxThread::Sleep(unsigned long milliseconds)
451{
452 ::Sleep(milliseconds);
453}
454
455// create/start thread
456// -------------------
457
458wxThreadError wxThread::Create()
459{
460 if ( !p_internal->Create(this) )
461 return wxTHREAD_NO_RESOURCE;
462
463 return wxTHREAD_NO_ERROR;
464}
465
466wxThreadError wxThread::Run()
467{
468 wxCriticalSectionLocker lock(m_critsect);
469
470 if ( p_internal->GetState() != STATE_NEW )
471 {
472 // actually, it may be almost any state at all, not only STATE_RUNNING
473 return wxTHREAD_RUNNING;
474 }
475
476 return Resume();
477}
478
479// suspend/resume thread
480// ---------------------
481
482wxThreadError wxThread::Pause()
483{
484 wxCriticalSectionLocker lock(m_critsect);
485
486 return p_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
487}
488
489wxThreadError wxThread::Resume()
490{
491 wxCriticalSectionLocker lock(m_critsect);
492
493 return p_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
494}
495
496// stopping thread
497// ---------------
498
499wxThread::ExitCode wxThread::Delete()
500{
501 ExitCode rc = 0;
502
503 // Delete() is always safe to call, so consider all possible states
504 if ( IsPaused() )
505 Resume();
506
507 if ( IsRunning() )
508 {
509 if ( IsMain() )
510 {
511 // set flag for wxIsWaitingForThread()
512 s_waitingForThread = TRUE;
513
514 wxBeginBusyCursor();
515 }
516
517 HANDLE hThread;
518 {
519 wxCriticalSectionLocker lock(m_critsect);
520
521 p_internal->Cancel();
522 hThread = p_internal->GetHandle();
523 }
524
525 // we can't just wait for the thread to terminate because it might be
526 // calling some GUI functions and so it will never terminate before we
527 // process the Windows messages that result from these functions
528 DWORD result;
529 do
530 {
531 result = ::MsgWaitForMultipleObjects
532 (
533 1, // number of objects to wait for
534 &hThread, // the objects
535 FALSE, // don't wait for all objects
536 INFINITE, // no timeout
537 QS_ALLEVENTS // return as soon as there are any events
538 );
539
540 switch ( result )
541 {
542 case 0xFFFFFFFF:
543 // error
544 wxLogSysError(_("Can not wait for thread termination"));
545 Kill();
546 return (ExitCode)-1;
547
548 case WAIT_OBJECT_0:
549 // thread we're waiting for terminated
550 break;
551
552 case WAIT_OBJECT_0 + 1:
553 // new message arrived, process it
554 if ( !wxTheApp->DoMessage() )
555 {
556 // WM_QUIT received: kill the thread
557 Kill();
558
559 return (ExitCode)-1;
560 }
561
562 if ( IsMain() )
563 {
564 // give the thread we're waiting for chance to exit
565 // from the GUI call it might have been in
566 if ( (s_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
567 {
568 wxMutexGuiLeave();
569 }
570 }
571
572 break;
573
574 default:
575 wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject"));
576 }
577 } while ( result != WAIT_OBJECT_0 );
578
579 if ( IsMain() )
580 {
581 s_waitingForThread = FALSE;
582
583 wxEndBusyCursor();
584 }
585
586 if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
587 {
588 wxLogLastError("GetExitCodeThread");
589
590 rc = (ExitCode)-1;
591 }
592
593 wxASSERT_MSG( (LPVOID)rc != (LPVOID)STILL_ACTIVE,
594 wxT("thread must be already terminated.") );
595
596 ::CloseHandle(hThread);
597 }
598
599 return rc;
600}
601
602wxThreadError wxThread::Kill()
603{
604 if ( !IsRunning() )
605 return wxTHREAD_NOT_RUNNING;
606
607 if ( !::TerminateThread(p_internal->GetHandle(), (DWORD)-1) )
608 {
609 wxLogSysError(_("Couldn't terminate thread"));
610
611 return wxTHREAD_MISC_ERROR;
612 }
613
614 delete this;
615
616 return wxTHREAD_NO_ERROR;
617}
618
619void wxThread::Exit(void *status)
620{
621 delete this;
622
623 ::ExitThread((DWORD)status);
624
625 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
626}
627
628void wxThread::SetPriority(unsigned int prio)
629{
630 wxCriticalSectionLocker lock(m_critsect);
631
632 p_internal->SetPriority(prio);
633}
634
635unsigned int wxThread::GetPriority() const
636{
637 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
638
639 return p_internal->GetPriority();
640}
641
642unsigned long wxThread::GetID() const
643{
644 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
645
646 return (unsigned long)p_internal->GetId();
647}
648
649bool wxThread::IsRunning() const
650{
651 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
652
653 return p_internal->GetState() == STATE_RUNNING;
654}
655
656bool wxThread::IsAlive() const
657{
658 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
659
660 return (p_internal->GetState() == STATE_RUNNING) ||
661 (p_internal->GetState() == STATE_PAUSED);
662}
663
664bool wxThread::IsPaused() const
665{
666 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
667
668 return (p_internal->GetState() == STATE_PAUSED);
669}
670
671bool wxThread::TestDestroy()
672{
673 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
674
675 return p_internal->GetState() == STATE_CANCELED;
676}
677
678wxThread::wxThread()
679{
680 p_internal = new wxThreadInternal();
681}
682
683wxThread::~wxThread()
684{
685 delete p_internal;
686}
687
688// ----------------------------------------------------------------------------
689// Automatic initialization for thread module
690// ----------------------------------------------------------------------------
691
692class wxThreadModule : public wxModule
693{
694public:
695 virtual bool OnInit();
696 virtual void OnExit();
697
698private:
699 DECLARE_DYNAMIC_CLASS(wxThreadModule)
700};
701
702IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
703
704bool wxThreadModule::OnInit()
705{
706 // allocate TLS index for storing the pointer to the current thread
707 s_tlsThisThread = ::TlsAlloc();
708 if ( s_tlsThisThread == 0xFFFFFFFF )
709 {
710 // in normal circumstances it will only happen if all other
711 // TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other
712 // words, this should never happen
713 wxLogSysError(_("Thread module initialization failed: "
714 "impossible to allocate index in thread "
715 "local storage"));
716
717 return FALSE;
718 }
719
720 // main thread doesn't have associated wxThread object, so store 0 in the
721 // TLS instead
722 if ( !::TlsSetValue(s_tlsThisThread, (LPVOID)0) )
723 {
724 ::TlsFree(s_tlsThisThread);
725 s_tlsThisThread = 0xFFFFFFFF;
726
727 wxLogSysError(_("Thread module initialization failed: "
728 "can not store value in thread local storage"));
729
730 return FALSE;
731 }
732
733 s_critsectWaitingForGui = new wxCriticalSection();
734
735 s_critsectGui = new wxCriticalSection();
736 s_critsectGui->Enter();
737
738 // no error return for GetCurrentThreadId()
739 s_idMainThread = ::GetCurrentThreadId();
740
741 return TRUE;
742}
743
744void wxThreadModule::OnExit()
745{
746 if ( !::TlsFree(s_tlsThisThread) )
747 {
748 wxLogLastError("TlsFree failed.");
749 }
750
751 if ( s_critsectGui )
752 {
753 s_critsectGui->Leave();
754 delete s_critsectGui;
755 s_critsectGui = NULL;
756 }
757
758 wxDELETE(s_critsectWaitingForGui);
759}
760
761// ----------------------------------------------------------------------------
762// under Windows, these functions are implemented usign a critical section and
763// not a mutex, so the names are a bit confusing
764// ----------------------------------------------------------------------------
765
766void WXDLLEXPORT wxMutexGuiEnter()
767{
768 // this would dead lock everything...
769 wxASSERT_MSG( !wxThread::IsMain(),
770 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
771
772 // the order in which we enter the critical sections here is crucial!!
773
774 // set the flag telling to the main thread that we want to do some GUI
775 {
776 wxCriticalSectionLocker enter(*s_critsectWaitingForGui);
777
778 s_nWaitingForGui++;
779 }
780
781 wxWakeUpMainThread();
782
783 // now we may block here because the main thread will soon let us in
784 // (during the next iteration of OnIdle())
785 s_critsectGui->Enter();
786}
787
788void WXDLLEXPORT wxMutexGuiLeave()
789{
790 wxCriticalSectionLocker enter(*s_critsectWaitingForGui);
791
792 if ( wxThread::IsMain() )
793 {
794 s_bGuiOwnedByMainThread = FALSE;
795 }
796 else
797 {
798 // decrement the number of waiters now
799 wxASSERT_MSG( s_nWaitingForGui > 0,
800 wxT("calling wxMutexGuiLeave() without entering it first?") );
801
802 s_nWaitingForGui--;
803
804 wxWakeUpMainThread();
805 }
806
807 s_critsectGui->Leave();
808}
809
810void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
811{
812 wxASSERT_MSG( wxThread::IsMain(),
813 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
814
815 wxCriticalSectionLocker enter(*s_critsectWaitingForGui);
816
817 if ( s_nWaitingForGui == 0 )
818 {
819 // no threads are waiting for GUI - so we may acquire the lock without
820 // any danger (but only if we don't already have it)
821 if ( !wxGuiOwnedByMainThread() )
822 {
823 s_critsectGui->Enter();
824
825 s_bGuiOwnedByMainThread = TRUE;
826 }
827 //else: already have it, nothing to do
828 }
829 else
830 {
831 // some threads are waiting, release the GUI lock if we have it
832 if ( wxGuiOwnedByMainThread() )
833 {
834 wxMutexGuiLeave();
835 }
836 //else: some other worker thread is doing GUI
837 }
838}
839
840bool WXDLLEXPORT wxGuiOwnedByMainThread()
841{
842 return s_bGuiOwnedByMainThread;
843}
844
845// wake up the main thread if it's in ::GetMessage()
846void WXDLLEXPORT wxWakeUpMainThread()
847{
848 // sending any message would do - hopefully WM_NULL is harmless enough
849 if ( !::PostThreadMessage(s_idMainThread, WM_NULL, 0, 0) )
850 {
851 // should never happen
852 wxLogLastError("PostThreadMessage(WM_NULL)");
853 }
854}
855
856bool WXDLLEXPORT wxIsWaitingForThread()
857{
858 return s_waitingForThread;
859}
860*/
861
862#endif // wxUSE_THREADS