]> git.saurik.com Git - wxWidgets.git/blob - src/msw/thread.cpp
Added facenames support to wxFont
[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 // this is here to regen the precompiled header in the ide compile otherwise the
17 // compiler crashes in vc5 (nfi why)
18 // For compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20
21 #if defined(__BORLANDC__)
22 #pragma hdrstop
23 #endif
24
25 #ifndef WX_PRECOMP
26 #include "wx/wx.h"
27 #endif
28
29 #include <stdio.h>
30
31 #include <windows.h>
32 #include "wx/module.h"
33 #include "wx/thread.h"
34
35 enum thread_state {
36 STATE_IDLE = 0,
37 STATE_RUNNING,
38 STATE_CANCELED,
39 STATE_EXITED
40 };
41
42 /////////////////////////////////////////////////////////////////////////////
43 // Static variables
44 /////////////////////////////////////////////////////////////////////////////
45
46 static HANDLE p_mainid;
47 wxMutex *wxMainMutex; // controls access to all GUI functions
48
49 /////////////////////////////////////////////////////////////////////////////
50 // Windows implementation
51 /////////////////////////////////////////////////////////////////////////////
52
53 class wxMutexInternal {
54 public:
55 HANDLE p_mutex;
56 };
57
58 wxMutex::wxMutex()
59 {
60 p_internal = new wxMutexInternal;
61 p_internal->p_mutex = CreateMutex(NULL, FALSE, NULL);
62 if ( !p_internal->p_mutex )
63 {
64 wxLogSysError(_("Can not create mutex."));
65 }
66
67 m_locked = 0;
68 }
69
70 wxMutex::~wxMutex()
71 {
72 if (m_locked > 0)
73 wxLogDebug("Warning: freeing a locked mutex (%d locks).", m_locked);
74 CloseHandle(p_internal->p_mutex);
75 }
76
77 wxMutexError wxMutex::Lock()
78 {
79 DWORD ret;
80
81 ret = WaitForSingleObject(p_internal->p_mutex, INFINITE);
82 if (ret == WAIT_ABANDONED)
83 return wxMUTEX_BUSY;
84
85 m_locked++;
86 return wxMUTEX_NO_ERROR;
87 }
88
89 wxMutexError wxMutex::TryLock()
90 {
91 DWORD ret;
92
93 ret = WaitForSingleObject(p_internal->p_mutex, 0);
94 if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
95 return wxMUTEX_BUSY;
96
97 m_locked++;
98 return wxMUTEX_NO_ERROR;
99 }
100
101 wxMutexError wxMutex::Unlock()
102 {
103 if (m_locked > 0)
104 m_locked--;
105
106 BOOL ret = ReleaseMutex(p_internal->p_mutex);
107 if ( ret != 0 )
108 {
109 wxLogSysError(_("Couldn't release a mutex"));
110 return wxMUTEX_MISC_ERROR;
111 }
112
113 return wxMUTEX_NO_ERROR;
114 }
115
116 class wxConditionInternal {
117 public:
118 HANDLE event;
119 int waiters;
120 };
121
122 wxCondition::wxCondition()
123 {
124 p_internal = new wxConditionInternal;
125 p_internal->event = CreateEvent(NULL, FALSE, FALSE, NULL);
126 if ( !p_internal->event )
127 {
128 wxLogSysError(_("Can not create event object."));
129 }
130
131 p_internal->waiters = 0;
132 }
133
134 wxCondition::~wxCondition()
135 {
136 CloseHandle(p_internal->event);
137 }
138
139 void wxCondition::Wait(wxMutex& mutex)
140 {
141 mutex.Unlock();
142 p_internal->waiters++;
143 WaitForSingleObject(p_internal->event, INFINITE);
144 p_internal->waiters--;
145 mutex.Lock();
146 }
147
148 bool wxCondition::Wait(wxMutex& mutex, unsigned long sec,
149 unsigned long nsec)
150 {
151 DWORD ret;
152
153 mutex.Unlock();
154 p_internal->waiters++;
155 ret = WaitForSingleObject(p_internal->event, (sec*1000)+(nsec/1000000));
156 p_internal->waiters--;
157 mutex.Lock();
158
159 return (ret != WAIT_TIMEOUT);
160 }
161
162 void wxCondition::Signal()
163 {
164 SetEvent(p_internal->event);
165 }
166
167 void wxCondition::Broadcast()
168 {
169 int i;
170
171 for (i=0;i<p_internal->waiters;i++)
172 {
173 if ( SetEvent(p_internal->event) == 0 )
174 {
175 wxLogSysError(_("Couldn't change the state of event object."));
176 }
177 }
178 }
179
180 class wxThreadInternal {
181 public:
182 static DWORD WinThreadStart(LPVOID arg);
183
184 HANDLE thread_id;
185 int state;
186 int prio, defer;
187 DWORD tid;
188 };
189
190 DWORD wxThreadInternal::WinThreadStart(LPVOID arg)
191 {
192 wxThread *ptr = (wxThread *)arg;
193 DWORD ret;
194
195 ret = (DWORD)ptr->Entry();
196 ptr->p_internal->state = STATE_EXITED;
197
198 return ret;
199 }
200
201 wxThreadError wxThread::Create()
202 {
203 int prio = p_internal->prio;
204
205 p_internal->thread_id = CreateThread(NULL, 0,
206 (LPTHREAD_START_ROUTINE)wxThreadInternal::WinThreadStart,
207 (void *)this, CREATE_SUSPENDED, &p_internal->tid);
208
209 if ( p_internal->thread_id == NULL )
210 {
211 wxLogSysError(_("Can't create thread"));
212 return wxTHREAD_NO_RESOURCE;
213 }
214
215 int win_prio;
216 if (prio <= 20)
217 win_prio = THREAD_PRIORITY_LOWEST;
218 else if (prio <= 40)
219 win_prio = THREAD_PRIORITY_BELOW_NORMAL;
220 else if (prio <= 60)
221 win_prio = THREAD_PRIORITY_NORMAL;
222 else if (prio <= 80)
223 win_prio = THREAD_PRIORITY_ABOVE_NORMAL;
224 else if (prio <= 100)
225 win_prio = THREAD_PRIORITY_HIGHEST;
226 else
227 {
228 wxFAIL_MSG("invalid value of thread priority parameter");
229 win_prio = THREAD_PRIORITY_NORMAL;
230 }
231
232 SetThreadPriority(p_internal->thread_id, win_prio);
233
234 ResumeThread(p_internal->thread_id);
235 p_internal->state = STATE_RUNNING;
236
237 return wxTHREAD_NO_ERROR;
238 }
239
240 wxThreadError wxThread::Destroy()
241 {
242 if (p_internal->state != STATE_RUNNING)
243 return wxTHREAD_NOT_RUNNING;
244
245 if (p_internal->defer == FALSE)
246 TerminateThread(p_internal->thread_id, 0);
247 else
248 p_internal->state = STATE_CANCELED;
249
250 return wxTHREAD_NO_ERROR;
251 }
252
253 wxThreadError wxThread::Pause()
254 {
255 DWORD nSuspendCount = ::SuspendThread(p_internal->thread_id);
256 if ( nSuspendCount == (DWORD)-1 )
257 {
258 wxLogSysError(_("Can not suspend thread %x"), p_internal->thread_id);
259
260 return wxTHREAD_MISC_ERROR; // no idea what might provoke this error...
261 }
262
263 return wxTHREAD_NO_ERROR;
264 }
265
266 wxThreadError wxThread::Resume()
267 {
268 DWORD nSuspendCount = ::ResumeThread(p_internal->thread_id);
269 if ( nSuspendCount == (DWORD)-1 )
270 {
271 wxLogSysError(_("Can not resume thread %x"), p_internal->thread_id);
272
273 return wxTHREAD_MISC_ERROR; // no idea what might provoke this error...
274 }
275
276 return wxTHREAD_NO_ERROR;
277 }
278
279 void wxThread::Exit(void *status)
280 {
281 p_internal->state = STATE_EXITED;
282 ExitThread((DWORD)status);
283 }
284
285 void wxThread::SetPriority(int prio)
286 {
287 p_internal->prio = prio;
288 }
289
290 int wxThread::GetPriority() const
291 {
292 return p_internal->prio;
293 }
294
295 void wxThread::DeferDestroy(bool on)
296 {
297 p_internal->defer = on;
298 }
299
300 void wxThread::TestDestroy()
301 {
302 if (p_internal->state == STATE_CANCELED)
303 ExitThread(0);
304 }
305
306 void *wxThread::Join()
307 {
308 DWORD exit_code;
309
310 if (p_internal->state == STATE_IDLE)
311 return NULL;
312
313 if (wxThread::IsMain())
314 wxMainMutex->Unlock();
315 WaitForSingleObject(p_internal->thread_id, INFINITE);
316 if (wxThread::IsMain())
317 wxMainMutex->Lock();
318
319 GetExitCodeThread(p_internal->thread_id, &exit_code);
320 CloseHandle(p_internal->thread_id);
321
322 p_internal->state = STATE_IDLE;
323
324 return (void *)exit_code;
325 }
326
327 unsigned long wxThread::GetID() const
328 {
329 return (unsigned long)p_internal->tid;
330 }
331
332 bool wxThread::IsRunning() const
333 {
334 return (p_internal->state == STATE_RUNNING);
335 }
336
337 bool wxThread::IsAlive() const
338 {
339 return (p_internal->state == STATE_RUNNING);
340 }
341
342 bool wxThread::IsMain()
343 {
344 return (GetCurrentThread() == p_mainid);
345 }
346
347 wxThread::wxThread()
348 {
349 p_internal = new wxThreadInternal();
350
351 p_internal->defer = FALSE;
352 p_internal->prio = WXTHREAD_DEFAULT_PRIORITY;
353 p_internal->state = STATE_IDLE;
354 }
355
356 wxThread::~wxThread()
357 {
358 Destroy();
359 Join();
360 delete p_internal;
361 }
362
363 // The default callback just joins the thread and throws away the result.
364 void wxThread::OnExit()
365 {
366 Join();
367 }
368
369 // Automatic initialization
370 class wxThreadModule : public wxModule {
371 DECLARE_DYNAMIC_CLASS(wxThreadModule)
372 public:
373 virtual bool OnInit() {
374 wxMainMutex = new wxMutex();
375 p_mainid = GetCurrentThread();
376 wxMainMutex->Lock();
377 return TRUE;
378 }
379
380 // Global cleanup
381 virtual void OnExit() {
382 wxMainMutex->Unlock();
383 delete wxMainMutex;
384 }
385 };
386
387 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
388
389 void WXDLLEXPORT wxMutexGuiEnter()
390 {
391 wxFAIL_MSG("not implemented");
392 }
393
394 void WXDLLEXPORT wxMutexGuiLeave()
395 {
396 wxFAIL_MSG("not implemented");
397 }