]> git.saurik.com Git - wxWidgets.git/blob - src/msw/thread.cpp
1. fruitless attempts to reproduce wxNotebook bug in the sample
[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__) || \
458 (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500)) \\
459 (defined(__GNUG__) && defined(__MSVCRT__)
460 typedef unsigned (__stdcall *RtlThreadStart)(void *);
461
462 m_hThread = (HANDLE)_beginthreadex(NULL, 0,
463 (RtlThreadStart)
464 wxThreadInternal::WinThreadStart,
465 thread, CREATE_SUSPENDED,
466 (unsigned int *)&m_tid);
467 #else // compiler doesn't have _beginthreadex
468 m_hThread = ::CreateThread
469 (
470 NULL, // default security
471 0, // default stack size
472 (LPTHREAD_START_ROUTINE) // thread entry point
473 wxThreadInternal::WinThreadStart, //
474 (LPVOID)thread, // parameter
475 CREATE_SUSPENDED, // flags
476 &m_tid // [out] thread id
477 );
478 #endif // _beginthreadex/CreateThread
479
480 if ( m_hThread == NULL )
481 {
482 wxLogSysError(_("Can't create thread"));
483
484 return FALSE;
485 }
486
487 if ( m_priority != WXTHREAD_DEFAULT_PRIORITY )
488 {
489 SetPriority(m_priority);
490 }
491
492 return TRUE;
493 }
494
495 bool wxThreadInternal::Suspend()
496 {
497 DWORD nSuspendCount = ::SuspendThread(m_hThread);
498 if ( nSuspendCount == (DWORD)-1 )
499 {
500 wxLogSysError(_("Can not suspend thread %x"), m_hThread);
501
502 return FALSE;
503 }
504
505 m_state = STATE_PAUSED;
506
507 return TRUE;
508 }
509
510 bool wxThreadInternal::Resume()
511 {
512 DWORD nSuspendCount = ::ResumeThread(m_hThread);
513 if ( nSuspendCount == (DWORD)-1 )
514 {
515 wxLogSysError(_("Can not resume thread %x"), m_hThread);
516
517 return FALSE;
518 }
519
520 m_state = STATE_RUNNING;
521
522 return TRUE;
523 }
524
525 // static functions
526 // ----------------
527
528 wxThread *wxThread::This()
529 {
530 wxThread *thread = (wxThread *)::TlsGetValue(gs_tlsThisThread);
531
532 // be careful, 0 may be a valid return value as well
533 if ( !thread && (::GetLastError() != NO_ERROR) )
534 {
535 wxLogSysError(_("Couldn't get the current thread pointer"));
536
537 // return NULL...
538 }
539
540 return thread;
541 }
542
543 bool wxThread::IsMain()
544 {
545 return ::GetCurrentThreadId() == gs_idMainThread;
546 }
547
548 #ifdef Yield
549 #undef Yield
550 #endif
551
552 void wxThread::Yield()
553 {
554 // 0 argument to Sleep() is special and means to just give away the rest of
555 // our timeslice
556 ::Sleep(0);
557 }
558
559 void wxThread::Sleep(unsigned long milliseconds)
560 {
561 ::Sleep(milliseconds);
562 }
563
564 int wxThread::GetCPUCount()
565 {
566 SYSTEM_INFO si;
567 GetSystemInfo(&si);
568
569 return si.dwNumberOfProcessors;
570 }
571
572 bool wxThread::SetConcurrency(size_t level)
573 {
574 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
575
576 // ok only for the default one
577 if ( level == 0 )
578 return 0;
579
580 // get system affinity mask first
581 HANDLE hProcess = ::GetCurrentProcess();
582 DWORD dwProcMask, dwSysMask;
583 if ( ::GetProcessAffinityMask(hProcess, &dwProcMask, &dwSysMask) == 0 )
584 {
585 wxLogLastError(_T("GetProcessAffinityMask"));
586
587 return FALSE;
588 }
589
590 // how many CPUs have we got?
591 if ( dwSysMask == 1 )
592 {
593 // don't bother with all this complicated stuff - on a single
594 // processor system it doesn't make much sense anyhow
595 return level == 1;
596 }
597
598 // calculate the process mask: it's a bit vector with one bit per
599 // processor; we want to schedule the process to run on first level
600 // CPUs
601 DWORD bit = 1;
602 while ( bit )
603 {
604 if ( dwSysMask & bit )
605 {
606 // ok, we can set this bit
607 dwProcMask |= bit;
608
609 // another process added
610 if ( !--level )
611 {
612 // and that's enough
613 break;
614 }
615 }
616
617 // next bit
618 bit <<= 1;
619 }
620
621 // could we set all bits?
622 if ( level != 0 )
623 {
624 wxLogDebug(_T("bad level %u in wxThread::SetConcurrency()"), level);
625
626 return FALSE;
627 }
628
629 // set it: we can't link to SetProcessAffinityMask() because it doesn't
630 // exist in Win9x, use RT binding instead
631
632 typedef BOOL (*SETPROCESSAFFINITYMASK)(HANDLE, DWORD);
633
634 // can use static var because we're always in the main thread here
635 static SETPROCESSAFFINITYMASK pfnSetProcessAffinityMask = NULL;
636
637 if ( !pfnSetProcessAffinityMask )
638 {
639 HMODULE hModKernel = ::LoadLibrary(_T("kernel32"));
640 if ( hModKernel )
641 {
642 pfnSetProcessAffinityMask = (SETPROCESSAFFINITYMASK)
643 ::GetProcAddress(hModKernel,
644 #if defined(__BORLANDC__) && (__BORLANDC__ <= 0x520)
645 "SetProcessAffinityMask");
646 #else
647 _T("SetProcessAffinityMask"));
648 #endif
649 }
650
651 // we've discovered a MT version of Win9x!
652 wxASSERT_MSG( pfnSetProcessAffinityMask,
653 _T("this system has several CPUs but no "
654 "SetProcessAffinityMask function?") );
655 }
656
657 if ( !pfnSetProcessAffinityMask )
658 {
659 // msg given above - do it only once
660 return FALSE;
661 }
662
663 if ( pfnSetProcessAffinityMask(hProcess, dwProcMask) == 0 )
664 {
665 wxLogLastError(_T("SetProcessAffinityMask"));
666
667 return FALSE;
668 }
669
670 return TRUE;
671 }
672
673 // ctor and dtor
674 // -------------
675
676 wxThread::wxThread(wxThreadKind kind)
677 {
678 m_internal = new wxThreadInternal();
679
680 m_isDetached = kind == wxTHREAD_DETACHED;
681 }
682
683 wxThread::~wxThread()
684 {
685 delete m_internal;
686 }
687
688 // create/start thread
689 // -------------------
690
691 wxThreadError wxThread::Create()
692 {
693 wxCriticalSectionLocker lock(m_critsect);
694
695 if ( !m_internal->Create(this) )
696 return wxTHREAD_NO_RESOURCE;
697
698 return wxTHREAD_NO_ERROR;
699 }
700
701 wxThreadError wxThread::Run()
702 {
703 wxCriticalSectionLocker lock(m_critsect);
704
705 if ( m_internal->GetState() != STATE_NEW )
706 {
707 // actually, it may be almost any state at all, not only STATE_RUNNING
708 return wxTHREAD_RUNNING;
709 }
710
711 // the thread has just been created and is still suspended - let it run
712 return Resume();
713 }
714
715 // suspend/resume thread
716 // ---------------------
717
718 wxThreadError wxThread::Pause()
719 {
720 wxCriticalSectionLocker lock(m_critsect);
721
722 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
723 }
724
725 wxThreadError wxThread::Resume()
726 {
727 wxCriticalSectionLocker lock(m_critsect);
728
729 return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
730 }
731
732 // stopping thread
733 // ---------------
734
735 wxThread::ExitCode wxThread::Wait()
736 {
737 // although under Windows we can wait for any thread, it's an error to
738 // wait for a detached one in wxWin API
739 wxCHECK_MSG( !IsDetached(), (ExitCode)-1,
740 _T("can't wait for detached thread") );
741
742 ExitCode rc = (ExitCode)-1;
743
744 (void)Delete(&rc);
745
746 m_internal->Free();
747
748 return rc;
749 }
750
751 wxThreadError wxThread::Delete(ExitCode *pRc)
752 {
753 ExitCode rc = 0;
754
755 // Delete() is always safe to call, so consider all possible states
756
757 // has the thread started to run?
758 bool shouldResume = FALSE;
759
760 {
761 wxCriticalSectionLocker lock(m_critsect);
762
763 if ( m_internal->GetState() == STATE_NEW )
764 {
765 // WinThreadStart() will see it and terminate immediately
766 m_internal->SetState(STATE_EXITED);
767
768 shouldResume = TRUE;
769 }
770 }
771
772 // is the thread paused?
773 if ( shouldResume || IsPaused() )
774 Resume();
775
776 HANDLE hThread = m_internal->GetHandle();
777
778 // does is still run?
779 if ( IsRunning() )
780 {
781 if ( IsMain() )
782 {
783 // set flag for wxIsWaitingForThread()
784 gs_waitingForThread = TRUE;
785
786 #if wxUSE_GUI
787 wxBeginBusyCursor();
788 #endif // wxUSE_GUI
789 }
790
791 // ask the thread to terminate
792 {
793 wxCriticalSectionLocker lock(m_critsect);
794
795 m_internal->Cancel();
796 }
797
798 #if wxUSE_GUI
799 // we can't just wait for the thread to terminate because it might be
800 // calling some GUI functions and so it will never terminate before we
801 // process the Windows messages that result from these functions
802 DWORD result;
803 do
804 {
805 result = ::MsgWaitForMultipleObjects
806 (
807 1, // number of objects to wait for
808 &hThread, // the objects
809 FALSE, // don't wait for all objects
810 INFINITE, // no timeout
811 QS_ALLEVENTS // return as soon as there are any events
812 );
813
814 switch ( result )
815 {
816 case 0xFFFFFFFF:
817 // error
818 wxLogSysError(_("Can not wait for thread termination"));
819 Kill();
820 return wxTHREAD_KILLED;
821
822 case WAIT_OBJECT_0:
823 // thread we're waiting for terminated
824 break;
825
826 case WAIT_OBJECT_0 + 1:
827 // new message arrived, process it
828 if ( !wxTheApp->DoMessage() )
829 {
830 // WM_QUIT received: kill the thread
831 Kill();
832
833 return wxTHREAD_KILLED;
834 }
835
836 if ( IsMain() )
837 {
838 // give the thread we're waiting for chance to exit
839 // from the GUI call it might have been in
840 if ( (gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
841 {
842 wxMutexGuiLeave();
843 }
844 }
845
846 break;
847
848 default:
849 wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject"));
850 }
851 } while ( result != WAIT_OBJECT_0 );
852 #else // !wxUSE_GUI
853 // simply wait for the thread to terminate
854 //
855 // OTOH, even console apps create windows (in wxExecute, for WinSock
856 // &c), so may be use MsgWaitForMultipleObject() too here?
857 if ( WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0 )
858 {
859 wxFAIL_MSG(wxT("unexpected result of WaitForSingleObject"));
860 }
861 #endif // wxUSE_GUI/!wxUSE_GUI
862
863 if ( IsMain() )
864 {
865 gs_waitingForThread = FALSE;
866
867 #if wxUSE_GUI
868 wxEndBusyCursor();
869 #endif // wxUSE_GUI
870 }
871 }
872
873 if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
874 {
875 wxLogLastError("GetExitCodeThread");
876
877 rc = (ExitCode)-1;
878 }
879
880 if ( IsDetached() )
881 {
882 // if the thread exits normally, this is done in WinThreadStart, but in
883 // this case it would have been too early because
884 // MsgWaitForMultipleObject() would fail if the therad handle was
885 // closed while we were waiting on it, so we must do it here
886 delete this;
887 }
888
889 wxASSERT_MSG( (DWORD)rc != STILL_ACTIVE,
890 wxT("thread must be already terminated.") );
891
892 if ( pRc )
893 *pRc = rc;
894
895 return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR;
896 }
897
898 wxThreadError wxThread::Kill()
899 {
900 if ( !IsRunning() )
901 return wxTHREAD_NOT_RUNNING;
902
903 if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
904 {
905 wxLogSysError(_("Couldn't terminate thread"));
906
907 return wxTHREAD_MISC_ERROR;
908 }
909
910 m_internal->Free();
911
912 if ( IsDetached() )
913 {
914 delete this;
915 }
916
917 return wxTHREAD_NO_ERROR;
918 }
919
920 void wxThread::Exit(ExitCode status)
921 {
922 m_internal->Free();
923
924 if ( IsDetached() )
925 {
926 delete this;
927 }
928
929 #if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
930 _endthreadex((unsigned)status);
931 #else // !VC++
932 ::ExitThread((DWORD)status);
933 #endif // VC++/!VC++
934
935 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
936 }
937
938 // priority setting
939 // ----------------
940
941 void wxThread::SetPriority(unsigned int prio)
942 {
943 wxCriticalSectionLocker lock(m_critsect);
944
945 m_internal->SetPriority(prio);
946 }
947
948 unsigned int wxThread::GetPriority() const
949 {
950 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
951
952 return m_internal->GetPriority();
953 }
954
955 unsigned long wxThread::GetId() const
956 {
957 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
958
959 return (unsigned long)m_internal->GetId();
960 }
961
962 bool wxThread::IsRunning() const
963 {
964 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
965
966 return m_internal->GetState() == STATE_RUNNING;
967 }
968
969 bool wxThread::IsAlive() const
970 {
971 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
972
973 return (m_internal->GetState() == STATE_RUNNING) ||
974 (m_internal->GetState() == STATE_PAUSED);
975 }
976
977 bool wxThread::IsPaused() const
978 {
979 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
980
981 return m_internal->GetState() == STATE_PAUSED;
982 }
983
984 bool wxThread::TestDestroy()
985 {
986 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
987
988 return m_internal->GetState() == STATE_CANCELED;
989 }
990
991 // ----------------------------------------------------------------------------
992 // Automatic initialization for thread module
993 // ----------------------------------------------------------------------------
994
995 class wxThreadModule : public wxModule
996 {
997 public:
998 virtual bool OnInit();
999 virtual void OnExit();
1000
1001 private:
1002 DECLARE_DYNAMIC_CLASS(wxThreadModule)
1003 };
1004
1005 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
1006
1007 bool wxThreadModule::OnInit()
1008 {
1009 // allocate TLS index for storing the pointer to the current thread
1010 gs_tlsThisThread = ::TlsAlloc();
1011 if ( gs_tlsThisThread == 0xFFFFFFFF )
1012 {
1013 // in normal circumstances it will only happen if all other
1014 // TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other
1015 // words, this should never happen
1016 wxLogSysError(_("Thread module initialization failed: "
1017 "impossible to allocate index in thread "
1018 "local storage"));
1019
1020 return FALSE;
1021 }
1022
1023 // main thread doesn't have associated wxThread object, so store 0 in the
1024 // TLS instead
1025 if ( !::TlsSetValue(gs_tlsThisThread, (LPVOID)0) )
1026 {
1027 ::TlsFree(gs_tlsThisThread);
1028 gs_tlsThisThread = 0xFFFFFFFF;
1029
1030 wxLogSysError(_("Thread module initialization failed: "
1031 "can not store value in thread local storage"));
1032
1033 return FALSE;
1034 }
1035
1036 gs_critsectWaitingForGui = new wxCriticalSection();
1037
1038 gs_critsectGui = new wxCriticalSection();
1039 gs_critsectGui->Enter();
1040
1041 // no error return for GetCurrentThreadId()
1042 gs_idMainThread = ::GetCurrentThreadId();
1043
1044 return TRUE;
1045 }
1046
1047 void wxThreadModule::OnExit()
1048 {
1049 if ( !::TlsFree(gs_tlsThisThread) )
1050 {
1051 wxLogLastError("TlsFree failed.");
1052 }
1053
1054 if ( gs_critsectGui )
1055 {
1056 gs_critsectGui->Leave();
1057 delete gs_critsectGui;
1058 gs_critsectGui = NULL;
1059 }
1060
1061 delete gs_critsectWaitingForGui;
1062 gs_critsectWaitingForGui = NULL;
1063 }
1064
1065 // ----------------------------------------------------------------------------
1066 // under Windows, these functions are implemented using a critical section and
1067 // not a mutex, so the names are a bit confusing
1068 // ----------------------------------------------------------------------------
1069
1070 void WXDLLEXPORT wxMutexGuiEnter()
1071 {
1072 // this would dead lock everything...
1073 wxASSERT_MSG( !wxThread::IsMain(),
1074 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
1075
1076 // the order in which we enter the critical sections here is crucial!!
1077
1078 // set the flag telling to the main thread that we want to do some GUI
1079 {
1080 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1081
1082 gs_nWaitingForGui++;
1083 }
1084
1085 wxWakeUpMainThread();
1086
1087 // now we may block here because the main thread will soon let us in
1088 // (during the next iteration of OnIdle())
1089 gs_critsectGui->Enter();
1090 }
1091
1092 void WXDLLEXPORT wxMutexGuiLeave()
1093 {
1094 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1095
1096 if ( wxThread::IsMain() )
1097 {
1098 gs_bGuiOwnedByMainThread = FALSE;
1099 }
1100 else
1101 {
1102 // decrement the number of waiters now
1103 wxASSERT_MSG( gs_nWaitingForGui > 0,
1104 wxT("calling wxMutexGuiLeave() without entering it first?") );
1105
1106 gs_nWaitingForGui--;
1107
1108 wxWakeUpMainThread();
1109 }
1110
1111 gs_critsectGui->Leave();
1112 }
1113
1114 void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
1115 {
1116 wxASSERT_MSG( wxThread::IsMain(),
1117 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1118
1119 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1120
1121 if ( gs_nWaitingForGui == 0 )
1122 {
1123 // no threads are waiting for GUI - so we may acquire the lock without
1124 // any danger (but only if we don't already have it)
1125 if ( !wxGuiOwnedByMainThread() )
1126 {
1127 gs_critsectGui->Enter();
1128
1129 gs_bGuiOwnedByMainThread = TRUE;
1130 }
1131 //else: already have it, nothing to do
1132 }
1133 else
1134 {
1135 // some threads are waiting, release the GUI lock if we have it
1136 if ( wxGuiOwnedByMainThread() )
1137 {
1138 wxMutexGuiLeave();
1139 }
1140 //else: some other worker thread is doing GUI
1141 }
1142 }
1143
1144 bool WXDLLEXPORT wxGuiOwnedByMainThread()
1145 {
1146 return gs_bGuiOwnedByMainThread;
1147 }
1148
1149 // wake up the main thread if it's in ::GetMessage()
1150 void WXDLLEXPORT wxWakeUpMainThread()
1151 {
1152 // sending any message would do - hopefully WM_NULL is harmless enough
1153 if ( !::PostThreadMessage(gs_idMainThread, WM_NULL, 0, 0) )
1154 {
1155 // should never happen
1156 wxLogLastError("PostThreadMessage(WM_NULL)");
1157 }
1158 }
1159
1160 bool WXDLLEXPORT wxIsWaitingForThread()
1161 {
1162 return gs_waitingForThread;
1163 }
1164
1165 #endif // wxUSE_THREADS