]> git.saurik.com Git - wxWidgets.git/blob - src/msw/thread.cpp
wxFileSystem now compiles if wxUSE_HTML (required by wxHTML)
[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 #ifdef __VISUALC__
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 #ifdef __VISUALC__
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, _T("SetProcessAffinityMask"));
630 }
631
632 // we've discovered a MT version of Win9x!
633 wxASSERT_MSG( pfnSetProcessAffinityMask,
634 _T("this system has several CPUs but no "
635 "SetProcessAffinityMask function?") );
636 }
637
638 if ( !pfnSetProcessAffinityMask )
639 {
640 // msg given above - do it only once
641 return FALSE;
642 }
643
644 if ( pfnSetProcessAffinityMask(hProcess, dwProcMask) == 0 )
645 {
646 wxLogLastError(_T("SetProcessAffinityMask"));
647
648 return FALSE;
649 }
650
651 return TRUE;
652 }
653
654 // ctor and dtor
655 // -------------
656
657 wxThread::wxThread(wxThreadKind kind)
658 {
659 m_internal = new wxThreadInternal();
660
661 m_isDetached = kind == wxTHREAD_DETACHED;
662 }
663
664 wxThread::~wxThread()
665 {
666 delete m_internal;
667 }
668
669 // create/start thread
670 // -------------------
671
672 wxThreadError wxThread::Create()
673 {
674 wxCriticalSectionLocker lock(m_critsect);
675
676 if ( !m_internal->Create(this) )
677 return wxTHREAD_NO_RESOURCE;
678
679 return wxTHREAD_NO_ERROR;
680 }
681
682 wxThreadError wxThread::Run()
683 {
684 wxCriticalSectionLocker lock(m_critsect);
685
686 if ( m_internal->GetState() != STATE_NEW )
687 {
688 // actually, it may be almost any state at all, not only STATE_RUNNING
689 return wxTHREAD_RUNNING;
690 }
691
692 // the thread has just been created and is still suspended - let it run
693 return Resume();
694 }
695
696 // suspend/resume thread
697 // ---------------------
698
699 wxThreadError wxThread::Pause()
700 {
701 wxCriticalSectionLocker lock(m_critsect);
702
703 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
704 }
705
706 wxThreadError wxThread::Resume()
707 {
708 wxCriticalSectionLocker lock(m_critsect);
709
710 return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
711 }
712
713 // stopping thread
714 // ---------------
715
716 wxThread::ExitCode wxThread::Wait()
717 {
718 // although under Windows we can wait for any thread, it's an error to
719 // wait for a detached one in wxWin API
720 wxCHECK_MSG( !IsDetached(), (ExitCode)-1,
721 _T("can't wait for detached thread") );
722
723 ExitCode rc = (ExitCode)-1;
724
725 (void)Delete(&rc);
726
727 m_internal->Free();
728
729 return rc;
730 }
731
732 wxThreadError wxThread::Delete(ExitCode *pRc)
733 {
734 ExitCode rc = 0;
735
736 // Delete() is always safe to call, so consider all possible states
737
738 // has the thread started to run?
739 bool shouldResume = FALSE;
740
741 {
742 wxCriticalSectionLocker lock(m_critsect);
743
744 if ( m_internal->GetState() == STATE_NEW )
745 {
746 // WinThreadStart() will see it and terminate immediately
747 m_internal->SetState(STATE_EXITED);
748
749 shouldResume = TRUE;
750 }
751 }
752
753 // is the thread paused?
754 if ( shouldResume || IsPaused() )
755 Resume();
756
757 HANDLE hThread = m_internal->GetHandle();
758
759 // does is still run?
760 if ( IsRunning() )
761 {
762 if ( IsMain() )
763 {
764 // set flag for wxIsWaitingForThread()
765 gs_waitingForThread = TRUE;
766
767 #if wxUSE_GUI
768 wxBeginBusyCursor();
769 #endif // wxUSE_GUI
770 }
771
772 // ask the thread to terminate
773 {
774 wxCriticalSectionLocker lock(m_critsect);
775
776 m_internal->Cancel();
777 }
778
779 #if wxUSE_GUI
780 // we can't just wait for the thread to terminate because it might be
781 // calling some GUI functions and so it will never terminate before we
782 // process the Windows messages that result from these functions
783 DWORD result;
784 do
785 {
786 result = ::MsgWaitForMultipleObjects
787 (
788 1, // number of objects to wait for
789 &hThread, // the objects
790 FALSE, // don't wait for all objects
791 INFINITE, // no timeout
792 QS_ALLEVENTS // return as soon as there are any events
793 );
794
795 switch ( result )
796 {
797 case 0xFFFFFFFF:
798 // error
799 wxLogSysError(_("Can not wait for thread termination"));
800 Kill();
801 return wxTHREAD_KILLED;
802
803 case WAIT_OBJECT_0:
804 // thread we're waiting for terminated
805 break;
806
807 case WAIT_OBJECT_0 + 1:
808 // new message arrived, process it
809 if ( !wxTheApp->DoMessage() )
810 {
811 // WM_QUIT received: kill the thread
812 Kill();
813
814 return wxTHREAD_KILLED;
815 }
816
817 if ( IsMain() )
818 {
819 // give the thread we're waiting for chance to exit
820 // from the GUI call it might have been in
821 if ( (gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
822 {
823 wxMutexGuiLeave();
824 }
825 }
826
827 break;
828
829 default:
830 wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject"));
831 }
832 } while ( result != WAIT_OBJECT_0 );
833 #else // !wxUSE_GUI
834 // simply wait for the thread to terminate
835 //
836 // OTOH, even console apps create windows (in wxExecute, for WinSock
837 // &c), so may be use MsgWaitForMultipleObject() too here?
838 if ( WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0 )
839 {
840 wxFAIL_MSG(wxT("unexpected result of WaitForSingleObject"));
841 }
842 #endif // wxUSE_GUI/!wxUSE_GUI
843
844 if ( IsMain() )
845 {
846 gs_waitingForThread = FALSE;
847
848 #if wxUSE_GUI
849 wxEndBusyCursor();
850 #endif // wxUSE_GUI
851 }
852 }
853
854 if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
855 {
856 wxLogLastError("GetExitCodeThread");
857
858 rc = (ExitCode)-1;
859 }
860
861 if ( IsDetached() )
862 {
863 // if the thread exits normally, this is done in WinThreadStart, but in
864 // this case it would have been too early because
865 // MsgWaitForMultipleObject() would fail if the therad handle was
866 // closed while we were waiting on it, so we must do it here
867 delete this;
868 }
869
870 wxASSERT_MSG( (DWORD)rc != STILL_ACTIVE,
871 wxT("thread must be already terminated.") );
872
873 if ( pRc )
874 *pRc = rc;
875
876 return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR;
877 }
878
879 wxThreadError wxThread::Kill()
880 {
881 if ( !IsRunning() )
882 return wxTHREAD_NOT_RUNNING;
883
884 if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
885 {
886 wxLogSysError(_("Couldn't terminate thread"));
887
888 return wxTHREAD_MISC_ERROR;
889 }
890
891 m_internal->Free();
892
893 if ( IsDetached() )
894 {
895 delete this;
896 }
897
898 return wxTHREAD_NO_ERROR;
899 }
900
901 void wxThread::Exit(ExitCode status)
902 {
903 m_internal->Free();
904
905 if ( IsDetached() )
906 {
907 delete this;
908 }
909
910 #ifdef __VISUALC__
911 _endthreadex((unsigned)status);
912 #else // !VC++
913 ::ExitThread((DWORD)status);
914 #endif // VC++/!VC++
915
916 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
917 }
918
919 // priority setting
920 // ----------------
921
922 void wxThread::SetPriority(unsigned int prio)
923 {
924 wxCriticalSectionLocker lock(m_critsect);
925
926 m_internal->SetPriority(prio);
927 }
928
929 unsigned int wxThread::GetPriority() const
930 {
931 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
932
933 return m_internal->GetPriority();
934 }
935
936 unsigned long wxThread::GetId() const
937 {
938 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
939
940 return (unsigned long)m_internal->GetId();
941 }
942
943 bool wxThread::IsRunning() const
944 {
945 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
946
947 return m_internal->GetState() == STATE_RUNNING;
948 }
949
950 bool wxThread::IsAlive() const
951 {
952 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
953
954 return (m_internal->GetState() == STATE_RUNNING) ||
955 (m_internal->GetState() == STATE_PAUSED);
956 }
957
958 bool wxThread::IsPaused() const
959 {
960 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
961
962 return m_internal->GetState() == STATE_PAUSED;
963 }
964
965 bool wxThread::TestDestroy()
966 {
967 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
968
969 return m_internal->GetState() == STATE_CANCELED;
970 }
971
972 // ----------------------------------------------------------------------------
973 // Automatic initialization for thread module
974 // ----------------------------------------------------------------------------
975
976 class wxThreadModule : public wxModule
977 {
978 public:
979 virtual bool OnInit();
980 virtual void OnExit();
981
982 private:
983 DECLARE_DYNAMIC_CLASS(wxThreadModule)
984 };
985
986 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
987
988 bool wxThreadModule::OnInit()
989 {
990 // allocate TLS index for storing the pointer to the current thread
991 gs_tlsThisThread = ::TlsAlloc();
992 if ( gs_tlsThisThread == 0xFFFFFFFF )
993 {
994 // in normal circumstances it will only happen if all other
995 // TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other
996 // words, this should never happen
997 wxLogSysError(_("Thread module initialization failed: "
998 "impossible to allocate index in thread "
999 "local storage"));
1000
1001 return FALSE;
1002 }
1003
1004 // main thread doesn't have associated wxThread object, so store 0 in the
1005 // TLS instead
1006 if ( !::TlsSetValue(gs_tlsThisThread, (LPVOID)0) )
1007 {
1008 ::TlsFree(gs_tlsThisThread);
1009 gs_tlsThisThread = 0xFFFFFFFF;
1010
1011 wxLogSysError(_("Thread module initialization failed: "
1012 "can not store value in thread local storage"));
1013
1014 return FALSE;
1015 }
1016
1017 gs_critsectWaitingForGui = new wxCriticalSection();
1018
1019 gs_critsectGui = new wxCriticalSection();
1020 gs_critsectGui->Enter();
1021
1022 // no error return for GetCurrentThreadId()
1023 gs_idMainThread = ::GetCurrentThreadId();
1024
1025 return TRUE;
1026 }
1027
1028 void wxThreadModule::OnExit()
1029 {
1030 if ( !::TlsFree(gs_tlsThisThread) )
1031 {
1032 wxLogLastError("TlsFree failed.");
1033 }
1034
1035 if ( gs_critsectGui )
1036 {
1037 gs_critsectGui->Leave();
1038 delete gs_critsectGui;
1039 gs_critsectGui = NULL;
1040 }
1041
1042 delete gs_critsectWaitingForGui;
1043 gs_critsectWaitingForGui = NULL;
1044 }
1045
1046 // ----------------------------------------------------------------------------
1047 // under Windows, these functions are implemented using a critical section and
1048 // not a mutex, so the names are a bit confusing
1049 // ----------------------------------------------------------------------------
1050
1051 void WXDLLEXPORT wxMutexGuiEnter()
1052 {
1053 // this would dead lock everything...
1054 wxASSERT_MSG( !wxThread::IsMain(),
1055 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
1056
1057 // the order in which we enter the critical sections here is crucial!!
1058
1059 // set the flag telling to the main thread that we want to do some GUI
1060 {
1061 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1062
1063 gs_nWaitingForGui++;
1064 }
1065
1066 wxWakeUpMainThread();
1067
1068 // now we may block here because the main thread will soon let us in
1069 // (during the next iteration of OnIdle())
1070 gs_critsectGui->Enter();
1071 }
1072
1073 void WXDLLEXPORT wxMutexGuiLeave()
1074 {
1075 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1076
1077 if ( wxThread::IsMain() )
1078 {
1079 gs_bGuiOwnedByMainThread = FALSE;
1080 }
1081 else
1082 {
1083 // decrement the number of waiters now
1084 wxASSERT_MSG( gs_nWaitingForGui > 0,
1085 wxT("calling wxMutexGuiLeave() without entering it first?") );
1086
1087 gs_nWaitingForGui--;
1088
1089 wxWakeUpMainThread();
1090 }
1091
1092 gs_critsectGui->Leave();
1093 }
1094
1095 void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
1096 {
1097 wxASSERT_MSG( wxThread::IsMain(),
1098 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1099
1100 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
1101
1102 if ( gs_nWaitingForGui == 0 )
1103 {
1104 // no threads are waiting for GUI - so we may acquire the lock without
1105 // any danger (but only if we don't already have it)
1106 if ( !wxGuiOwnedByMainThread() )
1107 {
1108 gs_critsectGui->Enter();
1109
1110 gs_bGuiOwnedByMainThread = TRUE;
1111 }
1112 //else: already have it, nothing to do
1113 }
1114 else
1115 {
1116 // some threads are waiting, release the GUI lock if we have it
1117 if ( wxGuiOwnedByMainThread() )
1118 {
1119 wxMutexGuiLeave();
1120 }
1121 //else: some other worker thread is doing GUI
1122 }
1123 }
1124
1125 bool WXDLLEXPORT wxGuiOwnedByMainThread()
1126 {
1127 return gs_bGuiOwnedByMainThread;
1128 }
1129
1130 // wake up the main thread if it's in ::GetMessage()
1131 void WXDLLEXPORT wxWakeUpMainThread()
1132 {
1133 // sending any message would do - hopefully WM_NULL is harmless enough
1134 if ( !::PostThreadMessage(gs_idMainThread, WM_NULL, 0, 0) )
1135 {
1136 // should never happen
1137 wxLogLastError("PostThreadMessage(WM_NULL)");
1138 }
1139 }
1140
1141 bool WXDLLEXPORT wxIsWaitingForThread()
1142 {
1143 return gs_waitingForThread;
1144 }
1145
1146 #endif // wxUSE_THREADS