]> git.saurik.com Git - wxWidgets.git/blob - src/msw/thread.cpp
Added OnKeyDown, OnKeyUp.
[wxWidgets.git] / src / msw / thread.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: thread.cpp
3 // Purpose: wxThread Implementation
4 // Author: Original from Wolfram Gloger/Guilhem Lavaux
5 // Modified by: Vadim Zeitlin to make it work :-)
6 // Created: 04/22/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998),
9 // Vadim Zeitlin (1999)
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12
13 #ifdef __GNUG__
14 #pragma implementation "thread.h"
15 #endif
16
17 // ----------------------------------------------------------------------------
18 // headers
19 // ----------------------------------------------------------------------------
20
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
23
24 #if defined(__BORLANDC__)
25 #pragma hdrstop
26 #endif
27
28 #ifndef WX_PRECOMP
29 #include "wx/wx.h"
30 #endif
31
32 #if wxUSE_THREADS
33
34 #include <stdio.h>
35
36 #include <windows.h>
37
38 #include "wx/module.h"
39 #include "wx/thread.h"
40
41 enum thread_state
42 {
43 STATE_IDLE = 0,
44 STATE_RUNNING,
45 STATE_PAUSED,
46 STATE_CANCELED,
47 STATE_EXITED
48 };
49
50 // ----------------------------------------------------------------------------
51 // static variables
52 // ----------------------------------------------------------------------------
53
54 // id of the main thread - the one which can call GUI functions without first
55 // calling wxMutexGuiEnter()
56 static DWORD s_idMainThread = 0;
57
58 // if it's FALSE, some secondary thread is holding the GUI lock
59 static bool s_bGuiOwnedByMainThread = TRUE;
60
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
64 static wxCriticalSection *s_critsectGui = NULL;
65
66 // critical section which protects s_nWaitingForGui variable
67 static wxCriticalSection *s_critsectWaitingForGui = NULL;
68
69 // number of threads waiting for GUI in wxMutexGuiEnter()
70 static size_t s_nWaitingForGui = 0;
71
72 // ============================================================================
73 // Windows implementation of thread classes
74 // ============================================================================
75
76 // ----------------------------------------------------------------------------
77 // wxMutex implementation
78 // ----------------------------------------------------------------------------
79 class wxMutexInternal
80 {
81 public:
82 HANDLE p_mutex;
83 };
84
85 wxMutex::wxMutex()
86 {
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 }
93
94 m_locked = 0;
95 }
96
97 wxMutex::~wxMutex()
98 {
99 if (m_locked > 0)
100 wxLogDebug("Warning: freeing a locked mutex (%d locks).", m_locked);
101 CloseHandle(p_internal->p_mutex);
102 }
103
104 wxMutexError wxMutex::Lock()
105 {
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;
117
118 case WAIT_FAILED:
119 wxLogSysError(_("Couldn't acquire a mutex lock"));
120 return wxMUTEX_MISC_ERROR;
121
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;
129 }
130
131 wxMutexError wxMutex::TryLock()
132 {
133 DWORD ret;
134
135 ret = WaitForSingleObject(p_internal->p_mutex, 0);
136 if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
137 return wxMUTEX_BUSY;
138
139 m_locked++;
140 return wxMUTEX_NO_ERROR;
141 }
142
143 wxMutexError wxMutex::Unlock()
144 {
145 if (m_locked > 0)
146 m_locked--;
147
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 }
154
155 return wxMUTEX_NO_ERROR;
156 }
157
158 // ----------------------------------------------------------------------------
159 // wxCondition implementation
160 // ----------------------------------------------------------------------------
161
162 class wxConditionInternal
163 {
164 public:
165 HANDLE event;
166 int waiters;
167 };
168
169 wxCondition::wxCondition()
170 {
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 }
177
178 p_internal->waiters = 0;
179 }
180
181 wxCondition::~wxCondition()
182 {
183 CloseHandle(p_internal->event);
184 }
185
186 void wxCondition::Wait(wxMutex& mutex)
187 {
188 mutex.Unlock();
189 p_internal->waiters++;
190 WaitForSingleObject(p_internal->event, INFINITE);
191 p_internal->waiters--;
192 mutex.Lock();
193 }
194
195 bool wxCondition::Wait(wxMutex& mutex,
196 unsigned long sec,
197 unsigned long nsec)
198 {
199 DWORD ret;
200
201 mutex.Unlock();
202 p_internal->waiters++;
203 ret = WaitForSingleObject(p_internal->event, (sec*1000)+(nsec/1000000));
204 p_internal->waiters--;
205 mutex.Lock();
206
207 return (ret != WAIT_TIMEOUT);
208 }
209
210 void wxCondition::Signal()
211 {
212 SetEvent(p_internal->event);
213 }
214
215 void wxCondition::Broadcast()
216 {
217 int i;
218
219 for (i=0;i<p_internal->waiters;i++)
220 {
221 if ( SetEvent(p_internal->event) == 0 )
222 {
223 wxLogSysError(_("Couldn't change the state of event object."));
224 }
225 }
226 }
227
228 // ----------------------------------------------------------------------------
229 // wxCriticalSection implementation
230 // ----------------------------------------------------------------------------
231
232 class wxCriticalSectionInternal
233 {
234 public:
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
246 private:
247 CRITICAL_SECTION m_data;
248 };
249
250 wxCriticalSection::wxCriticalSection()
251 {
252 m_critsect = new wxCriticalSectionInternal;
253 }
254
255 wxCriticalSection::~wxCriticalSection()
256 {
257 delete m_critsect;
258 }
259
260 void wxCriticalSection::Enter()
261 {
262 ::EnterCriticalSection(*m_critsect);
263 }
264
265 void wxCriticalSection::Leave()
266 {
267 ::LeaveCriticalSection(*m_critsect);
268 }
269
270 // ----------------------------------------------------------------------------
271 // wxThread implementation
272 // ----------------------------------------------------------------------------
273
274 class wxThreadInternal
275 {
276 public:
277 static DWORD WinThreadStart(wxThread *thread);
278
279 HANDLE hThread;
280 thread_state state;
281 int prio, defer;
282 DWORD tid;
283 };
284
285 DWORD wxThreadInternal::WinThreadStart(wxThread *thread)
286 {
287 DWORD ret = (DWORD)thread->Entry();
288 thread->p_internal->state = STATE_EXITED;
289 thread->OnExit();
290
291 return ret;
292 }
293
294 wxThreadError wxThread::Create()
295 {
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 )
308 {
309 wxLogSysError(_("Can't create thread"));
310 return wxTHREAD_NO_RESOURCE;
311 }
312
313 int win_prio, prio = p_internal->prio;
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
330 if ( SetThreadPriority(p_internal->hThread, win_prio) == 0 )
331 {
332 wxLogSysError(_("Can't set thread priority"));
333 }
334
335 return Resume();
336 }
337
338 wxThreadError wxThread::Destroy()
339 {
340 if ( p_internal->state != STATE_RUNNING )
341 return wxTHREAD_NOT_RUNNING;
342
343 if ( p_internal->defer )
344 {
345 // soft termination: just set the flag and wait until the thread
346 // auto terminates
347 p_internal->state = STATE_CANCELED;
348 }
349 else
350 {
351 // kill the thread
352 OnExit();
353 if ( ::TerminateThread(p_internal->hThread, 0) == 0 )
354 {
355 wxLogLastError("TerminateThread");
356 }
357 }
358
359 return wxTHREAD_NO_ERROR;
360 }
361
362 wxThreadError wxThread::Pause()
363 {
364 DWORD nSuspendCount = ::SuspendThread(p_internal->hThread);
365 if ( nSuspendCount == (DWORD)-1 )
366 {
367 wxLogSysError(_("Can not suspend thread %x"), p_internal->hThread);
368
369 return wxTHREAD_MISC_ERROR; // no idea what might provoke this error...
370 }
371
372 p_internal->state = STATE_PAUSED;
373
374 return wxTHREAD_NO_ERROR;
375 }
376
377 wxThreadError wxThread::Resume()
378 {
379 DWORD nSuspendCount = ::ResumeThread(p_internal->hThread);
380 if ( nSuspendCount == (DWORD)-1 )
381 {
382 wxLogSysError(_("Can not resume thread %x"), p_internal->hThread);
383
384 return wxTHREAD_MISC_ERROR; // no idea what might provoke this error...
385 }
386
387 p_internal->state = STATE_RUNNING;
388
389 return wxTHREAD_NO_ERROR;
390 }
391
392 void wxThread::Exit(void *status)
393 {
394 p_internal->state = STATE_EXITED;
395 ExitThread((DWORD)status);
396 }
397
398 void wxThread::SetPriority(int prio)
399 {
400 p_internal->prio = prio;
401 }
402
403 int wxThread::GetPriority() const
404 {
405 return p_internal->prio;
406 }
407
408 void wxThread::DeferDestroy(bool on)
409 {
410 p_internal->defer = on;
411 }
412
413 bool wxThread::TestDestroy()
414 {
415 return p_internal->state == STATE_CANCELED;
416 }
417
418 void *wxThread::Join()
419 {
420 DWORD exit_code;
421
422 if (p_internal->state == STATE_IDLE)
423 return NULL;
424
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
431
432 GetExitCodeThread(p_internal->hThread, &exit_code);
433 CloseHandle(p_internal->hThread);
434
435 p_internal->state = STATE_IDLE;
436
437 return (void *)exit_code;
438 }
439
440 unsigned long wxThread::GetID() const
441 {
442 return (unsigned long)p_internal->tid;
443 }
444
445 bool wxThread::IsRunning() const
446 {
447 return (p_internal->state == STATE_RUNNING);
448 }
449
450 bool wxThread::IsAlive() const
451 {
452 return (p_internal->state == STATE_RUNNING);
453 }
454
455 bool wxThread::IsMain()
456 {
457 return ::GetCurrentThreadId() == s_idMainThread;
458 }
459
460 wxThread::wxThread()
461 {
462 p_internal = new wxThreadInternal();
463
464 p_internal->defer = FALSE;
465 p_internal->prio = WXTHREAD_DEFAULT_PRIORITY;
466 p_internal->state = STATE_IDLE;
467 }
468
469 wxThread::~wxThread()
470 {
471 Destroy();
472 Join();
473 delete p_internal;
474 }
475
476 void wxThread::OnExit()
477 {
478 }
479
480 // ----------------------------------------------------------------------------
481 // Automatic initialization for thread module
482 // ----------------------------------------------------------------------------
483
484 class wxThreadModule : public wxModule
485 {
486 public:
487 virtual bool OnInit();
488 virtual void OnExit();
489
490 private:
491 DECLARE_DYNAMIC_CLASS(wxThreadModule)
492 };
493
494 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
495
496 bool wxThreadModule::OnInit()
497 {
498 s_critsectWaitingForGui = new wxCriticalSection();
499
500 s_critsectGui = new wxCriticalSection();
501 s_critsectGui->Enter();
502
503 s_idMainThread = ::GetCurrentThreadId();
504
505 return TRUE;
506 }
507
508 void wxThreadModule::OnExit()
509 {
510 if ( s_critsectGui )
511 {
512 s_critsectGui->Leave();
513 delete s_critsectGui;
514 s_critsectGui = NULL;
515 }
516
517 wxDELETE(s_critsectWaitingForGui);
518 }
519
520 // ----------------------------------------------------------------------------
521 // under Windows, these functions are implemented usign a critical section and
522 // not a mutex, so the names are a bit confusing
523 // ----------------------------------------------------------------------------
524
525 void WXDLLEXPORT wxMutexGuiEnter()
526 {
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();
545 }
546
547 void WXDLLEXPORT wxMutexGuiLeave()
548 {
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
569 void 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
599 bool WXDLLEXPORT wxGuiOwnedByMainThread()
600 {
601 return s_bGuiOwnedByMainThread;
602 }
603
604 // wake up the main thread if it's in ::GetMessage()
605 void 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 }
613 }
614
615 #endif // wxUSE_THREADS