]> git.saurik.com Git - wxWidgets.git/blob - src/msw/thread.cpp
wxDataObject and wxDropSource implementations
[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(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