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