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