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