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