]> git.saurik.com Git - wxWidgets.git/blob - src/msw/thread.cpp
Thread fixes (but they still don't work at all...)
[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:
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__
13 #pragma implementation "thread.h"
14 #endif
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #if defined(__BORLANDC__)
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/wx.h"
29 #endif
30
31 #if wxUSE_THREADS
32
33 #include <stdio.h>
34
35 #include <windows.h>
36
37 #include "wx/module.h"
38 #include "wx/thread.h"
39
40 enum thread_state
41 {
42 STATE_IDLE = 0,
43 STATE_RUNNING,
44 STATE_CANCELED,
45 STATE_EXITED
46 };
47
48 // ----------------------------------------------------------------------------
49 // static variables
50 // ----------------------------------------------------------------------------
51
52 // id of the main thread - the one which can call GUI functions without first
53 // calling wxMutexGuiEnter()
54 static HANDLE s_idMainThread;
55
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
59 static wxCriticalSection *s_critsectGui;
60
61 // ============================================================================
62 // Windows implementation of thread classes
63 // ============================================================================
64
65 // ----------------------------------------------------------------------------
66 // wxMutex implementation
67 // ----------------------------------------------------------------------------
68 class wxMutexInternal
69 {
70 public:
71 HANDLE p_mutex;
72 };
73
74 wxMutex::wxMutex()
75 {
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 }
82
83 m_locked = 0;
84 }
85
86 wxMutex::~wxMutex()
87 {
88 if (m_locked > 0)
89 wxLogDebug("Warning: freeing a locked mutex (%d locks).", m_locked);
90 CloseHandle(p_internal->p_mutex);
91 }
92
93 wxMutexError wxMutex::Lock()
94 {
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;
106
107 case WAIT_FAILED:
108 wxLogSysError(_("Couldn't acquire a mutex lock"));
109 return wxMUTEX_MISC_ERROR;
110
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;
118 }
119
120 wxMutexError wxMutex::TryLock()
121 {
122 DWORD ret;
123
124 ret = WaitForSingleObject(p_internal->p_mutex, 0);
125 if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
126 return wxMUTEX_BUSY;
127
128 m_locked++;
129 return wxMUTEX_NO_ERROR;
130 }
131
132 wxMutexError wxMutex::Unlock()
133 {
134 if (m_locked > 0)
135 m_locked--;
136
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 }
143
144 return wxMUTEX_NO_ERROR;
145 }
146
147 // ----------------------------------------------------------------------------
148 // wxCondition implementation
149 // ----------------------------------------------------------------------------
150
151 class wxConditionInternal
152 {
153 public:
154 HANDLE event;
155 int waiters;
156 };
157
158 wxCondition::wxCondition()
159 {
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 }
166
167 p_internal->waiters = 0;
168 }
169
170 wxCondition::~wxCondition()
171 {
172 CloseHandle(p_internal->event);
173 }
174
175 void wxCondition::Wait(wxMutex& mutex)
176 {
177 mutex.Unlock();
178 p_internal->waiters++;
179 WaitForSingleObject(p_internal->event, INFINITE);
180 p_internal->waiters--;
181 mutex.Lock();
182 }
183
184 bool wxCondition::Wait(wxMutex& mutex,
185 unsigned long sec,
186 unsigned long nsec)
187 {
188 DWORD ret;
189
190 mutex.Unlock();
191 p_internal->waiters++;
192 ret = WaitForSingleObject(p_internal->event, (sec*1000)+(nsec/1000000));
193 p_internal->waiters--;
194 mutex.Lock();
195
196 return (ret != WAIT_TIMEOUT);
197 }
198
199 void wxCondition::Signal()
200 {
201 SetEvent(p_internal->event);
202 }
203
204 void wxCondition::Broadcast()
205 {
206 int i;
207
208 for (i=0;i<p_internal->waiters;i++)
209 {
210 if ( SetEvent(p_internal->event) == 0 )
211 {
212 wxLogSysError(_("Couldn't change the state of event object."));
213 }
214 }
215 }
216
217 // ----------------------------------------------------------------------------
218 // wxCriticalSection implementation
219 // ----------------------------------------------------------------------------
220
221 class wxCriticalSectionInternal
222 {
223 public:
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
235 private:
236 CRITICAL_SECTION m_data;
237 };
238
239 wxCriticalSection::wxCriticalSection()
240 {
241 m_critsect = new wxCriticalSectionInternal;
242 }
243
244 wxCriticalSection::~wxCriticalSection()
245 {
246 delete m_critsect;
247 }
248
249 void wxCriticalSection::Enter()
250 {
251 ::EnterCriticalSection(*m_critsect);
252 }
253
254 void wxCriticalSection::Leave()
255 {
256 ::LeaveCriticalSection(*m_critsect);
257 }
258
259 // ----------------------------------------------------------------------------
260 // wxThread implementation
261 // ----------------------------------------------------------------------------
262
263 class wxThreadInternal
264 {
265 public:
266 static DWORD WinThreadStart(LPVOID arg);
267
268 HANDLE thread_id;
269 int state;
270 int prio, defer;
271 DWORD tid;
272 };
273
274 DWORD wxThreadInternal::WinThreadStart(LPVOID arg)
275 {
276 wxThread *ptr = (wxThread *)arg;
277 DWORD ret;
278
279 ret = (DWORD)ptr->Entry();
280 ptr->p_internal->state = STATE_EXITED;
281
282 return ret;
283 }
284
285 wxThreadError wxThread::Create()
286 {
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;
322 }
323
324 wxThreadError wxThread::Destroy()
325 {
326 if (p_internal->state != STATE_RUNNING)
327 return wxTHREAD_NOT_RUNNING;
328
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);
336
337 return wxTHREAD_NO_ERROR;
338 }
339
340 wxThreadError 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
353 wxThreadError 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;
364 }
365
366 void wxThread::Exit(void *status)
367 {
368 p_internal->state = STATE_EXITED;
369 ExitThread((DWORD)status);
370 }
371
372 void wxThread::SetPriority(int prio)
373 {
374 p_internal->prio = prio;
375 }
376
377 int wxThread::GetPriority() const
378 {
379 return p_internal->prio;
380 }
381
382 void wxThread::DeferDestroy(bool on)
383 {
384 p_internal->defer = on;
385 }
386
387 bool wxThread::TestDestroy()
388 {
389 return p_internal->state == STATE_CANCELED;
390 }
391
392 void *wxThread::Join()
393 {
394 DWORD exit_code;
395
396 if (p_internal->state == STATE_IDLE)
397 return NULL;
398
399 if (wxThread::IsMain())
400 s_critsectGui->Leave();
401 WaitForSingleObject(p_internal->thread_id, INFINITE);
402 if (wxThread::IsMain())
403 s_critsectGui->Enter();
404
405 GetExitCodeThread(p_internal->thread_id, &exit_code);
406 CloseHandle(p_internal->thread_id);
407
408 p_internal->state = STATE_IDLE;
409
410 return (void *)exit_code;
411 }
412
413 unsigned long wxThread::GetID() const
414 {
415 return (unsigned long)p_internal->tid;
416 }
417
418 bool wxThread::IsRunning() const
419 {
420 return (p_internal->state == STATE_RUNNING);
421 }
422
423 bool wxThread::IsAlive() const
424 {
425 return (p_internal->state == STATE_RUNNING);
426 }
427
428 bool wxThread::IsMain()
429 {
430 return (GetCurrentThread() == s_idMainThread);
431 }
432
433 wxThread::wxThread()
434 {
435 p_internal = new wxThreadInternal();
436
437 p_internal->defer = FALSE;
438 p_internal->prio = WXTHREAD_DEFAULT_PRIORITY;
439 p_internal->state = STATE_IDLE;
440 }
441
442 wxThread::~wxThread()
443 {
444 Destroy();
445 Join();
446 delete p_internal;
447 }
448
449 void wxThread::OnExit()
450 {
451 }
452
453 // ----------------------------------------------------------------------------
454 // Automatic initialization for thread module
455 // ----------------------------------------------------------------------------
456
457 class wxThreadModule : public wxModule
458 {
459 public:
460 virtual bool OnInit();
461 virtual void OnExit();
462
463 private:
464 DECLARE_DYNAMIC_CLASS(wxThreadModule)
465 };
466
467 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
468
469 bool wxThreadModule::OnInit()
470 {
471 s_critsectGui = new wxCriticalSection();
472 s_critsectGui->Enter();
473 s_idMainThread = GetCurrentThread();
474
475 return TRUE;
476 }
477
478 void wxThreadModule::OnExit()
479 {
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
490 void WXDLLEXPORT wxMutexGuiEnter()
491 {
492 //s_critsectGui->Enter();
493 }
494
495 void WXDLLEXPORT wxMutexGuiLeave()
496 {
497 //s_critsectGui->Leave();
498 }
499
500 #endif // wxUSE_THREADS