]> git.saurik.com Git - wxWidgets.git/blame - src/msw/thread.cpp
catches program exceptions in release build (VC++ only)
[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
3222fde2
VZ
41enum thread_state
42{
43 STATE_IDLE = 0,
44 STATE_RUNNING,
bee503b0 45 STATE_PAUSED,
3222fde2
VZ
46 STATE_CANCELED,
47 STATE_EXITED
2bda0e17
KB
48};
49
3222fde2
VZ
50// ----------------------------------------------------------------------------
51// static variables
52// ----------------------------------------------------------------------------
2bda0e17 53
3222fde2
VZ
54// id of the main thread - the one which can call GUI functions without first
55// calling wxMutexGuiEnter()
bee503b0
VZ
56static DWORD s_idMainThread = 0;
57
58// if it's FALSE, some secondary thread is holding the GUI lock
59static bool s_bGuiOwnedByMainThread = TRUE;
2bda0e17 60
3222fde2
VZ
61// critical section which controls access to all GUI functions: any secondary
62// thread (i.e. except the main one) must enter this crit section before doing
63// any GUI calls
bee503b0
VZ
64static wxCriticalSection *s_critsectGui = NULL;
65
66// critical section which protects s_nWaitingForGui variable
67static wxCriticalSection *s_critsectWaitingForGui = NULL;
68
69// number of threads waiting for GUI in wxMutexGuiEnter()
70static size_t s_nWaitingForGui = 0;
2bda0e17 71
3222fde2
VZ
72// ============================================================================
73// Windows implementation of thread classes
74// ============================================================================
75
76// ----------------------------------------------------------------------------
77// wxMutex implementation
78// ----------------------------------------------------------------------------
79class wxMutexInternal
80{
2bda0e17 81public:
3222fde2 82 HANDLE p_mutex;
2bda0e17
KB
83};
84
ee4f8c2a 85wxMutex::wxMutex()
2bda0e17 86{
3222fde2
VZ
87 p_internal = new wxMutexInternal;
88 p_internal->p_mutex = CreateMutex(NULL, FALSE, NULL);
89 if ( !p_internal->p_mutex )
90 {
91 wxLogSysError(_("Can not create mutex."));
92 }
a6b0bd49 93
3222fde2 94 m_locked = 0;
2bda0e17
KB
95}
96
ee4f8c2a 97wxMutex::~wxMutex()
2bda0e17 98{
3222fde2
VZ
99 if (m_locked > 0)
100 wxLogDebug("Warning: freeing a locked mutex (%d locks).", m_locked);
101 CloseHandle(p_internal->p_mutex);
2bda0e17
KB
102}
103
ee4f8c2a 104wxMutexError wxMutex::Lock()
2bda0e17 105{
3222fde2
VZ
106 DWORD ret;
107
108 ret = WaitForSingleObject(p_internal->p_mutex, INFINITE);
109 switch ( ret )
110 {
111 case WAIT_ABANDONED:
112 return wxMUTEX_BUSY;
113
114 case WAIT_OBJECT_0:
115 // ok
116 break;
2bda0e17 117
3222fde2
VZ
118 case WAIT_FAILED:
119 wxLogSysError(_("Couldn't acquire a mutex lock"));
120 return wxMUTEX_MISC_ERROR;
2bda0e17 121
3222fde2
VZ
122 case WAIT_TIMEOUT:
123 default:
124 wxFAIL_MSG("impossible return value in wxMutex::Lock");
125 }
126
127 m_locked++;
128 return wxMUTEX_NO_ERROR;
2bda0e17
KB
129}
130
ee4f8c2a 131wxMutexError wxMutex::TryLock()
2bda0e17 132{
3222fde2 133 DWORD ret;
2bda0e17 134
3222fde2
VZ
135 ret = WaitForSingleObject(p_internal->p_mutex, 0);
136 if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
137 return wxMUTEX_BUSY;
2bda0e17 138
3222fde2
VZ
139 m_locked++;
140 return wxMUTEX_NO_ERROR;
2bda0e17
KB
141}
142
ee4f8c2a 143wxMutexError wxMutex::Unlock()
2bda0e17 144{
3222fde2
VZ
145 if (m_locked > 0)
146 m_locked--;
2bda0e17 147
3222fde2
VZ
148 BOOL ret = ReleaseMutex(p_internal->p_mutex);
149 if ( ret == 0 )
150 {
151 wxLogSysError(_("Couldn't release a mutex"));
152 return wxMUTEX_MISC_ERROR;
153 }
a6b0bd49 154
3222fde2 155 return wxMUTEX_NO_ERROR;
2bda0e17
KB
156}
157
3222fde2
VZ
158// ----------------------------------------------------------------------------
159// wxCondition implementation
160// ----------------------------------------------------------------------------
161
162class wxConditionInternal
163{
2bda0e17 164public:
3222fde2
VZ
165 HANDLE event;
166 int waiters;
2bda0e17
KB
167};
168
ee4f8c2a 169wxCondition::wxCondition()
2bda0e17 170{
3222fde2
VZ
171 p_internal = new wxConditionInternal;
172 p_internal->event = CreateEvent(NULL, FALSE, FALSE, NULL);
173 if ( !p_internal->event )
174 {
175 wxLogSysError(_("Can not create event object."));
176 }
a6b0bd49 177
3222fde2 178 p_internal->waiters = 0;
2bda0e17
KB
179}
180
ee4f8c2a 181wxCondition::~wxCondition()
2bda0e17 182{
3222fde2 183 CloseHandle(p_internal->event);
2bda0e17
KB
184}
185
186void wxCondition::Wait(wxMutex& mutex)
187{
3222fde2
VZ
188 mutex.Unlock();
189 p_internal->waiters++;
190 WaitForSingleObject(p_internal->event, INFINITE);
191 p_internal->waiters--;
192 mutex.Lock();
2bda0e17
KB
193}
194
3222fde2
VZ
195bool wxCondition::Wait(wxMutex& mutex,
196 unsigned long sec,
2bda0e17
KB
197 unsigned long nsec)
198{
3222fde2 199 DWORD ret;
2bda0e17 200
3222fde2
VZ
201 mutex.Unlock();
202 p_internal->waiters++;
203 ret = WaitForSingleObject(p_internal->event, (sec*1000)+(nsec/1000000));
204 p_internal->waiters--;
205 mutex.Lock();
2bda0e17 206
3222fde2 207 return (ret != WAIT_TIMEOUT);
2bda0e17
KB
208}
209
ee4f8c2a 210void wxCondition::Signal()
2bda0e17 211{
3222fde2 212 SetEvent(p_internal->event);
2bda0e17
KB
213}
214
ee4f8c2a 215void wxCondition::Broadcast()
2bda0e17 216{
3222fde2 217 int i;
2bda0e17 218
3222fde2 219 for (i=0;i<p_internal->waiters;i++)
a6b0bd49 220 {
3222fde2
VZ
221 if ( SetEvent(p_internal->event) == 0 )
222 {
223 wxLogSysError(_("Couldn't change the state of event object."));
224 }
a6b0bd49 225 }
2bda0e17
KB
226}
227
3222fde2
VZ
228// ----------------------------------------------------------------------------
229// wxCriticalSection implementation
230// ----------------------------------------------------------------------------
231
232class wxCriticalSectionInternal
233{
234public:
235 // init the critical section object
236 wxCriticalSectionInternal()
237 { ::InitializeCriticalSection(&m_data); }
238
239 // implicit cast to the associated data
240 operator CRITICAL_SECTION *() { return &m_data; }
241
242 // free the associated ressources
243 ~wxCriticalSectionInternal()
244 { ::DeleteCriticalSection(&m_data); }
245
246private:
247 CRITICAL_SECTION m_data;
248};
249
250wxCriticalSection::wxCriticalSection()
251{
252 m_critsect = new wxCriticalSectionInternal;
253}
254
255wxCriticalSection::~wxCriticalSection()
256{
257 delete m_critsect;
258}
259
260void wxCriticalSection::Enter()
261{
262 ::EnterCriticalSection(*m_critsect);
263}
264
265void wxCriticalSection::Leave()
266{
267 ::LeaveCriticalSection(*m_critsect);
268}
269
270// ----------------------------------------------------------------------------
271// wxThread implementation
272// ----------------------------------------------------------------------------
273
274class wxThreadInternal
275{
2bda0e17 276public:
bee503b0 277 static DWORD WinThreadStart(wxThread *thread);
2bda0e17 278
bee503b0
VZ
279 HANDLE hThread;
280 thread_state state;
281 int prio, defer;
282 DWORD tid;
2bda0e17
KB
283};
284
bee503b0 285DWORD wxThreadInternal::WinThreadStart(wxThread *thread)
2bda0e17 286{
bee503b0
VZ
287 DWORD ret = (DWORD)thread->Entry();
288 thread->p_internal->state = STATE_EXITED;
289 thread->OnExit();
2bda0e17 290
3222fde2 291 return ret;
2bda0e17
KB
292}
293
ee4f8c2a 294wxThreadError wxThread::Create()
2bda0e17 295{
bee503b0
VZ
296 p_internal->hThread = ::CreateThread
297 (
298 NULL, // default security
299 0, // default stack size
300 (LPTHREAD_START_ROUTINE)
301 wxThreadInternal::WinThreadStart, // entry point
302 (void *)this, // parameter
303 CREATE_SUSPENDED, // flags
304 &p_internal->tid // [out] thread id
305 );
306
307 if ( p_internal->hThread == NULL )
3222fde2
VZ
308 {
309 wxLogSysError(_("Can't create thread"));
310 return wxTHREAD_NO_RESOURCE;
311 }
312
bee503b0 313 int win_prio, prio = p_internal->prio;
3222fde2
VZ
314 if (prio <= 20)
315 win_prio = THREAD_PRIORITY_LOWEST;
316 else if (prio <= 40)
317 win_prio = THREAD_PRIORITY_BELOW_NORMAL;
318 else if (prio <= 60)
319 win_prio = THREAD_PRIORITY_NORMAL;
320 else if (prio <= 80)
321 win_prio = THREAD_PRIORITY_ABOVE_NORMAL;
322 else if (prio <= 100)
323 win_prio = THREAD_PRIORITY_HIGHEST;
324 else
325 {
326 wxFAIL_MSG("invalid value of thread priority parameter");
327 win_prio = THREAD_PRIORITY_NORMAL;
328 }
329
bee503b0
VZ
330 if ( SetThreadPriority(p_internal->hThread, win_prio) == 0 )
331 {
332 wxLogSysError(_("Can't set thread priority"));
333 }
3222fde2 334
bee503b0 335 return Resume();
2bda0e17
KB
336}
337
338wxThreadError wxThread::Destroy()
339{
bee503b0 340 if ( p_internal->state != STATE_RUNNING )
3222fde2 341 return wxTHREAD_NOT_RUNNING;
2bda0e17 342
3222fde2 343 if ( p_internal->defer )
bee503b0 344 {
3222fde2
VZ
345 // soft termination: just set the flag and wait until the thread
346 // auto terminates
347 p_internal->state = STATE_CANCELED;
bee503b0 348 }
3222fde2 349 else
bee503b0 350 {
3222fde2 351 // kill the thread
bee503b0
VZ
352 OnExit();
353 if ( ::TerminateThread(p_internal->hThread, 0) == 0 )
354 {
355 wxLogLastError("TerminateThread");
356 }
357 }
2bda0e17 358
3222fde2 359 return wxTHREAD_NO_ERROR;
a6b0bd49
VZ
360}
361
362wxThreadError wxThread::Pause()
363{
bee503b0 364 DWORD nSuspendCount = ::SuspendThread(p_internal->hThread);
a6b0bd49
VZ
365 if ( nSuspendCount == (DWORD)-1 )
366 {
bee503b0 367 wxLogSysError(_("Can not suspend thread %x"), p_internal->hThread);
a6b0bd49
VZ
368
369 return wxTHREAD_MISC_ERROR; // no idea what might provoke this error...
370 }
371
bee503b0
VZ
372 p_internal->state = STATE_PAUSED;
373
a6b0bd49
VZ
374 return wxTHREAD_NO_ERROR;
375}
376
377wxThreadError wxThread::Resume()
378{
bee503b0 379 DWORD nSuspendCount = ::ResumeThread(p_internal->hThread);
a6b0bd49
VZ
380 if ( nSuspendCount == (DWORD)-1 )
381 {
bee503b0 382 wxLogSysError(_("Can not resume thread %x"), p_internal->hThread);
a6b0bd49
VZ
383
384 return wxTHREAD_MISC_ERROR; // no idea what might provoke this error...
385 }
386
bee503b0
VZ
387 p_internal->state = STATE_RUNNING;
388
a6b0bd49 389 return wxTHREAD_NO_ERROR;
2bda0e17
KB
390}
391
392void wxThread::Exit(void *status)
393{
3222fde2
VZ
394 p_internal->state = STATE_EXITED;
395 ExitThread((DWORD)status);
2bda0e17
KB
396}
397
398void wxThread::SetPriority(int prio)
399{
3222fde2 400 p_internal->prio = prio;
2bda0e17
KB
401}
402
38009d39 403int wxThread::GetPriority() const
2bda0e17 404{
3222fde2 405 return p_internal->prio;
2bda0e17
KB
406}
407
408void wxThread::DeferDestroy(bool on)
409{
3222fde2 410 p_internal->defer = on;
2bda0e17
KB
411}
412
3222fde2 413bool wxThread::TestDestroy()
2bda0e17 414{
3222fde2 415 return p_internal->state == STATE_CANCELED;
2bda0e17
KB
416}
417
418void *wxThread::Join()
419{
3222fde2 420 DWORD exit_code;
2bda0e17 421
3222fde2
VZ
422 if (p_internal->state == STATE_IDLE)
423 return NULL;
2bda0e17 424
bee503b0
VZ
425 // FIXME this dead locks... wxThread class design must be changed
426#if 0
427 WaitForSingleObject(p_internal->hThread, INFINITE);
428#else
429 ::TerminateThread(p_internal->hThread, 0);
430#endif // 0
2bda0e17 431
bee503b0
VZ
432 GetExitCodeThread(p_internal->hThread, &exit_code);
433 CloseHandle(p_internal->hThread);
2bda0e17 434
3222fde2 435 p_internal->state = STATE_IDLE;
2bda0e17 436
3222fde2 437 return (void *)exit_code;
2bda0e17
KB
438}
439
ee4f8c2a 440unsigned long wxThread::GetID() const
2bda0e17 441{
3222fde2 442 return (unsigned long)p_internal->tid;
2bda0e17
KB
443}
444
72fd19a1
JS
445bool wxThread::IsRunning() const
446{
3222fde2 447 return (p_internal->state == STATE_RUNNING);
72fd19a1
JS
448}
449
450bool wxThread::IsAlive() const
451{
3222fde2 452 return (p_internal->state == STATE_RUNNING);
72fd19a1
JS
453}
454
38009d39 455bool wxThread::IsMain()
2bda0e17 456{
bee503b0 457 return ::GetCurrentThreadId() == s_idMainThread;
2bda0e17
KB
458}
459
460wxThread::wxThread()
461{
3222fde2 462 p_internal = new wxThreadInternal();
2bda0e17 463
3222fde2
VZ
464 p_internal->defer = FALSE;
465 p_internal->prio = WXTHREAD_DEFAULT_PRIORITY;
466 p_internal->state = STATE_IDLE;
2bda0e17
KB
467}
468
469wxThread::~wxThread()
470{
3222fde2
VZ
471 Destroy();
472 Join();
473 delete p_internal;
2bda0e17
KB
474}
475
2bda0e17
KB
476void wxThread::OnExit()
477{
2bda0e17
KB
478}
479
3222fde2
VZ
480// ----------------------------------------------------------------------------
481// Automatic initialization for thread module
482// ----------------------------------------------------------------------------
2bda0e17 483
3222fde2 484class wxThreadModule : public wxModule
a6b0bd49 485{
3222fde2
VZ
486public:
487 virtual bool OnInit();
488 virtual void OnExit();
d524867f 489
3222fde2
VZ
490private:
491 DECLARE_DYNAMIC_CLASS(wxThreadModule)
492};
d524867f
RR
493
494IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
495
3222fde2 496bool wxThreadModule::OnInit()
d524867f 497{
bee503b0
VZ
498 s_critsectWaitingForGui = new wxCriticalSection();
499
3222fde2
VZ
500 s_critsectGui = new wxCriticalSection();
501 s_critsectGui->Enter();
bee503b0
VZ
502
503 s_idMainThread = ::GetCurrentThreadId();
3222fde2 504
d524867f
RR
505 return TRUE;
506}
507
3222fde2 508void wxThreadModule::OnExit()
d524867f 509{
3222fde2
VZ
510 if ( s_critsectGui )
511 {
512 s_critsectGui->Leave();
513 delete s_critsectGui;
514 s_critsectGui = NULL;
515 }
bee503b0
VZ
516
517 wxDELETE(s_critsectWaitingForGui);
3222fde2
VZ
518}
519
bee503b0 520// ----------------------------------------------------------------------------
3222fde2
VZ
521// under Windows, these functions are implemented usign a critical section and
522// not a mutex, so the names are a bit confusing
bee503b0
VZ
523// ----------------------------------------------------------------------------
524
3222fde2
VZ
525void WXDLLEXPORT wxMutexGuiEnter()
526{
bee503b0
VZ
527 // this would dead lock everything...
528 wxASSERT_MSG( !wxThread::IsMain(),
529 "main thread doesn't want to block in wxMutexGuiEnter()!" );
530
531 // the order in which we enter the critical sections here is crucial!!
532
533 // set the flag telling to the main thread that we want to do some GUI
534 {
535 wxCriticalSectionLocker enter(*s_critsectWaitingForGui);
536
537 s_nWaitingForGui++;
538 }
539
540 wxWakeUpMainThread();
541
542 // now we may block here because the main thread will soon let us in
543 // (during the next iteration of OnIdle())
544 s_critsectGui->Enter();
3222fde2
VZ
545}
546
547void WXDLLEXPORT wxMutexGuiLeave()
548{
bee503b0
VZ
549 wxCriticalSectionLocker enter(*s_critsectWaitingForGui);
550
551 if ( wxThread::IsMain() )
552 {
553 s_bGuiOwnedByMainThread = FALSE;
554 }
555 else
556 {
557 // decrement the number of waiters now
558 wxASSERT_MSG( s_nWaitingForGui > 0,
559 "calling wxMutexGuiLeave() without entering it first?" );
560
561 s_nWaitingForGui--;
562
563 wxWakeUpMainThread();
564 }
565
566 s_critsectGui->Leave();
567}
568
569void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
570{
571 wxASSERT_MSG( wxThread::IsMain(),
572 "only main thread may call wxMutexGuiLeaveOrEnter()!" );
573
574 wxCriticalSectionLocker enter(*s_critsectWaitingForGui);
575
576 if ( s_nWaitingForGui == 0 )
577 {
578 // no threads are waiting for GUI - so we may acquire the lock without
579 // any danger (but only if we don't already have it)
580 if ( !wxGuiOwnedByMainThread() )
581 {
582 s_critsectGui->Enter();
583
584 s_bGuiOwnedByMainThread = TRUE;
585 }
586 //else: already have it, nothing to do
587 }
588 else
589 {
590 // some threads are waiting, release the GUI lock if we have it
591 if ( wxGuiOwnedByMainThread() )
592 {
593 wxMutexGuiLeave();
594 }
595 //else: some other worker thread is doing GUI
596 }
597}
598
599bool WXDLLEXPORT wxGuiOwnedByMainThread()
600{
601 return s_bGuiOwnedByMainThread;
602}
603
604// wake up the main thread if it's in ::GetMessage()
605void WXDLLEXPORT wxWakeUpMainThread()
606{
607 // sending any message would do - hopefully WM_NULL is harmless enough
608 if ( !::PostThreadMessage(s_idMainThread, WM_NULL, 0, 0) )
609 {
610 // should never happen
611 wxLogLastError("PostThreadMessage(WM_NULL)");
612 }
3222fde2 613}
d524867f 614
3222fde2 615#endif // wxUSE_THREADS