]> git.saurik.com Git - wxWidgets.git/blob - src/msw/thread.cpp
no message
[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 m_locked = 0;
63 }
64
65 wxMutex::~wxMutex()
66 {
67 if (m_locked > 0)
68 wxDebugMsg("wxMutex warning: freeing a locked mutex (%d locks)\n", m_locked);
69 CloseHandle(p_internal->p_mutex);
70 }
71
72 wxMutexError wxMutex::Lock()
73 {
74 DWORD ret;
75
76 ret = WaitForSingleObject(p_internal->p_mutex, INFINITE);
77 if (ret == WAIT_ABANDONED)
78 return MUTEX_BUSY;
79
80 m_locked++;
81 return MUTEX_NO_ERROR;
82 }
83
84 wxMutexError wxMutex::TryLock()
85 {
86 DWORD ret;
87
88 ret = WaitForSingleObject(p_internal->p_mutex, 0);
89 if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
90 return MUTEX_BUSY;
91
92 m_locked++;
93 return MUTEX_NO_ERROR;
94 }
95
96 wxMutexError wxMutex::Unlock()
97 {
98 BOOL ret;
99
100 if (m_locked > 0)
101 m_locked--;
102
103 // Why does this have 3 args? The redundant ones removed by JACS
104 // ret = ReleaseMutex(p_internal->p_mutex, 1, NULL);
105 ret = ReleaseMutex(p_internal->p_mutex);
106 return MUTEX_NO_ERROR;
107 }
108
109 class wxConditionInternal {
110 public:
111 HANDLE event;
112 int waiters;
113 };
114
115 wxCondition::wxCondition()
116 {
117 p_internal = new wxConditionInternal;
118 p_internal->event = CreateEvent(NULL, FALSE, FALSE, NULL);
119 p_internal->waiters = 0;
120 }
121
122 wxCondition::~wxCondition()
123 {
124 CloseHandle(p_internal->event);
125 }
126
127 void wxCondition::Wait(wxMutex& mutex)
128 {
129 mutex.Unlock();
130 p_internal->waiters++;
131 WaitForSingleObject(p_internal->event, INFINITE);
132 p_internal->waiters--;
133 mutex.Lock();
134 }
135
136 bool wxCondition::Wait(wxMutex& mutex, unsigned long sec,
137 unsigned long nsec)
138 {
139 DWORD ret;
140
141 mutex.Unlock();
142 p_internal->waiters++;
143 ret = WaitForSingleObject(p_internal->event, (sec*1000)+(nsec/1000000));
144 p_internal->waiters--;
145 mutex.Lock();
146
147 return (ret != WAIT_TIMEOUT);
148 }
149
150 void wxCondition::Signal()
151 {
152 SetEvent(p_internal->event);
153 }
154
155 void wxCondition::Broadcast()
156 {
157 int i;
158
159 for (i=0;i<p_internal->waiters;i++)
160 SetEvent(p_internal->event);
161 }
162
163 class wxThreadInternal {
164 public:
165 static DWORD WinThreadStart(LPVOID arg);
166
167 HANDLE thread_id;
168 int state;
169 int prio, defer;
170 DWORD tid;
171 };
172
173 DWORD wxThreadInternal::WinThreadStart(LPVOID arg)
174 {
175 wxThread *ptr = (wxThread *)arg;
176 DWORD ret;
177
178 ret = (DWORD)ptr->Entry();
179 ptr->p_internal->state = STATE_EXITED;
180
181 return ret;
182 }
183
184 wxThreadError wxThread::Create()
185 {
186 int win_prio, prio = p_internal->prio;
187
188 p_internal->thread_id = CreateThread(NULL, 0,
189 (LPTHREAD_START_ROUTINE)wxThreadInternal::WinThreadStart,
190 (void *)this, CREATE_SUSPENDED, &p_internal->tid);
191 if (p_internal->thread_id == NULL) {
192 printf("Error = %d\n", GetLastError());
193 return THREAD_NO_RESOURCE;
194 }
195
196 if (prio <= 20)
197 win_prio = THREAD_PRIORITY_LOWEST;
198 else if (prio <= 40)
199 win_prio = THREAD_PRIORITY_BELOW_NORMAL;
200 else if (prio <= 60)
201 win_prio = THREAD_PRIORITY_NORMAL;
202 else if (prio <= 80)
203 win_prio = THREAD_PRIORITY_ABOVE_NORMAL;
204 else if (prio <= 100)
205 win_prio = THREAD_PRIORITY_HIGHEST;
206
207 SetThreadPriority(p_internal->thread_id, win_prio);
208
209 ResumeThread(p_internal->thread_id);
210 p_internal->state = STATE_RUNNING;
211
212 return THREAD_NO_ERROR;
213 }
214
215 wxThreadError wxThread::Destroy()
216 {
217 if (p_internal->state != STATE_RUNNING)
218 return THREAD_NOT_RUNNING;
219
220 if (p_internal->defer == FALSE)
221 TerminateThread(p_internal->thread_id, 0);
222 else
223 p_internal->state = STATE_CANCELED;
224
225 return THREAD_NO_ERROR;
226 }
227
228 void wxThread::Exit(void *status)
229 {
230 p_internal->state = STATE_EXITED;
231 ExitThread((DWORD)status);
232 }
233
234 void wxThread::SetPriority(int prio)
235 {
236 p_internal->prio = prio;
237 }
238
239 int wxThread::GetPriority() const
240 {
241 return p_internal->prio;
242 }
243
244 void wxThread::DeferDestroy(bool on)
245 {
246 p_internal->defer = on;
247 }
248
249 void wxThread::TestDestroy()
250 {
251 if (p_internal->state == STATE_CANCELED)
252 ExitThread(0);
253 }
254
255 void *wxThread::Join()
256 {
257 DWORD exit_code;
258
259 if (p_internal->state == STATE_IDLE)
260 return NULL;
261
262 if (wxThread::IsMain())
263 wxMainMutex.Unlock();
264 WaitForSingleObject(p_internal->thread_id, INFINITE);
265 if (wxThread::IsMain())
266 wxMainMutex.Lock();
267
268 GetExitCodeThread(p_internal->thread_id, &exit_code);
269 CloseHandle(p_internal->thread_id);
270
271 p_internal->state = STATE_IDLE;
272
273 return (void *)exit_code;
274 }
275
276 unsigned long wxThread::GetID() const
277 {
278 return (unsigned long)p_internal->tid;
279 }
280
281 bool wxThread::IsMain()
282 {
283 return (GetCurrentThread() == p_mainid);
284 }
285
286 wxThread::wxThread()
287 {
288 p_internal = new wxThreadInternal();
289
290 p_internal->defer = FALSE;
291 p_internal->prio = WXTHREAD_DEFAULT_PRIORITY;
292 p_internal->state = STATE_IDLE;
293 }
294
295 wxThread::~wxThread()
296 {
297 Destroy();
298 Join();
299 delete p_internal;
300 }
301
302 // The default callback just joins the thread and throws away the result.
303 void wxThread::OnExit()
304 {
305 Join();
306 }
307
308 // Automatic initialization
309 class wxThreadModule : public wxModule {
310 DECLARE_DYNAMIC_CLASS(wxThreadModule)
311 public:
312 virtual bool OnInit() {
313 p_mainid = GetCurrentThread();
314 wxMainMutex.Lock();
315 return TRUE;
316 }
317
318 // Global cleanup
319 virtual void OnExit() {
320 wxMainMutex.Unlock();
321 }
322 };
323
324 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
325