]> git.saurik.com Git - wxWidgets.git/blob - src/msw/thread.cpp
wxEVT_SCROLL_THUMBRELEASE instead of wxEVT_SCROLLWIN_THUMBRELEASE
[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
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)
66 enum 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
80 static DWORD gs_tlsThisThread = 0xFFFFFFFF;
81
82 // id of the main thread - the one which can call GUI functions without first
83 // calling wxMutexGuiEnter()
84 static DWORD gs_idMainThread = 0;
85
86 // if it's FALSE, some secondary thread is holding the GUI lock
87 static 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
92 static wxCriticalSection *gs_critsectGui = NULL;
93
94 // critical section which protects gs_nWaitingForGui variable
95 static wxCriticalSection *gs_critsectWaitingForGui = NULL;
96
97 // number of threads waiting for GUI in wxMutexGuiEnter()
98 static size_t gs_nWaitingForGui = 0;
99
100 // are we waiting for a thread termination?
101 static bool gs_waitingForThread = FALSE;
102
103 // ============================================================================
104 // Windows implementation of thread classes
105 // ============================================================================
106
107 // ----------------------------------------------------------------------------
108 // wxMutex implementation
109 // ----------------------------------------------------------------------------
110
111 class wxMutexInternal
112 {
113 public:
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
125 public:
126 HANDLE m_mutex;
127 };
128
129 wxMutex::wxMutex()
130 {
131 m_internal = new wxMutexInternal;
132
133 m_locked = 0;
134 }
135
136 wxMutex::~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
146 wxMutexError 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
173 wxMutexError 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
185 wxMutexError 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
204 class wxConditionInternal
205 {
206 public:
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
249 wxCondition::wxCondition()
250 {
251 m_internal = new wxConditionInternal;
252 }
253
254 wxCondition::~wxCondition()
255 {
256 delete m_internal;
257 }
258
259 void wxCondition::Wait()
260 {
261 (void)m_internal->Wait(INFINITE);
262 }
263
264 bool wxCondition::Wait(unsigned long sec,
265 unsigned long nsec)
266 {
267 return m_internal->Wait(sec*1000 + nsec/1000000);
268 }
269
270 void 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
283 void 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
298 wxCriticalSection::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
306 wxCriticalSection::~wxCriticalSection()
307 {
308 ::DeleteCriticalSection((CRITICAL_SECTION *)m_buffer);
309 }
310
311 void wxCriticalSection::Enter()
312 {
313 ::EnterCriticalSection((CRITICAL_SECTION *)m_buffer);
314 }
315
316 void wxCriticalSection::Leave()
317 {
318 ::LeaveCriticalSection((CRITICAL_SECTION *)m_buffer);
319 }
320
321 // ----------------------------------------------------------------------------
322 // wxThread implementation
323 // ----------------------------------------------------------------------------
324
325 // wxThreadInternal class
326 // ----------------------
327
328 class wxThreadInternal
329 {
330 public:
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
379 private:
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
386 DWORD 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
424 void 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
452 bool 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
493 bool 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
508 bool 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
526 wxThread *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
541 bool wxThread::IsMain()
542 {
543 return ::GetCurrentThreadId() == gs_idMainThread;
544 }
545
546 #ifdef Yield
547 #undef Yield
548 #endif
549
550 void 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
557 void wxThread::Sleep(unsigned long milliseconds)
558 {
559 ::Sleep(milliseconds);
560 }
561
562 int wxThread::GetCPUCount()
563 {
564 SYSTEM_INFO si;
565 GetSystemInfo(&si);
566
567 return si.dwNumberOfProcessors;
568 }
569
570 bool 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
674 wxThread::wxThread(wxThreadKind kind)
675 {
676 m_internal = new wxThreadInternal();
677
678 m_isDetached = kind == wxTHREAD_DETACHED;
679 }
680
681 wxThread::~wxThread()
682 {
683 delete m_internal;
684 }
685
686 // create/start thread
687 // -------------------
688
689 wxThreadError 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
699 wxThreadError 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
716 wxThreadError wxThread::Pause()
717 {
718 wxCriticalSectionLocker lock(m_critsect);
719
720 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
721 }
722
723 wxThreadError 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
733 wxThread::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
749 wxThreadError 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
896 wxThreadError 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
918 void 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
939 void wxThread::SetPriority(unsigned int prio)
940 {
941 wxCriticalSectionLocker lock(m_critsect);
942
943 m_internal->SetPriority(prio);
944 }
945
946 unsigned int wxThread::GetPriority() const
947 {
948 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
949
950 return m_internal->GetPriority();
951 }
952
953 unsigned long wxThread::GetId() const
954 {
955 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
956
957 return (unsigned long)m_internal->GetId();
958 }
959
960 bool wxThread::IsRunning() const
961 {
962 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
963
964 return m_internal->GetState() == STATE_RUNNING;
965 }
966
967 bool 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
975 bool wxThread::IsPaused() const
976 {
977 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
978
979 return m_internal->GetState() == STATE_PAUSED;
980 }
981
982 bool 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
993 class wxThreadModule : public wxModule
994 {
995 public:
996 virtual bool OnInit();
997 virtual void OnExit();
998
999 private:
1000 DECLARE_DYNAMIC_CLASS(wxThreadModule)
1001 };
1002
1003 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
1004
1005 bool 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
1045 void 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
1068 void 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
1090 void 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
1112 void 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
1142 bool WXDLLEXPORT wxGuiOwnedByMainThread()
1143 {
1144 return gs_bGuiOwnedByMainThread;
1145 }
1146
1147 // wake up the main thread if it's in ::GetMessage()
1148 void 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
1158 bool WXDLLEXPORT wxIsWaitingForThread()
1159 {
1160 return gs_waitingForThread;
1161 }
1162
1163 #endif // wxUSE_THREADS