]> git.saurik.com Git - wxWidgets.git/blame - src/msw/thread.cpp
Better scrolling to cursor.
[wxWidgets.git] / src / msw / thread.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
9e84b847 2// Name: src/msw/thread.cpp
2bda0e17
KB
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$
9e84b847
VZ
8// Copyright: (c) Wolfram Gloger (1996, 1997), Guilhem Lavaux (1998);
9// Vadim Zeitlin (1999-2002)
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
e0256755 29# include "wx/wx.h"
2bda0e17
KB
30#endif
31
3222fde2
VZ
32#if wxUSE_THREADS
33
0d0512bd 34#include "wx/msw/private.h"
17b439e8 35#include "wx/msw/missing.h"
3222fde2 36
2bda0e17
KB
37#include "wx/module.h"
38#include "wx/thread.h"
39
b568d04f
VZ
40// must have this symbol defined to get _beginthread/_endthread declarations
41#ifndef _MT
42 #define _MT
43#endif
44
9f51f2b6
VZ
45#if defined(__BORLANDC__)
46 #if !defined(__MT__)
47 // I can't set -tWM in the IDE (anyone?) so have to do this
48 #define __MT__
49 #endif
50
51 #if !defined(__MFC_COMPAT__)
52 // Needed to know about _beginthreadex etc..
53 #define __MFC_COMPAT__
54 #endif
55#endif // BC++
56
57// define wxUSE_BEGIN_THREAD if the compiler has _beginthreadex() function
58// which should be used instead of Win32 ::CreateThread() if possible
e0256755
GRG
59#if defined(__VISUALC__) || \
60 (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500)) || \
9f51f2b6 61 (defined(__GNUG__) && defined(__MSVCRT__)) || \
ba14d986 62 defined(__WATCOMC__) || defined(__MWERKS__)
ccebc98a 63
9f51f2b6
VZ
64 #undef wxUSE_BEGIN_THREAD
65 #define wxUSE_BEGIN_THREAD
8536082d
BJ
66#endif
67
9f51f2b6
VZ
68#ifdef wxUSE_BEGIN_THREAD
69 // this is where _beginthreadex() is declared
b568d04f 70 #include <process.h>
9f51f2b6
VZ
71
72 // the return type of the thread function entry point
73 typedef unsigned THREAD_RETVAL;
74
75 // the calling convention of the thread function entry point
76 #define THREAD_CALLCONV __stdcall
77#else
78 // the settings for CreateThread()
79 typedef DWORD THREAD_RETVAL;
80 #define THREAD_CALLCONV WINAPI
b568d04f
VZ
81#endif
82
83// ----------------------------------------------------------------------------
84// constants
85// ----------------------------------------------------------------------------
86
bf1852e1
VZ
87// the possible states of the thread ("=>" shows all possible transitions from
88// this state)
89enum wxThreadState
90{
91 STATE_NEW, // didn't start execution yet (=> RUNNING)
92 STATE_RUNNING, // thread is running (=> PAUSED, CANCELED)
93 STATE_PAUSED, // thread is temporarily suspended (=> RUNNING)
94 STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED)
95 STATE_EXITED // thread is terminating
2bda0e17
KB
96};
97
3222fde2 98// ----------------------------------------------------------------------------
b568d04f 99// this module globals
3222fde2 100// ----------------------------------------------------------------------------
2bda0e17 101
bf1852e1 102// TLS index of the slot where we store the pointer to the current thread
b568d04f 103static DWORD gs_tlsThisThread = 0xFFFFFFFF;
bf1852e1 104
3222fde2
VZ
105// id of the main thread - the one which can call GUI functions without first
106// calling wxMutexGuiEnter()
b568d04f 107static DWORD gs_idMainThread = 0;
bee503b0
VZ
108
109// if it's FALSE, some secondary thread is holding the GUI lock
b568d04f 110static bool gs_bGuiOwnedByMainThread = TRUE;
2bda0e17 111
3222fde2
VZ
112// critical section which controls access to all GUI functions: any secondary
113// thread (i.e. except the main one) must enter this crit section before doing
114// any GUI calls
b568d04f 115static wxCriticalSection *gs_critsectGui = NULL;
bee503b0 116
b568d04f
VZ
117// critical section which protects gs_nWaitingForGui variable
118static wxCriticalSection *gs_critsectWaitingForGui = NULL;
bee503b0
VZ
119
120// number of threads waiting for GUI in wxMutexGuiEnter()
b568d04f 121static size_t gs_nWaitingForGui = 0;
2bda0e17 122
bf1852e1 123// are we waiting for a thread termination?
b568d04f 124static bool gs_waitingForThread = FALSE;
bf1852e1 125
3222fde2 126// ============================================================================
9e84b847 127// Windows implementation of thread and related classes
3222fde2
VZ
128// ============================================================================
129
130// ----------------------------------------------------------------------------
9e84b847
VZ
131// wxCriticalSection
132// ----------------------------------------------------------------------------
133
134wxCriticalSection::wxCriticalSection()
135{
dac348b9 136 wxCOMPILE_TIME_ASSERT( sizeof(CRITICAL_SECTION) <= sizeof(wxCritSectBuffer),
9e84b847
VZ
137 wxCriticalSectionBufferTooSmall );
138
139 ::InitializeCriticalSection((CRITICAL_SECTION *)m_buffer);
140}
141
142wxCriticalSection::~wxCriticalSection()
143{
144 ::DeleteCriticalSection((CRITICAL_SECTION *)m_buffer);
145}
146
147void wxCriticalSection::Enter()
148{
149 ::EnterCriticalSection((CRITICAL_SECTION *)m_buffer);
150}
151
152void wxCriticalSection::Leave()
153{
154 ::LeaveCriticalSection((CRITICAL_SECTION *)m_buffer);
155}
156
157// ----------------------------------------------------------------------------
158// wxMutex
3222fde2 159// ----------------------------------------------------------------------------
0d0512bd 160
3222fde2
VZ
161class wxMutexInternal
162{
2bda0e17 163public:
9e84b847
VZ
164 wxMutexInternal(wxMutexType mutexType);
165 ~wxMutexInternal();
7f684264 166
9e84b847
VZ
167 bool IsOk() const { return m_mutex != NULL; }
168
169 wxMutexError Lock() { return LockTimeout(INFINITE); }
170 wxMutexError TryLock() { return LockTimeout(0); }
171 wxMutexError Unlock();
172
173private:
174 wxMutexError LockTimeout(DWORD milliseconds);
7f684264 175
7f684264 176 HANDLE m_mutex;
22f3361e
VZ
177
178 DECLARE_NO_COPY_CLASS(wxMutexInternal)
2bda0e17
KB
179};
180
9e84b847
VZ
181// all mutexes are recursive under Win32 so we don't use mutexType
182wxMutexInternal::wxMutexInternal(wxMutexType WXUNUSED(mutexType))
2bda0e17 183{
9e84b847
VZ
184 // create a nameless (hence intra process and always private) mutex
185 m_mutex = ::CreateMutex
186 (
187 NULL, // default secutiry attributes
188 FALSE, // not initially locked
189 NULL // no name
190 );
a6b0bd49 191
9e84b847
VZ
192 if ( !m_mutex )
193 {
194 wxLogLastError(_T("CreateMutex()"));
195 }
2bda0e17
KB
196}
197
9e84b847 198wxMutexInternal::~wxMutexInternal()
2bda0e17 199{
9e84b847 200 if ( m_mutex )
7f684264 201 {
9e84b847
VZ
202 if ( !::CloseHandle(m_mutex) )
203 {
204 wxLogLastError(_T("CloseHandle(mutex)"));
205 }
7f684264 206 }
2bda0e17
KB
207}
208
9e84b847 209wxMutexError wxMutexInternal::LockTimeout(DWORD milliseconds)
2bda0e17 210{
9e84b847
VZ
211 DWORD rc = ::WaitForSingleObject(m_mutex, milliseconds);
212 if ( rc == WAIT_ABANDONED )
3222fde2 213 {
9e84b847
VZ
214 // the previous caller died without releasing the mutex, but now we can
215 // really lock it
216 wxLogDebug(_T("WaitForSingleObject() returned WAIT_ABANDONED"));
217
218 // use 0 timeout, normally we should always get it
219 rc = ::WaitForSingleObject(m_mutex, 0);
220 }
3222fde2 221
9e84b847
VZ
222 switch ( rc )
223 {
3222fde2
VZ
224 case WAIT_OBJECT_0:
225 // ok
226 break;
2bda0e17 227
3222fde2 228 case WAIT_TIMEOUT:
9e84b847
VZ
229 return wxMUTEX_BUSY;
230
231 case WAIT_ABANDONED: // checked for above
3222fde2 232 default:
223d09f6 233 wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
9e84b847 234 // fall through
3222fde2 235
9e84b847
VZ
236 case WAIT_FAILED:
237 wxLogLastError(_T("WaitForSingleObject(mutex)"));
238 return wxMUTEX_MISC_ERROR;
239 }
2bda0e17 240
3222fde2 241 return wxMUTEX_NO_ERROR;
2bda0e17
KB
242}
243
9e84b847 244wxMutexError wxMutexInternal::Unlock()
2bda0e17 245{
9e84b847 246 if ( !::ReleaseMutex(m_mutex) )
3222fde2 247 {
2b5f62a0 248 wxLogLastError(_T("ReleaseMutex()"));
9e84b847 249
3222fde2
VZ
250 return wxMUTEX_MISC_ERROR;
251 }
a6b0bd49 252
3222fde2 253 return wxMUTEX_NO_ERROR;
2bda0e17
KB
254}
255
be809868 256// --------------------------------------------------------------------------
9e84b847 257// wxSemaphore
be809868
VZ
258// --------------------------------------------------------------------------
259
9e84b847 260// a trivial wrapper around Win32 semaphore
be809868 261class wxSemaphoreInternal
3222fde2 262{
2bda0e17 263public:
9e84b847 264 wxSemaphoreInternal(int initialcount, int maxcount);
be809868
VZ
265 ~wxSemaphoreInternal();
266
9e84b847 267 bool IsOk() const { return m_semaphore != NULL; }
be809868 268
9e84b847
VZ
269 wxSemaError Wait() { return WaitTimeout(INFINITE); }
270 wxSemaError TryWait() { return WaitTimeout(0); }
271 wxSemaError WaitTimeout(unsigned long milliseconds);
be809868 272
9e84b847 273 wxSemaError Post();
be809868
VZ
274
275private:
276 HANDLE m_semaphore;
22f3361e
VZ
277
278 DECLARE_NO_COPY_CLASS(wxSemaphoreInternal)
be809868
VZ
279};
280
9e84b847 281wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
be809868
VZ
282{
283 if ( maxcount == 0 )
b568d04f 284 {
be809868
VZ
285 // make it practically infinite
286 maxcount = INT_MAX;
287 }
4d1c1c3c 288
9e84b847
VZ
289 m_semaphore = ::CreateSemaphore
290 (
291 NULL, // default security attributes
292 initialcount,
293 maxcount,
294 NULL // no name
295 );
296
be809868
VZ
297 if ( !m_semaphore )
298 {
299 wxLogLastError(_T("CreateSemaphore()"));
b568d04f 300 }
be809868
VZ
301}
302
303wxSemaphoreInternal::~wxSemaphoreInternal()
304{
9e84b847 305 if ( m_semaphore )
b568d04f 306 {
9e84b847
VZ
307 if ( !::CloseHandle(m_semaphore) )
308 {
309 wxLogLastError(_T("CloseHandle(semaphore)"));
310 }
be809868
VZ
311 }
312}
b568d04f 313
9e84b847 314wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds)
be809868 315{
9e84b847 316 DWORD rc = ::WaitForSingleObject( m_semaphore, milliseconds );
be809868 317
9e84b847 318 switch ( rc )
be809868
VZ
319 {
320 case WAIT_OBJECT_0:
9e84b847 321 return wxSEMA_NO_ERROR;
b568d04f 322
be809868 323 case WAIT_TIMEOUT:
9e84b847 324 return wxSEMA_BUSY;
be809868
VZ
325
326 default:
9e84b847 327 wxLogLastError(_T("WaitForSingleObject(semaphore)"));
b568d04f
VZ
328 }
329
9e84b847 330 return wxSEMA_MISC_ERROR;
be809868
VZ
331}
332
9e84b847 333wxSemaError wxSemaphoreInternal::Post()
be809868 334{
9e84b847 335 if ( !::ReleaseSemaphore(m_semaphore, 1, NULL /* ptr to previous count */) )
4d1c1c3c 336 {
be809868 337 wxLogLastError(_T("ReleaseSemaphore"));
be809868 338
9e84b847
VZ
339 return wxSEMA_MISC_ERROR;
340 }
be809868 341
9e84b847 342 return wxSEMA_NO_ERROR;
be809868 343}
4d1c1c3c 344
be809868 345// --------------------------------------------------------------------------
9e84b847 346// wxCondition
be809868
VZ
347// --------------------------------------------------------------------------
348
9e84b847
VZ
349// Win32 doesn't have explicit support for the POSIX condition variables and
350// the Win32 events have quite different semantics, so we reimplement the
351// conditions from scratch using the mutexes and semaphores
be809868
VZ
352class wxConditionInternal
353{
354public:
c112e100 355 wxConditionInternal(wxMutex& mutex);
be809868 356
9e84b847 357 bool IsOk() const { return m_mutex.IsOk() && m_semaphore.IsOk(); }
be809868 358
9e84b847
VZ
359 wxCondError Wait();
360 wxCondError WaitTimeout(unsigned long milliseconds);
be809868 361
9e84b847
VZ
362 wxCondError Signal();
363 wxCondError Broadcast();
be809868
VZ
364
365private:
9e84b847
VZ
366 // the number of threads currently waiting for this condition
367 LONG m_numWaiters;
be809868 368
9e84b847
VZ
369 // the critical section protecting m_numWaiters
370 wxCriticalSection m_csWaiters;
be809868 371
9e84b847 372 wxMutex& m_mutex;
be809868
VZ
373 wxSemaphore m_semaphore;
374};
375
c112e100
VZ
376wxConditionInternal::wxConditionInternal(wxMutex& mutex)
377 : m_mutex(mutex)
be809868 378{
9e84b847
VZ
379 // another thread can't access it until we return from ctor, so no need to
380 // protect access to m_numWaiters here
be809868
VZ
381 m_numWaiters = 0;
382}
383
9e84b847 384wxCondError wxConditionInternal::Wait()
be809868
VZ
385{
386 // increment the number of waiters
9e84b847 387 ::InterlockedIncrement(&m_numWaiters);
be809868 388
c112e100 389 m_mutex.Unlock();
be809868
VZ
390
391 // a potential race condition can occur here
392 //
393 // after a thread increments nwaiters, and unlocks the mutex and before the
394 // semaphore.Wait() is called, if another thread can cause a signal to be
395 // generated
396 //
397 // this race condition is handled by using a semaphore and incrementing the
398 // semaphore only if 'nwaiters' is greater that zero since the semaphore,
399 // can 'remember' signals the race condition will not occur
400
401 // wait ( if necessary ) and decrement semaphore
9e84b847 402 wxSemaError err = m_semaphore.Wait();
c112e100 403 m_mutex.Lock();
9e84b847
VZ
404
405 return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : wxCOND_MISC_ERROR;
be809868
VZ
406}
407
9e84b847 408wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds)
be809868 409{
9e84b847 410 ::InterlockedIncrement(&m_numWaiters);
be809868 411
c112e100 412 m_mutex.Unlock();
be809868
VZ
413
414 // a race condition can occur at this point in the code
415 //
416 // please see the comments in Wait(), for details
417
9e84b847 418 wxSemaError err = m_semaphore.WaitTimeout(milliseconds);
be809868 419
9e84b847 420 if ( err == wxSEMA_BUSY )
4d1c1c3c 421 {
be809868
VZ
422 // another potential race condition exists here it is caused when a
423 // 'waiting' thread timesout, and returns from WaitForSingleObject, but
424 // has not yet decremented 'nwaiters'.
425 //
426 // at this point if another thread calls signal() then the semaphore
427 // will be incremented, but the waiting thread will miss it.
428 //
429 // to handle this particular case, the waiting thread calls
430 // WaitForSingleObject again with a timeout of 0, after locking
431 // 'nwaiters_mutex'. this call does not block because of the zero
432 // timeout, but will allow the waiting thread to catch the missed
433 // signals.
9e84b847
VZ
434 wxCriticalSectionLocker lock(m_csWaiters);
435
436 err = m_semaphore.WaitTimeout(0);
be809868 437
9e84b847 438 if ( err != wxSEMA_NO_ERROR )
4d1c1c3c 439 {
be809868 440 m_numWaiters--;
4d1c1c3c
VZ
441 }
442 }
443
c112e100 444 m_mutex.Lock();
be809868 445
9e84b847 446 return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : wxCOND_MISC_ERROR;
be809868
VZ
447}
448
9e84b847 449wxCondError wxConditionInternal::Signal()
be809868 450{
9e84b847 451 wxCriticalSectionLocker lock(m_csWaiters);
be809868
VZ
452
453 if ( m_numWaiters > 0 )
b568d04f 454 {
be809868 455 // increment the semaphore by 1
9e84b847
VZ
456 if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
457 return wxCOND_MISC_ERROR;
be809868
VZ
458
459 m_numWaiters--;
b568d04f
VZ
460 }
461
9e84b847 462 return wxCOND_NO_ERROR;
be809868 463}
4d1c1c3c 464
9e84b847 465wxCondError wxConditionInternal::Broadcast()
be809868 466{
9e84b847 467 wxCriticalSectionLocker lock(m_csWaiters);
2bda0e17 468
be809868
VZ
469 while ( m_numWaiters > 0 )
470 {
9e84b847
VZ
471 if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
472 return wxCOND_MISC_ERROR;
473
be809868
VZ
474 m_numWaiters--;
475 }
476
9e84b847 477 return wxCOND_NO_ERROR;
3222fde2
VZ
478}
479
480// ----------------------------------------------------------------------------
481// wxThread implementation
482// ----------------------------------------------------------------------------
483
bf1852e1
VZ
484// wxThreadInternal class
485// ----------------------
486
3222fde2
VZ
487class wxThreadInternal
488{
2bda0e17 489public:
bf1852e1
VZ
490 wxThreadInternal()
491 {
492 m_hThread = 0;
493 m_state = STATE_NEW;
494 m_priority = WXTHREAD_DEFAULT_PRIORITY;
495 }
496
b568d04f
VZ
497 ~wxThreadInternal()
498 {
499 Free();
500 }
501
502 void Free()
503 {
504 if ( m_hThread )
505 {
506 if ( !::CloseHandle(m_hThread) )
507 {
f6bcfd97 508 wxLogLastError(wxT("CloseHandle(thread)"));
b568d04f
VZ
509 }
510
511 m_hThread = 0;
512 }
513 }
514
bf1852e1 515 // create a new (suspended) thread (for the given thread object)
6fe73788 516 bool Create(wxThread *thread, unsigned int stackSize);
bf1852e1
VZ
517
518 // suspend/resume/terminate
519 bool Suspend();
520 bool Resume();
521 void Cancel() { m_state = STATE_CANCELED; }
522
523 // thread state
524 void SetState(wxThreadState state) { m_state = state; }
525 wxThreadState GetState() const { return m_state; }
526
527 // thread priority
b568d04f 528 void SetPriority(unsigned int priority);
bf1852e1
VZ
529 unsigned int GetPriority() const { return m_priority; }
530
531 // thread handle and id
532 HANDLE GetHandle() const { return m_hThread; }
533 DWORD GetId() const { return m_tid; }
534
535 // thread function
9f51f2b6 536 static THREAD_RETVAL THREAD_CALLCONV WinThreadStart(void *thread);
2bda0e17 537
bf1852e1
VZ
538private:
539 HANDLE m_hThread; // handle of the thread
540 wxThreadState m_state; // state, see wxThreadState enum
541 unsigned int m_priority; // thread priority in "wx" units
542 DWORD m_tid; // thread id
22f3361e
VZ
543
544 DECLARE_NO_COPY_CLASS(wxThreadInternal)
2bda0e17
KB
545};
546
08d7397c 547THREAD_RETVAL THREAD_CALLCONV wxThreadInternal::WinThreadStart(void *param)
2bda0e17 548{
9f51f2b6 549 THREAD_RETVAL rc;
f6bcfd97
BP
550 bool wasCancelled;
551
552 // first of all, check whether we hadn't been cancelled already and don't
553 // start the user code at all then
9f51f2b6 554 wxThread *thread = (wxThread *)param;
696e1ea0
VZ
555 if ( thread->m_internal->GetState() == STATE_EXITED )
556 {
9f51f2b6 557 rc = (THREAD_RETVAL)-1;
f6bcfd97 558 wasCancelled = TRUE;
696e1ea0 559 }
f6bcfd97 560 else // do run thread
bf1852e1 561 {
f6bcfd97
BP
562 // store the thread object in the TLS
563 if ( !::TlsSetValue(gs_tlsThisThread, thread) )
564 {
565 wxLogSysError(_("Can not start thread: error writing TLS."));
bf1852e1 566
f6bcfd97
BP
567 return (DWORD)-1;
568 }
bf1852e1 569
9f51f2b6 570 rc = (THREAD_RETVAL)thread->Entry();
b568d04f 571
f6bcfd97
BP
572 // enter m_critsect before changing the thread state
573 thread->m_critsect.Enter();
574 wasCancelled = thread->m_internal->GetState() == STATE_CANCELED;
575 thread->m_internal->SetState(STATE_EXITED);
576 thread->m_critsect.Leave();
577 }
b568d04f 578
bee503b0 579 thread->OnExit();
2bda0e17 580
f6bcfd97 581 // if the thread was cancelled (from Delete()), then its handle is still
b568d04f
VZ
582 // needed there
583 if ( thread->IsDetached() && !wasCancelled )
584 {
585 // auto delete
586 delete thread;
587 }
588 //else: the joinable threads handle will be closed when Wait() is done
bf1852e1 589
b568d04f 590 return rc;
2bda0e17
KB
591}
592
b568d04f 593void wxThreadInternal::SetPriority(unsigned int priority)
2bda0e17 594{
b568d04f 595 m_priority = priority;
3222fde2 596
bf1852e1
VZ
597 // translate wxWindows priority to the Windows one
598 int win_priority;
599 if (m_priority <= 20)
600 win_priority = THREAD_PRIORITY_LOWEST;
601 else if (m_priority <= 40)
602 win_priority = THREAD_PRIORITY_BELOW_NORMAL;
603 else if (m_priority <= 60)
604 win_priority = THREAD_PRIORITY_NORMAL;
605 else if (m_priority <= 80)
606 win_priority = THREAD_PRIORITY_ABOVE_NORMAL;
607 else if (m_priority <= 100)
608 win_priority = THREAD_PRIORITY_HIGHEST;
3222fde2
VZ
609 else
610 {
223d09f6 611 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
bf1852e1 612 win_priority = THREAD_PRIORITY_NORMAL;
3222fde2
VZ
613 }
614
b568d04f 615 if ( !::SetThreadPriority(m_hThread, win_priority) )
bee503b0
VZ
616 {
617 wxLogSysError(_("Can't set thread priority"));
618 }
b568d04f
VZ
619}
620
6fe73788 621bool wxThreadInternal::Create(wxThread *thread, unsigned int stackSize)
b568d04f
VZ
622{
623 // for compilers which have it, we should use C RTL function for thread
624 // creation instead of Win32 API one because otherwise we will have memory
625 // leaks if the thread uses C RTL (and most threads do)
9f51f2b6 626#ifdef wxUSE_BEGIN_THREAD
414c639c
VZ
627
628 // Watcom is reported to not like 0 stack size (which means "use default"
629 // for the other compilers and is also the default value for stackSize)
630#ifdef __WATCOMC__
631 if ( !stackSize )
632 stackSize = 10240;
633#endif // __WATCOMC__
634
9f51f2b6
VZ
635 m_hThread = (HANDLE)_beginthreadex
636 (
6fe73788
RL
637 NULL, // default security
638 stackSize,
639 wxThreadInternal::WinThreadStart, // entry point
640 thread,
641 CREATE_SUSPENDED,
642 (unsigned int *)&m_tid
9f51f2b6 643 );
611cb666 644#else // compiler doesn't have _beginthreadex
b568d04f
VZ
645 m_hThread = ::CreateThread
646 (
647 NULL, // default security
414c639c 648 stackSize, // stack size
9f51f2b6 649 wxThreadInternal::WinThreadStart, // thread entry point
b568d04f
VZ
650 (LPVOID)thread, // parameter
651 CREATE_SUSPENDED, // flags
652 &m_tid // [out] thread id
653 );
611cb666 654#endif // _beginthreadex/CreateThread
b568d04f
VZ
655
656 if ( m_hThread == NULL )
657 {
658 wxLogSysError(_("Can't create thread"));
659
660 return FALSE;
661 }
662
663 if ( m_priority != WXTHREAD_DEFAULT_PRIORITY )
664 {
665 SetPriority(m_priority);
666 }
3222fde2 667
bf1852e1 668 return TRUE;
2bda0e17
KB
669}
670
bf1852e1 671bool wxThreadInternal::Suspend()
2bda0e17 672{
bf1852e1
VZ
673 DWORD nSuspendCount = ::SuspendThread(m_hThread);
674 if ( nSuspendCount == (DWORD)-1 )
bee503b0 675 {
bf1852e1
VZ
676 wxLogSysError(_("Can not suspend thread %x"), m_hThread);
677
678 return FALSE;
bee503b0 679 }
2bda0e17 680
bf1852e1
VZ
681 m_state = STATE_PAUSED;
682
683 return TRUE;
a6b0bd49
VZ
684}
685
bf1852e1 686bool wxThreadInternal::Resume()
a6b0bd49 687{
bf1852e1 688 DWORD nSuspendCount = ::ResumeThread(m_hThread);
a6b0bd49
VZ
689 if ( nSuspendCount == (DWORD)-1 )
690 {
bf1852e1 691 wxLogSysError(_("Can not resume thread %x"), m_hThread);
a6b0bd49 692
bf1852e1 693 return FALSE;
a6b0bd49
VZ
694 }
695
f6bcfd97
BP
696 // don't change the state from STATE_EXITED because it's special and means
697 // we are going to terminate without running any user code - if we did it,
698 // the codei n Delete() wouldn't work
699 if ( m_state != STATE_EXITED )
700 {
701 m_state = STATE_RUNNING;
702 }
bee503b0 703
bf1852e1 704 return TRUE;
a6b0bd49
VZ
705}
706
bf1852e1
VZ
707// static functions
708// ----------------
709
710wxThread *wxThread::This()
a6b0bd49 711{
b568d04f 712 wxThread *thread = (wxThread *)::TlsGetValue(gs_tlsThisThread);
bf1852e1
VZ
713
714 // be careful, 0 may be a valid return value as well
715 if ( !thread && (::GetLastError() != NO_ERROR) )
a6b0bd49 716 {
bf1852e1 717 wxLogSysError(_("Couldn't get the current thread pointer"));
a6b0bd49 718
bf1852e1 719 // return NULL...
a6b0bd49
VZ
720 }
721
bf1852e1
VZ
722 return thread;
723}
724
725bool wxThread::IsMain()
726{
b568d04f 727 return ::GetCurrentThreadId() == gs_idMainThread;
bf1852e1
VZ
728}
729
c25a510b
JS
730#ifdef Yield
731#undef Yield
732#endif
733
bf1852e1
VZ
734void wxThread::Yield()
735{
b568d04f
VZ
736 // 0 argument to Sleep() is special and means to just give away the rest of
737 // our timeslice
bf1852e1
VZ
738 ::Sleep(0);
739}
740
741void wxThread::Sleep(unsigned long milliseconds)
742{
743 ::Sleep(milliseconds);
744}
745
ef8d96c2
VZ
746int wxThread::GetCPUCount()
747{
28a4627c
VZ
748 SYSTEM_INFO si;
749 GetSystemInfo(&si);
750
751 return si.dwNumberOfProcessors;
ef8d96c2
VZ
752}
753
4958ea8f
RD
754unsigned long wxThread::GetCurrentId()
755{
756 return (unsigned long)::GetCurrentThreadId();
757}
758
ef8d96c2
VZ
759bool wxThread::SetConcurrency(size_t level)
760{
28a4627c
VZ
761 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
762
ef8d96c2 763 // ok only for the default one
28a4627c
VZ
764 if ( level == 0 )
765 return 0;
766
767 // get system affinity mask first
768 HANDLE hProcess = ::GetCurrentProcess();
769 DWORD dwProcMask, dwSysMask;
770 if ( ::GetProcessAffinityMask(hProcess, &dwProcMask, &dwSysMask) == 0 )
771 {
772 wxLogLastError(_T("GetProcessAffinityMask"));
773
774 return FALSE;
775 }
776
777 // how many CPUs have we got?
778 if ( dwSysMask == 1 )
779 {
780 // don't bother with all this complicated stuff - on a single
781 // processor system it doesn't make much sense anyhow
782 return level == 1;
783 }
784
785 // calculate the process mask: it's a bit vector with one bit per
786 // processor; we want to schedule the process to run on first level
787 // CPUs
788 DWORD bit = 1;
789 while ( bit )
790 {
791 if ( dwSysMask & bit )
792 {
793 // ok, we can set this bit
794 dwProcMask |= bit;
795
796 // another process added
797 if ( !--level )
798 {
799 // and that's enough
800 break;
801 }
802 }
803
804 // next bit
805 bit <<= 1;
806 }
807
808 // could we set all bits?
809 if ( level != 0 )
810 {
811 wxLogDebug(_T("bad level %u in wxThread::SetConcurrency()"), level);
812
813 return FALSE;
814 }
815
816 // set it: we can't link to SetProcessAffinityMask() because it doesn't
817 // exist in Win9x, use RT binding instead
818
696e1ea0 819 typedef BOOL (*SETPROCESSAFFINITYMASK)(HANDLE, DWORD);
28a4627c
VZ
820
821 // can use static var because we're always in the main thread here
822 static SETPROCESSAFFINITYMASK pfnSetProcessAffinityMask = NULL;
823
824 if ( !pfnSetProcessAffinityMask )
825 {
826 HMODULE hModKernel = ::LoadLibrary(_T("kernel32"));
827 if ( hModKernel )
828 {
829 pfnSetProcessAffinityMask = (SETPROCESSAFFINITYMASK)
f6bcfd97 830 ::GetProcAddress(hModKernel, "SetProcessAffinityMask");
28a4627c
VZ
831 }
832
833 // we've discovered a MT version of Win9x!
834 wxASSERT_MSG( pfnSetProcessAffinityMask,
f6bcfd97 835 _T("this system has several CPUs but no SetProcessAffinityMask function?") );
28a4627c
VZ
836 }
837
838 if ( !pfnSetProcessAffinityMask )
839 {
840 // msg given above - do it only once
841 return FALSE;
842 }
843
696e1ea0 844 if ( pfnSetProcessAffinityMask(hProcess, dwProcMask) == 0 )
28a4627c
VZ
845 {
846 wxLogLastError(_T("SetProcessAffinityMask"));
847
848 return FALSE;
849 }
850
851 return TRUE;
ef8d96c2
VZ
852}
853
b568d04f
VZ
854// ctor and dtor
855// -------------
856
857wxThread::wxThread(wxThreadKind kind)
858{
9fc3ad34 859 m_internal = new wxThreadInternal();
b568d04f
VZ
860
861 m_isDetached = kind == wxTHREAD_DETACHED;
862}
863
864wxThread::~wxThread()
865{
9fc3ad34 866 delete m_internal;
b568d04f
VZ
867}
868
bf1852e1
VZ
869// create/start thread
870// -------------------
871
6fe73788 872wxThreadError wxThread::Create(unsigned int stackSize)
bf1852e1 873{
b568d04f
VZ
874 wxCriticalSectionLocker lock(m_critsect);
875
6fe73788 876 if ( !m_internal->Create(this, stackSize) )
bf1852e1 877 return wxTHREAD_NO_RESOURCE;
bee503b0 878
a6b0bd49 879 return wxTHREAD_NO_ERROR;
2bda0e17
KB
880}
881
bf1852e1 882wxThreadError wxThread::Run()
2bda0e17 883{
bf1852e1
VZ
884 wxCriticalSectionLocker lock(m_critsect);
885
9fc3ad34 886 if ( m_internal->GetState() != STATE_NEW )
bf1852e1
VZ
887 {
888 // actually, it may be almost any state at all, not only STATE_RUNNING
889 return wxTHREAD_RUNNING;
890 }
891
b568d04f 892 // the thread has just been created and is still suspended - let it run
bf1852e1 893 return Resume();
2bda0e17
KB
894}
895
bf1852e1
VZ
896// suspend/resume thread
897// ---------------------
898
899wxThreadError wxThread::Pause()
2bda0e17 900{
bf1852e1
VZ
901 wxCriticalSectionLocker lock(m_critsect);
902
9fc3ad34 903 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
2bda0e17
KB
904}
905
bf1852e1 906wxThreadError wxThread::Resume()
2bda0e17 907{
bf1852e1
VZ
908 wxCriticalSectionLocker lock(m_critsect);
909
9fc3ad34 910 return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
2bda0e17
KB
911}
912
bf1852e1
VZ
913// stopping thread
914// ---------------
915
b568d04f
VZ
916wxThread::ExitCode wxThread::Wait()
917{
918 // although under Windows we can wait for any thread, it's an error to
919 // wait for a detached one in wxWin API
920 wxCHECK_MSG( !IsDetached(), (ExitCode)-1,
921 _T("can't wait for detached thread") );
922
923 ExitCode rc = (ExitCode)-1;
924
925 (void)Delete(&rc);
926
9fc3ad34 927 m_internal->Free();
b568d04f
VZ
928
929 return rc;
930}
931
932wxThreadError wxThread::Delete(ExitCode *pRc)
2bda0e17 933{
bf1852e1
VZ
934 ExitCode rc = 0;
935
936 // Delete() is always safe to call, so consider all possible states
696e1ea0 937
f6bcfd97
BP
938 // we might need to resume the thread, but we might also not need to cancel
939 // it if it doesn't run yet
940 bool shouldResume = FALSE,
941 shouldCancel = TRUE,
942 isRunning = FALSE;
696e1ea0 943
f6bcfd97 944 // check if the thread already started to run
696e1ea0
VZ
945 {
946 wxCriticalSectionLocker lock(m_critsect);
947
948 if ( m_internal->GetState() == STATE_NEW )
949 {
f6bcfd97
BP
950 // WinThreadStart() will see it and terminate immediately, no need
951 // to cancel the thread - but we still need to resume it to let it
952 // run
696e1ea0
VZ
953 m_internal->SetState(STATE_EXITED);
954
f6bcfd97
BP
955 Resume(); // it knows about STATE_EXITED special case
956
957 shouldCancel = FALSE;
958 isRunning = TRUE;
959
960 // shouldResume is correctly set to FALSE here
961 }
962 else
963 {
964 shouldResume = IsPaused();
696e1ea0
VZ
965 }
966 }
967
f6bcfd97
BP
968 // resume the thread if it is paused
969 if ( shouldResume )
bf1852e1
VZ
970 Resume();
971
9fc3ad34 972 HANDLE hThread = m_internal->GetHandle();
b568d04f 973
0ef2ebba
VZ
974 // does is still run?
975 if ( isRunning || IsRunning() )
bf1852e1
VZ
976 {
977 if ( IsMain() )
978 {
979 // set flag for wxIsWaitingForThread()
b568d04f 980 gs_waitingForThread = TRUE;
bf1852e1
VZ
981 }
982
b568d04f 983 // ask the thread to terminate
f6bcfd97 984 if ( shouldCancel )
bf1852e1
VZ
985 {
986 wxCriticalSectionLocker lock(m_critsect);
987
9fc3ad34 988 m_internal->Cancel();
bf1852e1
VZ
989 }
990
b568d04f 991#if wxUSE_GUI
bf1852e1
VZ
992 // we can't just wait for the thread to terminate because it might be
993 // calling some GUI functions and so it will never terminate before we
994 // process the Windows messages that result from these functions
6cd4655b 995 DWORD result = 0; // suppress warnings from broken compilers
bf1852e1
VZ
996 do
997 {
14205189
VZ
998 if ( IsMain() )
999 {
1000 // give the thread we're waiting for chance to do the GUI call
1001 // it might be in
1002 if ( (gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
1003 {
1004 wxMutexGuiLeave();
1005 }
1006 }
1007
bf1852e1
VZ
1008 result = ::MsgWaitForMultipleObjects
1009 (
1010 1, // number of objects to wait for
1011 &hThread, // the objects
1012 FALSE, // don't wait for all objects
1013 INFINITE, // no timeout
14205189
VZ
1014 QS_ALLINPUT | // return as soon as there are any events
1015 QS_ALLPOSTMESSAGE
bf1852e1
VZ
1016 );
1017
1018 switch ( result )
1019 {
1020 case 0xFFFFFFFF:
1021 // error
1022 wxLogSysError(_("Can not wait for thread termination"));
1023 Kill();
b568d04f 1024 return wxTHREAD_KILLED;
bf1852e1
VZ
1025
1026 case WAIT_OBJECT_0:
1027 // thread we're waiting for terminated
1028 break;
1029
1030 case WAIT_OBJECT_0 + 1:
0ef2ebba
VZ
1031 // new message arrived, process it
1032 if ( !wxTheApp->DoMessage() )
bf1852e1 1033 {
0ef2ebba
VZ
1034 // WM_QUIT received: kill the thread
1035 Kill();
1036
1037 return wxTHREAD_KILLED;
bf1852e1 1038 }
bf1852e1
VZ
1039 break;
1040
1041 default:
223d09f6 1042 wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject"));
bf1852e1
VZ
1043 }
1044 } while ( result != WAIT_OBJECT_0 );
b568d04f
VZ
1045#else // !wxUSE_GUI
1046 // simply wait for the thread to terminate
1047 //
1048 // OTOH, even console apps create windows (in wxExecute, for WinSock
1049 // &c), so may be use MsgWaitForMultipleObject() too here?
1050 if ( WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0 )
1051 {
1052 wxFAIL_MSG(wxT("unexpected result of WaitForSingleObject"));
1053 }
1054#endif // wxUSE_GUI/!wxUSE_GUI
bf1852e1
VZ
1055
1056 if ( IsMain() )
1057 {
b568d04f 1058 gs_waitingForThread = FALSE;
bf1852e1 1059 }
b568d04f 1060 }
bf1852e1 1061
10671c67
VZ
1062 // although the thread might be already in the EXITED state it might not
1063 // have terminated yet and so we are not sure that it has actually
1064 // terminated if the "if" above hadn't been taken
1065 do
b568d04f 1066 {
10671c67
VZ
1067 if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
1068 {
1069 wxLogLastError(wxT("GetExitCodeThread"));
bf1852e1 1070
10671c67
VZ
1071 rc = (ExitCode)-1;
1072 }
1073 } while ( (DWORD)rc == STILL_ACTIVE );
bf1852e1 1074
b568d04f
VZ
1075 if ( IsDetached() )
1076 {
1077 // if the thread exits normally, this is done in WinThreadStart, but in
1078 // this case it would have been too early because
f6bcfd97 1079 // MsgWaitForMultipleObject() would fail if the thread handle was
b568d04f
VZ
1080 // closed while we were waiting on it, so we must do it here
1081 delete this;
bf1852e1
VZ
1082 }
1083
b568d04f
VZ
1084 if ( pRc )
1085 *pRc = rc;
1086
1087 return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR;
2bda0e17
KB
1088}
1089
bf1852e1 1090wxThreadError wxThread::Kill()
2bda0e17 1091{
bf1852e1
VZ
1092 if ( !IsRunning() )
1093 return wxTHREAD_NOT_RUNNING;
1094
9fc3ad34 1095 if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
bf1852e1
VZ
1096 {
1097 wxLogSysError(_("Couldn't terminate thread"));
1098
1099 return wxTHREAD_MISC_ERROR;
1100 }
1101
9fc3ad34 1102 m_internal->Free();
b568d04f
VZ
1103
1104 if ( IsDetached() )
1105 {
1106 delete this;
1107 }
bf1852e1
VZ
1108
1109 return wxTHREAD_NO_ERROR;
2bda0e17
KB
1110}
1111
b568d04f 1112void wxThread::Exit(ExitCode status)
2bda0e17 1113{
9fc3ad34 1114 m_internal->Free();
2bda0e17 1115
b568d04f
VZ
1116 if ( IsDetached() )
1117 {
1118 delete this;
1119 }
1120
9f51f2b6 1121#ifdef wxUSE_BEGIN_THREAD
b568d04f
VZ
1122 _endthreadex((unsigned)status);
1123#else // !VC++
bf1852e1 1124 ::ExitThread((DWORD)status);
b568d04f 1125#endif // VC++/!VC++
2bda0e17 1126
223d09f6 1127 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
bf1852e1 1128}
2bda0e17 1129
b568d04f
VZ
1130// priority setting
1131// ----------------
1132
bf1852e1
VZ
1133void wxThread::SetPriority(unsigned int prio)
1134{
1135 wxCriticalSectionLocker lock(m_critsect);
1136
9fc3ad34 1137 m_internal->SetPriority(prio);
bf1852e1 1138}
2bda0e17 1139
bf1852e1
VZ
1140unsigned int wxThread::GetPriority() const
1141{
b568d04f 1142 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
2bda0e17 1143
9fc3ad34 1144 return m_internal->GetPriority();
2bda0e17
KB
1145}
1146
b568d04f 1147unsigned long wxThread::GetId() const
2bda0e17 1148{
b568d04f 1149 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
bf1852e1 1150
9fc3ad34 1151 return (unsigned long)m_internal->GetId();
2bda0e17
KB
1152}
1153
72fd19a1
JS
1154bool wxThread::IsRunning() const
1155{
b568d04f 1156 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
bf1852e1 1157
9fc3ad34 1158 return m_internal->GetState() == STATE_RUNNING;
72fd19a1
JS
1159}
1160
1161bool wxThread::IsAlive() const
1162{
b568d04f 1163 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
bf1852e1 1164
9fc3ad34
VZ
1165 return (m_internal->GetState() == STATE_RUNNING) ||
1166 (m_internal->GetState() == STATE_PAUSED);
72fd19a1
JS
1167}
1168
a737331d
GL
1169bool wxThread::IsPaused() const
1170{
b568d04f 1171 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
a737331d 1172
9fc3ad34 1173 return m_internal->GetState() == STATE_PAUSED;
a737331d
GL
1174}
1175
8c10faf1 1176bool wxThread::TestDestroy()
2bda0e17 1177{
b568d04f 1178 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
bf1852e1 1179
9fc3ad34 1180 return m_internal->GetState() == STATE_CANCELED;
2bda0e17
KB
1181}
1182
3222fde2
VZ
1183// ----------------------------------------------------------------------------
1184// Automatic initialization for thread module
1185// ----------------------------------------------------------------------------
2bda0e17 1186
3222fde2 1187class wxThreadModule : public wxModule
a6b0bd49 1188{
3222fde2
VZ
1189public:
1190 virtual bool OnInit();
1191 virtual void OnExit();
d524867f 1192
3222fde2
VZ
1193private:
1194 DECLARE_DYNAMIC_CLASS(wxThreadModule)
1195};
d524867f
RR
1196
1197IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
1198
3222fde2 1199bool wxThreadModule::OnInit()
d524867f 1200{
bf1852e1 1201 // allocate TLS index for storing the pointer to the current thread
b568d04f
VZ
1202 gs_tlsThisThread = ::TlsAlloc();
1203 if ( gs_tlsThisThread == 0xFFFFFFFF )
bf1852e1
VZ
1204 {
1205 // in normal circumstances it will only happen if all other
1206 // TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other
1207 // words, this should never happen
f6bcfd97 1208 wxLogSysError(_("Thread module initialization failed: impossible to allocate index in thread local storage"));
bf1852e1
VZ
1209
1210 return FALSE;
1211 }
1212
1213 // main thread doesn't have associated wxThread object, so store 0 in the
1214 // TLS instead
b568d04f 1215 if ( !::TlsSetValue(gs_tlsThisThread, (LPVOID)0) )
bf1852e1 1216 {
b568d04f
VZ
1217 ::TlsFree(gs_tlsThisThread);
1218 gs_tlsThisThread = 0xFFFFFFFF;
bf1852e1 1219
f6bcfd97 1220 wxLogSysError(_("Thread module initialization failed: can not store value in thread local storage"));
bf1852e1
VZ
1221
1222 return FALSE;
1223 }
1224
b568d04f 1225 gs_critsectWaitingForGui = new wxCriticalSection();
bee503b0 1226
b568d04f
VZ
1227 gs_critsectGui = new wxCriticalSection();
1228 gs_critsectGui->Enter();
bee503b0 1229
bf1852e1 1230 // no error return for GetCurrentThreadId()
b568d04f 1231 gs_idMainThread = ::GetCurrentThreadId();
3222fde2 1232
d524867f
RR
1233 return TRUE;
1234}
1235
3222fde2 1236void wxThreadModule::OnExit()
d524867f 1237{
b568d04f 1238 if ( !::TlsFree(gs_tlsThisThread) )
bf1852e1 1239 {
f6bcfd97 1240 wxLogLastError(wxT("TlsFree failed."));
bf1852e1
VZ
1241 }
1242
b568d04f 1243 if ( gs_critsectGui )
3222fde2 1244 {
b568d04f
VZ
1245 gs_critsectGui->Leave();
1246 delete gs_critsectGui;
1247 gs_critsectGui = NULL;
3222fde2 1248 }
bee503b0 1249
b568d04f
VZ
1250 delete gs_critsectWaitingForGui;
1251 gs_critsectWaitingForGui = NULL;
3222fde2
VZ
1252}
1253
bee503b0 1254// ----------------------------------------------------------------------------
b568d04f 1255// under Windows, these functions are implemented using a critical section and
3222fde2 1256// not a mutex, so the names are a bit confusing
bee503b0
VZ
1257// ----------------------------------------------------------------------------
1258
3222fde2
VZ
1259void WXDLLEXPORT wxMutexGuiEnter()
1260{
bee503b0
VZ
1261 // this would dead lock everything...
1262 wxASSERT_MSG( !wxThread::IsMain(),
223d09f6 1263 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
bee503b0
VZ
1264
1265 // the order in which we enter the critical sections here is crucial!!
1266
1267 // set the flag telling to the main thread that we want to do some GUI
1268 {
b568d04f 1269 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
bee503b0 1270
b568d04f 1271 gs_nWaitingForGui++;
bee503b0
VZ
1272 }
1273
1274 wxWakeUpMainThread();
1275
1276 // now we may block here because the main thread will soon let us in
1277 // (during the next iteration of OnIdle())
b568d04f 1278 gs_critsectGui->Enter();
3222fde2
VZ
1279}
1280
1281void WXDLLEXPORT wxMutexGuiLeave()
1282{
b568d04f 1283 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
bee503b0
VZ
1284
1285 if ( wxThread::IsMain() )
1286 {
b568d04f 1287 gs_bGuiOwnedByMainThread = FALSE;
bee503b0
VZ
1288 }
1289 else
1290 {
4d1c1c3c 1291 // decrement the number of threads waiting for GUI access now
b568d04f 1292 wxASSERT_MSG( gs_nWaitingForGui > 0,
223d09f6 1293 wxT("calling wxMutexGuiLeave() without entering it first?") );
bee503b0 1294
b568d04f 1295 gs_nWaitingForGui--;
bee503b0
VZ
1296
1297 wxWakeUpMainThread();
1298 }
1299
b568d04f 1300 gs_critsectGui->Leave();
bee503b0
VZ
1301}
1302
1303void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
1304{
1305 wxASSERT_MSG( wxThread::IsMain(),
223d09f6 1306 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
bee503b0 1307
b568d04f 1308 wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
bee503b0 1309
b568d04f 1310 if ( gs_nWaitingForGui == 0 )
bee503b0
VZ
1311 {
1312 // no threads are waiting for GUI - so we may acquire the lock without
1313 // any danger (but only if we don't already have it)
1314 if ( !wxGuiOwnedByMainThread() )
1315 {
b568d04f 1316 gs_critsectGui->Enter();
bee503b0 1317
b568d04f 1318 gs_bGuiOwnedByMainThread = TRUE;
bee503b0
VZ
1319 }
1320 //else: already have it, nothing to do
1321 }
1322 else
1323 {
1324 // some threads are waiting, release the GUI lock if we have it
1325 if ( wxGuiOwnedByMainThread() )
1326 {
1327 wxMutexGuiLeave();
1328 }
1329 //else: some other worker thread is doing GUI
1330 }
1331}
1332
1333bool WXDLLEXPORT wxGuiOwnedByMainThread()
1334{
b568d04f 1335 return gs_bGuiOwnedByMainThread;
bee503b0
VZ
1336}
1337
1338// wake up the main thread if it's in ::GetMessage()
1339void WXDLLEXPORT wxWakeUpMainThread()
1340{
1341 // sending any message would do - hopefully WM_NULL is harmless enough
b568d04f 1342 if ( !::PostThreadMessage(gs_idMainThread, WM_NULL, 0, 0) )
bee503b0
VZ
1343 {
1344 // should never happen
f6bcfd97 1345 wxLogLastError(wxT("PostThreadMessage(WM_NULL)"));
bee503b0 1346 }
3222fde2 1347}
d524867f 1348
bf1852e1
VZ
1349bool WXDLLEXPORT wxIsWaitingForThread()
1350{
b568d04f 1351 return gs_waitingForThread;
bf1852e1
VZ
1352}
1353
9e84b847
VZ
1354// ----------------------------------------------------------------------------
1355// include common implementation code
1356// ----------------------------------------------------------------------------
1357
1358#include "wx/thrimpl.cpp"
1359
3222fde2 1360#endif // wxUSE_THREADS
6fe73788 1361