]> git.saurik.com Git - wxWidgets.git/blame - src/msw/thread.cpp
patches for BC++ 5.3 from Ricky Gonzales <gonzales@pyramid3.net>
[wxWidgets.git] / src / msw / thread.cpp
CommitLineData
2bda0e17
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: thread.cpp
3// Purpose: wxThread Implementation
4// Author: Original from Wolfram Gloger/Guilhem Lavaux
bee503b0 5// Modified by: Vadim Zeitlin to make it work :-)
2bda0e17
KB
6// Created: 04/22/98
7// RCS-ID: $Id$
bee503b0
VZ
8// Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998),
9// Vadim Zeitlin (1999)
2bda0e17
KB
10// Licence: wxWindows licence
11/////////////////////////////////////////////////////////////////////////////
12
13#ifdef __GNUG__
3222fde2 14 #pragma implementation "thread.h"
2bda0e17
KB
15#endif
16
3222fde2
VZ
17// ----------------------------------------------------------------------------
18// headers
19// ----------------------------------------------------------------------------
20
a3b46648 21// For compilers that support precompilation, includes "wx.h".
2bda0e17
KB
22#include "wx/wxprec.h"
23
24#if defined(__BORLANDC__)
3222fde2 25 #pragma hdrstop
2bda0e17
KB
26#endif
27
28#ifndef WX_PRECOMP
3222fde2 29 #include "wx/wx.h"
2bda0e17
KB
30#endif
31
3222fde2
VZ
32#if wxUSE_THREADS
33
0d0512bd 34#include "wx/msw/private.h"
3222fde2 35
2bda0e17
KB
36#include "wx/module.h"
37#include "wx/thread.h"
38
b568d04f
VZ
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
bf1852e1
VZ
52// the possible states of the thread ("=>" shows all possible transitions from
53// this state)
54enum 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
2bda0e17
KB
61};
62
3222fde2 63// ----------------------------------------------------------------------------
b568d04f 64// this module globals
3222fde2 65// ----------------------------------------------------------------------------
2bda0e17 66
bf1852e1 67// TLS index of the slot where we store the pointer to the current thread
b568d04f 68static DWORD gs_tlsThisThread = 0xFFFFFFFF;
bf1852e1 69
3222fde2
VZ
70// id of the main thread - the one which can call GUI functions without first
71// calling wxMutexGuiEnter()
b568d04f 72static DWORD gs_idMainThread = 0;
bee503b0
VZ
73
74// if it's FALSE, some secondary thread is holding the GUI lock
b568d04f 75static bool gs_bGuiOwnedByMainThread = TRUE;
2bda0e17 76
3222fde2
VZ
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
b568d04f 80static wxCriticalSection *gs_critsectGui = NULL;
bee503b0 81
b568d04f
VZ
82// critical section which protects gs_nWaitingForGui variable
83static wxCriticalSection *gs_critsectWaitingForGui = NULL;
bee503b0
VZ
84
85// number of threads waiting for GUI in wxMutexGuiEnter()
b568d04f 86static size_t gs_nWaitingForGui = 0;
2bda0e17 87
bf1852e1 88// are we waiting for a thread termination?
b568d04f 89static bool gs_waitingForThread = FALSE;
bf1852e1 90
3222fde2
VZ
91// ============================================================================
92// Windows implementation of thread classes
93// ============================================================================
94
95// ----------------------------------------------------------------------------
96// wxMutex implementation
97// ----------------------------------------------------------------------------
0d0512bd 98
3222fde2
VZ
99class wxMutexInternal
100{
2bda0e17 101public:
7f684264
VZ
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
113public:
114 HANDLE m_mutex;
2bda0e17
KB
115};
116
ee4f8c2a 117wxMutex::wxMutex()
2bda0e17 118{
9fc3ad34 119 m_internal = new wxMutexInternal;
a6b0bd49 120
3222fde2 121 m_locked = 0;
2bda0e17
KB
122}
123
ee4f8c2a 124wxMutex::~wxMutex()
2bda0e17 125{
7f684264
VZ
126 if ( m_locked > 0 )
127 {
128 wxLogDebug(_T("Warning: freeing a locked mutex (%d locks)."), m_locked);
129 }
130
131 delete m_internal;
2bda0e17
KB
132}
133
ee4f8c2a 134wxMutexError wxMutex::Lock()
2bda0e17 135{
3222fde2
VZ
136 DWORD ret;
137
7f684264 138 ret = WaitForSingleObject(m_internal->m_mutex, INFINITE);
3222fde2
VZ
139 switch ( ret )
140 {
141 case WAIT_ABANDONED:
142 return wxMUTEX_BUSY;
143
144 case WAIT_OBJECT_0:
145 // ok
146 break;
2bda0e17 147
3222fde2
VZ
148 case WAIT_FAILED:
149 wxLogSysError(_("Couldn't acquire a mutex lock"));
150 return wxMUTEX_MISC_ERROR;
2bda0e17 151
3222fde2
VZ
152 case WAIT_TIMEOUT:
153 default:
223d09f6 154 wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
3222fde2
VZ
155 }
156
157 m_locked++;
158 return wxMUTEX_NO_ERROR;
2bda0e17
KB
159}
160
ee4f8c2a 161wxMutexError wxMutex::TryLock()
2bda0e17 162{
3222fde2 163 DWORD ret;
2bda0e17 164
7f684264 165 ret = WaitForSingleObject(m_internal->m_mutex, 0);
3222fde2
VZ
166 if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
167 return wxMUTEX_BUSY;
2bda0e17 168
3222fde2
VZ
169 m_locked++;
170 return wxMUTEX_NO_ERROR;
2bda0e17
KB
171}
172
ee4f8c2a 173wxMutexError wxMutex::Unlock()
2bda0e17 174{
3222fde2
VZ
175 if (m_locked > 0)
176 m_locked--;
2bda0e17 177
7f684264 178 BOOL ret = ReleaseMutex(m_internal->m_mutex);
3222fde2
VZ
179 if ( ret == 0 )
180 {
181 wxLogSysError(_("Couldn't release a mutex"));
182 return wxMUTEX_MISC_ERROR;
183 }
a6b0bd49 184
3222fde2 185 return wxMUTEX_NO_ERROR;
2bda0e17
KB
186}
187
3222fde2
VZ
188// ----------------------------------------------------------------------------
189// wxCondition implementation
190// ----------------------------------------------------------------------------
191
192class wxConditionInternal
193{
2bda0e17 194public:
b568d04f
VZ
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
9fc3ad34 210 bool Wait(DWORD timeout)
b568d04f 211 {
b568d04f
VZ
212 waiters++;
213
214 // FIXME this should be MsgWaitForMultipleObjects() as well probably
215 DWORD rc = ::WaitForSingleObject(event, timeout);
216
217 waiters--;
b568d04f
VZ
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
3222fde2
VZ
233 HANDLE event;
234 int waiters;
2bda0e17
KB
235};
236
ee4f8c2a 237wxCondition::wxCondition()
2bda0e17 238{
9fc3ad34 239 m_internal = new wxConditionInternal;
2bda0e17
KB
240}
241
ee4f8c2a 242wxCondition::~wxCondition()
2bda0e17 243{
9fc3ad34 244 delete m_internal;
2bda0e17
KB
245}
246
9fc3ad34 247void wxCondition::Wait()
2bda0e17 248{
9fc3ad34 249 (void)m_internal->Wait(INFINITE);
2bda0e17
KB
250}
251
9fc3ad34 252bool wxCondition::Wait(unsigned long sec,
2bda0e17
KB
253 unsigned long nsec)
254{
9fc3ad34 255 return m_internal->Wait(sec*1000 + nsec/1000000);
2bda0e17
KB
256}
257
ee4f8c2a 258void wxCondition::Signal()
2bda0e17 259{
b568d04f
VZ
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.
9fc3ad34 265 if ( !::SetEvent(m_internal->event) )
b568d04f
VZ
266 {
267 wxLogLastError("SetEvent");
268 }
2bda0e17
KB
269}
270
ee4f8c2a 271void wxCondition::Broadcast()
2bda0e17 272{
b568d04f
VZ
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
9fc3ad34 276 for ( int i = 0; i < m_internal->waiters; i++ )
a6b0bd49 277 {
b568d04f 278 Signal();
a6b0bd49 279 }
2bda0e17
KB
280}
281
3222fde2
VZ
282// ----------------------------------------------------------------------------
283// wxCriticalSection implementation
284// ----------------------------------------------------------------------------
285
3222fde2
VZ
286wxCriticalSection::wxCriticalSection()
287{
b568d04f 288 wxASSERT_MSG( sizeof(CRITICAL_SECTION) <= sizeof(m_buffer),
0d0512bd
VZ
289 _T("must increase buffer size in wx/thread.h") );
290
291 ::InitializeCriticalSection((CRITICAL_SECTION *)m_buffer);
3222fde2
VZ
292}
293
294wxCriticalSection::~wxCriticalSection()
295{
0d0512bd 296 ::DeleteCriticalSection((CRITICAL_SECTION *)m_buffer);
3222fde2
VZ
297}
298
299void wxCriticalSection::Enter()
300{
0d0512bd 301 ::EnterCriticalSection((CRITICAL_SECTION *)m_buffer);
3222fde2
VZ
302}
303
304void wxCriticalSection::Leave()
305{
0d0512bd 306 ::LeaveCriticalSection((CRITICAL_SECTION *)m_buffer);
3222fde2
VZ
307}
308
309// ----------------------------------------------------------------------------
310// wxThread implementation
311// ----------------------------------------------------------------------------
312
bf1852e1
VZ
313// wxThreadInternal class
314// ----------------------
315
3222fde2
VZ
316class wxThreadInternal
317{
2bda0e17 318public:
bf1852e1
VZ
319 wxThreadInternal()
320 {
321 m_hThread = 0;
322 m_state = STATE_NEW;
323 m_priority = WXTHREAD_DEFAULT_PRIORITY;
324 }
325
b568d04f
VZ
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
bf1852e1
VZ
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
b568d04f 357 void SetPriority(unsigned int priority);
bf1852e1
VZ
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
bee503b0 365 static DWORD WinThreadStart(wxThread *thread);
2bda0e17 366
bf1852e1
VZ
367private:
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
2bda0e17
KB
372};
373
bee503b0 374DWORD wxThreadInternal::WinThreadStart(wxThread *thread)
2bda0e17 375{
696e1ea0
VZ
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
bf1852e1 382 // store the thread object in the TLS
b568d04f 383 if ( !::TlsSetValue(gs_tlsThisThread, thread) )
bf1852e1
VZ
384 {
385 wxLogSysError(_("Can not start thread: error writing TLS."));
386
387 return (DWORD)-1;
388 }
389
b568d04f
VZ
390 DWORD rc = (DWORD)thread->Entry();
391
392 // enter m_critsect before changing the thread state
393 thread->m_critsect.Enter();
9fc3ad34
VZ
394 bool wasCancelled = thread->m_internal->GetState() == STATE_CANCELED;
395 thread->m_internal->SetState(STATE_EXITED);
b568d04f
VZ
396 thread->m_critsect.Leave();
397
bee503b0 398 thread->OnExit();
2bda0e17 399
b568d04f
VZ
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
bf1852e1 408
b568d04f 409 return rc;
2bda0e17
KB
410}
411
b568d04f 412void wxThreadInternal::SetPriority(unsigned int priority)
2bda0e17 413{
b568d04f 414 m_priority = priority;
3222fde2 415
bf1852e1
VZ
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;
3222fde2
VZ
428 else
429 {
223d09f6 430 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
bf1852e1 431 win_priority = THREAD_PRIORITY_NORMAL;
3222fde2
VZ
432 }
433
b568d04f 434 if ( !::SetThreadPriority(m_hThread, win_priority) )
bee503b0
VZ
435 {
436 wxLogSysError(_("Can't set thread priority"));
437 }
b568d04f
VZ
438}
439
440bool 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,
696e1ea0 449 (RtlThreadStart)
b568d04f
VZ
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 }
3222fde2 477
bf1852e1 478 return TRUE;
2bda0e17
KB
479}
480
bf1852e1 481bool wxThreadInternal::Suspend()
2bda0e17 482{
bf1852e1
VZ
483 DWORD nSuspendCount = ::SuspendThread(m_hThread);
484 if ( nSuspendCount == (DWORD)-1 )
bee503b0 485 {
bf1852e1
VZ
486 wxLogSysError(_("Can not suspend thread %x"), m_hThread);
487
488 return FALSE;
bee503b0 489 }
2bda0e17 490
bf1852e1
VZ
491 m_state = STATE_PAUSED;
492
493 return TRUE;
a6b0bd49
VZ
494}
495
bf1852e1 496bool wxThreadInternal::Resume()
a6b0bd49 497{
bf1852e1 498 DWORD nSuspendCount = ::ResumeThread(m_hThread);
a6b0bd49
VZ
499 if ( nSuspendCount == (DWORD)-1 )
500 {
bf1852e1 501 wxLogSysError(_("Can not resume thread %x"), m_hThread);
a6b0bd49 502
bf1852e1 503 return FALSE;
a6b0bd49
VZ
504 }
505
bf1852e1 506 m_state = STATE_RUNNING;
bee503b0 507
bf1852e1 508 return TRUE;
a6b0bd49
VZ
509}
510
bf1852e1
VZ
511// static functions
512// ----------------
513
514wxThread *wxThread::This()
a6b0bd49 515{
b568d04f 516 wxThread *thread = (wxThread *)::TlsGetValue(gs_tlsThisThread);
bf1852e1
VZ
517
518 // be careful, 0 may be a valid return value as well
519 if ( !thread && (::GetLastError() != NO_ERROR) )
a6b0bd49 520 {
bf1852e1 521 wxLogSysError(_("Couldn't get the current thread pointer"));
a6b0bd49 522
bf1852e1 523 // return NULL...
a6b0bd49
VZ
524 }
525
bf1852e1
VZ
526 return thread;
527}
528
529bool wxThread::IsMain()
530{
b568d04f 531 return ::GetCurrentThreadId() == gs_idMainThread;
bf1852e1
VZ
532}
533
c25a510b
JS
534#ifdef Yield
535#undef Yield
536#endif
537
bf1852e1
VZ
538void wxThread::Yield()
539{
b568d04f
VZ
540 // 0 argument to Sleep() is special and means to just give away the rest of
541 // our timeslice
bf1852e1
VZ
542 ::Sleep(0);
543}
544
545void wxThread::Sleep(unsigned long milliseconds)
546{
547 ::Sleep(milliseconds);
548}
549
ef8d96c2
VZ
550int wxThread::GetCPUCount()
551{
28a4627c
VZ
552 SYSTEM_INFO si;
553 GetSystemInfo(&si);
554
555 return si.dwNumberOfProcessors;
ef8d96c2
VZ
556}
557
558bool wxThread::SetConcurrency(size_t level)
559{
28a4627c
VZ
560 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
561
ef8d96c2 562 // ok only for the default one
28a4627c
VZ
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
696e1ea0 618 typedef BOOL (*SETPROCESSAFFINITYMASK)(HANDLE, DWORD);
28a4627c
VZ
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
696e1ea0 644 if ( pfnSetProcessAffinityMask(hProcess, dwProcMask) == 0 )
28a4627c
VZ
645 {
646 wxLogLastError(_T("SetProcessAffinityMask"));
647
648 return FALSE;
649 }
650
651 return TRUE;
ef8d96c2
VZ
652}
653
b568d04f
VZ
654// ctor and dtor
655// -------------
656
657wxThread::wxThread(wxThreadKind kind)
658{
9fc3ad34 659 m_internal = new wxThreadInternal();
b568d04f
VZ
660
661 m_isDetached = kind == wxTHREAD_DETACHED;
662}
663
664wxThread::~wxThread()
665{
9fc3ad34 666 delete m_internal;
b568d04f
VZ
667}
668
bf1852e1
VZ
669// create/start thread
670// -------------------
671
672wxThreadError wxThread::Create()
673{
b568d04f
VZ
674 wxCriticalSectionLocker lock(m_critsect);
675
9fc3ad34 676 if ( !m_internal->Create(this) )
bf1852e1 677 return wxTHREAD_NO_RESOURCE;
bee503b0 678
a6b0bd49 679 return wxTHREAD_NO_ERROR;
2bda0e17
KB
680}
681
bf1852e1 682wxThreadError wxThread::Run()
2bda0e17 683{
bf1852e1
VZ
684 wxCriticalSectionLocker lock(m_critsect);
685
9fc3ad34 686 if ( m_internal->GetState() != STATE_NEW )
bf1852e1
VZ
687 {
688 // actually, it may be almost any state at all, not only STATE_RUNNING
689 return wxTHREAD_RUNNING;
690 }
691
b568d04f 692 // the thread has just been created and is still suspended - let it run
bf1852e1 693 return Resume();
2bda0e17
KB
694}
695
bf1852e1
VZ
696// suspend/resume thread
697// ---------------------
698
699wxThreadError wxThread::Pause()
2bda0e17 700{
bf1852e1
VZ
701 wxCriticalSectionLocker lock(m_critsect);
702
9fc3ad34 703 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
2bda0e17
KB
704}
705
bf1852e1 706wxThreadError wxThread::Resume()
2bda0e17 707{
bf1852e1
VZ
708 wxCriticalSectionLocker lock(m_critsect);
709
9fc3ad34 710 return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
2bda0e17
KB
711}
712
bf1852e1
VZ
713// stopping thread
714// ---------------
715
b568d04f
VZ
716wxThread::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
9fc3ad34 727 m_internal->Free();
b568d04f
VZ
728
729 return rc;
730}
731
732wxThreadError wxThread::Delete(ExitCode *pRc)
2bda0e17 733{
bf1852e1
VZ
734 ExitCode rc = 0;
735
736 // Delete() is always safe to call, so consider all possible states
696e1ea0
VZ
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() )
bf1852e1
VZ
755 Resume();
756
9fc3ad34 757 HANDLE hThread = m_internal->GetHandle();
b568d04f 758
696e1ea0 759 // does is still run?
bf1852e1
VZ
760 if ( IsRunning() )
761 {
762 if ( IsMain() )
763 {
764 // set flag for wxIsWaitingForThread()
b568d04f 765 gs_waitingForThread = TRUE;
bf1852e1 766
b568d04f 767#if wxUSE_GUI
bf1852e1 768 wxBeginBusyCursor();
b568d04f 769#endif // wxUSE_GUI
bf1852e1
VZ
770 }
771
b568d04f 772 // ask the thread to terminate
bf1852e1
VZ
773 {
774 wxCriticalSectionLocker lock(m_critsect);
775
9fc3ad34 776 m_internal->Cancel();
bf1852e1
VZ
777 }
778
b568d04f 779#if wxUSE_GUI
bf1852e1
VZ
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();
b568d04f 801 return wxTHREAD_KILLED;
bf1852e1
VZ
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
b568d04f 814 return wxTHREAD_KILLED;
bf1852e1
VZ
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
b568d04f 821 if ( (gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
bf1852e1
VZ
822 {
823 wxMutexGuiLeave();
824 }
825 }
826
827 break;
828
829 default:
223d09f6 830 wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject"));
bf1852e1
VZ
831 }
832 } while ( result != WAIT_OBJECT_0 );
b568d04f
VZ
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
bf1852e1
VZ
843
844 if ( IsMain() )
845 {
b568d04f 846 gs_waitingForThread = FALSE;
bf1852e1 847
b568d04f 848#if wxUSE_GUI
bf1852e1 849 wxEndBusyCursor();
b568d04f 850#endif // wxUSE_GUI
bf1852e1 851 }
b568d04f 852 }
bf1852e1 853
b568d04f
VZ
854 if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
855 {
856 wxLogLastError("GetExitCodeThread");
bf1852e1 857
b568d04f
VZ
858 rc = (ExitCode)-1;
859 }
bf1852e1 860
b568d04f
VZ
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;
bf1852e1
VZ
868 }
869
b568d04f
VZ
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;
2bda0e17
KB
877}
878
bf1852e1 879wxThreadError wxThread::Kill()
2bda0e17 880{
bf1852e1
VZ
881 if ( !IsRunning() )
882 return wxTHREAD_NOT_RUNNING;
883
9fc3ad34 884 if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
bf1852e1
VZ
885 {
886 wxLogSysError(_("Couldn't terminate thread"));
887
888 return wxTHREAD_MISC_ERROR;
889 }
890
9fc3ad34 891 m_internal->Free();
b568d04f
VZ
892
893 if ( IsDetached() )
894 {
895 delete this;
896 }
bf1852e1
VZ
897
898 return wxTHREAD_NO_ERROR;
2bda0e17
KB
899}
900
b568d04f 901void wxThread::Exit(ExitCode status)
2bda0e17 902{
9fc3ad34 903 m_internal->Free();
2bda0e17 904
b568d04f
VZ
905 if ( IsDetached() )
906 {
907 delete this;
908 }
909
910#ifdef __VISUALC__
911 _endthreadex((unsigned)status);
912#else // !VC++
bf1852e1 913 ::ExitThread((DWORD)status);
b568d04f 914#endif // VC++/!VC++
2bda0e17 915
223d09f6 916 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
bf1852e1 917}
2bda0e17 918
b568d04f
VZ
919// priority setting
920// ----------------
921
bf1852e1
VZ
922void wxThread::SetPriority(unsigned int prio)
923{
924 wxCriticalSectionLocker lock(m_critsect);
925
9fc3ad34 926 m_internal->SetPriority(prio);
bf1852e1 927}
2bda0e17 928
bf1852e1
VZ
929unsigned int wxThread::GetPriority() const
930{
b568d04f 931 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
2bda0e17 932
9fc3ad34 933 return m_internal->GetPriority();
2bda0e17
KB
934}
935
b568d04f 936unsigned long wxThread::GetId() const
2bda0e17 937{
b568d04f 938 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
bf1852e1 939
9fc3ad34 940 return (unsigned long)m_internal->GetId();
2bda0e17
KB
941}
942
72fd19a1
JS
943bool wxThread::IsRunning() const
944{
b568d04f 945 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
bf1852e1 946
9fc3ad34 947 return m_internal->GetState() == STATE_RUNNING;
72fd19a1
JS
948}
949
950bool wxThread::IsAlive() const
951{
b568d04f 952 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
bf1852e1 953
9fc3ad34
VZ
954 return (m_internal->GetState() == STATE_RUNNING) ||
955 (m_internal->GetState() == STATE_PAUSED);
72fd19a1
JS
956}
957
a737331d
GL
958bool wxThread::IsPaused() const
959{
b568d04f 960 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
a737331d 961
9fc3ad34 962 return m_internal->GetState() == STATE_PAUSED;
a737331d
GL
963}
964
8c10faf1 965bool wxThread::TestDestroy()
2bda0e17 966{
b568d04f 967 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
bf1852e1 968
9fc3ad34 969 return m_internal->GetState() == STATE_CANCELED;
2bda0e17
KB
970}
971
3222fde2
VZ
972// ----------------------------------------------------------------------------
973// Automatic initialization for thread module
974// ----------------------------------------------------------------------------
2bda0e17 975
3222fde2 976class wxThreadModule : public wxModule
a6b0bd49 977{
3222fde2
VZ
978public:
979 virtual bool OnInit();
980 virtual void OnExit();
d524867f 981
3222fde2
VZ
982private:
983 DECLARE_DYNAMIC_CLASS(wxThreadModule)
984};
d524867f
RR
985
986IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
987
3222fde2 988bool wxThreadModule::OnInit()
d524867f 989{
bf1852e1 990 // allocate TLS index for storing the pointer to the current thread
b568d04f
VZ
991 gs_tlsThisThread = ::TlsAlloc();
992 if ( gs_tlsThisThread == 0xFFFFFFFF )
bf1852e1
VZ
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
b568d04f 1006 if ( !::TlsSetValue(gs_tlsThisThread, (LPVOID)0) )
bf1852e1 1007 {
b568d04f
VZ
1008 ::TlsFree(gs_tlsThisThread);
1009 gs_tlsThisThread = 0xFFFFFFFF;
bf1852e1
VZ
1010
1011 wxLogSysError(_("Thread module initialization failed: "
1012 "can not store value in thread local storage"));
1013
1014 return FALSE;
1015 }
1016
b568d04f 1017 gs_critsectWaitingForGui = new wxCriticalSection();
bee503b0 1018
b568d04f
VZ
1019 gs_critsectGui = new wxCriticalSection();
1020 gs_critsectGui->Enter();
bee503b0 1021
bf1852e1 1022 // no error return for GetCurrentThreadId()
b568d04f 1023 gs_idMainThread = ::GetCurrentThreadId();
3222fde2 1024
d524867f
RR
1025 return TRUE;
1026}
1027
3222fde2 1028void wxThreadModule::OnExit()
d524867f 1029{
b568d04f 1030 if ( !::TlsFree(gs_tlsThisThread) )
bf1852e1
VZ
1031 {
1032 wxLogLastError("TlsFree failed.");
1033 }
1034
b568d04f 1035 if ( gs_critsectGui )
3222fde2 1036 {
b568d04f
VZ
1037 gs_critsectGui->Leave();
1038 delete gs_critsectGui;
1039 gs_critsectGui = NULL;
3222fde2 1040 }
bee503b0 1041
b568d04f
VZ
1042 delete gs_critsectWaitingForGui;
1043 gs_critsectWaitingForGui = NULL;
3222fde2
VZ
1044}
1045
bee503b0 1046// ----------------------------------------------------------------------------
b568d04f 1047// under Windows, these functions are implemented using a critical section and
3222fde2 1048// not a mutex, so the names are a bit confusing
bee503b0
VZ
1049// ----------------------------------------------------------------------------
1050
3222fde2
VZ
1051void WXDLLEXPORT wxMutexGuiEnter()
1052{
bee503b0
VZ
1053 // this would dead lock everything...
1054 wxASSERT_MSG( !wxThread::IsMain(),
223d09f6 1055 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
bee503b0
VZ
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 {
b568d04f 1061 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
bee503b0 1062
b568d04f 1063 gs_nWaitingForGui++;
bee503b0
VZ
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())
b568d04f 1070 gs_critsectGui->Enter();
3222fde2
VZ
1071}
1072
1073void WXDLLEXPORT wxMutexGuiLeave()
1074{
b568d04f 1075 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
bee503b0
VZ
1076
1077 if ( wxThread::IsMain() )
1078 {
b568d04f 1079 gs_bGuiOwnedByMainThread = FALSE;
bee503b0
VZ
1080 }
1081 else
1082 {
1083 // decrement the number of waiters now
b568d04f 1084 wxASSERT_MSG( gs_nWaitingForGui > 0,
223d09f6 1085 wxT("calling wxMutexGuiLeave() without entering it first?") );
bee503b0 1086
b568d04f 1087 gs_nWaitingForGui--;
bee503b0
VZ
1088
1089 wxWakeUpMainThread();
1090 }
1091
b568d04f 1092 gs_critsectGui->Leave();
bee503b0
VZ
1093}
1094
1095void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
1096{
1097 wxASSERT_MSG( wxThread::IsMain(),
223d09f6 1098 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
bee503b0 1099
b568d04f 1100 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
bee503b0 1101
b568d04f 1102 if ( gs_nWaitingForGui == 0 )
bee503b0
VZ
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 {
b568d04f 1108 gs_critsectGui->Enter();
bee503b0 1109
b568d04f 1110 gs_bGuiOwnedByMainThread = TRUE;
bee503b0
VZ
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
1125bool WXDLLEXPORT wxGuiOwnedByMainThread()
1126{
b568d04f 1127 return gs_bGuiOwnedByMainThread;
bee503b0
VZ
1128}
1129
1130// wake up the main thread if it's in ::GetMessage()
1131void WXDLLEXPORT wxWakeUpMainThread()
1132{
1133 // sending any message would do - hopefully WM_NULL is harmless enough
b568d04f 1134 if ( !::PostThreadMessage(gs_idMainThread, WM_NULL, 0, 0) )
bee503b0
VZ
1135 {
1136 // should never happen
1137 wxLogLastError("PostThreadMessage(WM_NULL)");
1138 }
3222fde2 1139}
d524867f 1140
bf1852e1
VZ
1141bool WXDLLEXPORT wxIsWaitingForThread()
1142{
b568d04f 1143 return gs_waitingForThread;
bf1852e1
VZ
1144}
1145
3222fde2 1146#endif // wxUSE_THREADS