]> git.saurik.com Git - wxWidgets.git/blame - src/msw/thread.cpp
Doc & Symantec C++ fixes
[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
5// Modified by:
6// Created: 04/22/98
7// RCS-ID: $Id$
8// Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998)
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
3222fde2 13 #pragma implementation "thread.h"
2bda0e17
KB
14#endif
15
3222fde2
VZ
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
a3b46648 20// For compilers that support precompilation, includes "wx.h".
2bda0e17
KB
21#include "wx/wxprec.h"
22
23#if defined(__BORLANDC__)
3222fde2 24 #pragma hdrstop
2bda0e17
KB
25#endif
26
27#ifndef WX_PRECOMP
3222fde2 28 #include "wx/wx.h"
2bda0e17
KB
29#endif
30
3222fde2
VZ
31#if wxUSE_THREADS
32
2bda0e17
KB
33#include <stdio.h>
34
35#include <windows.h>
3222fde2 36
2bda0e17
KB
37#include "wx/module.h"
38#include "wx/thread.h"
39
3222fde2
VZ
40enum thread_state
41{
42 STATE_IDLE = 0,
43 STATE_RUNNING,
44 STATE_CANCELED,
45 STATE_EXITED
2bda0e17
KB
46};
47
3222fde2
VZ
48// ----------------------------------------------------------------------------
49// static variables
50// ----------------------------------------------------------------------------
2bda0e17 51
3222fde2
VZ
52// id of the main thread - the one which can call GUI functions without first
53// calling wxMutexGuiEnter()
54static HANDLE s_idMainThread;
2bda0e17 55
3222fde2
VZ
56// critical section which controls access to all GUI functions: any secondary
57// thread (i.e. except the main one) must enter this crit section before doing
58// any GUI calls
59static wxCriticalSection *s_critsectGui;
2bda0e17 60
3222fde2
VZ
61// ============================================================================
62// Windows implementation of thread classes
63// ============================================================================
64
65// ----------------------------------------------------------------------------
66// wxMutex implementation
67// ----------------------------------------------------------------------------
68class wxMutexInternal
69{
2bda0e17 70public:
3222fde2 71 HANDLE p_mutex;
2bda0e17
KB
72};
73
ee4f8c2a 74wxMutex::wxMutex()
2bda0e17 75{
3222fde2
VZ
76 p_internal = new wxMutexInternal;
77 p_internal->p_mutex = CreateMutex(NULL, FALSE, NULL);
78 if ( !p_internal->p_mutex )
79 {
80 wxLogSysError(_("Can not create mutex."));
81 }
a6b0bd49 82
3222fde2 83 m_locked = 0;
2bda0e17
KB
84}
85
ee4f8c2a 86wxMutex::~wxMutex()
2bda0e17 87{
3222fde2
VZ
88 if (m_locked > 0)
89 wxLogDebug("Warning: freeing a locked mutex (%d locks).", m_locked);
90 CloseHandle(p_internal->p_mutex);
2bda0e17
KB
91}
92
ee4f8c2a 93wxMutexError wxMutex::Lock()
2bda0e17 94{
3222fde2
VZ
95 DWORD ret;
96
97 ret = WaitForSingleObject(p_internal->p_mutex, INFINITE);
98 switch ( ret )
99 {
100 case WAIT_ABANDONED:
101 return wxMUTEX_BUSY;
102
103 case WAIT_OBJECT_0:
104 // ok
105 break;
2bda0e17 106
3222fde2
VZ
107 case WAIT_FAILED:
108 wxLogSysError(_("Couldn't acquire a mutex lock"));
109 return wxMUTEX_MISC_ERROR;
2bda0e17 110
3222fde2
VZ
111 case WAIT_TIMEOUT:
112 default:
113 wxFAIL_MSG("impossible return value in wxMutex::Lock");
114 }
115
116 m_locked++;
117 return wxMUTEX_NO_ERROR;
2bda0e17
KB
118}
119
ee4f8c2a 120wxMutexError wxMutex::TryLock()
2bda0e17 121{
3222fde2 122 DWORD ret;
2bda0e17 123
3222fde2
VZ
124 ret = WaitForSingleObject(p_internal->p_mutex, 0);
125 if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
126 return wxMUTEX_BUSY;
2bda0e17 127
3222fde2
VZ
128 m_locked++;
129 return wxMUTEX_NO_ERROR;
2bda0e17
KB
130}
131
ee4f8c2a 132wxMutexError wxMutex::Unlock()
2bda0e17 133{
3222fde2
VZ
134 if (m_locked > 0)
135 m_locked--;
2bda0e17 136
3222fde2
VZ
137 BOOL ret = ReleaseMutex(p_internal->p_mutex);
138 if ( ret == 0 )
139 {
140 wxLogSysError(_("Couldn't release a mutex"));
141 return wxMUTEX_MISC_ERROR;
142 }
a6b0bd49 143
3222fde2 144 return wxMUTEX_NO_ERROR;
2bda0e17
KB
145}
146
3222fde2
VZ
147// ----------------------------------------------------------------------------
148// wxCondition implementation
149// ----------------------------------------------------------------------------
150
151class wxConditionInternal
152{
2bda0e17 153public:
3222fde2
VZ
154 HANDLE event;
155 int waiters;
2bda0e17
KB
156};
157
ee4f8c2a 158wxCondition::wxCondition()
2bda0e17 159{
3222fde2
VZ
160 p_internal = new wxConditionInternal;
161 p_internal->event = CreateEvent(NULL, FALSE, FALSE, NULL);
162 if ( !p_internal->event )
163 {
164 wxLogSysError(_("Can not create event object."));
165 }
a6b0bd49 166
3222fde2 167 p_internal->waiters = 0;
2bda0e17
KB
168}
169
ee4f8c2a 170wxCondition::~wxCondition()
2bda0e17 171{
3222fde2 172 CloseHandle(p_internal->event);
2bda0e17
KB
173}
174
175void wxCondition::Wait(wxMutex& mutex)
176{
3222fde2
VZ
177 mutex.Unlock();
178 p_internal->waiters++;
179 WaitForSingleObject(p_internal->event, INFINITE);
180 p_internal->waiters--;
181 mutex.Lock();
2bda0e17
KB
182}
183
3222fde2
VZ
184bool wxCondition::Wait(wxMutex& mutex,
185 unsigned long sec,
2bda0e17
KB
186 unsigned long nsec)
187{
3222fde2 188 DWORD ret;
2bda0e17 189
3222fde2
VZ
190 mutex.Unlock();
191 p_internal->waiters++;
192 ret = WaitForSingleObject(p_internal->event, (sec*1000)+(nsec/1000000));
193 p_internal->waiters--;
194 mutex.Lock();
2bda0e17 195
3222fde2 196 return (ret != WAIT_TIMEOUT);
2bda0e17
KB
197}
198
ee4f8c2a 199void wxCondition::Signal()
2bda0e17 200{
3222fde2 201 SetEvent(p_internal->event);
2bda0e17
KB
202}
203
ee4f8c2a 204void wxCondition::Broadcast()
2bda0e17 205{
3222fde2 206 int i;
2bda0e17 207
3222fde2 208 for (i=0;i<p_internal->waiters;i++)
a6b0bd49 209 {
3222fde2
VZ
210 if ( SetEvent(p_internal->event) == 0 )
211 {
212 wxLogSysError(_("Couldn't change the state of event object."));
213 }
a6b0bd49 214 }
2bda0e17
KB
215}
216
3222fde2
VZ
217// ----------------------------------------------------------------------------
218// wxCriticalSection implementation
219// ----------------------------------------------------------------------------
220
221class wxCriticalSectionInternal
222{
223public:
224 // init the critical section object
225 wxCriticalSectionInternal()
226 { ::InitializeCriticalSection(&m_data); }
227
228 // implicit cast to the associated data
229 operator CRITICAL_SECTION *() { return &m_data; }
230
231 // free the associated ressources
232 ~wxCriticalSectionInternal()
233 { ::DeleteCriticalSection(&m_data); }
234
235private:
236 CRITICAL_SECTION m_data;
237};
238
239wxCriticalSection::wxCriticalSection()
240{
241 m_critsect = new wxCriticalSectionInternal;
242}
243
244wxCriticalSection::~wxCriticalSection()
245{
246 delete m_critsect;
247}
248
249void wxCriticalSection::Enter()
250{
251 ::EnterCriticalSection(*m_critsect);
252}
253
254void wxCriticalSection::Leave()
255{
256 ::LeaveCriticalSection(*m_critsect);
257}
258
259// ----------------------------------------------------------------------------
260// wxThread implementation
261// ----------------------------------------------------------------------------
262
263class wxThreadInternal
264{
2bda0e17 265public:
3222fde2 266 static DWORD WinThreadStart(LPVOID arg);
2bda0e17 267
3222fde2
VZ
268 HANDLE thread_id;
269 int state;
270 int prio, defer;
271 DWORD tid;
2bda0e17
KB
272};
273
274DWORD wxThreadInternal::WinThreadStart(LPVOID arg)
275{
3222fde2
VZ
276 wxThread *ptr = (wxThread *)arg;
277 DWORD ret;
2bda0e17 278
3222fde2
VZ
279 ret = (DWORD)ptr->Entry();
280 ptr->p_internal->state = STATE_EXITED;
2bda0e17 281
3222fde2 282 return ret;
2bda0e17
KB
283}
284
ee4f8c2a 285wxThreadError wxThread::Create()
2bda0e17 286{
3222fde2
VZ
287 int prio = p_internal->prio;
288
289 p_internal->thread_id = CreateThread(NULL, 0,
290 (LPTHREAD_START_ROUTINE)wxThreadInternal::WinThreadStart,
291 (void *)this, CREATE_SUSPENDED, &p_internal->tid);
292
293 if ( p_internal->thread_id == NULL )
294 {
295 wxLogSysError(_("Can't create thread"));
296 return wxTHREAD_NO_RESOURCE;
297 }
298
299 int win_prio;
300 if (prio <= 20)
301 win_prio = THREAD_PRIORITY_LOWEST;
302 else if (prio <= 40)
303 win_prio = THREAD_PRIORITY_BELOW_NORMAL;
304 else if (prio <= 60)
305 win_prio = THREAD_PRIORITY_NORMAL;
306 else if (prio <= 80)
307 win_prio = THREAD_PRIORITY_ABOVE_NORMAL;
308 else if (prio <= 100)
309 win_prio = THREAD_PRIORITY_HIGHEST;
310 else
311 {
312 wxFAIL_MSG("invalid value of thread priority parameter");
313 win_prio = THREAD_PRIORITY_NORMAL;
314 }
315
316 SetThreadPriority(p_internal->thread_id, win_prio);
317
318 ResumeThread(p_internal->thread_id);
319 p_internal->state = STATE_RUNNING;
320
321 return wxTHREAD_NO_ERROR;
2bda0e17
KB
322}
323
324wxThreadError wxThread::Destroy()
325{
3222fde2
VZ
326 if (p_internal->state != STATE_RUNNING)
327 return wxTHREAD_NOT_RUNNING;
2bda0e17 328
3222fde2
VZ
329 if ( p_internal->defer )
330 // soft termination: just set the flag and wait until the thread
331 // auto terminates
332 p_internal->state = STATE_CANCELED;
333 else
334 // kill the thread
335 TerminateThread(p_internal->thread_id, 0);
2bda0e17 336
3222fde2 337 return wxTHREAD_NO_ERROR;
a6b0bd49
VZ
338}
339
340wxThreadError wxThread::Pause()
341{
342 DWORD nSuspendCount = ::SuspendThread(p_internal->thread_id);
343 if ( nSuspendCount == (DWORD)-1 )
344 {
345 wxLogSysError(_("Can not suspend thread %x"), p_internal->thread_id);
346
347 return wxTHREAD_MISC_ERROR; // no idea what might provoke this error...
348 }
349
350 return wxTHREAD_NO_ERROR;
351}
352
353wxThreadError wxThread::Resume()
354{
355 DWORD nSuspendCount = ::ResumeThread(p_internal->thread_id);
356 if ( nSuspendCount == (DWORD)-1 )
357 {
358 wxLogSysError(_("Can not resume thread %x"), p_internal->thread_id);
359
360 return wxTHREAD_MISC_ERROR; // no idea what might provoke this error...
361 }
362
363 return wxTHREAD_NO_ERROR;
2bda0e17
KB
364}
365
366void wxThread::Exit(void *status)
367{
3222fde2
VZ
368 p_internal->state = STATE_EXITED;
369 ExitThread((DWORD)status);
2bda0e17
KB
370}
371
372void wxThread::SetPriority(int prio)
373{
3222fde2 374 p_internal->prio = prio;
2bda0e17
KB
375}
376
38009d39 377int wxThread::GetPriority() const
2bda0e17 378{
3222fde2 379 return p_internal->prio;
2bda0e17
KB
380}
381
382void wxThread::DeferDestroy(bool on)
383{
3222fde2 384 p_internal->defer = on;
2bda0e17
KB
385}
386
3222fde2 387bool wxThread::TestDestroy()
2bda0e17 388{
3222fde2 389 return p_internal->state == STATE_CANCELED;
2bda0e17
KB
390}
391
392void *wxThread::Join()
393{
3222fde2 394 DWORD exit_code;
2bda0e17 395
3222fde2
VZ
396 if (p_internal->state == STATE_IDLE)
397 return NULL;
2bda0e17 398
3222fde2
VZ
399 if (wxThread::IsMain())
400 s_critsectGui->Leave();
401 WaitForSingleObject(p_internal->thread_id, INFINITE);
402 if (wxThread::IsMain())
403 s_critsectGui->Enter();
2bda0e17 404
3222fde2
VZ
405 GetExitCodeThread(p_internal->thread_id, &exit_code);
406 CloseHandle(p_internal->thread_id);
2bda0e17 407
3222fde2 408 p_internal->state = STATE_IDLE;
2bda0e17 409
3222fde2 410 return (void *)exit_code;
2bda0e17
KB
411}
412
ee4f8c2a 413unsigned long wxThread::GetID() const
2bda0e17 414{
3222fde2 415 return (unsigned long)p_internal->tid;
2bda0e17
KB
416}
417
72fd19a1
JS
418bool wxThread::IsRunning() const
419{
3222fde2 420 return (p_internal->state == STATE_RUNNING);
72fd19a1
JS
421}
422
423bool wxThread::IsAlive() const
424{
3222fde2 425 return (p_internal->state == STATE_RUNNING);
72fd19a1
JS
426}
427
38009d39 428bool wxThread::IsMain()
2bda0e17 429{
3222fde2 430 return (GetCurrentThread() == s_idMainThread);
2bda0e17
KB
431}
432
433wxThread::wxThread()
434{
3222fde2 435 p_internal = new wxThreadInternal();
2bda0e17 436
3222fde2
VZ
437 p_internal->defer = FALSE;
438 p_internal->prio = WXTHREAD_DEFAULT_PRIORITY;
439 p_internal->state = STATE_IDLE;
2bda0e17
KB
440}
441
442wxThread::~wxThread()
443{
3222fde2
VZ
444 Destroy();
445 Join();
446 delete p_internal;
2bda0e17
KB
447}
448
2bda0e17
KB
449void wxThread::OnExit()
450{
2bda0e17
KB
451}
452
3222fde2
VZ
453// ----------------------------------------------------------------------------
454// Automatic initialization for thread module
455// ----------------------------------------------------------------------------
2bda0e17 456
3222fde2 457class wxThreadModule : public wxModule
a6b0bd49 458{
3222fde2
VZ
459public:
460 virtual bool OnInit();
461 virtual void OnExit();
d524867f 462
3222fde2
VZ
463private:
464 DECLARE_DYNAMIC_CLASS(wxThreadModule)
465};
d524867f
RR
466
467IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
468
3222fde2 469bool wxThreadModule::OnInit()
d524867f 470{
3222fde2
VZ
471 s_critsectGui = new wxCriticalSection();
472 s_critsectGui->Enter();
473 s_idMainThread = GetCurrentThread();
474
d524867f
RR
475 return TRUE;
476}
477
3222fde2 478void wxThreadModule::OnExit()
d524867f 479{
3222fde2
VZ
480 if ( s_critsectGui )
481 {
482 s_critsectGui->Leave();
483 delete s_critsectGui;
484 s_critsectGui = NULL;
485 }
486}
487
488// under Windows, these functions are implemented usign a critical section and
489// not a mutex, so the names are a bit confusing
490void WXDLLEXPORT wxMutexGuiEnter()
491{
492 //s_critsectGui->Enter();
493}
494
495void WXDLLEXPORT wxMutexGuiLeave()
496{
497 //s_critsectGui->Leave();
498}
d524867f 499
3222fde2 500#endif // wxUSE_THREADS