]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/threadpsx.cpp
224a3a15b8f8fd797db79b9c19a1673f641bdc05
[wxWidgets.git] / src / gtk / 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)
9 // Guilhem Lavaux (1998)
10 // Robert Roebling (1999)
11 // Licence: wxWindows licence
12 /////////////////////////////////////////////////////////////////////////////
13
14 #ifdef __GNUG__
15 #pragma implementation "thread.h"
16 #endif
17
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <pthread.h>
21 #include <errno.h>
22 #include "wx/thread.h"
23 #include "wx/module.h"
24 #include "wx/utils.h"
25 #include "wx/log.h"
26
27 enum thread_state
28 {
29 STATE_IDLE = 0,
30 STATE_RUNNING,
31 STATE_PAUSING,
32 STATE_PAUSED,
33 STATE_CANCELED,
34 STATE_EXITED
35 };
36
37 //--------------------------------------------------------------------
38 // global data
39 //--------------------------------------------------------------------
40
41 static pthread_t p_mainid;
42
43 wxMutex *wxMainMutex; // controls access to all GUI functions
44
45 //--------------------------------------------------------------------
46 // common GUI thread code
47 //--------------------------------------------------------------------
48
49 #include "threadgui.inc"
50
51 //--------------------------------------------------------------------
52 // wxMutex (Posix implementation)
53 //--------------------------------------------------------------------
54
55 class wxMutexInternal
56 {
57 public:
58 pthread_mutex_t p_mutex;
59 };
60
61 wxMutex::wxMutex()
62 {
63 p_internal = new wxMutexInternal;
64 pthread_mutex_init(&(p_internal->p_mutex), NULL);
65 m_locked = 0;
66 }
67
68 wxMutex::~wxMutex()
69 {
70 if (m_locked > 0)
71 wxLogDebug( "wxMutex warning: freeing a locked mutex (%d locks)\n", m_locked );
72
73 pthread_mutex_destroy(&(p_internal->p_mutex));
74 delete p_internal;
75 }
76
77 wxMutexError wxMutex::Lock()
78 {
79 int err;
80
81 err = pthread_mutex_lock(&(p_internal->p_mutex));
82 if (err == EDEADLK)
83 return wxMUTEX_DEAD_LOCK;
84
85 m_locked++;
86 return wxMUTEX_NO_ERROR;
87 }
88
89 wxMutexError wxMutex::TryLock()
90 {
91 int err;
92
93 if (m_locked)
94 return wxMUTEX_BUSY;
95
96 err = pthread_mutex_trylock(&(p_internal->p_mutex));
97 switch (err)
98 {
99 case EBUSY: return wxMUTEX_BUSY;
100 }
101 m_locked++;
102 return wxMUTEX_NO_ERROR;
103 }
104
105 wxMutexError wxMutex::Unlock()
106 {
107 if (m_locked > 0)
108 m_locked--;
109 else
110 return wxMUTEX_UNLOCKED;
111
112 pthread_mutex_unlock(&(p_internal->p_mutex));
113 return wxMUTEX_NO_ERROR;
114 }
115
116 //--------------------------------------------------------------------
117 // wxCondition (Posix implementation)
118 //--------------------------------------------------------------------
119
120 class wxConditionInternal
121 {
122 public:
123 pthread_cond_t p_condition;
124 };
125
126 wxCondition::wxCondition()
127 {
128 p_internal = new wxConditionInternal;
129 pthread_cond_init(&(p_internal->p_condition), NULL);
130 }
131
132 wxCondition::~wxCondition()
133 {
134 pthread_cond_destroy(&(p_internal->p_condition));
135 delete p_internal;
136 }
137
138 void wxCondition::Wait(wxMutex& mutex)
139 {
140 pthread_cond_wait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex));
141 }
142
143 bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec)
144 {
145 struct timespec tspec;
146
147 tspec.tv_sec = time(NULL)+sec;
148 tspec.tv_nsec = nsec;
149 return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT);
150 }
151
152 void wxCondition::Signal()
153 {
154 pthread_cond_signal(&(p_internal->p_condition));
155 }
156
157 void wxCondition::Broadcast()
158 {
159 pthread_cond_broadcast(&(p_internal->p_condition));
160 }
161
162 //--------------------------------------------------------------------
163 // wxThread (Posix implementation)
164 //--------------------------------------------------------------------
165
166 class wxThreadInternal
167 {
168 public:
169 wxThreadInternal() { state = STATE_IDLE; }
170 ~wxThreadInternal() {}
171 static void *PthreadStart(void *ptr);
172 pthread_t thread_id;
173 int state;
174 int prio;
175 int defer_destroy;
176 };
177
178 void *wxThreadInternal::PthreadStart(void *ptr)
179 {
180 wxThread *thread = (wxThread *)ptr;
181
182 // Call the main entry
183 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
184 void* status = thread->Entry();
185
186 thread->Exit(status);
187
188 return NULL;
189 }
190
191 wxThreadError wxThread::Create()
192 {
193 pthread_attr_t a;
194 int min_prio, max_prio, p;
195 struct sched_param sp;
196
197 if (p_internal->state != STATE_IDLE)
198 return wxTHREAD_RUNNING;
199
200 // Change thread priority
201 pthread_attr_init(&a);
202 pthread_attr_getschedpolicy(&a, &p);
203
204 min_prio = sched_get_priority_min(p);
205 max_prio = sched_get_priority_max(p);
206
207 pthread_attr_getschedparam(&a, &sp);
208 sp.sched_priority = min_prio +
209 (p_internal->prio*(max_prio-min_prio))/100;
210 pthread_attr_setschedparam(&a, &sp);
211
212 // this is the point of no return
213 p_internal->state = STATE_RUNNING;
214 if (pthread_create(&p_internal->thread_id, &a,
215 wxThreadInternal::PthreadStart, (void *)this) != 0)
216 {
217 p_internal->state = STATE_IDLE;
218 pthread_attr_destroy(&a);
219 return wxTHREAD_NO_RESOURCE;
220 }
221 pthread_attr_destroy(&a);
222
223 return wxTHREAD_NO_ERROR;
224 }
225
226 void wxThread::SetPriority(int prio)
227 {
228 if (p_internal->state == STATE_RUNNING)
229 return;
230
231 if (prio > 100) prio = 100;
232
233 if (prio < 0) prio = 0;
234
235 p_internal->prio = prio;
236 }
237
238 int wxThread::GetPriority() const
239 {
240 return p_internal->prio;
241 }
242
243 void wxThread::DeferDestroy(bool on)
244 {
245 if (on)
246 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
247 else
248 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
249 }
250
251 wxThreadError wxThread::Destroy()
252 {
253 int res = 0;
254
255 if (p_internal->state == STATE_RUNNING)
256 {
257 res = pthread_cancel(p_internal->thread_id);
258 if (res == 0)
259 p_internal->state = STATE_CANCELED;
260 }
261
262 return wxTHREAD_NO_ERROR;
263 }
264
265 wxThreadError wxThread::Pause()
266 {
267 if (p_internal->state != STATE_RUNNING)
268 return wxTHREAD_NOT_RUNNING;
269
270 if (!p_internal->defer_destroy)
271 return wxTHREAD_MISC_ERROR;
272
273 p_internal->state = STATE_PAUSING;
274 return wxTHREAD_NO_ERROR;
275 }
276
277 wxThreadError wxThread::Resume()
278 {
279 if (p_internal->state == STATE_PAUSING || p_internal->state == STATE_PAUSED)
280 p_internal->state = STATE_RUNNING;
281
282 return wxTHREAD_NO_ERROR;
283 }
284
285 void *wxThread::Join()
286 {
287 void* status = 0;
288
289 if (p_internal->state != STATE_IDLE)
290 {
291 bool do_unlock = wxThread::IsMain();
292
293 while (p_internal->state == STATE_RUNNING)
294 wxYield();
295
296 if (do_unlock) wxMainMutex->Unlock();
297
298 pthread_join(p_internal->thread_id, &status);
299
300 if (do_unlock) wxMainMutex->Lock();
301
302 p_internal->state = STATE_IDLE;
303 }
304
305 return status;
306 }
307
308 unsigned long wxThread::GetID() const
309 {
310 return p_internal->thread_id;
311 }
312
313 void wxThread::Exit(void *status)
314 {
315 wxThread* ptr = this;
316
317 THREAD_SEND_EXIT_MSG(ptr);
318 p_internal->state = STATE_EXITED;
319 pthread_exit(status);
320 }
321
322 void wxThread::TestDestroy()
323 {
324 if (p_internal->state == STATE_PAUSING)
325 {
326 p_internal->state = STATE_PAUSED;
327 while (p_internal->state == STATE_PAUSED)
328 {
329 pthread_testcancel();
330 usleep(1);
331 }
332 }
333 pthread_testcancel();
334 }
335
336 bool wxThread::IsMain()
337 {
338 return (bool)pthread_equal(pthread_self(), p_mainid);
339 }
340
341 bool wxThread::IsRunning() const
342 {
343 return (p_internal->state == STATE_RUNNING);
344 }
345
346 bool wxThread::IsAlive() const
347 {
348 return (p_internal->state == STATE_RUNNING) ||
349 (p_internal->state == STATE_PAUSING) ||
350 (p_internal->state == STATE_PAUSED);
351 }
352
353 wxThread::wxThread()
354 {
355 p_internal = new wxThreadInternal();
356 }
357
358 wxThread::~wxThread()
359 {
360 Destroy();
361 Join();
362 delete p_internal;
363 }
364
365 // The default callback just joins the thread and throws away the result.
366 void wxThread::OnExit()
367 {
368 Join();
369 }
370
371 //--------------------------------------------------------------------
372 // wxThreadModule
373 //--------------------------------------------------------------------
374
375 class wxThreadModule : public wxModule
376 {
377 DECLARE_DYNAMIC_CLASS(wxThreadModule)
378
379 public:
380 virtual bool OnInit()
381 {
382 wxMainMutex = new wxMutex();
383 wxThreadGuiInit();
384 p_mainid = pthread_self();
385 wxMainMutex->Lock();
386
387 return TRUE;
388 }
389
390 virtual void OnExit()
391 {
392 wxMainMutex->Unlock();
393 wxThreadGuiExit();
394 delete wxMainMutex;
395 }
396 };
397
398 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
399