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