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