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