]> git.saurik.com Git - wxWidgets.git/blame - src/msw/thread.cpp
added wxLog::Suspend/Resume and wxYield() uses them now so that it won't flush
[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))
ccebc98a
JS
45
46#if defined(__BORLANDC__) && !defined(__MT__)
47// I can't set -tWM in the IDE (anyone?) so have to do this
48#define __MT__
49#endif
50
8536082d
BJ
51#if defined(__BORLANDC__) && !defined(__MFC_COMPAT__)
52// Needed to know about _beginthreadex etc..
53#define __MFC_COMPAT__
54#endif
55
56
b568d04f
VZ
57 #include <process.h>
58#endif
59
60// ----------------------------------------------------------------------------
61// constants
62// ----------------------------------------------------------------------------
63
bf1852e1
VZ
64// the possible states of the thread ("=>" shows all possible transitions from
65// this state)
66enum wxThreadState
67{
68 STATE_NEW, // didn't start execution yet (=> RUNNING)
69 STATE_RUNNING, // thread is running (=> PAUSED, CANCELED)
70 STATE_PAUSED, // thread is temporarily suspended (=> RUNNING)
71 STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED)
72 STATE_EXITED // thread is terminating
2bda0e17
KB
73};
74
3222fde2 75// ----------------------------------------------------------------------------
b568d04f 76// this module globals
3222fde2 77// ----------------------------------------------------------------------------
2bda0e17 78
bf1852e1 79// TLS index of the slot where we store the pointer to the current thread
b568d04f 80static DWORD gs_tlsThisThread = 0xFFFFFFFF;
bf1852e1 81
3222fde2
VZ
82// id of the main thread - the one which can call GUI functions without first
83// calling wxMutexGuiEnter()
b568d04f 84static DWORD gs_idMainThread = 0;
bee503b0
VZ
85
86// if it's FALSE, some secondary thread is holding the GUI lock
b568d04f 87static bool gs_bGuiOwnedByMainThread = TRUE;
2bda0e17 88
3222fde2
VZ
89// critical section which controls access to all GUI functions: any secondary
90// thread (i.e. except the main one) must enter this crit section before doing
91// any GUI calls
b568d04f 92static wxCriticalSection *gs_critsectGui = NULL;
bee503b0 93
b568d04f
VZ
94// critical section which protects gs_nWaitingForGui variable
95static wxCriticalSection *gs_critsectWaitingForGui = NULL;
bee503b0
VZ
96
97// number of threads waiting for GUI in wxMutexGuiEnter()
b568d04f 98static size_t gs_nWaitingForGui = 0;
2bda0e17 99
bf1852e1 100// are we waiting for a thread termination?
b568d04f 101static bool gs_waitingForThread = FALSE;
bf1852e1 102
3222fde2
VZ
103// ============================================================================
104// Windows implementation of thread classes
105// ============================================================================
106
107// ----------------------------------------------------------------------------
108// wxMutex implementation
109// ----------------------------------------------------------------------------
0d0512bd 110
3222fde2
VZ
111class wxMutexInternal
112{
2bda0e17 113public:
7f684264
VZ
114 wxMutexInternal()
115 {
116 m_mutex = ::CreateMutex(NULL, FALSE, NULL);
117 if ( !m_mutex )
118 {
119 wxLogSysError(_("Can not create mutex"));
120 }
121 }
122
123 ~wxMutexInternal() { if ( m_mutex ) CloseHandle(m_mutex); }
124
125public:
126 HANDLE m_mutex;
2bda0e17
KB
127};
128
ee4f8c2a 129wxMutex::wxMutex()
2bda0e17 130{
9fc3ad34 131 m_internal = new wxMutexInternal;
a6b0bd49 132
3222fde2 133 m_locked = 0;
2bda0e17
KB
134}
135
ee4f8c2a 136wxMutex::~wxMutex()
2bda0e17 137{
7f684264
VZ
138 if ( m_locked > 0 )
139 {
140 wxLogDebug(_T("Warning: freeing a locked mutex (%d locks)."), m_locked);
141 }
142
143 delete m_internal;
2bda0e17
KB
144}
145
ee4f8c2a 146wxMutexError wxMutex::Lock()
2bda0e17 147{
3222fde2
VZ
148 DWORD ret;
149
7f684264 150 ret = WaitForSingleObject(m_internal->m_mutex, INFINITE);
3222fde2
VZ
151 switch ( ret )
152 {
153 case WAIT_ABANDONED:
154 return wxMUTEX_BUSY;
155
156 case WAIT_OBJECT_0:
157 // ok
158 break;
2bda0e17 159
3222fde2
VZ
160 case WAIT_FAILED:
161 wxLogSysError(_("Couldn't acquire a mutex lock"));
162 return wxMUTEX_MISC_ERROR;
2bda0e17 163
3222fde2
VZ
164 case WAIT_TIMEOUT:
165 default:
223d09f6 166 wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
3222fde2
VZ
167 }
168
169 m_locked++;
170 return wxMUTEX_NO_ERROR;
2bda0e17
KB
171}
172
ee4f8c2a 173wxMutexError wxMutex::TryLock()
2bda0e17 174{
3222fde2 175 DWORD ret;
2bda0e17 176
7f684264 177 ret = WaitForSingleObject(m_internal->m_mutex, 0);
3222fde2
VZ
178 if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
179 return wxMUTEX_BUSY;
2bda0e17 180
3222fde2
VZ
181 m_locked++;
182 return wxMUTEX_NO_ERROR;
2bda0e17
KB
183}
184
ee4f8c2a 185wxMutexError wxMutex::Unlock()
2bda0e17 186{
3222fde2
VZ
187 if (m_locked > 0)
188 m_locked--;
2bda0e17 189
7f684264 190 BOOL ret = ReleaseMutex(m_internal->m_mutex);
3222fde2
VZ
191 if ( ret == 0 )
192 {
193 wxLogSysError(_("Couldn't release a mutex"));
194 return wxMUTEX_MISC_ERROR;
195 }
a6b0bd49 196
3222fde2 197 return wxMUTEX_NO_ERROR;
2bda0e17
KB
198}
199
3222fde2
VZ
200// ----------------------------------------------------------------------------
201// wxCondition implementation
202// ----------------------------------------------------------------------------
203
204class wxConditionInternal
205{
2bda0e17 206public:
b568d04f
VZ
207 wxConditionInternal()
208 {
209 event = ::CreateEvent(
210 NULL, // default secutiry
211 FALSE, // not manual reset
212 FALSE, // nonsignaled initially
213 NULL // nameless event
214 );
215 if ( !event )
216 {
217 wxLogSysError(_("Can not create event object."));
218 }
219 waiters = 0;
220 }
221
9fc3ad34 222 bool Wait(DWORD timeout)
b568d04f 223 {
b568d04f
VZ
224 waiters++;
225
226 // FIXME this should be MsgWaitForMultipleObjects() as well probably
227 DWORD rc = ::WaitForSingleObject(event, timeout);
228
229 waiters--;
b568d04f
VZ
230
231 return rc != WAIT_TIMEOUT;
232 }
233
234 ~wxConditionInternal()
235 {
236 if ( event )
237 {
238 if ( !::CloseHandle(event) )
239 {
240 wxLogLastError("CloseHandle(event)");
241 }
242 }
243 }
244
3222fde2
VZ
245 HANDLE event;
246 int waiters;
2bda0e17
KB
247};
248
ee4f8c2a 249wxCondition::wxCondition()
2bda0e17 250{
9fc3ad34 251 m_internal = new wxConditionInternal;
2bda0e17
KB
252}
253
ee4f8c2a 254wxCondition::~wxCondition()
2bda0e17 255{
9fc3ad34 256 delete m_internal;
2bda0e17
KB
257}
258
9fc3ad34 259void wxCondition::Wait()
2bda0e17 260{
9fc3ad34 261 (void)m_internal->Wait(INFINITE);
2bda0e17
KB
262}
263
9fc3ad34 264bool wxCondition::Wait(unsigned long sec,
2bda0e17
KB
265 unsigned long nsec)
266{
9fc3ad34 267 return m_internal->Wait(sec*1000 + nsec/1000000);
2bda0e17
KB
268}
269
ee4f8c2a 270void wxCondition::Signal()
2bda0e17 271{
b568d04f
VZ
272 // set the event to signaled: if a thread is already waiting on it, it will
273 // be woken up, otherwise the event will remain in the signaled state until
274 // someone waits on it. In any case, the system will return it to a non
275 // signalled state afterwards. If multiple threads are waiting, only one
276 // will be woken up.
9fc3ad34 277 if ( !::SetEvent(m_internal->event) )
b568d04f
VZ
278 {
279 wxLogLastError("SetEvent");
280 }
2bda0e17
KB
281}
282
ee4f8c2a 283void wxCondition::Broadcast()
2bda0e17 284{
b568d04f
VZ
285 // this works because all these threads are already waiting and so each
286 // SetEvent() inside Signal() is really a PulseEvent() because the event
287 // state is immediately returned to non-signaled
9fc3ad34 288 for ( int i = 0; i < m_internal->waiters; i++ )
a6b0bd49 289 {
b568d04f 290 Signal();
a6b0bd49 291 }
2bda0e17
KB
292}
293
3222fde2
VZ
294// ----------------------------------------------------------------------------
295// wxCriticalSection implementation
296// ----------------------------------------------------------------------------
297
3222fde2
VZ
298wxCriticalSection::wxCriticalSection()
299{
b568d04f 300 wxASSERT_MSG( sizeof(CRITICAL_SECTION) <= sizeof(m_buffer),
0d0512bd
VZ
301 _T("must increase buffer size in wx/thread.h") );
302
303 ::InitializeCriticalSection((CRITICAL_SECTION *)m_buffer);
3222fde2
VZ
304}
305
306wxCriticalSection::~wxCriticalSection()
307{
0d0512bd 308 ::DeleteCriticalSection((CRITICAL_SECTION *)m_buffer);
3222fde2
VZ
309}
310
311void wxCriticalSection::Enter()
312{
0d0512bd 313 ::EnterCriticalSection((CRITICAL_SECTION *)m_buffer);
3222fde2
VZ
314}
315
316void wxCriticalSection::Leave()
317{
0d0512bd 318 ::LeaveCriticalSection((CRITICAL_SECTION *)m_buffer);
3222fde2
VZ
319}
320
321// ----------------------------------------------------------------------------
322// wxThread implementation
323// ----------------------------------------------------------------------------
324
bf1852e1
VZ
325// wxThreadInternal class
326// ----------------------
327
3222fde2
VZ
328class wxThreadInternal
329{
2bda0e17 330public:
bf1852e1
VZ
331 wxThreadInternal()
332 {
333 m_hThread = 0;
334 m_state = STATE_NEW;
335 m_priority = WXTHREAD_DEFAULT_PRIORITY;
336 }
337
b568d04f
VZ
338 ~wxThreadInternal()
339 {
340 Free();
341 }
342
343 void Free()
344 {
345 if ( m_hThread )
346 {
347 if ( !::CloseHandle(m_hThread) )
348 {
349 wxLogLastError("CloseHandle(thread)");
350 }
351
352 m_hThread = 0;
353 }
354 }
355
bf1852e1
VZ
356 // create a new (suspended) thread (for the given thread object)
357 bool Create(wxThread *thread);
358
359 // suspend/resume/terminate
360 bool Suspend();
361 bool Resume();
362 void Cancel() { m_state = STATE_CANCELED; }
363
364 // thread state
365 void SetState(wxThreadState state) { m_state = state; }
366 wxThreadState GetState() const { return m_state; }
367
368 // thread priority
b568d04f 369 void SetPriority(unsigned int priority);
bf1852e1
VZ
370 unsigned int GetPriority() const { return m_priority; }
371
372 // thread handle and id
373 HANDLE GetHandle() const { return m_hThread; }
374 DWORD GetId() const { return m_tid; }
375
376 // thread function
bee503b0 377 static DWORD WinThreadStart(wxThread *thread);
2bda0e17 378
bf1852e1
VZ
379private:
380 HANDLE m_hThread; // handle of the thread
381 wxThreadState m_state; // state, see wxThreadState enum
382 unsigned int m_priority; // thread priority in "wx" units
383 DWORD m_tid; // thread id
2bda0e17
KB
384};
385
bee503b0 386DWORD wxThreadInternal::WinThreadStart(wxThread *thread)
2bda0e17 387{
696e1ea0
VZ
388 // first of all, check whether we hadn't been cancelled already
389 if ( thread->m_internal->GetState() == STATE_EXITED )
390 {
391 return (DWORD)-1;
392 }
393
bf1852e1 394 // store the thread object in the TLS
b568d04f 395 if ( !::TlsSetValue(gs_tlsThisThread, thread) )
bf1852e1
VZ
396 {
397 wxLogSysError(_("Can not start thread: error writing TLS."));
398
399 return (DWORD)-1;
400 }
401
b568d04f
VZ
402 DWORD rc = (DWORD)thread->Entry();
403
404 // enter m_critsect before changing the thread state
405 thread->m_critsect.Enter();
9fc3ad34
VZ
406 bool wasCancelled = thread->m_internal->GetState() == STATE_CANCELED;
407 thread->m_internal->SetState(STATE_EXITED);
b568d04f
VZ
408 thread->m_critsect.Leave();
409
bee503b0 410 thread->OnExit();
2bda0e17 411
b568d04f
VZ
412 // if the thread was cancelled (from Delete()), then it the handle is still
413 // needed there
414 if ( thread->IsDetached() && !wasCancelled )
415 {
416 // auto delete
417 delete thread;
418 }
419 //else: the joinable threads handle will be closed when Wait() is done
bf1852e1 420
b568d04f 421 return rc;
2bda0e17
KB
422}
423
b568d04f 424void wxThreadInternal::SetPriority(unsigned int priority)
2bda0e17 425{
b568d04f 426 m_priority = priority;
3222fde2 427
bf1852e1
VZ
428 // translate wxWindows priority to the Windows one
429 int win_priority;
430 if (m_priority <= 20)
431 win_priority = THREAD_PRIORITY_LOWEST;
432 else if (m_priority <= 40)
433 win_priority = THREAD_PRIORITY_BELOW_NORMAL;
434 else if (m_priority <= 60)
435 win_priority = THREAD_PRIORITY_NORMAL;
436 else if (m_priority <= 80)
437 win_priority = THREAD_PRIORITY_ABOVE_NORMAL;
438 else if (m_priority <= 100)
439 win_priority = THREAD_PRIORITY_HIGHEST;
3222fde2
VZ
440 else
441 {
223d09f6 442 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
bf1852e1 443 win_priority = THREAD_PRIORITY_NORMAL;
3222fde2
VZ
444 }
445
b568d04f 446 if ( !::SetThreadPriority(m_hThread, win_priority) )
bee503b0
VZ
447 {
448 wxLogSysError(_("Can't set thread priority"));
449 }
b568d04f
VZ
450}
451
452bool wxThreadInternal::Create(wxThread *thread)
453{
454 // for compilers which have it, we should use C RTL function for thread
455 // creation instead of Win32 API one because otherwise we will have memory
456 // leaks if the thread uses C RTL (and most threads do)
7ab9bf9f 457#if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
b568d04f
VZ
458 typedef unsigned (__stdcall *RtlThreadStart)(void *);
459
460 m_hThread = (HANDLE)_beginthreadex(NULL, 0,
696e1ea0 461 (RtlThreadStart)
b568d04f
VZ
462 wxThreadInternal::WinThreadStart,
463 thread, CREATE_SUSPENDED,
464 (unsigned int *)&m_tid);
465#else // !VC++
466 m_hThread = ::CreateThread
467 (
468 NULL, // default security
469 0, // default stack size
470 (LPTHREAD_START_ROUTINE) // thread entry point
471 wxThreadInternal::WinThreadStart, //
472 (LPVOID)thread, // parameter
473 CREATE_SUSPENDED, // flags
474 &m_tid // [out] thread id
475 );
476#endif // VC++/!VC++
477
478 if ( m_hThread == NULL )
479 {
480 wxLogSysError(_("Can't create thread"));
481
482 return FALSE;
483 }
484
485 if ( m_priority != WXTHREAD_DEFAULT_PRIORITY )
486 {
487 SetPriority(m_priority);
488 }
3222fde2 489
bf1852e1 490 return TRUE;
2bda0e17
KB
491}
492
bf1852e1 493bool wxThreadInternal::Suspend()
2bda0e17 494{
bf1852e1
VZ
495 DWORD nSuspendCount = ::SuspendThread(m_hThread);
496 if ( nSuspendCount == (DWORD)-1 )
bee503b0 497 {
bf1852e1
VZ
498 wxLogSysError(_("Can not suspend thread %x"), m_hThread);
499
500 return FALSE;
bee503b0 501 }
2bda0e17 502
bf1852e1
VZ
503 m_state = STATE_PAUSED;
504
505 return TRUE;
a6b0bd49
VZ
506}
507
bf1852e1 508bool wxThreadInternal::Resume()
a6b0bd49 509{
bf1852e1 510 DWORD nSuspendCount = ::ResumeThread(m_hThread);
a6b0bd49
VZ
511 if ( nSuspendCount == (DWORD)-1 )
512 {
bf1852e1 513 wxLogSysError(_("Can not resume thread %x"), m_hThread);
a6b0bd49 514
bf1852e1 515 return FALSE;
a6b0bd49
VZ
516 }
517
bf1852e1 518 m_state = STATE_RUNNING;
bee503b0 519
bf1852e1 520 return TRUE;
a6b0bd49
VZ
521}
522
bf1852e1
VZ
523// static functions
524// ----------------
525
526wxThread *wxThread::This()
a6b0bd49 527{
b568d04f 528 wxThread *thread = (wxThread *)::TlsGetValue(gs_tlsThisThread);
bf1852e1
VZ
529
530 // be careful, 0 may be a valid return value as well
531 if ( !thread && (::GetLastError() != NO_ERROR) )
a6b0bd49 532 {
bf1852e1 533 wxLogSysError(_("Couldn't get the current thread pointer"));
a6b0bd49 534
bf1852e1 535 // return NULL...
a6b0bd49
VZ
536 }
537
bf1852e1
VZ
538 return thread;
539}
540
541bool wxThread::IsMain()
542{
b568d04f 543 return ::GetCurrentThreadId() == gs_idMainThread;
bf1852e1
VZ
544}
545
c25a510b
JS
546#ifdef Yield
547#undef Yield
548#endif
549
bf1852e1
VZ
550void wxThread::Yield()
551{
b568d04f
VZ
552 // 0 argument to Sleep() is special and means to just give away the rest of
553 // our timeslice
bf1852e1
VZ
554 ::Sleep(0);
555}
556
557void wxThread::Sleep(unsigned long milliseconds)
558{
559 ::Sleep(milliseconds);
560}
561
ef8d96c2
VZ
562int wxThread::GetCPUCount()
563{
28a4627c
VZ
564 SYSTEM_INFO si;
565 GetSystemInfo(&si);
566
567 return si.dwNumberOfProcessors;
ef8d96c2
VZ
568}
569
570bool wxThread::SetConcurrency(size_t level)
571{
28a4627c
VZ
572 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
573
ef8d96c2 574 // ok only for the default one
28a4627c
VZ
575 if ( level == 0 )
576 return 0;
577
578 // get system affinity mask first
579 HANDLE hProcess = ::GetCurrentProcess();
580 DWORD dwProcMask, dwSysMask;
581 if ( ::GetProcessAffinityMask(hProcess, &dwProcMask, &dwSysMask) == 0 )
582 {
583 wxLogLastError(_T("GetProcessAffinityMask"));
584
585 return FALSE;
586 }
587
588 // how many CPUs have we got?
589 if ( dwSysMask == 1 )
590 {
591 // don't bother with all this complicated stuff - on a single
592 // processor system it doesn't make much sense anyhow
593 return level == 1;
594 }
595
596 // calculate the process mask: it's a bit vector with one bit per
597 // processor; we want to schedule the process to run on first level
598 // CPUs
599 DWORD bit = 1;
600 while ( bit )
601 {
602 if ( dwSysMask & bit )
603 {
604 // ok, we can set this bit
605 dwProcMask |= bit;
606
607 // another process added
608 if ( !--level )
609 {
610 // and that's enough
611 break;
612 }
613 }
614
615 // next bit
616 bit <<= 1;
617 }
618
619 // could we set all bits?
620 if ( level != 0 )
621 {
622 wxLogDebug(_T("bad level %u in wxThread::SetConcurrency()"), level);
623
624 return FALSE;
625 }
626
627 // set it: we can't link to SetProcessAffinityMask() because it doesn't
628 // exist in Win9x, use RT binding instead
629
696e1ea0 630 typedef BOOL (*SETPROCESSAFFINITYMASK)(HANDLE, DWORD);
28a4627c
VZ
631
632 // can use static var because we're always in the main thread here
633 static SETPROCESSAFFINITYMASK pfnSetProcessAffinityMask = NULL;
634
635 if ( !pfnSetProcessAffinityMask )
636 {
637 HMODULE hModKernel = ::LoadLibrary(_T("kernel32"));
638 if ( hModKernel )
639 {
640 pfnSetProcessAffinityMask = (SETPROCESSAFFINITYMASK)
a8ee71c7
OK
641 ::GetProcAddress(hModKernel,
642#if defined(__BORLANDC__) && (__BORLANDC__ <= 0x520)
643 "SetProcessAffinityMask");
644#else
645 _T("SetProcessAffinityMask"));
646#endif
28a4627c
VZ
647 }
648
649 // we've discovered a MT version of Win9x!
650 wxASSERT_MSG( pfnSetProcessAffinityMask,
651 _T("this system has several CPUs but no "
652 "SetProcessAffinityMask function?") );
653 }
654
655 if ( !pfnSetProcessAffinityMask )
656 {
657 // msg given above - do it only once
658 return FALSE;
659 }
660
696e1ea0 661 if ( pfnSetProcessAffinityMask(hProcess, dwProcMask) == 0 )
28a4627c
VZ
662 {
663 wxLogLastError(_T("SetProcessAffinityMask"));
664
665 return FALSE;
666 }
667
668 return TRUE;
ef8d96c2
VZ
669}
670
b568d04f
VZ
671// ctor and dtor
672// -------------
673
674wxThread::wxThread(wxThreadKind kind)
675{
9fc3ad34 676 m_internal = new wxThreadInternal();
b568d04f
VZ
677
678 m_isDetached = kind == wxTHREAD_DETACHED;
679}
680
681wxThread::~wxThread()
682{
9fc3ad34 683 delete m_internal;
b568d04f
VZ
684}
685
bf1852e1
VZ
686// create/start thread
687// -------------------
688
689wxThreadError wxThread::Create()
690{
b568d04f
VZ
691 wxCriticalSectionLocker lock(m_critsect);
692
9fc3ad34 693 if ( !m_internal->Create(this) )
bf1852e1 694 return wxTHREAD_NO_RESOURCE;
bee503b0 695
a6b0bd49 696 return wxTHREAD_NO_ERROR;
2bda0e17
KB
697}
698
bf1852e1 699wxThreadError wxThread::Run()
2bda0e17 700{
bf1852e1
VZ
701 wxCriticalSectionLocker lock(m_critsect);
702
9fc3ad34 703 if ( m_internal->GetState() != STATE_NEW )
bf1852e1
VZ
704 {
705 // actually, it may be almost any state at all, not only STATE_RUNNING
706 return wxTHREAD_RUNNING;
707 }
708
b568d04f 709 // the thread has just been created and is still suspended - let it run
bf1852e1 710 return Resume();
2bda0e17
KB
711}
712
bf1852e1
VZ
713// suspend/resume thread
714// ---------------------
715
716wxThreadError wxThread::Pause()
2bda0e17 717{
bf1852e1
VZ
718 wxCriticalSectionLocker lock(m_critsect);
719
9fc3ad34 720 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
2bda0e17
KB
721}
722
bf1852e1 723wxThreadError wxThread::Resume()
2bda0e17 724{
bf1852e1
VZ
725 wxCriticalSectionLocker lock(m_critsect);
726
9fc3ad34 727 return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
2bda0e17
KB
728}
729
bf1852e1
VZ
730// stopping thread
731// ---------------
732
b568d04f
VZ
733wxThread::ExitCode wxThread::Wait()
734{
735 // although under Windows we can wait for any thread, it's an error to
736 // wait for a detached one in wxWin API
737 wxCHECK_MSG( !IsDetached(), (ExitCode)-1,
738 _T("can't wait for detached thread") );
739
740 ExitCode rc = (ExitCode)-1;
741
742 (void)Delete(&rc);
743
9fc3ad34 744 m_internal->Free();
b568d04f
VZ
745
746 return rc;
747}
748
749wxThreadError wxThread::Delete(ExitCode *pRc)
2bda0e17 750{
bf1852e1
VZ
751 ExitCode rc = 0;
752
753 // Delete() is always safe to call, so consider all possible states
696e1ea0
VZ
754
755 // has the thread started to run?
756 bool shouldResume = FALSE;
757
758 {
759 wxCriticalSectionLocker lock(m_critsect);
760
761 if ( m_internal->GetState() == STATE_NEW )
762 {
763 // WinThreadStart() will see it and terminate immediately
764 m_internal->SetState(STATE_EXITED);
765
766 shouldResume = TRUE;
767 }
768 }
769
770 // is the thread paused?
771 if ( shouldResume || IsPaused() )
bf1852e1
VZ
772 Resume();
773
9fc3ad34 774 HANDLE hThread = m_internal->GetHandle();
b568d04f 775
696e1ea0 776 // does is still run?
bf1852e1
VZ
777 if ( IsRunning() )
778 {
779 if ( IsMain() )
780 {
781 // set flag for wxIsWaitingForThread()
b568d04f 782 gs_waitingForThread = TRUE;
bf1852e1 783
b568d04f 784#if wxUSE_GUI
bf1852e1 785 wxBeginBusyCursor();
b568d04f 786#endif // wxUSE_GUI
bf1852e1
VZ
787 }
788
b568d04f 789 // ask the thread to terminate
bf1852e1
VZ
790 {
791 wxCriticalSectionLocker lock(m_critsect);
792
9fc3ad34 793 m_internal->Cancel();
bf1852e1
VZ
794 }
795
b568d04f 796#if wxUSE_GUI
bf1852e1
VZ
797 // we can't just wait for the thread to terminate because it might be
798 // calling some GUI functions and so it will never terminate before we
799 // process the Windows messages that result from these functions
800 DWORD result;
801 do
802 {
803 result = ::MsgWaitForMultipleObjects
804 (
805 1, // number of objects to wait for
806 &hThread, // the objects
807 FALSE, // don't wait for all objects
808 INFINITE, // no timeout
809 QS_ALLEVENTS // return as soon as there are any events
810 );
811
812 switch ( result )
813 {
814 case 0xFFFFFFFF:
815 // error
816 wxLogSysError(_("Can not wait for thread termination"));
817 Kill();
b568d04f 818 return wxTHREAD_KILLED;
bf1852e1
VZ
819
820 case WAIT_OBJECT_0:
821 // thread we're waiting for terminated
822 break;
823
824 case WAIT_OBJECT_0 + 1:
825 // new message arrived, process it
826 if ( !wxTheApp->DoMessage() )
827 {
828 // WM_QUIT received: kill the thread
829 Kill();
830
b568d04f 831 return wxTHREAD_KILLED;
bf1852e1
VZ
832 }
833
834 if ( IsMain() )
835 {
836 // give the thread we're waiting for chance to exit
837 // from the GUI call it might have been in
b568d04f 838 if ( (gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
bf1852e1
VZ
839 {
840 wxMutexGuiLeave();
841 }
842 }
843
844 break;
845
846 default:
223d09f6 847 wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject"));
bf1852e1
VZ
848 }
849 } while ( result != WAIT_OBJECT_0 );
b568d04f
VZ
850#else // !wxUSE_GUI
851 // simply wait for the thread to terminate
852 //
853 // OTOH, even console apps create windows (in wxExecute, for WinSock
854 // &c), so may be use MsgWaitForMultipleObject() too here?
855 if ( WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0 )
856 {
857 wxFAIL_MSG(wxT("unexpected result of WaitForSingleObject"));
858 }
859#endif // wxUSE_GUI/!wxUSE_GUI
bf1852e1
VZ
860
861 if ( IsMain() )
862 {
b568d04f 863 gs_waitingForThread = FALSE;
bf1852e1 864
b568d04f 865#if wxUSE_GUI
bf1852e1 866 wxEndBusyCursor();
b568d04f 867#endif // wxUSE_GUI
bf1852e1 868 }
b568d04f 869 }
bf1852e1 870
b568d04f
VZ
871 if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
872 {
873 wxLogLastError("GetExitCodeThread");
bf1852e1 874
b568d04f
VZ
875 rc = (ExitCode)-1;
876 }
bf1852e1 877
b568d04f
VZ
878 if ( IsDetached() )
879 {
880 // if the thread exits normally, this is done in WinThreadStart, but in
881 // this case it would have been too early because
882 // MsgWaitForMultipleObject() would fail if the therad handle was
883 // closed while we were waiting on it, so we must do it here
884 delete this;
bf1852e1
VZ
885 }
886
b568d04f
VZ
887 wxASSERT_MSG( (DWORD)rc != STILL_ACTIVE,
888 wxT("thread must be already terminated.") );
889
890 if ( pRc )
891 *pRc = rc;
892
893 return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR;
2bda0e17
KB
894}
895
bf1852e1 896wxThreadError wxThread::Kill()
2bda0e17 897{
bf1852e1
VZ
898 if ( !IsRunning() )
899 return wxTHREAD_NOT_RUNNING;
900
9fc3ad34 901 if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
bf1852e1
VZ
902 {
903 wxLogSysError(_("Couldn't terminate thread"));
904
905 return wxTHREAD_MISC_ERROR;
906 }
907
9fc3ad34 908 m_internal->Free();
b568d04f
VZ
909
910 if ( IsDetached() )
911 {
912 delete this;
913 }
bf1852e1
VZ
914
915 return wxTHREAD_NO_ERROR;
2bda0e17
KB
916}
917
b568d04f 918void wxThread::Exit(ExitCode status)
2bda0e17 919{
9fc3ad34 920 m_internal->Free();
2bda0e17 921
b568d04f
VZ
922 if ( IsDetached() )
923 {
924 delete this;
925 }
926
7ab9bf9f 927#if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
b568d04f
VZ
928 _endthreadex((unsigned)status);
929#else // !VC++
bf1852e1 930 ::ExitThread((DWORD)status);
b568d04f 931#endif // VC++/!VC++
2bda0e17 932
223d09f6 933 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
bf1852e1 934}
2bda0e17 935
b568d04f
VZ
936// priority setting
937// ----------------
938
bf1852e1
VZ
939void wxThread::SetPriority(unsigned int prio)
940{
941 wxCriticalSectionLocker lock(m_critsect);
942
9fc3ad34 943 m_internal->SetPriority(prio);
bf1852e1 944}
2bda0e17 945
bf1852e1
VZ
946unsigned int wxThread::GetPriority() const
947{
b568d04f 948 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
2bda0e17 949
9fc3ad34 950 return m_internal->GetPriority();
2bda0e17
KB
951}
952
b568d04f 953unsigned long wxThread::GetId() const
2bda0e17 954{
b568d04f 955 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
bf1852e1 956
9fc3ad34 957 return (unsigned long)m_internal->GetId();
2bda0e17
KB
958}
959
72fd19a1
JS
960bool wxThread::IsRunning() const
961{
b568d04f 962 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
bf1852e1 963
9fc3ad34 964 return m_internal->GetState() == STATE_RUNNING;
72fd19a1
JS
965}
966
967bool wxThread::IsAlive() const
968{
b568d04f 969 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
bf1852e1 970
9fc3ad34
VZ
971 return (m_internal->GetState() == STATE_RUNNING) ||
972 (m_internal->GetState() == STATE_PAUSED);
72fd19a1
JS
973}
974
a737331d
GL
975bool wxThread::IsPaused() const
976{
b568d04f 977 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
a737331d 978
9fc3ad34 979 return m_internal->GetState() == STATE_PAUSED;
a737331d
GL
980}
981
8c10faf1 982bool wxThread::TestDestroy()
2bda0e17 983{
b568d04f 984 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
bf1852e1 985
9fc3ad34 986 return m_internal->GetState() == STATE_CANCELED;
2bda0e17
KB
987}
988
3222fde2
VZ
989// ----------------------------------------------------------------------------
990// Automatic initialization for thread module
991// ----------------------------------------------------------------------------
2bda0e17 992
3222fde2 993class wxThreadModule : public wxModule
a6b0bd49 994{
3222fde2
VZ
995public:
996 virtual bool OnInit();
997 virtual void OnExit();
d524867f 998
3222fde2
VZ
999private:
1000 DECLARE_DYNAMIC_CLASS(wxThreadModule)
1001};
d524867f
RR
1002
1003IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
1004
3222fde2 1005bool wxThreadModule::OnInit()
d524867f 1006{
bf1852e1 1007 // allocate TLS index for storing the pointer to the current thread
b568d04f
VZ
1008 gs_tlsThisThread = ::TlsAlloc();
1009 if ( gs_tlsThisThread == 0xFFFFFFFF )
bf1852e1
VZ
1010 {
1011 // in normal circumstances it will only happen if all other
1012 // TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other
1013 // words, this should never happen
1014 wxLogSysError(_("Thread module initialization failed: "
1015 "impossible to allocate index in thread "
1016 "local storage"));
1017
1018 return FALSE;
1019 }
1020
1021 // main thread doesn't have associated wxThread object, so store 0 in the
1022 // TLS instead
b568d04f 1023 if ( !::TlsSetValue(gs_tlsThisThread, (LPVOID)0) )
bf1852e1 1024 {
b568d04f
VZ
1025 ::TlsFree(gs_tlsThisThread);
1026 gs_tlsThisThread = 0xFFFFFFFF;
bf1852e1
VZ
1027
1028 wxLogSysError(_("Thread module initialization failed: "
1029 "can not store value in thread local storage"));
1030
1031 return FALSE;
1032 }
1033
b568d04f 1034 gs_critsectWaitingForGui = new wxCriticalSection();
bee503b0 1035
b568d04f
VZ
1036 gs_critsectGui = new wxCriticalSection();
1037 gs_critsectGui->Enter();
bee503b0 1038
bf1852e1 1039 // no error return for GetCurrentThreadId()
b568d04f 1040 gs_idMainThread = ::GetCurrentThreadId();
3222fde2 1041
d524867f
RR
1042 return TRUE;
1043}
1044
3222fde2 1045void wxThreadModule::OnExit()
d524867f 1046{
b568d04f 1047 if ( !::TlsFree(gs_tlsThisThread) )
bf1852e1
VZ
1048 {
1049 wxLogLastError("TlsFree failed.");
1050 }
1051
b568d04f 1052 if ( gs_critsectGui )
3222fde2 1053 {
b568d04f
VZ
1054 gs_critsectGui->Leave();
1055 delete gs_critsectGui;
1056 gs_critsectGui = NULL;
3222fde2 1057 }
bee503b0 1058
b568d04f
VZ
1059 delete gs_critsectWaitingForGui;
1060 gs_critsectWaitingForGui = NULL;
3222fde2
VZ
1061}
1062
bee503b0 1063// ----------------------------------------------------------------------------
b568d04f 1064// under Windows, these functions are implemented using a critical section and
3222fde2 1065// not a mutex, so the names are a bit confusing
bee503b0
VZ
1066// ----------------------------------------------------------------------------
1067
3222fde2
VZ
1068void WXDLLEXPORT wxMutexGuiEnter()
1069{
bee503b0
VZ
1070 // this would dead lock everything...
1071 wxASSERT_MSG( !wxThread::IsMain(),
223d09f6 1072 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
bee503b0
VZ
1073
1074 // the order in which we enter the critical sections here is crucial!!
1075
1076 // set the flag telling to the main thread that we want to do some GUI
1077 {
b568d04f 1078 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
bee503b0 1079
b568d04f 1080 gs_nWaitingForGui++;
bee503b0
VZ
1081 }
1082
1083 wxWakeUpMainThread();
1084
1085 // now we may block here because the main thread will soon let us in
1086 // (during the next iteration of OnIdle())
b568d04f 1087 gs_critsectGui->Enter();
3222fde2
VZ
1088}
1089
1090void WXDLLEXPORT wxMutexGuiLeave()
1091{
b568d04f 1092 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
bee503b0
VZ
1093
1094 if ( wxThread::IsMain() )
1095 {
b568d04f 1096 gs_bGuiOwnedByMainThread = FALSE;
bee503b0
VZ
1097 }
1098 else
1099 {
1100 // decrement the number of waiters now
b568d04f 1101 wxASSERT_MSG( gs_nWaitingForGui > 0,
223d09f6 1102 wxT("calling wxMutexGuiLeave() without entering it first?") );
bee503b0 1103
b568d04f 1104 gs_nWaitingForGui--;
bee503b0
VZ
1105
1106 wxWakeUpMainThread();
1107 }
1108
b568d04f 1109 gs_critsectGui->Leave();
bee503b0
VZ
1110}
1111
1112void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
1113{
1114 wxASSERT_MSG( wxThread::IsMain(),
223d09f6 1115 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
bee503b0 1116
b568d04f 1117 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
bee503b0 1118
b568d04f 1119 if ( gs_nWaitingForGui == 0 )
bee503b0
VZ
1120 {
1121 // no threads are waiting for GUI - so we may acquire the lock without
1122 // any danger (but only if we don't already have it)
1123 if ( !wxGuiOwnedByMainThread() )
1124 {
b568d04f 1125 gs_critsectGui->Enter();
bee503b0 1126
b568d04f 1127 gs_bGuiOwnedByMainThread = TRUE;
bee503b0
VZ
1128 }
1129 //else: already have it, nothing to do
1130 }
1131 else
1132 {
1133 // some threads are waiting, release the GUI lock if we have it
1134 if ( wxGuiOwnedByMainThread() )
1135 {
1136 wxMutexGuiLeave();
1137 }
1138 //else: some other worker thread is doing GUI
1139 }
1140}
1141
1142bool WXDLLEXPORT wxGuiOwnedByMainThread()
1143{
b568d04f 1144 return gs_bGuiOwnedByMainThread;
bee503b0
VZ
1145}
1146
1147// wake up the main thread if it's in ::GetMessage()
1148void WXDLLEXPORT wxWakeUpMainThread()
1149{
1150 // sending any message would do - hopefully WM_NULL is harmless enough
b568d04f 1151 if ( !::PostThreadMessage(gs_idMainThread, WM_NULL, 0, 0) )
bee503b0
VZ
1152 {
1153 // should never happen
1154 wxLogLastError("PostThreadMessage(WM_NULL)");
1155 }
3222fde2 1156}
d524867f 1157
bf1852e1
VZ
1158bool WXDLLEXPORT wxIsWaitingForThread()
1159{
b568d04f 1160 return gs_waitingForThread;
bf1852e1
VZ
1161}
1162
3222fde2 1163#endif // wxUSE_THREADS