]> git.saurik.com Git - wxWidgets.git/blob - src/msw/thread.cpp
wxCritSection change to accomodate mem checking system
[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 <stdio.h>
35
36 #include <windows.h>
37
38 #include "wx/module.h"
39 #include "wx/thread.h"
40
41 // the possible states of the thread ("=>" shows all possible transitions from
42 // this state)
43 enum wxThreadState
44 {
45 STATE_NEW, // didn't start execution yet (=> RUNNING)
46 STATE_RUNNING, // thread is running (=> PAUSED, CANCELED)
47 STATE_PAUSED, // thread is temporarily suspended (=> RUNNING)
48 STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED)
49 STATE_EXITED // thread is terminating
50 };
51
52 // ----------------------------------------------------------------------------
53 // static variables
54 // ----------------------------------------------------------------------------
55
56 // TLS index of the slot where we store the pointer to the current thread
57 static DWORD s_tlsThisThread = 0xFFFFFFFF;
58
59 // id of the main thread - the one which can call GUI functions without first
60 // calling wxMutexGuiEnter()
61 static DWORD s_idMainThread = 0;
62
63 // if it's FALSE, some secondary thread is holding the GUI lock
64 static bool s_bGuiOwnedByMainThread = TRUE;
65
66 // critical section which controls access to all GUI functions: any secondary
67 // thread (i.e. except the main one) must enter this crit section before doing
68 // any GUI calls
69 static wxCriticalSection *s_critsectGui = NULL;
70
71 // critical section which protects s_nWaitingForGui variable
72 static wxCriticalSection *s_critsectWaitingForGui = NULL;
73
74 // number of threads waiting for GUI in wxMutexGuiEnter()
75 static size_t s_nWaitingForGui = 0;
76
77 // are we waiting for a thread termination?
78 static bool s_waitingForThread = FALSE;
79
80 // ============================================================================
81 // Windows implementation of thread classes
82 // ============================================================================
83
84 // ----------------------------------------------------------------------------
85 // wxMutex implementation
86 // ----------------------------------------------------------------------------
87 class wxMutexInternal
88 {
89 public:
90 HANDLE p_mutex;
91 };
92
93 wxMutex::wxMutex()
94 {
95 p_internal = new wxMutexInternal;
96 p_internal->p_mutex = CreateMutex(NULL, FALSE, NULL);
97 if ( !p_internal->p_mutex )
98 {
99 wxLogSysError(_("Can not create mutex."));
100 }
101
102 m_locked = 0;
103 }
104
105 wxMutex::~wxMutex()
106 {
107 if (m_locked > 0)
108 wxLogDebug("Warning: freeing a locked mutex (%d locks).", m_locked);
109 CloseHandle(p_internal->p_mutex);
110 }
111
112 wxMutexError wxMutex::Lock()
113 {
114 DWORD ret;
115
116 ret = WaitForSingleObject(p_internal->p_mutex, INFINITE);
117 switch ( ret )
118 {
119 case WAIT_ABANDONED:
120 return wxMUTEX_BUSY;
121
122 case WAIT_OBJECT_0:
123 // ok
124 break;
125
126 case WAIT_FAILED:
127 wxLogSysError(_("Couldn't acquire a mutex lock"));
128 return wxMUTEX_MISC_ERROR;
129
130 case WAIT_TIMEOUT:
131 default:
132 wxFAIL_MSG("impossible return value in wxMutex::Lock");
133 }
134
135 m_locked++;
136 return wxMUTEX_NO_ERROR;
137 }
138
139 wxMutexError wxMutex::TryLock()
140 {
141 DWORD ret;
142
143 ret = WaitForSingleObject(p_internal->p_mutex, 0);
144 if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
145 return wxMUTEX_BUSY;
146
147 m_locked++;
148 return wxMUTEX_NO_ERROR;
149 }
150
151 wxMutexError wxMutex::Unlock()
152 {
153 if (m_locked > 0)
154 m_locked--;
155
156 BOOL ret = ReleaseMutex(p_internal->p_mutex);
157 if ( ret == 0 )
158 {
159 wxLogSysError(_("Couldn't release a mutex"));
160 return wxMUTEX_MISC_ERROR;
161 }
162
163 return wxMUTEX_NO_ERROR;
164 }
165
166 // ----------------------------------------------------------------------------
167 // wxCondition implementation
168 // ----------------------------------------------------------------------------
169
170 class wxConditionInternal
171 {
172 public:
173 HANDLE event;
174 int waiters;
175 };
176
177 wxCondition::wxCondition()
178 {
179 p_internal = new wxConditionInternal;
180 p_internal->event = CreateEvent(NULL, FALSE, FALSE, NULL);
181 if ( !p_internal->event )
182 {
183 wxLogSysError(_("Can not create event object."));
184 }
185
186 p_internal->waiters = 0;
187 }
188
189 wxCondition::~wxCondition()
190 {
191 CloseHandle(p_internal->event);
192 }
193
194 void wxCondition::Wait(wxMutex& mutex)
195 {
196 mutex.Unlock();
197 p_internal->waiters++;
198 WaitForSingleObject(p_internal->event, INFINITE);
199 p_internal->waiters--;
200 mutex.Lock();
201 }
202
203 bool wxCondition::Wait(wxMutex& mutex,
204 unsigned long sec,
205 unsigned long nsec)
206 {
207 DWORD ret;
208
209 mutex.Unlock();
210 p_internal->waiters++;
211 ret = WaitForSingleObject(p_internal->event, (sec*1000)+(nsec/1000000));
212 p_internal->waiters--;
213 mutex.Lock();
214
215 return (ret != WAIT_TIMEOUT);
216 }
217
218 void wxCondition::Signal()
219 {
220 SetEvent(p_internal->event);
221 }
222
223 void wxCondition::Broadcast()
224 {
225 int i;
226
227 for (i=0;i<p_internal->waiters;i++)
228 {
229 if ( SetEvent(p_internal->event) == 0 )
230 {
231 wxLogSysError(_("Couldn't change the state of event object."));
232 }
233 }
234 }
235
236 // ----------------------------------------------------------------------------
237 // wxCriticalSection implementation
238 // ----------------------------------------------------------------------------
239
240 class wxCriticalSectionInternal
241 {
242 public:
243 // init the critical section object
244 wxCriticalSectionInternal()
245 { ::InitializeCriticalSection(&m_data); }
246
247 // implicit cast to the associated data
248 operator CRITICAL_SECTION *() { return &m_data; }
249
250 // free the associated ressources
251 ~wxCriticalSectionInternal()
252 { ::DeleteCriticalSection(&m_data); }
253
254 private:
255 CRITICAL_SECTION m_data;
256 };
257
258 wxCriticalSection::wxCriticalSection()
259 {
260 m_critsect = NULL;
261 }
262
263 wxCriticalSection::~wxCriticalSection()
264 {
265 if ( m_critsect )
266 delete m_critsect;
267 }
268
269 void wxCriticalSection::Enter()
270 {
271 m_critsect = new wxCriticalSectionInternal;
272
273 ::EnterCriticalSection(*m_critsect);
274 }
275
276 void wxCriticalSection::Leave()
277 {
278 wxCHECK_RET( m_critsect, "Leave() without matching Enter()" );
279
280 ::LeaveCriticalSection(*m_critsect);
281 }
282
283 // ----------------------------------------------------------------------------
284 // wxThread implementation
285 // ----------------------------------------------------------------------------
286
287 // wxThreadInternal class
288 // ----------------------
289
290 class wxThreadInternal
291 {
292 public:
293 wxThreadInternal()
294 {
295 m_hThread = 0;
296 m_state = STATE_NEW;
297 m_priority = WXTHREAD_DEFAULT_PRIORITY;
298 }
299
300 // create a new (suspended) thread (for the given thread object)
301 bool Create(wxThread *thread);
302
303 // suspend/resume/terminate
304 bool Suspend();
305 bool Resume();
306 void Cancel() { m_state = STATE_CANCELED; }
307
308 // thread state
309 void SetState(wxThreadState state) { m_state = state; }
310 wxThreadState GetState() const { return m_state; }
311
312 // thread priority
313 void SetPriority(unsigned int priority) { m_priority = priority; }
314 unsigned int GetPriority() const { return m_priority; }
315
316 // thread handle and id
317 HANDLE GetHandle() const { return m_hThread; }
318 DWORD GetId() const { return m_tid; }
319
320 // thread function
321 static DWORD WinThreadStart(wxThread *thread);
322
323 private:
324 HANDLE m_hThread; // handle of the thread
325 wxThreadState m_state; // state, see wxThreadState enum
326 unsigned int m_priority; // thread priority in "wx" units
327 DWORD m_tid; // thread id
328 };
329
330 DWORD wxThreadInternal::WinThreadStart(wxThread *thread)
331 {
332 // store the thread object in the TLS
333 if ( !::TlsSetValue(s_tlsThisThread, thread) )
334 {
335 wxLogSysError(_("Can not start thread: error writing TLS."));
336
337 return (DWORD)-1;
338 }
339
340 DWORD ret = (DWORD)thread->Entry();
341 thread->p_internal->SetState(STATE_EXITED);
342 thread->OnExit();
343
344 delete thread;
345
346 return ret;
347 }
348
349 bool wxThreadInternal::Create(wxThread *thread)
350 {
351 m_hThread = ::CreateThread
352 (
353 NULL, // default security
354 0, // default stack size
355 (LPTHREAD_START_ROUTINE) // thread entry point
356 wxThreadInternal::WinThreadStart, //
357 (LPVOID)thread, // parameter
358 CREATE_SUSPENDED, // flags
359 &m_tid // [out] thread id
360 );
361
362 if ( m_hThread == NULL )
363 {
364 wxLogSysError(_("Can't create thread"));
365
366 return FALSE;
367 }
368
369 // translate wxWindows priority to the Windows one
370 int win_priority;
371 if (m_priority <= 20)
372 win_priority = THREAD_PRIORITY_LOWEST;
373 else if (m_priority <= 40)
374 win_priority = THREAD_PRIORITY_BELOW_NORMAL;
375 else if (m_priority <= 60)
376 win_priority = THREAD_PRIORITY_NORMAL;
377 else if (m_priority <= 80)
378 win_priority = THREAD_PRIORITY_ABOVE_NORMAL;
379 else if (m_priority <= 100)
380 win_priority = THREAD_PRIORITY_HIGHEST;
381 else
382 {
383 wxFAIL_MSG("invalid value of thread priority parameter");
384 win_priority = THREAD_PRIORITY_NORMAL;
385 }
386
387 if ( ::SetThreadPriority(m_hThread, win_priority) == 0 )
388 {
389 wxLogSysError(_("Can't set thread priority"));
390 }
391
392 return TRUE;
393 }
394
395 bool wxThreadInternal::Suspend()
396 {
397 DWORD nSuspendCount = ::SuspendThread(m_hThread);
398 if ( nSuspendCount == (DWORD)-1 )
399 {
400 wxLogSysError(_("Can not suspend thread %x"), m_hThread);
401
402 return FALSE;
403 }
404
405 m_state = STATE_PAUSED;
406
407 return TRUE;
408 }
409
410 bool wxThreadInternal::Resume()
411 {
412 DWORD nSuspendCount = ::ResumeThread(m_hThread);
413 if ( nSuspendCount == (DWORD)-1 )
414 {
415 wxLogSysError(_("Can not resume thread %x"), m_hThread);
416
417 return FALSE;
418 }
419
420 m_state = STATE_RUNNING;
421
422 return TRUE;
423 }
424
425 // static functions
426 // ----------------
427
428 wxThread *wxThread::This()
429 {
430 wxThread *thread = (wxThread *)::TlsGetValue(s_tlsThisThread);
431
432 // be careful, 0 may be a valid return value as well
433 if ( !thread && (::GetLastError() != NO_ERROR) )
434 {
435 wxLogSysError(_("Couldn't get the current thread pointer"));
436
437 // return NULL...
438 }
439
440 return thread;
441 }
442
443 bool wxThread::IsMain()
444 {
445 return ::GetCurrentThreadId() == s_idMainThread;
446 }
447
448 void wxThread::Yield()
449 {
450 // 0 argument to Sleep() is special
451 ::Sleep(0);
452 }
453
454 void wxThread::Sleep(unsigned long milliseconds)
455 {
456 ::Sleep(milliseconds);
457 }
458
459 // create/start thread
460 // -------------------
461
462 wxThreadError wxThread::Create()
463 {
464 if ( !p_internal->Create(this) )
465 return wxTHREAD_NO_RESOURCE;
466
467 return wxTHREAD_NO_ERROR;
468 }
469
470 wxThreadError wxThread::Run()
471 {
472 wxCriticalSectionLocker lock(m_critsect);
473
474 if ( p_internal->GetState() != STATE_NEW )
475 {
476 // actually, it may be almost any state at all, not only STATE_RUNNING
477 return wxTHREAD_RUNNING;
478 }
479
480 return Resume();
481 }
482
483 // suspend/resume thread
484 // ---------------------
485
486 wxThreadError wxThread::Pause()
487 {
488 wxCriticalSectionLocker lock(m_critsect);
489
490 return p_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
491 }
492
493 wxThreadError wxThread::Resume()
494 {
495 wxCriticalSectionLocker lock(m_critsect);
496
497 return p_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
498 }
499
500 // stopping thread
501 // ---------------
502
503 wxThread::ExitCode wxThread::Delete()
504 {
505 ExitCode rc = 0;
506
507 // Delete() is always safe to call, so consider all possible states
508 if ( IsPaused() )
509 Resume();
510
511 if ( IsRunning() )
512 {
513 if ( IsMain() )
514 {
515 // set flag for wxIsWaitingForThread()
516 s_waitingForThread = TRUE;
517
518 wxBeginBusyCursor();
519 }
520
521 HANDLE hThread;
522 {
523 wxCriticalSectionLocker lock(m_critsect);
524
525 p_internal->Cancel();
526 hThread = p_internal->GetHandle();
527 }
528
529 // we can't just wait for the thread to terminate because it might be
530 // calling some GUI functions and so it will never terminate before we
531 // process the Windows messages that result from these functions
532 DWORD result;
533 do
534 {
535 result = ::MsgWaitForMultipleObjects
536 (
537 1, // number of objects to wait for
538 &hThread, // the objects
539 FALSE, // don't wait for all objects
540 INFINITE, // no timeout
541 QS_ALLEVENTS // return as soon as there are any events
542 );
543
544 switch ( result )
545 {
546 case 0xFFFFFFFF:
547 // error
548 wxLogSysError(_("Can not wait for thread termination"));
549 Kill();
550 return (ExitCode)-1;
551
552 case WAIT_OBJECT_0:
553 // thread we're waiting for terminated
554 break;
555
556 case WAIT_OBJECT_0 + 1:
557 // new message arrived, process it
558 if ( !wxTheApp->DoMessage() )
559 {
560 // WM_QUIT received: kill the thread
561 Kill();
562
563 return (ExitCode)-1;
564 }
565
566 if ( IsMain() )
567 {
568 // give the thread we're waiting for chance to exit
569 // from the GUI call it might have been in
570 if ( (s_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
571 {
572 wxMutexGuiLeave();
573 }
574 }
575
576 break;
577
578 default:
579 wxFAIL_MSG("unexpected result of MsgWaitForMultipleObject");
580 }
581 } while ( result != WAIT_OBJECT_0 );
582
583 if ( IsMain() )
584 {
585 s_waitingForThread = FALSE;
586
587 wxEndBusyCursor();
588 }
589
590 if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
591 {
592 wxLogLastError("GetExitCodeThread");
593
594 rc = (ExitCode)-1;
595 }
596
597 wxASSERT_MSG( (LPVOID)rc != (LPVOID)STILL_ACTIVE,
598 "thread must be already terminated." );
599
600 ::CloseHandle(hThread);
601 }
602
603 return rc;
604 }
605
606 wxThreadError wxThread::Kill()
607 {
608 if ( !IsRunning() )
609 return wxTHREAD_NOT_RUNNING;
610
611 if ( !::TerminateThread(p_internal->GetHandle(), (DWORD)-1) )
612 {
613 wxLogSysError(_("Couldn't terminate thread"));
614
615 return wxTHREAD_MISC_ERROR;
616 }
617
618 delete this;
619
620 return wxTHREAD_NO_ERROR;
621 }
622
623 void wxThread::Exit(void *status)
624 {
625 delete this;
626
627 ::ExitThread((DWORD)status);
628
629 wxFAIL_MSG("Couldn't return from ExitThread()!");
630 }
631
632 void wxThread::SetPriority(unsigned int prio)
633 {
634 wxCriticalSectionLocker lock(m_critsect);
635
636 p_internal->SetPriority(prio);
637 }
638
639 unsigned int wxThread::GetPriority() const
640 {
641 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
642
643 return p_internal->GetPriority();
644 }
645
646 unsigned long wxThread::GetID() const
647 {
648 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
649
650 return (unsigned long)p_internal->GetId();
651 }
652
653 bool wxThread::IsRunning() const
654 {
655 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
656
657 return p_internal->GetState() == STATE_RUNNING;
658 }
659
660 bool wxThread::IsAlive() const
661 {
662 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
663
664 return (p_internal->GetState() == STATE_RUNNING) ||
665 (p_internal->GetState() == STATE_PAUSED);
666 }
667
668 bool wxThread::TestDestroy()
669 {
670 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
671
672 return p_internal->GetState() == STATE_CANCELED;
673 }
674
675 wxThread::wxThread()
676 {
677 p_internal = new wxThreadInternal();
678 }
679
680 wxThread::~wxThread()
681 {
682 delete p_internal;
683 }
684
685 // ----------------------------------------------------------------------------
686 // Automatic initialization for thread module
687 // ----------------------------------------------------------------------------
688
689 class wxThreadModule : public wxModule
690 {
691 public:
692 virtual bool OnInit();
693 virtual void OnExit();
694
695 private:
696 DECLARE_DYNAMIC_CLASS(wxThreadModule)
697 };
698
699 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
700
701 bool wxThreadModule::OnInit()
702 {
703 // allocate TLS index for storing the pointer to the current thread
704 s_tlsThisThread = ::TlsAlloc();
705 if ( s_tlsThisThread == 0xFFFFFFFF )
706 {
707 // in normal circumstances it will only happen if all other
708 // TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other
709 // words, this should never happen
710 wxLogSysError(_("Thread module initialization failed: "
711 "impossible to allocate index in thread "
712 "local storage"));
713
714 return FALSE;
715 }
716
717 // main thread doesn't have associated wxThread object, so store 0 in the
718 // TLS instead
719 if ( !::TlsSetValue(s_tlsThisThread, (LPVOID)0) )
720 {
721 ::TlsFree(s_tlsThisThread);
722 s_tlsThisThread = 0xFFFFFFFF;
723
724 wxLogSysError(_("Thread module initialization failed: "
725 "can not store value in thread local storage"));
726
727 return FALSE;
728 }
729
730 s_critsectWaitingForGui = new wxCriticalSection();
731
732 s_critsectGui = new wxCriticalSection();
733 s_critsectGui->Enter();
734
735 // no error return for GetCurrentThreadId()
736 s_idMainThread = ::GetCurrentThreadId();
737
738 return TRUE;
739 }
740
741 void wxThreadModule::OnExit()
742 {
743 if ( !::TlsFree(s_tlsThisThread) )
744 {
745 wxLogLastError("TlsFree failed.");
746 }
747
748 if ( s_critsectGui )
749 {
750 s_critsectGui->Leave();
751 delete s_critsectGui;
752 s_critsectGui = NULL;
753 }
754
755 wxDELETE(s_critsectWaitingForGui);
756 }
757
758 // ----------------------------------------------------------------------------
759 // under Windows, these functions are implemented usign a critical section and
760 // not a mutex, so the names are a bit confusing
761 // ----------------------------------------------------------------------------
762
763 void WXDLLEXPORT wxMutexGuiEnter()
764 {
765 // this would dead lock everything...
766 wxASSERT_MSG( !wxThread::IsMain(),
767 "main thread doesn't want to block in wxMutexGuiEnter()!" );
768
769 // the order in which we enter the critical sections here is crucial!!
770
771 // set the flag telling to the main thread that we want to do some GUI
772 {
773 wxCriticalSectionLocker enter(*s_critsectWaitingForGui);
774
775 s_nWaitingForGui++;
776 }
777
778 wxWakeUpMainThread();
779
780 // now we may block here because the main thread will soon let us in
781 // (during the next iteration of OnIdle())
782 s_critsectGui->Enter();
783 }
784
785 void WXDLLEXPORT wxMutexGuiLeave()
786 {
787 wxCriticalSectionLocker enter(*s_critsectWaitingForGui);
788
789 if ( wxThread::IsMain() )
790 {
791 s_bGuiOwnedByMainThread = FALSE;
792 }
793 else
794 {
795 // decrement the number of waiters now
796 wxASSERT_MSG( s_nWaitingForGui > 0,
797 "calling wxMutexGuiLeave() without entering it first?" );
798
799 s_nWaitingForGui--;
800
801 wxWakeUpMainThread();
802 }
803
804 s_critsectGui->Leave();
805 }
806
807 void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
808 {
809 wxASSERT_MSG( wxThread::IsMain(),
810 "only main thread may call wxMutexGuiLeaveOrEnter()!" );
811
812 wxCriticalSectionLocker enter(*s_critsectWaitingForGui);
813
814 if ( s_nWaitingForGui == 0 )
815 {
816 // no threads are waiting for GUI - so we may acquire the lock without
817 // any danger (but only if we don't already have it)
818 if ( !wxGuiOwnedByMainThread() )
819 {
820 s_critsectGui->Enter();
821
822 s_bGuiOwnedByMainThread = TRUE;
823 }
824 //else: already have it, nothing to do
825 }
826 else
827 {
828 // some threads are waiting, release the GUI lock if we have it
829 if ( wxGuiOwnedByMainThread() )
830 {
831 wxMutexGuiLeave();
832 }
833 //else: some other worker thread is doing GUI
834 }
835 }
836
837 bool WXDLLEXPORT wxGuiOwnedByMainThread()
838 {
839 return s_bGuiOwnedByMainThread;
840 }
841
842 // wake up the main thread if it's in ::GetMessage()
843 void WXDLLEXPORT wxWakeUpMainThread()
844 {
845 // sending any message would do - hopefully WM_NULL is harmless enough
846 if ( !::PostThreadMessage(s_idMainThread, WM_NULL, 0, 0) )
847 {
848 // should never happen
849 wxLogLastError("PostThreadMessage(WM_NULL)");
850 }
851 }
852
853 bool WXDLLEXPORT wxIsWaitingForThread()
854 {
855 return s_waitingForThread;
856 }
857
858 #endif // wxUSE_THREADS