]> git.saurik.com Git - wxWidgets.git/blame - src/msw/thread.cpp
mac support as stubs added
[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__
13#pragma implementation "thread.h"
14#endif
15
78322206
UU
16// this is here to regen the precompiled header in the ide compile otherwise the
17// compiler crashes in vc5 (nfi why)
a3b46648 18// For compilers that support precompilation, includes "wx.h".
2bda0e17
KB
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
35enum thread_state {
36 STATE_IDLE = 0,
37 STATE_RUNNING,
38 STATE_CANCELED,
39 STATE_EXITED
40};
41
42/////////////////////////////////////////////////////////////////////////////
43// Static variables
44/////////////////////////////////////////////////////////////////////////////
45
46static HANDLE p_mainid;
6773ae19 47wxMutex *wxMainMutex; // controls access to all GUI functions
2bda0e17
KB
48
49/////////////////////////////////////////////////////////////////////////////
50// Windows implementation
51/////////////////////////////////////////////////////////////////////////////
52
53class wxMutexInternal {
54public:
55 HANDLE p_mutex;
56};
57
ee4f8c2a 58wxMutex::wxMutex()
2bda0e17
KB
59{
60 p_internal = new wxMutexInternal;
61 p_internal->p_mutex = CreateMutex(NULL, FALSE, NULL);
a6b0bd49
VZ
62 if ( !p_internal->p_mutex )
63 {
64 wxLogSysError(_("Can not create mutex."));
65 }
66
2bda0e17
KB
67 m_locked = 0;
68}
69
ee4f8c2a 70wxMutex::~wxMutex()
2bda0e17 71{
b89156b5 72 if (m_locked > 0)
a6b0bd49 73 wxLogDebug("Warning: freeing a locked mutex (%d locks).", m_locked);
2bda0e17
KB
74 CloseHandle(p_internal->p_mutex);
75}
76
ee4f8c2a 77wxMutexError wxMutex::Lock()
2bda0e17
KB
78{
79 DWORD ret;
80
81 ret = WaitForSingleObject(p_internal->p_mutex, INFINITE);
82 if (ret == WAIT_ABANDONED)
a6b0bd49 83 return wxMUTEX_BUSY;
2bda0e17
KB
84
85 m_locked++;
a6b0bd49 86 return wxMUTEX_NO_ERROR;
2bda0e17
KB
87}
88
ee4f8c2a 89wxMutexError wxMutex::TryLock()
2bda0e17
KB
90{
91 DWORD ret;
92
93 ret = WaitForSingleObject(p_internal->p_mutex, 0);
94 if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
a6b0bd49 95 return wxMUTEX_BUSY;
2bda0e17
KB
96
97 m_locked++;
a6b0bd49 98 return wxMUTEX_NO_ERROR;
2bda0e17
KB
99}
100
ee4f8c2a 101wxMutexError wxMutex::Unlock()
2bda0e17 102{
2bda0e17
KB
103 if (m_locked > 0)
104 m_locked--;
105
a6b0bd49
VZ
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;
2bda0e17
KB
114}
115
116class wxConditionInternal {
117public:
118 HANDLE event;
119 int waiters;
120};
121
ee4f8c2a 122wxCondition::wxCondition()
2bda0e17
KB
123{
124 p_internal = new wxConditionInternal;
125 p_internal->event = CreateEvent(NULL, FALSE, FALSE, NULL);
a6b0bd49
VZ
126 if ( !p_internal->event )
127 {
128 wxLogSysError(_("Can not create event object."));
129 }
130
2bda0e17
KB
131 p_internal->waiters = 0;
132}
133
ee4f8c2a 134wxCondition::~wxCondition()
2bda0e17
KB
135{
136 CloseHandle(p_internal->event);
137}
138
139void 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
148bool 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
ee4f8c2a 162void wxCondition::Signal()
2bda0e17
KB
163{
164 SetEvent(p_internal->event);
165}
166
ee4f8c2a 167void wxCondition::Broadcast()
2bda0e17
KB
168{
169 int i;
170
171 for (i=0;i<p_internal->waiters;i++)
a6b0bd49
VZ
172 {
173 if ( SetEvent(p_internal->event) == 0 )
174 {
175 wxLogSysError(_("Couldn't change the state of event object."));
176 }
177 }
2bda0e17
KB
178}
179
180class wxThreadInternal {
181public:
182 static DWORD WinThreadStart(LPVOID arg);
183
184 HANDLE thread_id;
185 int state;
186 int prio, defer;
187 DWORD tid;
188};
189
190DWORD 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
ee4f8c2a 201wxThreadError wxThread::Create()
2bda0e17 202{
a6b0bd49 203 int prio = p_internal->prio;
2bda0e17
KB
204
205 p_internal->thread_id = CreateThread(NULL, 0,
206 (LPTHREAD_START_ROUTINE)wxThreadInternal::WinThreadStart,
207 (void *)this, CREATE_SUSPENDED, &p_internal->tid);
a6b0bd49
VZ
208
209 if ( p_internal->thread_id == NULL )
210 {
211 wxLogSysError(_("Can't create thread"));
212 return wxTHREAD_NO_RESOURCE;
2bda0e17
KB
213 }
214
a6b0bd49 215 int win_prio;
2bda0e17
KB
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;
a6b0bd49
VZ
226 else
227 {
228 wxFAIL_MSG("invalid value of thread priority parameter");
229 win_prio = THREAD_PRIORITY_NORMAL;
230 }
2bda0e17
KB
231
232 SetThreadPriority(p_internal->thread_id, win_prio);
233
234 ResumeThread(p_internal->thread_id);
235 p_internal->state = STATE_RUNNING;
236
a6b0bd49 237 return wxTHREAD_NO_ERROR;
2bda0e17
KB
238}
239
240wxThreadError wxThread::Destroy()
241{
242 if (p_internal->state != STATE_RUNNING)
a6b0bd49 243 return wxTHREAD_NOT_RUNNING;
2bda0e17
KB
244
245 if (p_internal->defer == FALSE)
246 TerminateThread(p_internal->thread_id, 0);
247 else
248 p_internal->state = STATE_CANCELED;
249
a6b0bd49
VZ
250 return wxTHREAD_NO_ERROR;
251}
252
253wxThreadError 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
266wxThreadError 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;
2bda0e17
KB
277}
278
279void wxThread::Exit(void *status)
280{
281 p_internal->state = STATE_EXITED;
282 ExitThread((DWORD)status);
283}
284
285void wxThread::SetPriority(int prio)
286{
287 p_internal->prio = prio;
288}
289
38009d39 290int wxThread::GetPriority() const
2bda0e17
KB
291{
292 return p_internal->prio;
293}
294
295void wxThread::DeferDestroy(bool on)
296{
297 p_internal->defer = on;
298}
299
300void wxThread::TestDestroy()
301{
302 if (p_internal->state == STATE_CANCELED)
303 ExitThread(0);
304}
305
306void *wxThread::Join()
307{
308 DWORD exit_code;
309
310 if (p_internal->state == STATE_IDLE)
311 return NULL;
312
313 if (wxThread::IsMain())
6773ae19 314 wxMainMutex->Unlock();
2bda0e17
KB
315 WaitForSingleObject(p_internal->thread_id, INFINITE);
316 if (wxThread::IsMain())
6773ae19 317 wxMainMutex->Lock();
2bda0e17
KB
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
ee4f8c2a 327unsigned long wxThread::GetID() const
2bda0e17
KB
328{
329 return (unsigned long)p_internal->tid;
330}
331
72fd19a1
JS
332bool wxThread::IsRunning() const
333{
334 return (p_internal->state == STATE_RUNNING);
335}
336
337bool wxThread::IsAlive() const
338{
339 return (p_internal->state == STATE_RUNNING);
340}
341
38009d39 342bool wxThread::IsMain()
2bda0e17
KB
343{
344 return (GetCurrentThread() == p_mainid);
345}
346
347wxThread::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
356wxThread::~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.
364void wxThread::OnExit()
365{
366 Join();
367}
368
369// Automatic initialization
370class wxThreadModule : public wxModule {
371 DECLARE_DYNAMIC_CLASS(wxThreadModule)
372public:
ee4f8c2a 373 virtual bool OnInit() {
6773ae19 374 wxMainMutex = new wxMutex();
2bda0e17 375 p_mainid = GetCurrentThread();
6773ae19 376 wxMainMutex->Lock();
2bda0e17
KB
377 return TRUE;
378 }
379
380 // Global cleanup
ee4f8c2a 381 virtual void OnExit() {
6773ae19
GL
382 wxMainMutex->Unlock();
383 delete wxMainMutex;
2bda0e17
KB
384 }
385};
386
387IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
388
a6b0bd49
VZ
389void WXDLLEXPORT wxMutexGuiEnter()
390{
391 wxFAIL_MSG("not implemented");
392}
393
394void WXDLLEXPORT wxMutexGuiLeave()
395{
396 wxFAIL_MSG("not implemented");
397}