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