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