]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/thread.cpp
added wxLog::Suspend/Resume and wxYield() uses them now so that it won't flush
[wxWidgets.git] / src / msw / 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 "wx/msw/private.h"
35
36#include "wx/module.h"
37#include "wx/thread.h"
38
39// must have this symbol defined to get _beginthread/_endthread declarations
40#ifndef _MT
41 #define _MT
42#endif
43
44#if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
45
46#if defined(__BORLANDC__) && !defined(__MT__)
47// I can't set -tWM in the IDE (anyone?) so have to do this
48#define __MT__
49#endif
50
51#if defined(__BORLANDC__) && !defined(__MFC_COMPAT__)
52// Needed to know about _beginthreadex etc..
53#define __MFC_COMPAT__
54#endif
55
56
57 #include <process.h>
58#endif
59
60// ----------------------------------------------------------------------------
61// constants
62// ----------------------------------------------------------------------------
63
64// the possible states of the thread ("=>" shows all possible transitions from
65// this state)
66enum wxThreadState
67{
68 STATE_NEW, // didn't start execution yet (=> RUNNING)
69 STATE_RUNNING, // thread is running (=> PAUSED, CANCELED)
70 STATE_PAUSED, // thread is temporarily suspended (=> RUNNING)
71 STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED)
72 STATE_EXITED // thread is terminating
73};
74
75// ----------------------------------------------------------------------------
76// this module globals
77// ----------------------------------------------------------------------------
78
79// TLS index of the slot where we store the pointer to the current thread
80static DWORD gs_tlsThisThread = 0xFFFFFFFF;
81
82// id of the main thread - the one which can call GUI functions without first
83// calling wxMutexGuiEnter()
84static DWORD gs_idMainThread = 0;
85
86// if it's FALSE, some secondary thread is holding the GUI lock
87static bool gs_bGuiOwnedByMainThread = TRUE;
88
89// critical section which controls access to all GUI functions: any secondary
90// thread (i.e. except the main one) must enter this crit section before doing
91// any GUI calls
92static wxCriticalSection *gs_critsectGui = NULL;
93
94// critical section which protects gs_nWaitingForGui variable
95static wxCriticalSection *gs_critsectWaitingForGui = NULL;
96
97// number of threads waiting for GUI in wxMutexGuiEnter()
98static size_t gs_nWaitingForGui = 0;
99
100// are we waiting for a thread termination?
101static bool gs_waitingForThread = FALSE;
102
103// ============================================================================
104// Windows implementation of thread classes
105// ============================================================================
106
107// ----------------------------------------------------------------------------
108// wxMutex implementation
109// ----------------------------------------------------------------------------
110
111class wxMutexInternal
112{
113public:
114 wxMutexInternal()
115 {
116 m_mutex = ::CreateMutex(NULL, FALSE, NULL);
117 if ( !m_mutex )
118 {
119 wxLogSysError(_("Can not create mutex"));
120 }
121 }
122
123 ~wxMutexInternal() { if ( m_mutex ) CloseHandle(m_mutex); }
124
125public:
126 HANDLE m_mutex;
127};
128
129wxMutex::wxMutex()
130{
131 m_internal = new wxMutexInternal;
132
133 m_locked = 0;
134}
135
136wxMutex::~wxMutex()
137{
138 if ( m_locked > 0 )
139 {
140 wxLogDebug(_T("Warning: freeing a locked mutex (%d locks)."), m_locked);
141 }
142
143 delete m_internal;
144}
145
146wxMutexError wxMutex::Lock()
147{
148 DWORD ret;
149
150 ret = WaitForSingleObject(m_internal->m_mutex, INFINITE);
151 switch ( ret )
152 {
153 case WAIT_ABANDONED:
154 return wxMUTEX_BUSY;
155
156 case WAIT_OBJECT_0:
157 // ok
158 break;
159
160 case WAIT_FAILED:
161 wxLogSysError(_("Couldn't acquire a mutex lock"));
162 return wxMUTEX_MISC_ERROR;
163
164 case WAIT_TIMEOUT:
165 default:
166 wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
167 }
168
169 m_locked++;
170 return wxMUTEX_NO_ERROR;
171}
172
173wxMutexError wxMutex::TryLock()
174{
175 DWORD ret;
176
177 ret = WaitForSingleObject(m_internal->m_mutex, 0);
178 if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
179 return wxMUTEX_BUSY;
180
181 m_locked++;
182 return wxMUTEX_NO_ERROR;
183}
184
185wxMutexError wxMutex::Unlock()
186{
187 if (m_locked > 0)
188 m_locked--;
189
190 BOOL ret = ReleaseMutex(m_internal->m_mutex);
191 if ( ret == 0 )
192 {
193 wxLogSysError(_("Couldn't release a mutex"));
194 return wxMUTEX_MISC_ERROR;
195 }
196
197 return wxMUTEX_NO_ERROR;
198}
199
200// ----------------------------------------------------------------------------
201// wxCondition implementation
202// ----------------------------------------------------------------------------
203
204class wxConditionInternal
205{
206public:
207 wxConditionInternal()
208 {
209 event = ::CreateEvent(
210 NULL, // default secutiry
211 FALSE, // not manual reset
212 FALSE, // nonsignaled initially
213 NULL // nameless event
214 );
215 if ( !event )
216 {
217 wxLogSysError(_("Can not create event object."));
218 }
219 waiters = 0;
220 }
221
222 bool Wait(DWORD timeout)
223 {
224 waiters++;
225
226 // FIXME this should be MsgWaitForMultipleObjects() as well probably
227 DWORD rc = ::WaitForSingleObject(event, timeout);
228
229 waiters--;
230
231 return rc != WAIT_TIMEOUT;
232 }
233
234 ~wxConditionInternal()
235 {
236 if ( event )
237 {
238 if ( !::CloseHandle(event) )
239 {
240 wxLogLastError("CloseHandle(event)");
241 }
242 }
243 }
244
245 HANDLE event;
246 int waiters;
247};
248
249wxCondition::wxCondition()
250{
251 m_internal = new wxConditionInternal;
252}
253
254wxCondition::~wxCondition()
255{
256 delete m_internal;
257}
258
259void wxCondition::Wait()
260{
261 (void)m_internal->Wait(INFINITE);
262}
263
264bool wxCondition::Wait(unsigned long sec,
265 unsigned long nsec)
266{
267 return m_internal->Wait(sec*1000 + nsec/1000000);
268}
269
270void wxCondition::Signal()
271{
272 // set the event to signaled: if a thread is already waiting on it, it will
273 // be woken up, otherwise the event will remain in the signaled state until
274 // someone waits on it. In any case, the system will return it to a non
275 // signalled state afterwards. If multiple threads are waiting, only one
276 // will be woken up.
277 if ( !::SetEvent(m_internal->event) )
278 {
279 wxLogLastError("SetEvent");
280 }
281}
282
283void wxCondition::Broadcast()
284{
285 // this works because all these threads are already waiting and so each
286 // SetEvent() inside Signal() is really a PulseEvent() because the event
287 // state is immediately returned to non-signaled
288 for ( int i = 0; i < m_internal->waiters; i++ )
289 {
290 Signal();
291 }
292}
293
294// ----------------------------------------------------------------------------
295// wxCriticalSection implementation
296// ----------------------------------------------------------------------------
297
298wxCriticalSection::wxCriticalSection()
299{
300 wxASSERT_MSG( sizeof(CRITICAL_SECTION) <= sizeof(m_buffer),
301 _T("must increase buffer size in wx/thread.h") );
302
303 ::InitializeCriticalSection((CRITICAL_SECTION *)m_buffer);
304}
305
306wxCriticalSection::~wxCriticalSection()
307{
308 ::DeleteCriticalSection((CRITICAL_SECTION *)m_buffer);
309}
310
311void wxCriticalSection::Enter()
312{
313 ::EnterCriticalSection((CRITICAL_SECTION *)m_buffer);
314}
315
316void wxCriticalSection::Leave()
317{
318 ::LeaveCriticalSection((CRITICAL_SECTION *)m_buffer);
319}
320
321// ----------------------------------------------------------------------------
322// wxThread implementation
323// ----------------------------------------------------------------------------
324
325// wxThreadInternal class
326// ----------------------
327
328class wxThreadInternal
329{
330public:
331 wxThreadInternal()
332 {
333 m_hThread = 0;
334 m_state = STATE_NEW;
335 m_priority = WXTHREAD_DEFAULT_PRIORITY;
336 }
337
338 ~wxThreadInternal()
339 {
340 Free();
341 }
342
343 void Free()
344 {
345 if ( m_hThread )
346 {
347 if ( !::CloseHandle(m_hThread) )
348 {
349 wxLogLastError("CloseHandle(thread)");
350 }
351
352 m_hThread = 0;
353 }
354 }
355
356 // create a new (suspended) thread (for the given thread object)
357 bool Create(wxThread *thread);
358
359 // suspend/resume/terminate
360 bool Suspend();
361 bool Resume();
362 void Cancel() { m_state = STATE_CANCELED; }
363
364 // thread state
365 void SetState(wxThreadState state) { m_state = state; }
366 wxThreadState GetState() const { return m_state; }
367
368 // thread priority
369 void SetPriority(unsigned int priority);
370 unsigned int GetPriority() const { return m_priority; }
371
372 // thread handle and id
373 HANDLE GetHandle() const { return m_hThread; }
374 DWORD GetId() const { return m_tid; }
375
376 // thread function
377 static DWORD WinThreadStart(wxThread *thread);
378
379private:
380 HANDLE m_hThread; // handle of the thread
381 wxThreadState m_state; // state, see wxThreadState enum
382 unsigned int m_priority; // thread priority in "wx" units
383 DWORD m_tid; // thread id
384};
385
386DWORD wxThreadInternal::WinThreadStart(wxThread *thread)
387{
388 // first of all, check whether we hadn't been cancelled already
389 if ( thread->m_internal->GetState() == STATE_EXITED )
390 {
391 return (DWORD)-1;
392 }
393
394 // store the thread object in the TLS
395 if ( !::TlsSetValue(gs_tlsThisThread, thread) )
396 {
397 wxLogSysError(_("Can not start thread: error writing TLS."));
398
399 return (DWORD)-1;
400 }
401
402 DWORD rc = (DWORD)thread->Entry();
403
404 // enter m_critsect before changing the thread state
405 thread->m_critsect.Enter();
406 bool wasCancelled = thread->m_internal->GetState() == STATE_CANCELED;
407 thread->m_internal->SetState(STATE_EXITED);
408 thread->m_critsect.Leave();
409
410 thread->OnExit();
411
412 // if the thread was cancelled (from Delete()), then it the handle is still
413 // needed there
414 if ( thread->IsDetached() && !wasCancelled )
415 {
416 // auto delete
417 delete thread;
418 }
419 //else: the joinable threads handle will be closed when Wait() is done
420
421 return rc;
422}
423
424void wxThreadInternal::SetPriority(unsigned int priority)
425{
426 m_priority = priority;
427
428 // translate wxWindows priority to the Windows one
429 int win_priority;
430 if (m_priority <= 20)
431 win_priority = THREAD_PRIORITY_LOWEST;
432 else if (m_priority <= 40)
433 win_priority = THREAD_PRIORITY_BELOW_NORMAL;
434 else if (m_priority <= 60)
435 win_priority = THREAD_PRIORITY_NORMAL;
436 else if (m_priority <= 80)
437 win_priority = THREAD_PRIORITY_ABOVE_NORMAL;
438 else if (m_priority <= 100)
439 win_priority = THREAD_PRIORITY_HIGHEST;
440 else
441 {
442 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
443 win_priority = THREAD_PRIORITY_NORMAL;
444 }
445
446 if ( !::SetThreadPriority(m_hThread, win_priority) )
447 {
448 wxLogSysError(_("Can't set thread priority"));
449 }
450}
451
452bool wxThreadInternal::Create(wxThread *thread)
453{
454 // for compilers which have it, we should use C RTL function for thread
455 // creation instead of Win32 API one because otherwise we will have memory
456 // leaks if the thread uses C RTL (and most threads do)
457#if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
458 typedef unsigned (__stdcall *RtlThreadStart)(void *);
459
460 m_hThread = (HANDLE)_beginthreadex(NULL, 0,
461 (RtlThreadStart)
462 wxThreadInternal::WinThreadStart,
463 thread, CREATE_SUSPENDED,
464 (unsigned int *)&m_tid);
465#else // !VC++
466 m_hThread = ::CreateThread
467 (
468 NULL, // default security
469 0, // default stack size
470 (LPTHREAD_START_ROUTINE) // thread entry point
471 wxThreadInternal::WinThreadStart, //
472 (LPVOID)thread, // parameter
473 CREATE_SUSPENDED, // flags
474 &m_tid // [out] thread id
475 );
476#endif // VC++/!VC++
477
478 if ( m_hThread == NULL )
479 {
480 wxLogSysError(_("Can't create thread"));
481
482 return FALSE;
483 }
484
485 if ( m_priority != WXTHREAD_DEFAULT_PRIORITY )
486 {
487 SetPriority(m_priority);
488 }
489
490 return TRUE;
491}
492
493bool wxThreadInternal::Suspend()
494{
495 DWORD nSuspendCount = ::SuspendThread(m_hThread);
496 if ( nSuspendCount == (DWORD)-1 )
497 {
498 wxLogSysError(_("Can not suspend thread %x"), m_hThread);
499
500 return FALSE;
501 }
502
503 m_state = STATE_PAUSED;
504
505 return TRUE;
506}
507
508bool wxThreadInternal::Resume()
509{
510 DWORD nSuspendCount = ::ResumeThread(m_hThread);
511 if ( nSuspendCount == (DWORD)-1 )
512 {
513 wxLogSysError(_("Can not resume thread %x"), m_hThread);
514
515 return FALSE;
516 }
517
518 m_state = STATE_RUNNING;
519
520 return TRUE;
521}
522
523// static functions
524// ----------------
525
526wxThread *wxThread::This()
527{
528 wxThread *thread = (wxThread *)::TlsGetValue(gs_tlsThisThread);
529
530 // be careful, 0 may be a valid return value as well
531 if ( !thread && (::GetLastError() != NO_ERROR) )
532 {
533 wxLogSysError(_("Couldn't get the current thread pointer"));
534
535 // return NULL...
536 }
537
538 return thread;
539}
540
541bool wxThread::IsMain()
542{
543 return ::GetCurrentThreadId() == gs_idMainThread;
544}
545
546#ifdef Yield
547#undef Yield
548#endif
549
550void wxThread::Yield()
551{
552 // 0 argument to Sleep() is special and means to just give away the rest of
553 // our timeslice
554 ::Sleep(0);
555}
556
557void wxThread::Sleep(unsigned long milliseconds)
558{
559 ::Sleep(milliseconds);
560}
561
562int wxThread::GetCPUCount()
563{
564 SYSTEM_INFO si;
565 GetSystemInfo(&si);
566
567 return si.dwNumberOfProcessors;
568}
569
570bool wxThread::SetConcurrency(size_t level)
571{
572 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
573
574 // ok only for the default one
575 if ( level == 0 )
576 return 0;
577
578 // get system affinity mask first
579 HANDLE hProcess = ::GetCurrentProcess();
580 DWORD dwProcMask, dwSysMask;
581 if ( ::GetProcessAffinityMask(hProcess, &dwProcMask, &dwSysMask) == 0 )
582 {
583 wxLogLastError(_T("GetProcessAffinityMask"));
584
585 return FALSE;
586 }
587
588 // how many CPUs have we got?
589 if ( dwSysMask == 1 )
590 {
591 // don't bother with all this complicated stuff - on a single
592 // processor system it doesn't make much sense anyhow
593 return level == 1;
594 }
595
596 // calculate the process mask: it's a bit vector with one bit per
597 // processor; we want to schedule the process to run on first level
598 // CPUs
599 DWORD bit = 1;
600 while ( bit )
601 {
602 if ( dwSysMask & bit )
603 {
604 // ok, we can set this bit
605 dwProcMask |= bit;
606
607 // another process added
608 if ( !--level )
609 {
610 // and that's enough
611 break;
612 }
613 }
614
615 // next bit
616 bit <<= 1;
617 }
618
619 // could we set all bits?
620 if ( level != 0 )
621 {
622 wxLogDebug(_T("bad level %u in wxThread::SetConcurrency()"), level);
623
624 return FALSE;
625 }
626
627 // set it: we can't link to SetProcessAffinityMask() because it doesn't
628 // exist in Win9x, use RT binding instead
629
630 typedef BOOL (*SETPROCESSAFFINITYMASK)(HANDLE, DWORD);
631
632 // can use static var because we're always in the main thread here
633 static SETPROCESSAFFINITYMASK pfnSetProcessAffinityMask = NULL;
634
635 if ( !pfnSetProcessAffinityMask )
636 {
637 HMODULE hModKernel = ::LoadLibrary(_T("kernel32"));
638 if ( hModKernel )
639 {
640 pfnSetProcessAffinityMask = (SETPROCESSAFFINITYMASK)
641 ::GetProcAddress(hModKernel,
642#if defined(__BORLANDC__) && (__BORLANDC__ <= 0x520)
643 "SetProcessAffinityMask");
644#else
645 _T("SetProcessAffinityMask"));
646#endif
647 }
648
649 // we've discovered a MT version of Win9x!
650 wxASSERT_MSG( pfnSetProcessAffinityMask,
651 _T("this system has several CPUs but no "
652 "SetProcessAffinityMask function?") );
653 }
654
655 if ( !pfnSetProcessAffinityMask )
656 {
657 // msg given above - do it only once
658 return FALSE;
659 }
660
661 if ( pfnSetProcessAffinityMask(hProcess, dwProcMask) == 0 )
662 {
663 wxLogLastError(_T("SetProcessAffinityMask"));
664
665 return FALSE;
666 }
667
668 return TRUE;
669}
670
671// ctor and dtor
672// -------------
673
674wxThread::wxThread(wxThreadKind kind)
675{
676 m_internal = new wxThreadInternal();
677
678 m_isDetached = kind == wxTHREAD_DETACHED;
679}
680
681wxThread::~wxThread()
682{
683 delete m_internal;
684}
685
686// create/start thread
687// -------------------
688
689wxThreadError wxThread::Create()
690{
691 wxCriticalSectionLocker lock(m_critsect);
692
693 if ( !m_internal->Create(this) )
694 return wxTHREAD_NO_RESOURCE;
695
696 return wxTHREAD_NO_ERROR;
697}
698
699wxThreadError wxThread::Run()
700{
701 wxCriticalSectionLocker lock(m_critsect);
702
703 if ( m_internal->GetState() != STATE_NEW )
704 {
705 // actually, it may be almost any state at all, not only STATE_RUNNING
706 return wxTHREAD_RUNNING;
707 }
708
709 // the thread has just been created and is still suspended - let it run
710 return Resume();
711}
712
713// suspend/resume thread
714// ---------------------
715
716wxThreadError wxThread::Pause()
717{
718 wxCriticalSectionLocker lock(m_critsect);
719
720 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
721}
722
723wxThreadError wxThread::Resume()
724{
725 wxCriticalSectionLocker lock(m_critsect);
726
727 return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
728}
729
730// stopping thread
731// ---------------
732
733wxThread::ExitCode wxThread::Wait()
734{
735 // although under Windows we can wait for any thread, it's an error to
736 // wait for a detached one in wxWin API
737 wxCHECK_MSG( !IsDetached(), (ExitCode)-1,
738 _T("can't wait for detached thread") );
739
740 ExitCode rc = (ExitCode)-1;
741
742 (void)Delete(&rc);
743
744 m_internal->Free();
745
746 return rc;
747}
748
749wxThreadError wxThread::Delete(ExitCode *pRc)
750{
751 ExitCode rc = 0;
752
753 // Delete() is always safe to call, so consider all possible states
754
755 // has the thread started to run?
756 bool shouldResume = FALSE;
757
758 {
759 wxCriticalSectionLocker lock(m_critsect);
760
761 if ( m_internal->GetState() == STATE_NEW )
762 {
763 // WinThreadStart() will see it and terminate immediately
764 m_internal->SetState(STATE_EXITED);
765
766 shouldResume = TRUE;
767 }
768 }
769
770 // is the thread paused?
771 if ( shouldResume || IsPaused() )
772 Resume();
773
774 HANDLE hThread = m_internal->GetHandle();
775
776 // does is still run?
777 if ( IsRunning() )
778 {
779 if ( IsMain() )
780 {
781 // set flag for wxIsWaitingForThread()
782 gs_waitingForThread = TRUE;
783
784#if wxUSE_GUI
785 wxBeginBusyCursor();
786#endif // wxUSE_GUI
787 }
788
789 // ask the thread to terminate
790 {
791 wxCriticalSectionLocker lock(m_critsect);
792
793 m_internal->Cancel();
794 }
795
796#if wxUSE_GUI
797 // we can't just wait for the thread to terminate because it might be
798 // calling some GUI functions and so it will never terminate before we
799 // process the Windows messages that result from these functions
800 DWORD result;
801 do
802 {
803 result = ::MsgWaitForMultipleObjects
804 (
805 1, // number of objects to wait for
806 &hThread, // the objects
807 FALSE, // don't wait for all objects
808 INFINITE, // no timeout
809 QS_ALLEVENTS // return as soon as there are any events
810 );
811
812 switch ( result )
813 {
814 case 0xFFFFFFFF:
815 // error
816 wxLogSysError(_("Can not wait for thread termination"));
817 Kill();
818 return wxTHREAD_KILLED;
819
820 case WAIT_OBJECT_0:
821 // thread we're waiting for terminated
822 break;
823
824 case WAIT_OBJECT_0 + 1:
825 // new message arrived, process it
826 if ( !wxTheApp->DoMessage() )
827 {
828 // WM_QUIT received: kill the thread
829 Kill();
830
831 return wxTHREAD_KILLED;
832 }
833
834 if ( IsMain() )
835 {
836 // give the thread we're waiting for chance to exit
837 // from the GUI call it might have been in
838 if ( (gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
839 {
840 wxMutexGuiLeave();
841 }
842 }
843
844 break;
845
846 default:
847 wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject"));
848 }
849 } while ( result != WAIT_OBJECT_0 );
850#else // !wxUSE_GUI
851 // simply wait for the thread to terminate
852 //
853 // OTOH, even console apps create windows (in wxExecute, for WinSock
854 // &c), so may be use MsgWaitForMultipleObject() too here?
855 if ( WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0 )
856 {
857 wxFAIL_MSG(wxT("unexpected result of WaitForSingleObject"));
858 }
859#endif // wxUSE_GUI/!wxUSE_GUI
860
861 if ( IsMain() )
862 {
863 gs_waitingForThread = FALSE;
864
865#if wxUSE_GUI
866 wxEndBusyCursor();
867#endif // wxUSE_GUI
868 }
869 }
870
871 if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
872 {
873 wxLogLastError("GetExitCodeThread");
874
875 rc = (ExitCode)-1;
876 }
877
878 if ( IsDetached() )
879 {
880 // if the thread exits normally, this is done in WinThreadStart, but in
881 // this case it would have been too early because
882 // MsgWaitForMultipleObject() would fail if the therad handle was
883 // closed while we were waiting on it, so we must do it here
884 delete this;
885 }
886
887 wxASSERT_MSG( (DWORD)rc != STILL_ACTIVE,
888 wxT("thread must be already terminated.") );
889
890 if ( pRc )
891 *pRc = rc;
892
893 return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR;
894}
895
896wxThreadError wxThread::Kill()
897{
898 if ( !IsRunning() )
899 return wxTHREAD_NOT_RUNNING;
900
901 if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
902 {
903 wxLogSysError(_("Couldn't terminate thread"));
904
905 return wxTHREAD_MISC_ERROR;
906 }
907
908 m_internal->Free();
909
910 if ( IsDetached() )
911 {
912 delete this;
913 }
914
915 return wxTHREAD_NO_ERROR;
916}
917
918void wxThread::Exit(ExitCode status)
919{
920 m_internal->Free();
921
922 if ( IsDetached() )
923 {
924 delete this;
925 }
926
927#if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
928 _endthreadex((unsigned)status);
929#else // !VC++
930 ::ExitThread((DWORD)status);
931#endif // VC++/!VC++
932
933 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
934}
935
936// priority setting
937// ----------------
938
939void wxThread::SetPriority(unsigned int prio)
940{
941 wxCriticalSectionLocker lock(m_critsect);
942
943 m_internal->SetPriority(prio);
944}
945
946unsigned int wxThread::GetPriority() const
947{
948 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
949
950 return m_internal->GetPriority();
951}
952
953unsigned long wxThread::GetId() const
954{
955 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
956
957 return (unsigned long)m_internal->GetId();
958}
959
960bool wxThread::IsRunning() const
961{
962 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
963
964 return m_internal->GetState() == STATE_RUNNING;
965}
966
967bool wxThread::IsAlive() const
968{
969 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
970
971 return (m_internal->GetState() == STATE_RUNNING) ||
972 (m_internal->GetState() == STATE_PAUSED);
973}
974
975bool wxThread::IsPaused() const
976{
977 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
978
979 return m_internal->GetState() == STATE_PAUSED;
980}
981
982bool wxThread::TestDestroy()
983{
984 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
985
986 return m_internal->GetState() == STATE_CANCELED;
987}
988
989// ----------------------------------------------------------------------------
990// Automatic initialization for thread module
991// ----------------------------------------------------------------------------
992
993class wxThreadModule : public wxModule
994{
995public:
996 virtual bool OnInit();
997 virtual void OnExit();
998
999private:
1000 DECLARE_DYNAMIC_CLASS(wxThreadModule)
1001};
1002
1003IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
1004
1005bool wxThreadModule::OnInit()
1006{
1007 // allocate TLS index for storing the pointer to the current thread
1008 gs_tlsThisThread = ::TlsAlloc();
1009 if ( gs_tlsThisThread == 0xFFFFFFFF )
1010 {
1011 // in normal circumstances it will only happen if all other
1012 // TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other
1013 // words, this should never happen
1014 wxLogSysError(_("Thread module initialization failed: "
1015 "impossible to allocate index in thread "
1016 "local storage"));
1017
1018 return FALSE;
1019 }
1020
1021 // main thread doesn't have associated wxThread object, so store 0 in the
1022 // TLS instead
1023 if ( !::TlsSetValue(gs_tlsThisThread, (LPVOID)0) )
1024 {
1025 ::TlsFree(gs_tlsThisThread);
1026 gs_tlsThisThread = 0xFFFFFFFF;
1027
1028 wxLogSysError(_("Thread module initialization failed: "
1029 "can not store value in thread local storage"));
1030
1031 return FALSE;
1032 }
1033
1034 gs_critsectWaitingForGui = new wxCriticalSection();
1035
1036 gs_critsectGui = new wxCriticalSection();
1037 gs_critsectGui->Enter();
1038
1039 // no error return for GetCurrentThreadId()
1040 gs_idMainThread = ::GetCurrentThreadId();
1041
1042 return TRUE;
1043}
1044
1045void wxThreadModule::OnExit()
1046{
1047 if ( !::TlsFree(gs_tlsThisThread) )
1048 {
1049 wxLogLastError("TlsFree failed.");
1050 }
1051
1052 if ( gs_critsectGui )
1053 {
1054 gs_critsectGui->Leave();
1055 delete gs_critsectGui;
1056 gs_critsectGui = NULL;
1057 }
1058
1059 delete gs_critsectWaitingForGui;
1060 gs_critsectWaitingForGui = NULL;
1061}
1062
1063// ----------------------------------------------------------------------------
1064// under Windows, these functions are implemented using a critical section and
1065// not a mutex, so the names are a bit confusing
1066// ----------------------------------------------------------------------------
1067
1068void WXDLLEXPORT wxMutexGuiEnter()
1069{
1070 // this would dead lock everything...
1071 wxASSERT_MSG( !wxThread::IsMain(),
1072 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
1073
1074 // the order in which we enter the critical sections here is crucial!!
1075
1076 // set the flag telling to the main thread that we want to do some GUI
1077 {
1078 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1079
1080 gs_nWaitingForGui++;
1081 }
1082
1083 wxWakeUpMainThread();
1084
1085 // now we may block here because the main thread will soon let us in
1086 // (during the next iteration of OnIdle())
1087 gs_critsectGui->Enter();
1088}
1089
1090void WXDLLEXPORT wxMutexGuiLeave()
1091{
1092 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1093
1094 if ( wxThread::IsMain() )
1095 {
1096 gs_bGuiOwnedByMainThread = FALSE;
1097 }
1098 else
1099 {
1100 // decrement the number of waiters now
1101 wxASSERT_MSG( gs_nWaitingForGui > 0,
1102 wxT("calling wxMutexGuiLeave() without entering it first?") );
1103
1104 gs_nWaitingForGui--;
1105
1106 wxWakeUpMainThread();
1107 }
1108
1109 gs_critsectGui->Leave();
1110}
1111
1112void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
1113{
1114 wxASSERT_MSG( wxThread::IsMain(),
1115 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1116
1117 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1118
1119 if ( gs_nWaitingForGui == 0 )
1120 {
1121 // no threads are waiting for GUI - so we may acquire the lock without
1122 // any danger (but only if we don't already have it)
1123 if ( !wxGuiOwnedByMainThread() )
1124 {
1125 gs_critsectGui->Enter();
1126
1127 gs_bGuiOwnedByMainThread = TRUE;
1128 }
1129 //else: already have it, nothing to do
1130 }
1131 else
1132 {
1133 // some threads are waiting, release the GUI lock if we have it
1134 if ( wxGuiOwnedByMainThread() )
1135 {
1136 wxMutexGuiLeave();
1137 }
1138 //else: some other worker thread is doing GUI
1139 }
1140}
1141
1142bool WXDLLEXPORT wxGuiOwnedByMainThread()
1143{
1144 return gs_bGuiOwnedByMainThread;
1145}
1146
1147// wake up the main thread if it's in ::GetMessage()
1148void WXDLLEXPORT wxWakeUpMainThread()
1149{
1150 // sending any message would do - hopefully WM_NULL is harmless enough
1151 if ( !::PostThreadMessage(gs_idMainThread, WM_NULL, 0, 0) )
1152 {
1153 // should never happen
1154 wxLogLastError("PostThreadMessage(WM_NULL)");
1155 }
1156}
1157
1158bool WXDLLEXPORT wxIsWaitingForThread()
1159{
1160 return gs_waitingForThread;
1161}
1162
1163#endif // wxUSE_THREADS