]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk/threadpsx.cpp
OpenGl works now under GTK
[wxWidgets.git] / src / gtk / threadpsx.cpp
... / ...
CommitLineData
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
30enum 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
44static pthread_t p_mainid;
45
46wxMutex *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
58class wxMutexInternal
59{
60public:
61 pthread_mutex_t p_mutex;
62};
63
64wxMutex::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
71wxMutex::~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
80wxMutexError 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
93wxMutexError 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
111wxMutexError 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
131class wxConditionInternal
132{
133public:
134 pthread_cond_t p_condition;
135};
136
137wxCondition::wxCondition()
138{
139 p_internal = new wxConditionInternal;
140 pthread_cond_init( &(p_internal->p_condition), (const pthread_condattr_t *) NULL );
141}
142
143wxCondition::~wxCondition()
144{
145 pthread_cond_destroy( &(p_internal->p_condition) );
146
147 delete p_internal;
148}
149
150void wxCondition::Wait(wxMutex& mutex)
151{
152 pthread_cond_wait( &(p_internal->p_condition), &(mutex.p_internal->p_mutex) );
153}
154
155bool 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
164void wxCondition::Signal()
165{
166 pthread_cond_signal( &(p_internal->p_condition) );
167}
168
169void wxCondition::Broadcast()
170{
171 pthread_cond_broadcast( &(p_internal->p_condition) );
172}
173
174//--------------------------------------------------------------------
175// wxThread (Posix implementation)
176//--------------------------------------------------------------------
177
178class wxThreadInternal
179{
180public:
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
190void *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
203wxThreadError 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
238void 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
250int wxThread::GetPriority() const
251{
252 return p_internal->prio;
253}
254
255void 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
263wxThreadError 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
277wxThreadError 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
289wxThreadError 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
297void *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
320unsigned long wxThread::GetID() const
321{
322 return p_internal->thread_id;
323}
324
325void 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
334bool 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 pthread_testcancel();
346
347 return TRUE; /* what is this for? */
348}
349
350bool wxThread::IsMain()
351{
352 return (bool)pthread_equal(pthread_self(), p_mainid);
353}
354
355bool wxThread::IsRunning() const
356{
357 return (p_internal->state == STATE_RUNNING);
358}
359
360bool wxThread::IsAlive() const
361{
362 return (p_internal->state == STATE_RUNNING) ||
363 (p_internal->state == STATE_PAUSING) ||
364 (p_internal->state == STATE_PAUSED);
365}
366
367wxThread::wxThread()
368{
369 p_internal = new wxThreadInternal();
370}
371
372wxThread::~wxThread()
373{
374 Destroy();
375 Join();
376 delete p_internal;
377}
378
379/* The default callback just joins the thread and throws away the result. */
380void wxThread::OnExit()
381{
382 Join();
383}
384
385//--------------------------------------------------------------------
386// wxThreadModule
387//--------------------------------------------------------------------
388
389class wxThreadModule : public wxModule
390{
391public:
392 virtual bool OnInit();
393 virtual void OnExit();
394
395private:
396 DECLARE_DYNAMIC_CLASS(wxThreadModule)
397};
398
399IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
400
401bool wxThreadModule::OnInit()
402{
403 wxMainMutex = new wxMutex();
404 wxThreadGuiInit();
405 p_mainid = (int)getpid();
406 wxMainMutex->Lock();
407 return TRUE;
408}
409
410void wxThreadModule::OnExit()
411{
412 wxMainMutex->Unlock();
413 wxThreadGuiExit();
414 delete wxMainMutex;
415}
416
417