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