]> git.saurik.com Git - wxWidgets.git/blame - src/msw/thread.cpp
1. fruitless attempts to reproduce wxNotebook bug in the sample
[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)
611cb666
VZ
457#if defined(__VISUALC__) || \
458 (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500)) \\
459 (defined(__GNUG__) && defined(__MSVCRT__)
b568d04f
VZ
460 typedef unsigned (__stdcall *RtlThreadStart)(void *);
461
462 m_hThread = (HANDLE)_beginthreadex(NULL, 0,
696e1ea0 463 (RtlThreadStart)
b568d04f
VZ
464 wxThreadInternal::WinThreadStart,
465 thread, CREATE_SUSPENDED,
466 (unsigned int *)&m_tid);
611cb666 467#else // compiler doesn't have _beginthreadex
b568d04f
VZ
468 m_hThread = ::CreateThread
469 (
470 NULL, // default security
471 0, // default stack size
472 (LPTHREAD_START_ROUTINE) // thread entry point
473 wxThreadInternal::WinThreadStart, //
474 (LPVOID)thread, // parameter
475 CREATE_SUSPENDED, // flags
476 &m_tid // [out] thread id
477 );
611cb666 478#endif // _beginthreadex/CreateThread
b568d04f
VZ
479
480 if ( m_hThread == NULL )
481 {
482 wxLogSysError(_("Can't create thread"));
483
484 return FALSE;
485 }
486
487 if ( m_priority != WXTHREAD_DEFAULT_PRIORITY )
488 {
489 SetPriority(m_priority);
490 }
3222fde2 491
bf1852e1 492 return TRUE;
2bda0e17
KB
493}
494
bf1852e1 495bool wxThreadInternal::Suspend()
2bda0e17 496{
bf1852e1
VZ
497 DWORD nSuspendCount = ::SuspendThread(m_hThread);
498 if ( nSuspendCount == (DWORD)-1 )
bee503b0 499 {
bf1852e1
VZ
500 wxLogSysError(_("Can not suspend thread %x"), m_hThread);
501
502 return FALSE;
bee503b0 503 }
2bda0e17 504
bf1852e1
VZ
505 m_state = STATE_PAUSED;
506
507 return TRUE;
a6b0bd49
VZ
508}
509
bf1852e1 510bool wxThreadInternal::Resume()
a6b0bd49 511{
bf1852e1 512 DWORD nSuspendCount = ::ResumeThread(m_hThread);
a6b0bd49
VZ
513 if ( nSuspendCount == (DWORD)-1 )
514 {
bf1852e1 515 wxLogSysError(_("Can not resume thread %x"), m_hThread);
a6b0bd49 516
bf1852e1 517 return FALSE;
a6b0bd49
VZ
518 }
519
bf1852e1 520 m_state = STATE_RUNNING;
bee503b0 521
bf1852e1 522 return TRUE;
a6b0bd49
VZ
523}
524
bf1852e1
VZ
525// static functions
526// ----------------
527
528wxThread *wxThread::This()
a6b0bd49 529{
b568d04f 530 wxThread *thread = (wxThread *)::TlsGetValue(gs_tlsThisThread);
bf1852e1
VZ
531
532 // be careful, 0 may be a valid return value as well
533 if ( !thread && (::GetLastError() != NO_ERROR) )
a6b0bd49 534 {
bf1852e1 535 wxLogSysError(_("Couldn't get the current thread pointer"));
a6b0bd49 536
bf1852e1 537 // return NULL...
a6b0bd49
VZ
538 }
539
bf1852e1
VZ
540 return thread;
541}
542
543bool wxThread::IsMain()
544{
b568d04f 545 return ::GetCurrentThreadId() == gs_idMainThread;
bf1852e1
VZ
546}
547
c25a510b
JS
548#ifdef Yield
549#undef Yield
550#endif
551
bf1852e1
VZ
552void wxThread::Yield()
553{
b568d04f
VZ
554 // 0 argument to Sleep() is special and means to just give away the rest of
555 // our timeslice
bf1852e1
VZ
556 ::Sleep(0);
557}
558
559void wxThread::Sleep(unsigned long milliseconds)
560{
561 ::Sleep(milliseconds);
562}
563
ef8d96c2
VZ
564int wxThread::GetCPUCount()
565{
28a4627c
VZ
566 SYSTEM_INFO si;
567 GetSystemInfo(&si);
568
569 return si.dwNumberOfProcessors;
ef8d96c2
VZ
570}
571
572bool wxThread::SetConcurrency(size_t level)
573{
28a4627c
VZ
574 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
575
ef8d96c2 576 // ok only for the default one
28a4627c
VZ
577 if ( level == 0 )
578 return 0;
579
580 // get system affinity mask first
581 HANDLE hProcess = ::GetCurrentProcess();
582 DWORD dwProcMask, dwSysMask;
583 if ( ::GetProcessAffinityMask(hProcess, &dwProcMask, &dwSysMask) == 0 )
584 {
585 wxLogLastError(_T("GetProcessAffinityMask"));
586
587 return FALSE;
588 }
589
590 // how many CPUs have we got?
591 if ( dwSysMask == 1 )
592 {
593 // don't bother with all this complicated stuff - on a single
594 // processor system it doesn't make much sense anyhow
595 return level == 1;
596 }
597
598 // calculate the process mask: it's a bit vector with one bit per
599 // processor; we want to schedule the process to run on first level
600 // CPUs
601 DWORD bit = 1;
602 while ( bit )
603 {
604 if ( dwSysMask & bit )
605 {
606 // ok, we can set this bit
607 dwProcMask |= bit;
608
609 // another process added
610 if ( !--level )
611 {
612 // and that's enough
613 break;
614 }
615 }
616
617 // next bit
618 bit <<= 1;
619 }
620
621 // could we set all bits?
622 if ( level != 0 )
623 {
624 wxLogDebug(_T("bad level %u in wxThread::SetConcurrency()"), level);
625
626 return FALSE;
627 }
628
629 // set it: we can't link to SetProcessAffinityMask() because it doesn't
630 // exist in Win9x, use RT binding instead
631
696e1ea0 632 typedef BOOL (*SETPROCESSAFFINITYMASK)(HANDLE, DWORD);
28a4627c
VZ
633
634 // can use static var because we're always in the main thread here
635 static SETPROCESSAFFINITYMASK pfnSetProcessAffinityMask = NULL;
636
637 if ( !pfnSetProcessAffinityMask )
638 {
639 HMODULE hModKernel = ::LoadLibrary(_T("kernel32"));
640 if ( hModKernel )
641 {
642 pfnSetProcessAffinityMask = (SETPROCESSAFFINITYMASK)
a8ee71c7
OK
643 ::GetProcAddress(hModKernel,
644#if defined(__BORLANDC__) && (__BORLANDC__ <= 0x520)
645 "SetProcessAffinityMask");
646#else
647 _T("SetProcessAffinityMask"));
648#endif
28a4627c
VZ
649 }
650
651 // we've discovered a MT version of Win9x!
652 wxASSERT_MSG( pfnSetProcessAffinityMask,
653 _T("this system has several CPUs but no "
654 "SetProcessAffinityMask function?") );
655 }
656
657 if ( !pfnSetProcessAffinityMask )
658 {
659 // msg given above - do it only once
660 return FALSE;
661 }
662
696e1ea0 663 if ( pfnSetProcessAffinityMask(hProcess, dwProcMask) == 0 )
28a4627c
VZ
664 {
665 wxLogLastError(_T("SetProcessAffinityMask"));
666
667 return FALSE;
668 }
669
670 return TRUE;
ef8d96c2
VZ
671}
672
b568d04f
VZ
673// ctor and dtor
674// -------------
675
676wxThread::wxThread(wxThreadKind kind)
677{
9fc3ad34 678 m_internal = new wxThreadInternal();
b568d04f
VZ
679
680 m_isDetached = kind == wxTHREAD_DETACHED;
681}
682
683wxThread::~wxThread()
684{
9fc3ad34 685 delete m_internal;
b568d04f
VZ
686}
687
bf1852e1
VZ
688// create/start thread
689// -------------------
690
691wxThreadError wxThread::Create()
692{
b568d04f
VZ
693 wxCriticalSectionLocker lock(m_critsect);
694
9fc3ad34 695 if ( !m_internal->Create(this) )
bf1852e1 696 return wxTHREAD_NO_RESOURCE;
bee503b0 697
a6b0bd49 698 return wxTHREAD_NO_ERROR;
2bda0e17
KB
699}
700
bf1852e1 701wxThreadError wxThread::Run()
2bda0e17 702{
bf1852e1
VZ
703 wxCriticalSectionLocker lock(m_critsect);
704
9fc3ad34 705 if ( m_internal->GetState() != STATE_NEW )
bf1852e1
VZ
706 {
707 // actually, it may be almost any state at all, not only STATE_RUNNING
708 return wxTHREAD_RUNNING;
709 }
710
b568d04f 711 // the thread has just been created and is still suspended - let it run
bf1852e1 712 return Resume();
2bda0e17
KB
713}
714
bf1852e1
VZ
715// suspend/resume thread
716// ---------------------
717
718wxThreadError wxThread::Pause()
2bda0e17 719{
bf1852e1
VZ
720 wxCriticalSectionLocker lock(m_critsect);
721
9fc3ad34 722 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
2bda0e17
KB
723}
724
bf1852e1 725wxThreadError wxThread::Resume()
2bda0e17 726{
bf1852e1
VZ
727 wxCriticalSectionLocker lock(m_critsect);
728
9fc3ad34 729 return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
2bda0e17
KB
730}
731
bf1852e1
VZ
732// stopping thread
733// ---------------
734
b568d04f
VZ
735wxThread::ExitCode wxThread::Wait()
736{
737 // although under Windows we can wait for any thread, it's an error to
738 // wait for a detached one in wxWin API
739 wxCHECK_MSG( !IsDetached(), (ExitCode)-1,
740 _T("can't wait for detached thread") );
741
742 ExitCode rc = (ExitCode)-1;
743
744 (void)Delete(&rc);
745
9fc3ad34 746 m_internal->Free();
b568d04f
VZ
747
748 return rc;
749}
750
751wxThreadError wxThread::Delete(ExitCode *pRc)
2bda0e17 752{
bf1852e1
VZ
753 ExitCode rc = 0;
754
755 // Delete() is always safe to call, so consider all possible states
696e1ea0
VZ
756
757 // has the thread started to run?
758 bool shouldResume = FALSE;
759
760 {
761 wxCriticalSectionLocker lock(m_critsect);
762
763 if ( m_internal->GetState() == STATE_NEW )
764 {
765 // WinThreadStart() will see it and terminate immediately
766 m_internal->SetState(STATE_EXITED);
767
768 shouldResume = TRUE;
769 }
770 }
771
772 // is the thread paused?
773 if ( shouldResume || IsPaused() )
bf1852e1
VZ
774 Resume();
775
9fc3ad34 776 HANDLE hThread = m_internal->GetHandle();
b568d04f 777
696e1ea0 778 // does is still run?
bf1852e1
VZ
779 if ( IsRunning() )
780 {
781 if ( IsMain() )
782 {
783 // set flag for wxIsWaitingForThread()
b568d04f 784 gs_waitingForThread = TRUE;
bf1852e1 785
b568d04f 786#if wxUSE_GUI
bf1852e1 787 wxBeginBusyCursor();
b568d04f 788#endif // wxUSE_GUI
bf1852e1
VZ
789 }
790
b568d04f 791 // ask the thread to terminate
bf1852e1
VZ
792 {
793 wxCriticalSectionLocker lock(m_critsect);
794
9fc3ad34 795 m_internal->Cancel();
bf1852e1
VZ
796 }
797
b568d04f 798#if wxUSE_GUI
bf1852e1
VZ
799 // we can't just wait for the thread to terminate because it might be
800 // calling some GUI functions and so it will never terminate before we
801 // process the Windows messages that result from these functions
802 DWORD result;
803 do
804 {
805 result = ::MsgWaitForMultipleObjects
806 (
807 1, // number of objects to wait for
808 &hThread, // the objects
809 FALSE, // don't wait for all objects
810 INFINITE, // no timeout
811 QS_ALLEVENTS // return as soon as there are any events
812 );
813
814 switch ( result )
815 {
816 case 0xFFFFFFFF:
817 // error
818 wxLogSysError(_("Can not wait for thread termination"));
819 Kill();
b568d04f 820 return wxTHREAD_KILLED;
bf1852e1
VZ
821
822 case WAIT_OBJECT_0:
823 // thread we're waiting for terminated
824 break;
825
826 case WAIT_OBJECT_0 + 1:
827 // new message arrived, process it
828 if ( !wxTheApp->DoMessage() )
829 {
830 // WM_QUIT received: kill the thread
831 Kill();
832
b568d04f 833 return wxTHREAD_KILLED;
bf1852e1
VZ
834 }
835
836 if ( IsMain() )
837 {
838 // give the thread we're waiting for chance to exit
839 // from the GUI call it might have been in
b568d04f 840 if ( (gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
bf1852e1
VZ
841 {
842 wxMutexGuiLeave();
843 }
844 }
845
846 break;
847
848 default:
223d09f6 849 wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject"));
bf1852e1
VZ
850 }
851 } while ( result != WAIT_OBJECT_0 );
b568d04f
VZ
852#else // !wxUSE_GUI
853 // simply wait for the thread to terminate
854 //
855 // OTOH, even console apps create windows (in wxExecute, for WinSock
856 // &c), so may be use MsgWaitForMultipleObject() too here?
857 if ( WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0 )
858 {
859 wxFAIL_MSG(wxT("unexpected result of WaitForSingleObject"));
860 }
861#endif // wxUSE_GUI/!wxUSE_GUI
bf1852e1
VZ
862
863 if ( IsMain() )
864 {
b568d04f 865 gs_waitingForThread = FALSE;
bf1852e1 866
b568d04f 867#if wxUSE_GUI
bf1852e1 868 wxEndBusyCursor();
b568d04f 869#endif // wxUSE_GUI
bf1852e1 870 }
b568d04f 871 }
bf1852e1 872
b568d04f
VZ
873 if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
874 {
875 wxLogLastError("GetExitCodeThread");
bf1852e1 876
b568d04f
VZ
877 rc = (ExitCode)-1;
878 }
bf1852e1 879
b568d04f
VZ
880 if ( IsDetached() )
881 {
882 // if the thread exits normally, this is done in WinThreadStart, but in
883 // this case it would have been too early because
884 // MsgWaitForMultipleObject() would fail if the therad handle was
885 // closed while we were waiting on it, so we must do it here
886 delete this;
bf1852e1
VZ
887 }
888
b568d04f
VZ
889 wxASSERT_MSG( (DWORD)rc != STILL_ACTIVE,
890 wxT("thread must be already terminated.") );
891
892 if ( pRc )
893 *pRc = rc;
894
895 return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR;
2bda0e17
KB
896}
897
bf1852e1 898wxThreadError wxThread::Kill()
2bda0e17 899{
bf1852e1
VZ
900 if ( !IsRunning() )
901 return wxTHREAD_NOT_RUNNING;
902
9fc3ad34 903 if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
bf1852e1
VZ
904 {
905 wxLogSysError(_("Couldn't terminate thread"));
906
907 return wxTHREAD_MISC_ERROR;
908 }
909
9fc3ad34 910 m_internal->Free();
b568d04f
VZ
911
912 if ( IsDetached() )
913 {
914 delete this;
915 }
bf1852e1
VZ
916
917 return wxTHREAD_NO_ERROR;
2bda0e17
KB
918}
919
b568d04f 920void wxThread::Exit(ExitCode status)
2bda0e17 921{
9fc3ad34 922 m_internal->Free();
2bda0e17 923
b568d04f
VZ
924 if ( IsDetached() )
925 {
926 delete this;
927 }
928
7ab9bf9f 929#if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
b568d04f
VZ
930 _endthreadex((unsigned)status);
931#else // !VC++
bf1852e1 932 ::ExitThread((DWORD)status);
b568d04f 933#endif // VC++/!VC++
2bda0e17 934
223d09f6 935 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
bf1852e1 936}
2bda0e17 937
b568d04f
VZ
938// priority setting
939// ----------------
940
bf1852e1
VZ
941void wxThread::SetPriority(unsigned int prio)
942{
943 wxCriticalSectionLocker lock(m_critsect);
944
9fc3ad34 945 m_internal->SetPriority(prio);
bf1852e1 946}
2bda0e17 947
bf1852e1
VZ
948unsigned int wxThread::GetPriority() const
949{
b568d04f 950 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
2bda0e17 951
9fc3ad34 952 return m_internal->GetPriority();
2bda0e17
KB
953}
954
b568d04f 955unsigned long wxThread::GetId() const
2bda0e17 956{
b568d04f 957 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
bf1852e1 958
9fc3ad34 959 return (unsigned long)m_internal->GetId();
2bda0e17
KB
960}
961
72fd19a1
JS
962bool wxThread::IsRunning() const
963{
b568d04f 964 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
bf1852e1 965
9fc3ad34 966 return m_internal->GetState() == STATE_RUNNING;
72fd19a1
JS
967}
968
969bool wxThread::IsAlive() const
970{
b568d04f 971 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
bf1852e1 972
9fc3ad34
VZ
973 return (m_internal->GetState() == STATE_RUNNING) ||
974 (m_internal->GetState() == STATE_PAUSED);
72fd19a1
JS
975}
976
a737331d
GL
977bool wxThread::IsPaused() const
978{
b568d04f 979 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
a737331d 980
9fc3ad34 981 return m_internal->GetState() == STATE_PAUSED;
a737331d
GL
982}
983
8c10faf1 984bool wxThread::TestDestroy()
2bda0e17 985{
b568d04f 986 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
bf1852e1 987
9fc3ad34 988 return m_internal->GetState() == STATE_CANCELED;
2bda0e17
KB
989}
990
3222fde2
VZ
991// ----------------------------------------------------------------------------
992// Automatic initialization for thread module
993// ----------------------------------------------------------------------------
2bda0e17 994
3222fde2 995class wxThreadModule : public wxModule
a6b0bd49 996{
3222fde2
VZ
997public:
998 virtual bool OnInit();
999 virtual void OnExit();
d524867f 1000
3222fde2
VZ
1001private:
1002 DECLARE_DYNAMIC_CLASS(wxThreadModule)
1003};
d524867f
RR
1004
1005IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
1006
3222fde2 1007bool wxThreadModule::OnInit()
d524867f 1008{
bf1852e1 1009 // allocate TLS index for storing the pointer to the current thread
b568d04f
VZ
1010 gs_tlsThisThread = ::TlsAlloc();
1011 if ( gs_tlsThisThread == 0xFFFFFFFF )
bf1852e1
VZ
1012 {
1013 // in normal circumstances it will only happen if all other
1014 // TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other
1015 // words, this should never happen
1016 wxLogSysError(_("Thread module initialization failed: "
1017 "impossible to allocate index in thread "
1018 "local storage"));
1019
1020 return FALSE;
1021 }
1022
1023 // main thread doesn't have associated wxThread object, so store 0 in the
1024 // TLS instead
b568d04f 1025 if ( !::TlsSetValue(gs_tlsThisThread, (LPVOID)0) )
bf1852e1 1026 {
b568d04f
VZ
1027 ::TlsFree(gs_tlsThisThread);
1028 gs_tlsThisThread = 0xFFFFFFFF;
bf1852e1
VZ
1029
1030 wxLogSysError(_("Thread module initialization failed: "
1031 "can not store value in thread local storage"));
1032
1033 return FALSE;
1034 }
1035
b568d04f 1036 gs_critsectWaitingForGui = new wxCriticalSection();
bee503b0 1037
b568d04f
VZ
1038 gs_critsectGui = new wxCriticalSection();
1039 gs_critsectGui->Enter();
bee503b0 1040
bf1852e1 1041 // no error return for GetCurrentThreadId()
b568d04f 1042 gs_idMainThread = ::GetCurrentThreadId();
3222fde2 1043
d524867f
RR
1044 return TRUE;
1045}
1046
3222fde2 1047void wxThreadModule::OnExit()
d524867f 1048{
b568d04f 1049 if ( !::TlsFree(gs_tlsThisThread) )
bf1852e1
VZ
1050 {
1051 wxLogLastError("TlsFree failed.");
1052 }
1053
b568d04f 1054 if ( gs_critsectGui )
3222fde2 1055 {
b568d04f
VZ
1056 gs_critsectGui->Leave();
1057 delete gs_critsectGui;
1058 gs_critsectGui = NULL;
3222fde2 1059 }
bee503b0 1060
b568d04f
VZ
1061 delete gs_critsectWaitingForGui;
1062 gs_critsectWaitingForGui = NULL;
3222fde2
VZ
1063}
1064
bee503b0 1065// ----------------------------------------------------------------------------
b568d04f 1066// under Windows, these functions are implemented using a critical section and
3222fde2 1067// not a mutex, so the names are a bit confusing
bee503b0
VZ
1068// ----------------------------------------------------------------------------
1069
3222fde2
VZ
1070void WXDLLEXPORT wxMutexGuiEnter()
1071{
bee503b0
VZ
1072 // this would dead lock everything...
1073 wxASSERT_MSG( !wxThread::IsMain(),
223d09f6 1074 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
bee503b0
VZ
1075
1076 // the order in which we enter the critical sections here is crucial!!
1077
1078 // set the flag telling to the main thread that we want to do some GUI
1079 {
b568d04f 1080 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
bee503b0 1081
b568d04f 1082 gs_nWaitingForGui++;
bee503b0
VZ
1083 }
1084
1085 wxWakeUpMainThread();
1086
1087 // now we may block here because the main thread will soon let us in
1088 // (during the next iteration of OnIdle())
b568d04f 1089 gs_critsectGui->Enter();
3222fde2
VZ
1090}
1091
1092void WXDLLEXPORT wxMutexGuiLeave()
1093{
b568d04f 1094 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
bee503b0
VZ
1095
1096 if ( wxThread::IsMain() )
1097 {
b568d04f 1098 gs_bGuiOwnedByMainThread = FALSE;
bee503b0
VZ
1099 }
1100 else
1101 {
1102 // decrement the number of waiters now
b568d04f 1103 wxASSERT_MSG( gs_nWaitingForGui > 0,
223d09f6 1104 wxT("calling wxMutexGuiLeave() without entering it first?") );
bee503b0 1105
b568d04f 1106 gs_nWaitingForGui--;
bee503b0
VZ
1107
1108 wxWakeUpMainThread();
1109 }
1110
b568d04f 1111 gs_critsectGui->Leave();
bee503b0
VZ
1112}
1113
1114void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
1115{
1116 wxASSERT_MSG( wxThread::IsMain(),
223d09f6 1117 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
bee503b0 1118
b568d04f 1119 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
bee503b0 1120
b568d04f 1121 if ( gs_nWaitingForGui == 0 )
bee503b0
VZ
1122 {
1123 // no threads are waiting for GUI - so we may acquire the lock without
1124 // any danger (but only if we don't already have it)
1125 if ( !wxGuiOwnedByMainThread() )
1126 {
b568d04f 1127 gs_critsectGui->Enter();
bee503b0 1128
b568d04f 1129 gs_bGuiOwnedByMainThread = TRUE;
bee503b0
VZ
1130 }
1131 //else: already have it, nothing to do
1132 }
1133 else
1134 {
1135 // some threads are waiting, release the GUI lock if we have it
1136 if ( wxGuiOwnedByMainThread() )
1137 {
1138 wxMutexGuiLeave();
1139 }
1140 //else: some other worker thread is doing GUI
1141 }
1142}
1143
1144bool WXDLLEXPORT wxGuiOwnedByMainThread()
1145{
b568d04f 1146 return gs_bGuiOwnedByMainThread;
bee503b0
VZ
1147}
1148
1149// wake up the main thread if it's in ::GetMessage()
1150void WXDLLEXPORT wxWakeUpMainThread()
1151{
1152 // sending any message would do - hopefully WM_NULL is harmless enough
b568d04f 1153 if ( !::PostThreadMessage(gs_idMainThread, WM_NULL, 0, 0) )
bee503b0
VZ
1154 {
1155 // should never happen
1156 wxLogLastError("PostThreadMessage(WM_NULL)");
1157 }
3222fde2 1158}
d524867f 1159
bf1852e1
VZ
1160bool WXDLLEXPORT wxIsWaitingForThread()
1161{
b568d04f 1162 return gs_waitingForThread;
bf1852e1
VZ
1163}
1164
3222fde2 1165#endif // wxUSE_THREADS