]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/thread.cpp
corrected a crash in wxDialog::Show() which would happen if there was a
[wxWidgets.git] / src / msw / thread.cpp
... / ...
CommitLineData
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
35enum thread_state {
36 STATE_IDLE = 0,
37 STATE_RUNNING,
38 STATE_CANCELED,
39 STATE_EXITED
40};
41
42/////////////////////////////////////////////////////////////////////////////
43// Static variables
44/////////////////////////////////////////////////////////////////////////////
45
46static HANDLE p_mainid;
47wxMutex *wxMainMutex; // controls access to all GUI functions
48
49/////////////////////////////////////////////////////////////////////////////
50// Windows implementation
51/////////////////////////////////////////////////////////////////////////////
52
53class wxMutexInternal {
54public:
55 HANDLE p_mutex;
56};
57
58wxMutex::wxMutex()
59{
60 p_internal = new wxMutexInternal;
61 p_internal->p_mutex = CreateMutex(NULL, FALSE, NULL);
62 m_locked = 0;
63}
64
65wxMutex::~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
72wxMutexError 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
84wxMutexError 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
96wxMutexError 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
109class wxConditionInternal {
110public:
111 HANDLE event;
112 int waiters;
113};
114
115wxCondition::wxCondition()
116{
117 p_internal = new wxConditionInternal;
118 p_internal->event = CreateEvent(NULL, FALSE, FALSE, NULL);
119 p_internal->waiters = 0;
120}
121
122wxCondition::~wxCondition()
123{
124 CloseHandle(p_internal->event);
125}
126
127void 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
136bool 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
150void wxCondition::Signal()
151{
152 SetEvent(p_internal->event);
153}
154
155void wxCondition::Broadcast()
156{
157 int i;
158
159 for (i=0;i<p_internal->waiters;i++)
160 SetEvent(p_internal->event);
161}
162
163class wxThreadInternal {
164public:
165 static DWORD WinThreadStart(LPVOID arg);
166
167 HANDLE thread_id;
168 int state;
169 int prio, defer;
170 DWORD tid;
171};
172
173DWORD 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
184wxThreadError 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
215wxThreadError 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
228void wxThread::Exit(void *status)
229{
230 p_internal->state = STATE_EXITED;
231 ExitThread((DWORD)status);
232}
233
234void wxThread::SetPriority(int prio)
235{
236 p_internal->prio = prio;
237}
238
239int wxThread::GetPriority() const
240{
241 return p_internal->prio;
242}
243
244void wxThread::DeferDestroy(bool on)
245{
246 p_internal->defer = on;
247}
248
249void wxThread::TestDestroy()
250{
251 if (p_internal->state == STATE_CANCELED)
252 ExitThread(0);
253}
254
255void *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
276unsigned long wxThread::GetID() const
277{
278 return (unsigned long)p_internal->tid;
279}
280
281bool wxThread::IsMain()
282{
283 return (GetCurrentThread() == p_mainid);
284}
285
286wxThread::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
295wxThread::~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.
303void wxThread::OnExit()
304{
305 Join();
306}
307
308// Automatic initialization
309class wxThreadModule : public wxModule {
310 DECLARE_DYNAMIC_CLASS(wxThreadModule)
311public:
312 virtual bool OnInit() {
313 wxMainMutex = new wxMutex();
314 p_mainid = GetCurrentThread();
315 wxMainMutex->Lock();
316 return TRUE;
317 }
318
319 // Global cleanup
320 virtual void OnExit() {
321 wxMainMutex->Unlock();
322 delete wxMainMutex;
323 }
324};
325
326IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
327