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