]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/threadpsx.cpp
Now uses dcps.h
[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
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
36 enum 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
50 static pthread_t gs_pidMain;
51
52 // the key for the pointer to the associated wxThread object
53 static pthread_key_t gs_keySelf;
54
55 // this mutex must be acquired before any call to a GUI function
56 static wxMutex *gs_mutexGui;
57
58 //--------------------------------------------------------------------
59 // common GUI thread code
60 //--------------------------------------------------------------------
61
62 #include "threadgui.inc"
63
64 //--------------------------------------------------------------------
65 // wxMutex (Posix implementation)
66 //--------------------------------------------------------------------
67
68 class wxMutexInternal
69 {
70 public:
71 pthread_mutex_t p_mutex;
72 };
73
74 wxMutex::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
81 wxMutex::~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
90 wxMutexError 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
103 wxMutexError 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
121 wxMutexError 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
141 class wxConditionInternal
142 {
143 public:
144 pthread_cond_t p_condition;
145 };
146
147 wxCondition::wxCondition()
148 {
149 p_internal = new wxConditionInternal;
150 pthread_cond_init( &(p_internal->p_condition), (const pthread_condattr_t *) NULL );
151 }
152
153 wxCondition::~wxCondition()
154 {
155 pthread_cond_destroy( &(p_internal->p_condition) );
156
157 delete p_internal;
158 }
159
160 void wxCondition::Wait(wxMutex& mutex)
161 {
162 pthread_cond_wait( &(p_internal->p_condition), &(mutex.p_internal->p_mutex) );
163 }
164
165 bool 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
174 void wxCondition::Signal()
175 {
176 pthread_cond_signal( &(p_internal->p_condition) );
177 }
178
179 void wxCondition::Broadcast()
180 {
181 pthread_cond_broadcast( &(p_internal->p_condition) );
182 }
183
184 //--------------------------------------------------------------------
185 // wxThread (Posix implementation)
186 //--------------------------------------------------------------------
187
188 class wxThreadInternal
189 {
190 public:
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
216 private:
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
232 void *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
264 wxThreadError 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
275 void 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
286 wxThread *wxThread::This()
287 {
288 return (wxThread *)pthread_getspecific(gs_keySelf);
289 }
290
291 bool wxThread::IsMain()
292 {
293 return (bool)pthread_equal(pthread_self(), gs_pidMain);
294 }
295
296 void wxThread::Yield()
297 {
298 sched_yield();
299 }
300
301 void 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
312 wxThread::wxThread()
313 {
314 p_internal = new wxThreadInternal();
315 }
316
317 wxThreadError 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
363 wxThreadError wxThread::Run()
364 {
365 return p_internal->Run();
366 }
367
368 // -----------------------------------------------------------------------------
369 // misc accessors
370 // -----------------------------------------------------------------------------
371
372 void 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
406 unsigned int wxThread::GetPriority() const
407 {
408 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
409
410 return p_internal->GetPriority();
411 }
412
413 unsigned long wxThread::GetID() const
414 {
415 return (unsigned long)p_internal->thread_id;
416 }
417
418 // -----------------------------------------------------------------------------
419 // pause/resume
420 // -----------------------------------------------------------------------------
421
422 wxThreadError 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
438 wxThreadError 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
460 wxThread::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
487 wxThreadError 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
507 void 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
521 bool wxThread::TestDestroy() const
522 {
523 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
524
525 return p_internal->WasCancelled();
526 }
527
528 wxThread::~wxThread()
529 {
530 }
531
532 // -----------------------------------------------------------------------------
533 // state tests
534 // -----------------------------------------------------------------------------
535
536 bool wxThread::IsRunning() const
537 {
538 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
539
540 return p_internal->GetState() == STATE_RUNNING;
541 }
542
543 bool 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
562 class wxThreadModule : public wxModule
563 {
564 public:
565 virtual bool OnInit();
566 virtual void OnExit();
567
568 private:
569 DECLARE_DYNAMIC_CLASS(wxThreadModule)
570 };
571
572 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
573
574 bool 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
592 void wxThreadModule::OnExit()
593 {
594 gs_mutexGui->Unlock();
595 wxThreadGuiExit();
596 delete gs_mutexGui;
597
598 (void)pthread_key_delete(gs_keySelf);
599 }