]> git.saurik.com Git - wxWidgets.git/blame - src/msw/thread.cpp
Added dummy OnIdle to wxWindow in wxGTK; doc tweaks
[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
2bda0e17
KB
34#include <stdio.h>
35
36#include <windows.h>
3222fde2 37
2bda0e17
KB
38#include "wx/module.h"
39#include "wx/thread.h"
40
bf1852e1
VZ
41// the possible states of the thread ("=>" shows all possible transitions from
42// this state)
43enum wxThreadState
44{
45 STATE_NEW, // didn't start execution yet (=> RUNNING)
46 STATE_RUNNING, // thread is running (=> PAUSED, CANCELED)
47 STATE_PAUSED, // thread is temporarily suspended (=> RUNNING)
48 STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED)
49 STATE_EXITED // thread is terminating
2bda0e17
KB
50};
51
3222fde2
VZ
52// ----------------------------------------------------------------------------
53// static variables
54// ----------------------------------------------------------------------------
2bda0e17 55
bf1852e1
VZ
56// TLS index of the slot where we store the pointer to the current thread
57static DWORD s_tlsThisThread = 0xFFFFFFFF;
58
3222fde2
VZ
59// id of the main thread - the one which can call GUI functions without first
60// calling wxMutexGuiEnter()
bee503b0
VZ
61static DWORD s_idMainThread = 0;
62
63// if it's FALSE, some secondary thread is holding the GUI lock
64static bool s_bGuiOwnedByMainThread = TRUE;
2bda0e17 65
3222fde2
VZ
66// critical section which controls access to all GUI functions: any secondary
67// thread (i.e. except the main one) must enter this crit section before doing
68// any GUI calls
bee503b0
VZ
69static wxCriticalSection *s_critsectGui = NULL;
70
71// critical section which protects s_nWaitingForGui variable
72static wxCriticalSection *s_critsectWaitingForGui = NULL;
73
74// number of threads waiting for GUI in wxMutexGuiEnter()
75static size_t s_nWaitingForGui = 0;
2bda0e17 76
bf1852e1
VZ
77// are we waiting for a thread termination?
78static bool s_waitingForThread = FALSE;
79
3222fde2
VZ
80// ============================================================================
81// Windows implementation of thread classes
82// ============================================================================
83
84// ----------------------------------------------------------------------------
85// wxMutex implementation
86// ----------------------------------------------------------------------------
87class wxMutexInternal
88{
2bda0e17 89public:
3222fde2 90 HANDLE p_mutex;
2bda0e17
KB
91};
92
ee4f8c2a 93wxMutex::wxMutex()
2bda0e17 94{
3222fde2
VZ
95 p_internal = new wxMutexInternal;
96 p_internal->p_mutex = CreateMutex(NULL, FALSE, NULL);
97 if ( !p_internal->p_mutex )
98 {
99 wxLogSysError(_("Can not create mutex."));
100 }
a6b0bd49 101
3222fde2 102 m_locked = 0;
2bda0e17
KB
103}
104
ee4f8c2a 105wxMutex::~wxMutex()
2bda0e17 106{
3222fde2
VZ
107 if (m_locked > 0)
108 wxLogDebug("Warning: freeing a locked mutex (%d locks).", m_locked);
109 CloseHandle(p_internal->p_mutex);
2bda0e17
KB
110}
111
ee4f8c2a 112wxMutexError wxMutex::Lock()
2bda0e17 113{
3222fde2
VZ
114 DWORD ret;
115
116 ret = WaitForSingleObject(p_internal->p_mutex, INFINITE);
117 switch ( ret )
118 {
119 case WAIT_ABANDONED:
120 return wxMUTEX_BUSY;
121
122 case WAIT_OBJECT_0:
123 // ok
124 break;
2bda0e17 125
3222fde2
VZ
126 case WAIT_FAILED:
127 wxLogSysError(_("Couldn't acquire a mutex lock"));
128 return wxMUTEX_MISC_ERROR;
2bda0e17 129
3222fde2
VZ
130 case WAIT_TIMEOUT:
131 default:
132 wxFAIL_MSG("impossible return value in wxMutex::Lock");
133 }
134
135 m_locked++;
136 return wxMUTEX_NO_ERROR;
2bda0e17
KB
137}
138
ee4f8c2a 139wxMutexError wxMutex::TryLock()
2bda0e17 140{
3222fde2 141 DWORD ret;
2bda0e17 142
3222fde2
VZ
143 ret = WaitForSingleObject(p_internal->p_mutex, 0);
144 if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
145 return wxMUTEX_BUSY;
2bda0e17 146
3222fde2
VZ
147 m_locked++;
148 return wxMUTEX_NO_ERROR;
2bda0e17
KB
149}
150
ee4f8c2a 151wxMutexError wxMutex::Unlock()
2bda0e17 152{
3222fde2
VZ
153 if (m_locked > 0)
154 m_locked--;
2bda0e17 155
3222fde2
VZ
156 BOOL ret = ReleaseMutex(p_internal->p_mutex);
157 if ( ret == 0 )
158 {
159 wxLogSysError(_("Couldn't release a mutex"));
160 return wxMUTEX_MISC_ERROR;
161 }
a6b0bd49 162
3222fde2 163 return wxMUTEX_NO_ERROR;
2bda0e17
KB
164}
165
3222fde2
VZ
166// ----------------------------------------------------------------------------
167// wxCondition implementation
168// ----------------------------------------------------------------------------
169
170class wxConditionInternal
171{
2bda0e17 172public:
3222fde2
VZ
173 HANDLE event;
174 int waiters;
2bda0e17
KB
175};
176
ee4f8c2a 177wxCondition::wxCondition()
2bda0e17 178{
3222fde2
VZ
179 p_internal = new wxConditionInternal;
180 p_internal->event = CreateEvent(NULL, FALSE, FALSE, NULL);
181 if ( !p_internal->event )
182 {
183 wxLogSysError(_("Can not create event object."));
184 }
a6b0bd49 185
3222fde2 186 p_internal->waiters = 0;
2bda0e17
KB
187}
188
ee4f8c2a 189wxCondition::~wxCondition()
2bda0e17 190{
3222fde2 191 CloseHandle(p_internal->event);
2bda0e17
KB
192}
193
194void wxCondition::Wait(wxMutex& mutex)
195{
3222fde2
VZ
196 mutex.Unlock();
197 p_internal->waiters++;
198 WaitForSingleObject(p_internal->event, INFINITE);
199 p_internal->waiters--;
200 mutex.Lock();
2bda0e17
KB
201}
202
3222fde2
VZ
203bool wxCondition::Wait(wxMutex& mutex,
204 unsigned long sec,
2bda0e17
KB
205 unsigned long nsec)
206{
3222fde2 207 DWORD ret;
2bda0e17 208
3222fde2
VZ
209 mutex.Unlock();
210 p_internal->waiters++;
211 ret = WaitForSingleObject(p_internal->event, (sec*1000)+(nsec/1000000));
212 p_internal->waiters--;
213 mutex.Lock();
2bda0e17 214
3222fde2 215 return (ret != WAIT_TIMEOUT);
2bda0e17
KB
216}
217
ee4f8c2a 218void wxCondition::Signal()
2bda0e17 219{
3222fde2 220 SetEvent(p_internal->event);
2bda0e17
KB
221}
222
ee4f8c2a 223void wxCondition::Broadcast()
2bda0e17 224{
3222fde2 225 int i;
2bda0e17 226
3222fde2 227 for (i=0;i<p_internal->waiters;i++)
a6b0bd49 228 {
3222fde2
VZ
229 if ( SetEvent(p_internal->event) == 0 )
230 {
231 wxLogSysError(_("Couldn't change the state of event object."));
232 }
a6b0bd49 233 }
2bda0e17
KB
234}
235
3222fde2
VZ
236// ----------------------------------------------------------------------------
237// wxCriticalSection implementation
238// ----------------------------------------------------------------------------
239
240class wxCriticalSectionInternal
241{
242public:
243 // init the critical section object
244 wxCriticalSectionInternal()
245 { ::InitializeCriticalSection(&m_data); }
246
247 // implicit cast to the associated data
248 operator CRITICAL_SECTION *() { return &m_data; }
249
250 // free the associated ressources
251 ~wxCriticalSectionInternal()
252 { ::DeleteCriticalSection(&m_data); }
253
254private:
255 CRITICAL_SECTION m_data;
256};
257
258wxCriticalSection::wxCriticalSection()
259{
00fdc89d 260 m_critsect = NULL;
3222fde2
VZ
261}
262
263wxCriticalSection::~wxCriticalSection()
264{
f7c44a6a 265 wxASSERT_MSG( !m_critsect, "Forgot to Leave() critical section" );
3222fde2
VZ
266}
267
268void wxCriticalSection::Enter()
269{
00fdc89d
VZ
270 m_critsect = new wxCriticalSectionInternal;
271
3222fde2
VZ
272 ::EnterCriticalSection(*m_critsect);
273}
274
275void wxCriticalSection::Leave()
276{
00fdc89d
VZ
277 wxCHECK_RET( m_critsect, "Leave() without matching Enter()" );
278
3222fde2 279 ::LeaveCriticalSection(*m_critsect);
f7c44a6a
VZ
280
281 delete m_critsect;
282 m_critsect = NULL;
3222fde2
VZ
283}
284
285// ----------------------------------------------------------------------------
286// wxThread implementation
287// ----------------------------------------------------------------------------
288
bf1852e1
VZ
289// wxThreadInternal class
290// ----------------------
291
3222fde2
VZ
292class wxThreadInternal
293{
2bda0e17 294public:
bf1852e1
VZ
295 wxThreadInternal()
296 {
297 m_hThread = 0;
298 m_state = STATE_NEW;
299 m_priority = WXTHREAD_DEFAULT_PRIORITY;
300 }
301
302 // create a new (suspended) thread (for the given thread object)
303 bool Create(wxThread *thread);
304
305 // suspend/resume/terminate
306 bool Suspend();
307 bool Resume();
308 void Cancel() { m_state = STATE_CANCELED; }
309
310 // thread state
311 void SetState(wxThreadState state) { m_state = state; }
312 wxThreadState GetState() const { return m_state; }
313
314 // thread priority
315 void SetPriority(unsigned int priority) { m_priority = priority; }
316 unsigned int GetPriority() const { return m_priority; }
317
318 // thread handle and id
319 HANDLE GetHandle() const { return m_hThread; }
320 DWORD GetId() const { return m_tid; }
321
322 // thread function
bee503b0 323 static DWORD WinThreadStart(wxThread *thread);
2bda0e17 324
bf1852e1
VZ
325private:
326 HANDLE m_hThread; // handle of the thread
327 wxThreadState m_state; // state, see wxThreadState enum
328 unsigned int m_priority; // thread priority in "wx" units
329 DWORD m_tid; // thread id
2bda0e17
KB
330};
331
bee503b0 332DWORD wxThreadInternal::WinThreadStart(wxThread *thread)
2bda0e17 333{
bf1852e1
VZ
334 // store the thread object in the TLS
335 if ( !::TlsSetValue(s_tlsThisThread, thread) )
336 {
337 wxLogSysError(_("Can not start thread: error writing TLS."));
338
339 return (DWORD)-1;
340 }
341
bee503b0 342 DWORD ret = (DWORD)thread->Entry();
bf1852e1 343 thread->p_internal->SetState(STATE_EXITED);
bee503b0 344 thread->OnExit();
2bda0e17 345
bf1852e1
VZ
346 delete thread;
347
3222fde2 348 return ret;
2bda0e17
KB
349}
350
bf1852e1 351bool wxThreadInternal::Create(wxThread *thread)
2bda0e17 352{
bf1852e1
VZ
353 m_hThread = ::CreateThread
354 (
355 NULL, // default security
356 0, // default stack size
357 (LPTHREAD_START_ROUTINE) // thread entry point
358 wxThreadInternal::WinThreadStart, //
359 (LPVOID)thread, // parameter
360 CREATE_SUSPENDED, // flags
361 &m_tid // [out] thread id
362 );
363
364 if ( m_hThread == NULL )
3222fde2
VZ
365 {
366 wxLogSysError(_("Can't create thread"));
bf1852e1
VZ
367
368 return FALSE;
3222fde2
VZ
369 }
370
bf1852e1
VZ
371 // translate wxWindows priority to the Windows one
372 int win_priority;
373 if (m_priority <= 20)
374 win_priority = THREAD_PRIORITY_LOWEST;
375 else if (m_priority <= 40)
376 win_priority = THREAD_PRIORITY_BELOW_NORMAL;
377 else if (m_priority <= 60)
378 win_priority = THREAD_PRIORITY_NORMAL;
379 else if (m_priority <= 80)
380 win_priority = THREAD_PRIORITY_ABOVE_NORMAL;
381 else if (m_priority <= 100)
382 win_priority = THREAD_PRIORITY_HIGHEST;
3222fde2
VZ
383 else
384 {
385 wxFAIL_MSG("invalid value of thread priority parameter");
bf1852e1 386 win_priority = THREAD_PRIORITY_NORMAL;
3222fde2
VZ
387 }
388
bf1852e1 389 if ( ::SetThreadPriority(m_hThread, win_priority) == 0 )
bee503b0
VZ
390 {
391 wxLogSysError(_("Can't set thread priority"));
392 }
3222fde2 393
bf1852e1 394 return TRUE;
2bda0e17
KB
395}
396
bf1852e1 397bool wxThreadInternal::Suspend()
2bda0e17 398{
bf1852e1
VZ
399 DWORD nSuspendCount = ::SuspendThread(m_hThread);
400 if ( nSuspendCount == (DWORD)-1 )
bee503b0 401 {
bf1852e1
VZ
402 wxLogSysError(_("Can not suspend thread %x"), m_hThread);
403
404 return FALSE;
bee503b0 405 }
2bda0e17 406
bf1852e1
VZ
407 m_state = STATE_PAUSED;
408
409 return TRUE;
a6b0bd49
VZ
410}
411
bf1852e1 412bool wxThreadInternal::Resume()
a6b0bd49 413{
bf1852e1 414 DWORD nSuspendCount = ::ResumeThread(m_hThread);
a6b0bd49
VZ
415 if ( nSuspendCount == (DWORD)-1 )
416 {
bf1852e1 417 wxLogSysError(_("Can not resume thread %x"), m_hThread);
a6b0bd49 418
bf1852e1 419 return FALSE;
a6b0bd49
VZ
420 }
421
bf1852e1 422 m_state = STATE_RUNNING;
bee503b0 423
bf1852e1 424 return TRUE;
a6b0bd49
VZ
425}
426
bf1852e1
VZ
427// static functions
428// ----------------
429
430wxThread *wxThread::This()
a6b0bd49 431{
bf1852e1
VZ
432 wxThread *thread = (wxThread *)::TlsGetValue(s_tlsThisThread);
433
434 // be careful, 0 may be a valid return value as well
435 if ( !thread && (::GetLastError() != NO_ERROR) )
a6b0bd49 436 {
bf1852e1 437 wxLogSysError(_("Couldn't get the current thread pointer"));
a6b0bd49 438
bf1852e1 439 // return NULL...
a6b0bd49
VZ
440 }
441
bf1852e1
VZ
442 return thread;
443}
444
445bool wxThread::IsMain()
446{
447 return ::GetCurrentThreadId() == s_idMainThread;
448}
449
450void wxThread::Yield()
451{
452 // 0 argument to Sleep() is special
453 ::Sleep(0);
454}
455
456void wxThread::Sleep(unsigned long milliseconds)
457{
458 ::Sleep(milliseconds);
459}
460
461// create/start thread
462// -------------------
463
464wxThreadError wxThread::Create()
465{
466 if ( !p_internal->Create(this) )
467 return wxTHREAD_NO_RESOURCE;
bee503b0 468
a6b0bd49 469 return wxTHREAD_NO_ERROR;
2bda0e17
KB
470}
471
bf1852e1 472wxThreadError wxThread::Run()
2bda0e17 473{
bf1852e1
VZ
474 wxCriticalSectionLocker lock(m_critsect);
475
476 if ( p_internal->GetState() != STATE_NEW )
477 {
478 // actually, it may be almost any state at all, not only STATE_RUNNING
479 return wxTHREAD_RUNNING;
480 }
481
482 return Resume();
2bda0e17
KB
483}
484
bf1852e1
VZ
485// suspend/resume thread
486// ---------------------
487
488wxThreadError wxThread::Pause()
2bda0e17 489{
bf1852e1
VZ
490 wxCriticalSectionLocker lock(m_critsect);
491
492 return p_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
2bda0e17
KB
493}
494
bf1852e1 495wxThreadError wxThread::Resume()
2bda0e17 496{
bf1852e1
VZ
497 wxCriticalSectionLocker lock(m_critsect);
498
499 return p_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
2bda0e17
KB
500}
501
bf1852e1
VZ
502// stopping thread
503// ---------------
504
505wxThread::ExitCode wxThread::Delete()
2bda0e17 506{
bf1852e1
VZ
507 ExitCode rc = 0;
508
509 // Delete() is always safe to call, so consider all possible states
510 if ( IsPaused() )
511 Resume();
512
513 if ( IsRunning() )
514 {
515 if ( IsMain() )
516 {
517 // set flag for wxIsWaitingForThread()
518 s_waitingForThread = TRUE;
519
520 wxBeginBusyCursor();
521 }
522
523 HANDLE hThread;
524 {
525 wxCriticalSectionLocker lock(m_critsect);
526
527 p_internal->Cancel();
528 hThread = p_internal->GetHandle();
529 }
530
531 // we can't just wait for the thread to terminate because it might be
532 // calling some GUI functions and so it will never terminate before we
533 // process the Windows messages that result from these functions
534 DWORD result;
535 do
536 {
537 result = ::MsgWaitForMultipleObjects
538 (
539 1, // number of objects to wait for
540 &hThread, // the objects
541 FALSE, // don't wait for all objects
542 INFINITE, // no timeout
543 QS_ALLEVENTS // return as soon as there are any events
544 );
545
546 switch ( result )
547 {
548 case 0xFFFFFFFF:
549 // error
550 wxLogSysError(_("Can not wait for thread termination"));
551 Kill();
552 return (ExitCode)-1;
553
554 case WAIT_OBJECT_0:
555 // thread we're waiting for terminated
556 break;
557
558 case WAIT_OBJECT_0 + 1:
559 // new message arrived, process it
560 if ( !wxTheApp->DoMessage() )
561 {
562 // WM_QUIT received: kill the thread
563 Kill();
564
565 return (ExitCode)-1;
566 }
567
568 if ( IsMain() )
569 {
570 // give the thread we're waiting for chance to exit
571 // from the GUI call it might have been in
572 if ( (s_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
573 {
574 wxMutexGuiLeave();
575 }
576 }
577
578 break;
579
580 default:
581 wxFAIL_MSG("unexpected result of MsgWaitForMultipleObject");
582 }
583 } while ( result != WAIT_OBJECT_0 );
584
585 if ( IsMain() )
586 {
587 s_waitingForThread = FALSE;
588
589 wxEndBusyCursor();
590 }
591
592 if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
593 {
594 wxLogLastError("GetExitCodeThread");
595
596 rc = (ExitCode)-1;
597 }
598
599 wxASSERT_MSG( (LPVOID)rc != (LPVOID)STILL_ACTIVE,
600 "thread must be already terminated." );
601
602 ::CloseHandle(hThread);
603 }
604
605 return rc;
2bda0e17
KB
606}
607
bf1852e1 608wxThreadError wxThread::Kill()
2bda0e17 609{
bf1852e1
VZ
610 if ( !IsRunning() )
611 return wxTHREAD_NOT_RUNNING;
612
613 if ( !::TerminateThread(p_internal->GetHandle(), (DWORD)-1) )
614 {
615 wxLogSysError(_("Couldn't terminate thread"));
616
617 return wxTHREAD_MISC_ERROR;
618 }
619
620 delete this;
621
622 return wxTHREAD_NO_ERROR;
2bda0e17
KB
623}
624
bf1852e1 625void wxThread::Exit(void *status)
2bda0e17 626{
bf1852e1 627 delete this;
2bda0e17 628
bf1852e1 629 ::ExitThread((DWORD)status);
2bda0e17 630
bf1852e1
VZ
631 wxFAIL_MSG("Couldn't return from ExitThread()!");
632}
2bda0e17 633
bf1852e1
VZ
634void wxThread::SetPriority(unsigned int prio)
635{
636 wxCriticalSectionLocker lock(m_critsect);
637
638 p_internal->SetPriority(prio);
639}
2bda0e17 640
bf1852e1
VZ
641unsigned int wxThread::GetPriority() const
642{
643 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
2bda0e17 644
bf1852e1 645 return p_internal->GetPriority();
2bda0e17
KB
646}
647
ee4f8c2a 648unsigned long wxThread::GetID() const
2bda0e17 649{
bf1852e1
VZ
650 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
651
652 return (unsigned long)p_internal->GetId();
2bda0e17
KB
653}
654
72fd19a1
JS
655bool wxThread::IsRunning() const
656{
bf1852e1
VZ
657 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
658
659 return p_internal->GetState() == STATE_RUNNING;
72fd19a1
JS
660}
661
662bool wxThread::IsAlive() const
663{
bf1852e1
VZ
664 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
665
666 return (p_internal->GetState() == STATE_RUNNING) ||
667 (p_internal->GetState() == STATE_PAUSED);
72fd19a1
JS
668}
669
8c10faf1 670bool wxThread::TestDestroy()
2bda0e17 671{
bf1852e1
VZ
672 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
673
674 return p_internal->GetState() == STATE_CANCELED;
2bda0e17
KB
675}
676
677wxThread::wxThread()
678{
3222fde2 679 p_internal = new wxThreadInternal();
2bda0e17
KB
680}
681
682wxThread::~wxThread()
683{
3222fde2 684 delete p_internal;
2bda0e17
KB
685}
686
3222fde2
VZ
687// ----------------------------------------------------------------------------
688// Automatic initialization for thread module
689// ----------------------------------------------------------------------------
2bda0e17 690
3222fde2 691class wxThreadModule : public wxModule
a6b0bd49 692{
3222fde2
VZ
693public:
694 virtual bool OnInit();
695 virtual void OnExit();
d524867f 696
3222fde2
VZ
697private:
698 DECLARE_DYNAMIC_CLASS(wxThreadModule)
699};
d524867f
RR
700
701IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
702
3222fde2 703bool wxThreadModule::OnInit()
d524867f 704{
bf1852e1
VZ
705 // allocate TLS index for storing the pointer to the current thread
706 s_tlsThisThread = ::TlsAlloc();
707 if ( s_tlsThisThread == 0xFFFFFFFF )
708 {
709 // in normal circumstances it will only happen if all other
710 // TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other
711 // words, this should never happen
712 wxLogSysError(_("Thread module initialization failed: "
713 "impossible to allocate index in thread "
714 "local storage"));
715
716 return FALSE;
717 }
718
719 // main thread doesn't have associated wxThread object, so store 0 in the
720 // TLS instead
721 if ( !::TlsSetValue(s_tlsThisThread, (LPVOID)0) )
722 {
723 ::TlsFree(s_tlsThisThread);
724 s_tlsThisThread = 0xFFFFFFFF;
725
726 wxLogSysError(_("Thread module initialization failed: "
727 "can not store value in thread local storage"));
728
729 return FALSE;
730 }
731
bee503b0
VZ
732 s_critsectWaitingForGui = new wxCriticalSection();
733
3222fde2
VZ
734 s_critsectGui = new wxCriticalSection();
735 s_critsectGui->Enter();
bee503b0 736
bf1852e1 737 // no error return for GetCurrentThreadId()
bee503b0 738 s_idMainThread = ::GetCurrentThreadId();
3222fde2 739
d524867f
RR
740 return TRUE;
741}
742
3222fde2 743void wxThreadModule::OnExit()
d524867f 744{
bf1852e1
VZ
745 if ( !::TlsFree(s_tlsThisThread) )
746 {
747 wxLogLastError("TlsFree failed.");
748 }
749
3222fde2
VZ
750 if ( s_critsectGui )
751 {
752 s_critsectGui->Leave();
753 delete s_critsectGui;
754 s_critsectGui = NULL;
755 }
bee503b0
VZ
756
757 wxDELETE(s_critsectWaitingForGui);
3222fde2
VZ
758}
759
bee503b0 760// ----------------------------------------------------------------------------
3222fde2
VZ
761// under Windows, these functions are implemented usign a critical section and
762// not a mutex, so the names are a bit confusing
bee503b0
VZ
763// ----------------------------------------------------------------------------
764
3222fde2
VZ
765void WXDLLEXPORT wxMutexGuiEnter()
766{
bee503b0
VZ
767 // this would dead lock everything...
768 wxASSERT_MSG( !wxThread::IsMain(),
769 "main thread doesn't want to block in wxMutexGuiEnter()!" );
770
771 // the order in which we enter the critical sections here is crucial!!
772
773 // set the flag telling to the main thread that we want to do some GUI
774 {
775 wxCriticalSectionLocker enter(*s_critsectWaitingForGui);
776
777 s_nWaitingForGui++;
778 }
779
780 wxWakeUpMainThread();
781
782 // now we may block here because the main thread will soon let us in
783 // (during the next iteration of OnIdle())
784 s_critsectGui->Enter();
3222fde2
VZ
785}
786
787void WXDLLEXPORT wxMutexGuiLeave()
788{
bee503b0
VZ
789 wxCriticalSectionLocker enter(*s_critsectWaitingForGui);
790
791 if ( wxThread::IsMain() )
792 {
793 s_bGuiOwnedByMainThread = FALSE;
794 }
795 else
796 {
797 // decrement the number of waiters now
798 wxASSERT_MSG( s_nWaitingForGui > 0,
799 "calling wxMutexGuiLeave() without entering it first?" );
800
801 s_nWaitingForGui--;
802
803 wxWakeUpMainThread();
804 }
805
806 s_critsectGui->Leave();
807}
808
809void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
810{
811 wxASSERT_MSG( wxThread::IsMain(),
812 "only main thread may call wxMutexGuiLeaveOrEnter()!" );
813
814 wxCriticalSectionLocker enter(*s_critsectWaitingForGui);
815
816 if ( s_nWaitingForGui == 0 )
817 {
818 // no threads are waiting for GUI - so we may acquire the lock without
819 // any danger (but only if we don't already have it)
820 if ( !wxGuiOwnedByMainThread() )
821 {
822 s_critsectGui->Enter();
823
824 s_bGuiOwnedByMainThread = TRUE;
825 }
826 //else: already have it, nothing to do
827 }
828 else
829 {
830 // some threads are waiting, release the GUI lock if we have it
831 if ( wxGuiOwnedByMainThread() )
832 {
833 wxMutexGuiLeave();
834 }
835 //else: some other worker thread is doing GUI
836 }
837}
838
839bool WXDLLEXPORT wxGuiOwnedByMainThread()
840{
841 return s_bGuiOwnedByMainThread;
842}
843
844// wake up the main thread if it's in ::GetMessage()
845void WXDLLEXPORT wxWakeUpMainThread()
846{
847 // sending any message would do - hopefully WM_NULL is harmless enough
848 if ( !::PostThreadMessage(s_idMainThread, WM_NULL, 0, 0) )
849 {
850 // should never happen
851 wxLogLastError("PostThreadMessage(WM_NULL)");
852 }
3222fde2 853}
d524867f 854
bf1852e1
VZ
855bool WXDLLEXPORT wxIsWaitingForThread()
856{
857 return s_waitingForThread;
858}
859
3222fde2 860#endif // wxUSE_THREADS