]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk1/threadpsx.cpp
Made wxGTK dcps.cpp generic.
[wxWidgets.git] / src / gtk1 / 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
23#ifdef __linux__
24 #include <sched.h>
25#endif
26
27#include "wx/thread.h"
28#include "wx/module.h"
29#include "wx/utils.h"
30#include "wx/log.h"
31#include "wx/intl.h"
32
33#include "gdk/gdk.h"
34#include "gtk/gtk.h"
35
36enum thread_state
37{
38 STATE_NEW, // didn't start execution yet (=> RUNNING)
39 STATE_RUNNING,
40 STATE_PAUSED,
41 STATE_CANCELED,
42 STATE_EXITED
43};
44
45//--------------------------------------------------------------------
46// global data
47//--------------------------------------------------------------------
48
49// the id of the main thread
50static pthread_t gs_pidMain;
51
52// the key for the pointer to the associated wxThread object
53static pthread_key_t gs_keySelf;
54
55// this mutex must be acquired before any call to a GUI function
56static wxMutex *gs_mutexGui;
57
58//--------------------------------------------------------------------
59// common GUI thread code
60//--------------------------------------------------------------------
61
62#include "threadgui.inc"
63
64//--------------------------------------------------------------------
65// wxMutex (Posix implementation)
66//--------------------------------------------------------------------
67
68class wxMutexInternal
69{
70public:
71 pthread_mutex_t p_mutex;
72};
73
74wxMutex::wxMutex()
75{
76 p_internal = new wxMutexInternal;
77 pthread_mutex_init( &(p_internal->p_mutex), (const pthread_mutexattr_t*) NULL );
78 m_locked = 0;
79}
80
81wxMutex::~wxMutex()
82{
83 if (m_locked > 0)
84 wxLogDebug( "wxMutex warning: freeing a locked mutex (%d locks)", m_locked );
85
86 pthread_mutex_destroy( &(p_internal->p_mutex) );
87 delete p_internal;
88}
89
90wxMutexError wxMutex::Lock()
91{
92 int err = pthread_mutex_lock( &(p_internal->p_mutex) );
93 if (err == EDEADLK)
94 {
95 return wxMUTEX_DEAD_LOCK;
96 }
97
98 m_locked++;
99
100 return wxMUTEX_NO_ERROR;
101}
102
103wxMutexError wxMutex::TryLock()
104{
105 if (m_locked)
106 {
107 return wxMUTEX_BUSY;
108 }
109
110 int err = pthread_mutex_trylock( &(p_internal->p_mutex) );
111 switch (err)
112 {
113 case EBUSY: return wxMUTEX_BUSY;
114 }
115
116 m_locked++;
117
118 return wxMUTEX_NO_ERROR;
119}
120
121wxMutexError wxMutex::Unlock()
122{
123 if (m_locked > 0)
124 {
125 m_locked--;
126 }
127 else
128 {
129 return wxMUTEX_UNLOCKED;
130 }
131
132 pthread_mutex_unlock( &(p_internal->p_mutex) );
133
134 return wxMUTEX_NO_ERROR;
135}
136
137//--------------------------------------------------------------------
138// wxCondition (Posix implementation)
139//--------------------------------------------------------------------
140
141class wxConditionInternal
142{
143public:
144 pthread_cond_t p_condition;
145};
146
147wxCondition::wxCondition()
148{
149 p_internal = new wxConditionInternal;
150 pthread_cond_init( &(p_internal->p_condition), (const pthread_condattr_t *) NULL );
151}
152
153wxCondition::~wxCondition()
154{
155 pthread_cond_destroy( &(p_internal->p_condition) );
156
157 delete p_internal;
158}
159
160void wxCondition::Wait(wxMutex& mutex)
161{
162 pthread_cond_wait( &(p_internal->p_condition), &(mutex.p_internal->p_mutex) );
163}
164
165bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec)
166{
167 struct timespec tspec;
168
169 tspec.tv_sec = time(0L)+sec;
170 tspec.tv_nsec = nsec;
171 return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT);
172}
173
174void wxCondition::Signal()
175{
176 pthread_cond_signal( &(p_internal->p_condition) );
177}
178
179void wxCondition::Broadcast()
180{
181 pthread_cond_broadcast( &(p_internal->p_condition) );
182}
183
184//--------------------------------------------------------------------
185// wxThread (Posix implementation)
186//--------------------------------------------------------------------
187
188class wxThreadInternal
189{
190public:
191 wxThreadInternal() { m_state = STATE_NEW; }
192 ~wxThreadInternal() {}
193
194 // thread entry function
195 static void *PthreadStart(void *ptr);
196
197 // start the thread
198 wxThreadError Run();
199
200 // accessors
201 // priority
202 int GetPriority() const { return m_prio; }
203 void SetPriority(int prio) { m_prio = prio; }
204 // state
205 thread_state GetState() const { return m_state; }
206 void SetState(thread_state state) { m_state = state; }
207 // id
208 pthread_t GetId() const { return thread_id; }
209 // "cancelled" flag
210 void Cancel();
211 bool WasCancelled() const { return m_cancelled; }
212
213//private: -- should be!
214 pthread_t thread_id;
215
216private:
217 thread_state m_state; // see thread_state enum
218 int m_prio; // in wxWindows units: from 0 to 100
219
220 // set when the thread should terminate
221 bool m_cancelled;
222
223 // we start running when this condition becomes true
224 wxMutex m_mutexRun;
225 wxCondition m_condRun;
226
227 // this condition becomes true when we get back to PthreadStart() function
228 wxMutex m_mutexStop;
229 wxCondition m_condStop;
230};
231
232void *wxThreadInternal::PthreadStart(void *ptr)
233{
234 wxThread *thread = (wxThread *)ptr;
235 wxThreadInternal *pthread = thread->p_internal;
236
237 if ( pthread_setspecific(gs_keySelf, thread) != 0 )
238 {
239 wxLogError(_("Can not start thread: error writing TLS."));
240
241 return (void *)-1;
242 }
243
244 // wait for the condition to be signaled from Run()
245 pthread->m_mutexRun.Lock();
246 pthread->m_condRun.Wait(pthread->m_mutexRun);
247
248 // call the main entry
249 void* status = thread->Entry();
250
251 pthread->m_mutexRun.Unlock();
252
253 // wake up the pthread(s) waiting for our termination
254 pthread->m_condStop.Broadcast();
255
256 // terminate the thread
257 thread->Exit(status);
258
259 wxFAIL_MSG("wxThread::Exit() can't return.");
260
261 return NULL;
262}
263
264wxThreadError wxThreadInternal::Run()
265{
266 wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
267 "thread may only be started once after successful Create()" );
268
269 wxMutexLocker lock(&m_mutexRun);
270 m_condRun.Signal();
271
272 return wxTHREAD_NO_ERROR;
273}
274
275void wxThreadInternal::Cancel()
276{
277 wxMutexLocker lock(&m_mutexStop);
278 m_cancelled = TRUE;
279 m_condStop.Wait(m_mutexStop);
280}
281
282// -----------------------------------------------------------------------------
283// static functions
284// -----------------------------------------------------------------------------
285
286wxThread *wxThread::This()
287{
288 return (wxThread *)pthread_getspecific(gs_keySelf);
289}
290
291bool wxThread::IsMain()
292{
293 return (bool)pthread_equal(pthread_self(), gs_pidMain);
294}
295
296void wxThread::Yield()
297{
298 sched_yield();
299}
300
301void wxThread::Sleep(unsigned long milliseconds)
302{
303 // FIXME how to test for nanosleep() availability?
304
305 usleep(milliseconds * 1000); // usleep(3) wants microseconds
306}
307
308// -----------------------------------------------------------------------------
309// creating thread
310// -----------------------------------------------------------------------------
311
312wxThread::wxThread()
313{
314 p_internal = new wxThreadInternal();
315}
316
317wxThreadError wxThread::Create()
318{
319 if (p_internal->GetState() != STATE_NEW)
320 return wxTHREAD_RUNNING;
321
322 // set up the thread attribute: right now, we only set thread priority
323 pthread_attr_t attr;
324 pthread_attr_init(&attr);
325
326 int prio;
327 if ( pthread_attr_getschedpolicy(&attr, &prio) != 0 )
328 {
329 wxLogError(_("Can not retrieve thread scheduling policy."));
330 }
331
332 int min_prio = sched_get_priority_min(prio),
333 max_prio = sched_get_priority_max(prio);
334
335 if ( min_prio == -1 || max_prio == -1 )
336 {
337 wxLogError(_("Can not get priority range for scheduling policy %d."),
338 prio);
339 }
340 else
341 {
342 struct sched_param sp;
343 pthread_attr_getschedparam(&attr, &sp);
344 sp.sched_priority = min_prio +
345 (p_internal->GetPriority()*(max_prio-min_prio))/100;
346 pthread_attr_setschedparam(&attr, &sp);
347 }
348
349 // this is the point of no return
350 int rc = pthread_create(&p_internal->thread_id, &attr,
351 wxThreadInternal::PthreadStart, (void *)this);
352 pthread_attr_destroy(&attr);
353
354 if ( rc != 0 )
355 {
356 p_internal->SetState(STATE_EXITED);
357 return wxTHREAD_NO_RESOURCE;
358 }
359
360 return wxTHREAD_NO_ERROR;
361}
362
363wxThreadError wxThread::Run()
364{
365 return p_internal->Run();
366}
367
368// -----------------------------------------------------------------------------
369// misc accessors
370// -----------------------------------------------------------------------------
371
372void wxThread::SetPriority(unsigned int prio)
373{
374 wxCHECK_RET( (WXTHREAD_MIN_PRIORITY <= prio) &&
375 (prio <= WXTHREAD_MAX_PRIORITY), "invalid thread priority" );
376
377 wxCriticalSectionLocker lock(m_critsect);
378
379 switch ( p_internal->GetState() )
380 {
381 case STATE_NEW:
382 // thread not yet started, priority will be set when it is
383 p_internal->SetPriority(prio);
384 break;
385
386 case STATE_RUNNING:
387 case STATE_PAUSED:
388 {
389 struct sched_param sparam;
390 sparam.sched_priority = prio;
391
392 if ( pthread_setschedparam(p_internal->GetId(),
393 SCHED_OTHER, &sparam) != 0 )
394 {
395 wxLogError(_("Failed to set thread priority %d."), prio);
396 }
397 }
398 break;
399
400 case STATE_EXITED:
401 default:
402 wxFAIL_MSG("impossible to set thread priority in this state");
403 }
404}
405
406unsigned int wxThread::GetPriority() const
407{
408 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
409
410 return p_internal->GetPriority();
411}
412
413unsigned long wxThread::GetID() const
414{
415 return (unsigned long)p_internal->thread_id;
416}
417
418// -----------------------------------------------------------------------------
419// pause/resume
420// -----------------------------------------------------------------------------
421
422wxThreadError wxThread::Pause()
423{
424 wxCriticalSectionLocker lock(m_critsect);
425
426 if ( p_internal->GetState() != STATE_RUNNING )
427 {
428 wxLogDebug("Can't pause thread which is not running.");
429
430 return wxTHREAD_NOT_RUNNING;
431 }
432
433 p_internal->SetState(STATE_PAUSED);
434
435 return wxTHREAD_NO_ERROR;
436}
437
438wxThreadError wxThread::Resume()
439{
440 wxCriticalSectionLocker lock(m_critsect);
441
442 if ( p_internal->GetState() == STATE_PAUSED )
443 {
444 p_internal->SetState(STATE_RUNNING);
445
446 return wxTHREAD_NO_ERROR;
447 }
448 else
449 {
450 wxLogDebug("Attempt to resume a thread which is not paused.");
451
452 return wxTHREAD_MISC_ERROR;
453 }
454}
455
456// -----------------------------------------------------------------------------
457// exiting thread
458// -----------------------------------------------------------------------------
459
460wxThread::ExitCode wxThread::Delete()
461{
462 m_critsect.Enter();
463 thread_state state = p_internal->GetState();
464 m_critsect.Leave();
465
466 switch ( state )
467 {
468 case STATE_NEW:
469 case STATE_EXITED:
470 // nothing to do
471 break;
472
473 case STATE_PAUSED:
474 // resume the thread first
475 Resume();
476
477 // fall through
478
479 default:
480 // set the flag telling to the thread to stop and wait
481 p_internal->Cancel();
482 }
483
484 return NULL;
485}
486
487wxThreadError wxThread::Kill()
488{
489 switch ( p_internal->GetState() )
490 {
491 case STATE_NEW:
492 case STATE_EXITED:
493 return wxTHREAD_NOT_RUNNING;
494
495 default:
496 if ( pthread_cancel(p_internal->GetId()) != 0 )
497 {
498 wxLogError(_("Failed to terminate a thread."));
499
500 return wxTHREAD_MISC_ERROR;
501 }
502
503 return wxTHREAD_NO_ERROR;
504 }
505}
506
507void wxThread::Exit(void *status)
508{
509 wxThread *ptr = this;
510 THREAD_SEND_EXIT_MSG(ptr);
511
512 OnExit();
513
514 p_internal->SetState(STATE_EXITED);
515
516 delete this;
517
518 pthread_exit(status);
519}
520
521bool wxThread::TestDestroy() const
522{
523 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
524
525 return p_internal->WasCancelled();
526}
527
528wxThread::~wxThread()
529{
530}
531
532// -----------------------------------------------------------------------------
533// state tests
534// -----------------------------------------------------------------------------
535
536bool wxThread::IsRunning() const
537{
538 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
539
540 return p_internal->GetState() == STATE_RUNNING;
541}
542
543bool wxThread::IsAlive() const
544{
545 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
546
547 switch ( p_internal->GetState() )
548 {
549 case STATE_RUNNING:
550 case STATE_PAUSED:
551 return TRUE;
552
553 default:
554 return FALSE;
555 }
556}
557
558//--------------------------------------------------------------------
559// wxThreadModule
560//--------------------------------------------------------------------
561
562class wxThreadModule : public wxModule
563{
564public:
565 virtual bool OnInit();
566 virtual void OnExit();
567
568private:
569 DECLARE_DYNAMIC_CLASS(wxThreadModule)
570};
571
572IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
573
574bool wxThreadModule::OnInit()
575{
576 if ( pthread_key_create(&gs_keySelf, NULL /* dtor function */) != 0 )
577 {
578 wxLogError(_("Thread module initialization failed: "
579 "failed to create pthread key."));
580
581 return FALSE;
582 }
583
584 gs_mutexGui = new wxMutex();
585 wxThreadGuiInit();
586 gs_pidMain = (int)getpid();
587 gs_mutexGui->Lock();
588
589 return TRUE;
590}
591
592void wxThreadModule::OnExit()
593{
594 gs_mutexGui->Unlock();
595 wxThreadGuiExit();
596 delete gs_mutexGui;
597
598 (void)pthread_key_delete(gs_keySelf);
599}