]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/threadpsx.cpp
event/leave events
[wxWidgets.git] / src / gtk1 / threadpsx.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: threadpsx.cpp
3 // Purpose: wxThread (Posix) 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 #ifdef __GNUG__
12 #pragma implementation "thread.h"
13 #endif
14
15 #include <stdio.h>
16 #include <unistd.h>
17 #include <sched.h>
18 #include <pthread.h>
19 #include <errno.h>
20 #include "wx/thread.h"
21 #include "wx/module.h"
22 #include "wx/utils.h"
23
24 enum thread_state {
25 STATE_IDLE = 0,
26 STATE_RUNNING,
27 STATE_CANCELED,
28 STATE_EXITED
29 };
30
31 /////////////////////////////////////////////////////////////////////////////
32 // Static variables
33 /////////////////////////////////////////////////////////////////////////////
34
35 static pthread_t p_mainid;
36 wxMutex wxMainMutex; // controls access to all GUI functions
37
38 /////////////////////////////////////////////////////////////////////////////
39 // GUI thread manager
40 /////////////////////////////////////////////////////////////////////////////
41 #include "threadgui.inc"
42
43 /////////////////////////////////////////////////////////////////////////////
44 // wxThread: Posix Thread implementation (Mutex)
45 /////////////////////////////////////////////////////////////////////////////
46
47 class wxMutexInternal {
48 public:
49 pthread_mutex_t p_mutex;
50 };
51
52 wxMutex::wxMutex()
53 {
54 p_internal = new wxMutexInternal;
55 pthread_mutex_init(&(p_internal->p_mutex), NULL);
56 m_locked = 0;
57 }
58
59 wxMutex::~wxMutex()
60 {
61 if (m_locked > 0)
62 wxDebugMsg("wxMutex warning: freeing a locked mutex (%d locks)\n",
63 m_locked);
64
65 pthread_mutex_destroy(&(p_internal->p_mutex));
66 delete p_internal;
67 }
68
69 wxMutexError wxMutex::Lock()
70 {
71 int err;
72
73 err = pthread_mutex_lock(&(p_internal->p_mutex));
74 if (err == EDEADLK)
75 return MUTEX_DEAD_LOCK;
76 m_locked++;
77 return MUTEX_NO_ERROR;
78 }
79
80 wxMutexError wxMutex::TryLock()
81 {
82 int err;
83
84 if (m_locked)
85 return MUTEX_BUSY;
86 err = pthread_mutex_trylock(&(p_internal->p_mutex));
87 switch (err) {
88 case EBUSY: return MUTEX_BUSY;
89 }
90 m_locked++;
91 return MUTEX_NO_ERROR;
92 }
93
94 wxMutexError wxMutex::Unlock()
95 {
96 if (m_locked > 0)
97 m_locked--;
98 else
99 return MUTEX_UNLOCKED;
100 pthread_mutex_unlock(&(p_internal->p_mutex));
101 return MUTEX_NO_ERROR;
102 }
103
104 /////////////////////////////////////////////////////////////////////////////
105 // wxThread: Posix Thread implementation (Condition)
106 /////////////////////////////////////////////////////////////////////////////
107
108 class wxConditionInternal {
109 public:
110 pthread_cond_t p_condition;
111 };
112
113 wxCondition::wxCondition()
114 {
115 p_internal = new wxConditionInternal;
116 pthread_cond_init(&(p_internal->p_condition), NULL);
117 }
118
119 wxCondition::~wxCondition()
120 {
121 pthread_cond_destroy(&(p_internal->p_condition));
122 delete p_internal;
123 }
124
125 void wxCondition::Wait(wxMutex& mutex)
126 {
127 pthread_cond_wait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex));
128 }
129
130 bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec)
131 {
132 struct timespec tspec;
133
134 tspec.tv_sec = time(NULL)+sec;
135 tspec.tv_nsec = nsec;
136 return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT);
137 }
138
139 void wxCondition::Signal()
140 {
141 pthread_cond_signal(&(p_internal->p_condition));
142 }
143
144 void wxCondition::Broadcast()
145 {
146 pthread_cond_broadcast(&(p_internal->p_condition));
147 }
148
149 /////////////////////////////////////////////////////////////////////////////
150 // wxThread: Posix Thread implementation (Thread)
151 /////////////////////////////////////////////////////////////////////////////
152
153 class wxThreadInternal {
154 public:
155 wxThreadInternal() { state = STATE_IDLE; }
156 ~wxThreadInternal() {}
157 static void *PthreadStart(void *ptr);
158 pthread_t thread_id;
159 int state;
160 int prio;
161 };
162
163 void *wxThreadInternal::PthreadStart(void *ptr)
164 {
165 wxThread *thread = (wxThread *)ptr;
166
167 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
168 void* status = thread->Entry();
169 thread->Exit(status);
170
171 return NULL;
172 }
173
174 wxThreadError wxThread::Create()
175 {
176 pthread_attr_t a;
177 int min_prio, max_prio, p;
178 struct sched_param sp;
179
180 if (p_internal->state != STATE_IDLE)
181 return THREAD_RUNNING;
182
183 // Change thread priority
184 pthread_attr_init(&a);
185 pthread_attr_getschedpolicy(&a, &p);
186
187 min_prio = sched_get_priority_min(p);
188 max_prio = sched_get_priority_max(p);
189
190 pthread_attr_getschedparam(&a, &sp);
191 sp.sched_priority = min_prio +
192 (p_internal->prio*(max_prio-min_prio))/100;
193 pthread_attr_setschedparam(&a, &sp);
194
195 // this is the point of no return
196 p_internal->state = STATE_RUNNING;
197 if (pthread_create(&p_internal->thread_id, &a,
198 wxThreadInternal::PthreadStart, (void *)this) != 0) {
199 p_internal->state = STATE_IDLE;
200 pthread_attr_destroy(&a);
201 return THREAD_NO_RESOURCE;
202 }
203 pthread_attr_destroy(&a);
204 return THREAD_NO_ERROR;
205 }
206
207 void wxThread::SetPriority(int prio)
208 {
209 if (p_internal->state == STATE_RUNNING)
210 return;
211
212 if (prio > 100)
213 prio = 100;
214 if (prio < 0)
215 prio = 0;
216 p_internal->prio = prio;
217 }
218
219 int wxThread::GetPriority() const
220 {
221 return p_internal->prio;
222 }
223
224 void wxThread::DeferDestroy(bool on)
225 {
226 if (on)
227 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
228 else
229 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
230 }
231
232 wxThreadError wxThread::Destroy()
233 {
234 int res = 0;
235
236 if (p_internal->state == STATE_RUNNING) {
237 res = pthread_cancel(p_internal->thread_id);
238 if (res == 0)
239 p_internal->state = STATE_CANCELED;
240 }
241 return THREAD_NO_ERROR;
242 }
243
244 void *wxThread::Join()
245 {
246 void* status = 0;
247
248 if (p_internal->state != STATE_IDLE) {
249 bool do_unlock = wxThread::IsMain();
250
251 while (p_internal->state == STATE_RUNNING)
252 wxYield();
253
254 if (do_unlock)
255 wxMainMutex.Unlock();
256 pthread_join(p_internal->thread_id, &status);
257 if (do_unlock)
258 wxMainMutex.Lock();
259 p_internal->state = STATE_IDLE;
260 }
261 return status;
262 }
263
264 unsigned long wxThread::GetID() const
265 {
266 return (unsigned long)p_internal->thread_id;
267 }
268
269 void wxThread::Exit(void *status)
270 {
271 wxThread* ptr = this;
272
273 THREAD_SEND_EXIT_MSG(ptr);
274 p_internal->state = STATE_EXITED;
275 pthread_exit(status);
276 }
277
278 void wxThread::TestDestroy()
279 {
280 pthread_testcancel();
281 }
282
283 bool wxThread::IsMain()
284 {
285 return (bool)pthread_equal(pthread_self(), p_mainid);
286 }
287
288 wxThread::wxThread()
289 {
290 p_internal = new wxThreadInternal();
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 }
304
305 // Automatic initialization
306 class wxThreadModule : public wxModule {
307 DECLARE_DYNAMIC_CLASS(wxThreadModule)
308 public:
309 virtual bool OnInit() {
310 wxThreadGuiInit();
311 p_mainid = pthread_self();
312 wxMainMutex.Lock();
313
314 return TRUE;
315 }
316
317 virtual void OnExit() {
318 wxMainMutex.Unlock();
319 wxThreadGuiExit();
320 }
321 };
322
323 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)