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