]> git.saurik.com Git - wxWidgets.git/blob - src/unix/threadpsx.cpp
controls sample tests a bit more
[wxWidgets.git] / src / unix / 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 // Vadim Zeitlin (1999)
11 // Robert Roebling (1999)
12 // Licence: wxWindows licence
13 /////////////////////////////////////////////////////////////////////////////
14
15 // ============================================================================
16 // declaration
17 // ============================================================================
18
19 // ----------------------------------------------------------------------------
20 // headers
21 // ----------------------------------------------------------------------------
22
23 #ifdef __GNUG__
24 #pragma implementation "thread.h"
25 #endif
26
27 // With simple makefiles, we must ignore the file body if not using
28 // threads.
29 #include "wx/setup.h"
30
31 #if wxUSE_THREADS
32
33 #include "wx/thread.h"
34 #include "wx/module.h"
35 #include "wx/utils.h"
36 #include "wx/log.h"
37 #include "wx/intl.h"
38 #include "wx/dynarray.h"
39
40 #include <stdio.h>
41 #include <unistd.h>
42 #include <pthread.h>
43 #include <errno.h>
44 #include <time.h>
45
46 #if HAVE_SCHED_H
47 #include <sched.h>
48 #endif
49
50 #ifdef __WXGTK12__
51 #include "gtk/gtk.h"
52 #endif
53
54 // ----------------------------------------------------------------------------
55 // constants
56 // ----------------------------------------------------------------------------
57
58 // the possible states of the thread and transitions from them
59 enum wxThreadState
60 {
61 STATE_NEW, // didn't start execution yet (=> RUNNING)
62 STATE_RUNNING, // running (=> PAUSED or EXITED)
63 STATE_PAUSED, // suspended (=> RUNNING or EXITED)
64 STATE_EXITED // thread doesn't exist any more
65 };
66
67 // ----------------------------------------------------------------------------
68 // types
69 // ----------------------------------------------------------------------------
70
71 WX_DEFINE_ARRAY(wxThread *, wxArrayThread);
72
73 // -----------------------------------------------------------------------------
74 // global data
75 // -----------------------------------------------------------------------------
76
77 // we keep the list of all threads created by the application to be able to
78 // terminate them on exit if there are some left - otherwise the process would
79 // be left in memory
80 static wxArrayThread gs_allThreads;
81
82 // the id of the main thread
83 static pthread_t gs_tidMain;
84
85 // the key for the pointer to the associated wxThread object
86 static pthread_key_t gs_keySelf;
87
88 #ifndef __WXGTK12__
89 // this mutex must be acquired before any call to a GUI function
90 static wxMutex *gs_mutexGui;
91 #endif
92
93 // ============================================================================
94 // implementation
95 // ============================================================================
96
97 //--------------------------------------------------------------------
98 // wxMutex (Posix implementation)
99 //--------------------------------------------------------------------
100
101 class wxMutexInternal
102 {
103 public:
104 pthread_mutex_t p_mutex;
105 };
106
107 wxMutex::wxMutex()
108 {
109 p_internal = new wxMutexInternal;
110 pthread_mutex_init( &(p_internal->p_mutex), (const pthread_mutexattr_t*) NULL );
111 m_locked = 0;
112 }
113
114 wxMutex::~wxMutex()
115 {
116 if (m_locked > 0)
117 wxLogDebug(_T("Freeing a locked mutex (%d locks)"), m_locked);
118
119 pthread_mutex_destroy( &(p_internal->p_mutex) );
120 delete p_internal;
121 }
122
123 wxMutexError wxMutex::Lock()
124 {
125 int err = pthread_mutex_lock( &(p_internal->p_mutex) );
126 if (err == EDEADLK)
127 {
128 wxLogDebug(_T("Locking this mutex would lead to deadlock!"));
129
130 return wxMUTEX_DEAD_LOCK;
131 }
132
133 m_locked++;
134
135 return wxMUTEX_NO_ERROR;
136 }
137
138 wxMutexError wxMutex::TryLock()
139 {
140 if (m_locked)
141 {
142 return wxMUTEX_BUSY;
143 }
144
145 int err = pthread_mutex_trylock( &(p_internal->p_mutex) );
146 switch (err)
147 {
148 case EBUSY: return wxMUTEX_BUSY;
149 }
150
151 m_locked++;
152
153 return wxMUTEX_NO_ERROR;
154 }
155
156 wxMutexError wxMutex::Unlock()
157 {
158 if (m_locked > 0)
159 {
160 m_locked--;
161 }
162 else
163 {
164 wxLogDebug(_T("Unlocking not locked mutex."));
165
166 return wxMUTEX_UNLOCKED;
167 }
168
169 pthread_mutex_unlock( &(p_internal->p_mutex) );
170
171 return wxMUTEX_NO_ERROR;
172 }
173
174 //--------------------------------------------------------------------
175 // wxCondition (Posix implementation)
176 //--------------------------------------------------------------------
177
178 class wxConditionInternal
179 {
180 public:
181 pthread_cond_t p_condition;
182 };
183
184 wxCondition::wxCondition()
185 {
186 p_internal = new wxConditionInternal;
187 pthread_cond_init( &(p_internal->p_condition), (const pthread_condattr_t *) NULL );
188 }
189
190 wxCondition::~wxCondition()
191 {
192 pthread_cond_destroy( &(p_internal->p_condition) );
193
194 delete p_internal;
195 }
196
197 void wxCondition::Wait(wxMutex& mutex)
198 {
199 pthread_cond_wait( &(p_internal->p_condition), &(mutex.p_internal->p_mutex) );
200 }
201
202 bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec)
203 {
204 struct timespec tspec;
205
206 tspec.tv_sec = time(0L)+sec;
207 tspec.tv_nsec = nsec;
208 return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT);
209 }
210
211 void wxCondition::Signal()
212 {
213 pthread_cond_signal( &(p_internal->p_condition) );
214 }
215
216 void wxCondition::Broadcast()
217 {
218 pthread_cond_broadcast( &(p_internal->p_condition) );
219 }
220
221 //--------------------------------------------------------------------
222 // wxThread (Posix implementation)
223 //--------------------------------------------------------------------
224
225 class wxThreadInternal
226 {
227 public:
228 wxThreadInternal();
229 ~wxThreadInternal();
230
231 // thread entry function
232 static void *PthreadStart(void *ptr);
233
234 // thread actions
235 // start the thread
236 wxThreadError Run();
237 // ask the thread to terminate
238 void Wait();
239 // wake up threads waiting for our termination
240 void SignalExit();
241 // go to sleep until Resume() is called
242 void Pause();
243 // resume the thread
244 void Resume();
245
246 // accessors
247 // priority
248 int GetPriority() const { return m_prio; }
249 void SetPriority(int prio) { m_prio = prio; }
250 // state
251 wxThreadState GetState() const { return m_state; }
252 void SetState(wxThreadState state) { m_state = state; }
253 // id
254 pthread_t GetId() const { return m_threadId; }
255 pthread_t *GetIdPtr() { return &m_threadId; }
256 // "cancelled" flag
257 void SetCancelFlag() { m_cancelled = TRUE; }
258 bool WasCancelled() const { return m_cancelled; }
259
260 private:
261 pthread_t m_threadId; // id of the thread
262 wxThreadState m_state; // see wxThreadState enum
263 int m_prio; // in wxWindows units: from 0 to 100
264
265 // set when the thread should terminate
266 bool m_cancelled;
267
268 // this (mutex, cond) pair is used to synchronize the main thread and this
269 // thread in several situations:
270 // 1. The thread function blocks until condition is signaled by Run() when
271 // it's initially created - this allows thread creation in "suspended"
272 // state
273 // 2. The Delete() function blocks until the condition is signaled when the
274 // thread exits.
275 wxMutex m_mutex;
276 wxCondition m_cond;
277
278 // another (mutex, cond) pair for Pause()/Resume() usage
279 //
280 // VZ: it's possible that we might reuse the mutex and condition from above
281 // for this too, but as I'm not at all sure that it won't create subtle
282 // problems with race conditions between, say, Pause() and Delete() I
283 // prefer this may be a bit less efficient but much safer solution
284 wxMutex m_mutexSuspend;
285 wxCondition m_condSuspend;
286 };
287
288 void *wxThreadInternal::PthreadStart(void *ptr)
289 {
290 wxThread *thread = (wxThread *)ptr;
291 wxThreadInternal *pthread = thread->p_internal;
292
293 int rc = pthread_setspecific(gs_keySelf, thread);
294 if ( rc != 0 )
295 {
296 wxLogSysError(rc, _("Cannot start thread: error writing TLS"));
297
298 return (void *)-1;
299 }
300
301 // wait for the condition to be signaled from Run()
302 // mutex state: currently locked by the thread which created us
303 pthread->m_cond.Wait(pthread->m_mutex);
304
305 // mutex state: locked again on exit of Wait()
306
307 // call the main entry
308 void* status = thread->Entry();
309
310 // terminate the thread
311 thread->Exit(status);
312
313 wxFAIL_MSG(_T("wxThread::Exit() can't return."));
314
315 return NULL;
316 }
317
318 wxThreadInternal::wxThreadInternal()
319 {
320 m_state = STATE_NEW;
321 m_cancelled = FALSE;
322
323 // this mutex is locked during almost all thread lifetime - it will only be
324 // unlocked in the very end
325 m_mutex.Lock();
326
327 // this mutex is used in Pause()/Resume() and is also locked all the time
328 // unless the thread is paused
329 m_mutexSuspend.Lock();
330 }
331
332 wxThreadInternal::~wxThreadInternal()
333 {
334 // GL: moved to SignalExit
335 // m_mutexSuspend.Unlock();
336
337 // note that m_mutex will be unlocked by the thread which waits for our
338 // termination
339 }
340
341 wxThreadError wxThreadInternal::Run()
342 {
343 wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
344 _T("thread may only be started once after successful Create()") );
345
346 // the mutex was locked on Create(), so we will be able to lock it again
347 // only when the thread really starts executing and enters the wait -
348 // otherwise we might signal the condition before anybody is waiting for it
349 wxMutexLocker lock(m_mutex);
350 m_cond.Signal();
351
352 m_state = STATE_RUNNING;
353
354 return wxTHREAD_NO_ERROR;
355
356 // now the mutex is unlocked back - but just to allow Wait() function to
357 // terminate by relocking it, so the net result is that the worker thread
358 // starts executing and the mutex is still locked
359 }
360
361 void wxThreadInternal::Wait()
362 {
363 wxCHECK_RET( WasCancelled(), _T("thread should have been cancelled first") );
364
365 // if the thread we're waiting for is waiting for the GUI mutex, we will
366 // deadlock so make sure we release it temporarily
367 if ( wxThread::IsMain() )
368 wxMutexGuiLeave();
369
370 // entering Wait() releases the mutex thus allowing SignalExit() to acquire
371 // it and to signal us its termination
372 m_cond.Wait(m_mutex);
373
374 // mutex is still in the locked state - relocked on exit from Wait(), so
375 // unlock it - we don't need it any more, the thread has already terminated
376 m_mutex.Unlock();
377
378 // reacquire GUI mutex
379 if ( wxThread::IsMain() )
380 wxMutexGuiEnter();
381 }
382
383 void wxThreadInternal::SignalExit()
384 {
385 // GL: Unlock mutexSuspend here.
386 m_mutexSuspend.Unlock();
387
388 // as mutex is currently locked, this will block until some other thread
389 // (normally the same which created this one) unlocks it by entering Wait()
390 m_mutex.Lock();
391
392 // wake up all the threads waiting for our termination
393 m_cond.Broadcast();
394
395 // after this call mutex will be finally unlocked
396 m_mutex.Unlock();
397 }
398
399 void wxThreadInternal::Pause()
400 {
401 // the state is set from the thread which pauses us first, this function
402 // is called later so the state should have been already set
403 wxCHECK_RET( m_state == STATE_PAUSED,
404 _T("thread must first be paused with wxThread::Pause().") );
405
406 // don't pause the thread which is being terminated - this would lead to
407 // deadlock if the thread is paused after Delete() had called Resume() but
408 // before it had time to call Wait()
409 if ( WasCancelled() )
410 return;
411
412 // wait until the condition is signaled from Resume()
413 m_condSuspend.Wait(m_mutexSuspend);
414 }
415
416 void wxThreadInternal::Resume()
417 {
418 wxCHECK_RET( m_state == STATE_PAUSED,
419 _T("can't resume thread which is not suspended.") );
420
421 // we will be able to lock this mutex only when Pause() starts waiting
422 wxMutexLocker lock(m_mutexSuspend);
423 m_condSuspend.Signal();
424
425 SetState(STATE_RUNNING);
426 }
427
428 // -----------------------------------------------------------------------------
429 // static functions
430 // -----------------------------------------------------------------------------
431
432 wxThread *wxThread::This()
433 {
434 return (wxThread *)pthread_getspecific(gs_keySelf);
435 }
436
437 bool wxThread::IsMain()
438 {
439 return (bool)pthread_equal(pthread_self(), gs_tidMain);
440 }
441
442 void wxThread::Yield()
443 {
444 sched_yield();
445 }
446
447 void wxThread::Sleep(unsigned long milliseconds)
448 {
449 wxUsleep(milliseconds);
450 }
451
452 // -----------------------------------------------------------------------------
453 // creating thread
454 // -----------------------------------------------------------------------------
455
456 wxThread::wxThread()
457 {
458 // add this thread to the global list of all threads
459 gs_allThreads.Add(this);
460
461 p_internal = new wxThreadInternal();
462 }
463
464 wxThreadError wxThread::Create()
465 {
466 if (p_internal->GetState() != STATE_NEW)
467 return wxTHREAD_RUNNING;
468
469 // set up the thread attribute: right now, we only set thread priority
470 pthread_attr_t attr;
471 pthread_attr_init(&attr);
472
473 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
474 int prio;
475 if ( pthread_attr_getschedpolicy(&attr, &prio) != 0 )
476 {
477 wxLogError(_("Cannot retrieve thread scheduling policy."));
478 }
479
480 int min_prio = sched_get_priority_min(prio),
481 max_prio = sched_get_priority_max(prio);
482
483 if ( min_prio == -1 || max_prio == -1 )
484 {
485 wxLogError(_("Cannot get priority range for scheduling policy %d."),
486 prio);
487 }
488 else
489 {
490 struct sched_param sp;
491 pthread_attr_getschedparam(&attr, &sp);
492 sp.sched_priority = min_prio +
493 (p_internal->GetPriority()*(max_prio-min_prio))/100;
494 pthread_attr_setschedparam(&attr, &sp);
495 }
496 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
497
498 #ifdef HAVE_PTHREAD_ATTR_SETSCOPE
499 // this will make the threads created by this process really concurrent
500 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
501 #endif // HAVE_PTHREAD_ATTR_SETSCOPE
502
503 // create the new OS thread object
504 int rc = pthread_create(p_internal->GetIdPtr(), &attr,
505 wxThreadInternal::PthreadStart, (void *)this);
506 pthread_attr_destroy(&attr);
507
508 if ( rc != 0 )
509 {
510 p_internal->SetState(STATE_EXITED);
511 return wxTHREAD_NO_RESOURCE;
512 }
513
514 return wxTHREAD_NO_ERROR;
515 }
516
517 wxThreadError wxThread::Run()
518 {
519 return p_internal->Run();
520 }
521
522 // -----------------------------------------------------------------------------
523 // misc accessors
524 // -----------------------------------------------------------------------------
525
526 void wxThread::SetPriority(unsigned int prio)
527 {
528 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY <= (int)prio) &&
529 ((int)prio <= (int)WXTHREAD_MAX_PRIORITY),
530 _T("invalid thread priority") );
531
532 wxCriticalSectionLocker lock(m_critsect);
533
534 switch ( p_internal->GetState() )
535 {
536 case STATE_NEW:
537 // thread not yet started, priority will be set when it is
538 p_internal->SetPriority(prio);
539 break;
540
541 case STATE_RUNNING:
542 case STATE_PAUSED:
543 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
544 {
545 struct sched_param sparam;
546 sparam.sched_priority = prio;
547
548 if ( pthread_setschedparam(p_internal->GetId(),
549 SCHED_OTHER, &sparam) != 0 )
550 {
551 wxLogError(_("Failed to set thread priority %d."), prio);
552 }
553 }
554 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
555 break;
556
557 case STATE_EXITED:
558 default:
559 wxFAIL_MSG(_T("impossible to set thread priority in this state"));
560 }
561 }
562
563 unsigned int wxThread::GetPriority() const
564 {
565 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
566
567 return p_internal->GetPriority();
568 }
569
570 unsigned long wxThread::GetID() const
571 {
572 return (unsigned long)p_internal->GetId();
573 }
574
575 // -----------------------------------------------------------------------------
576 // pause/resume
577 // -----------------------------------------------------------------------------
578
579 wxThreadError wxThread::Pause()
580 {
581 wxCriticalSectionLocker lock(m_critsect);
582
583 if ( p_internal->GetState() != STATE_RUNNING )
584 {
585 wxLogDebug(_T("Can't pause thread which is not running."));
586
587 return wxTHREAD_NOT_RUNNING;
588 }
589
590 p_internal->SetState(STATE_PAUSED);
591
592 return wxTHREAD_NO_ERROR;
593 }
594
595 wxThreadError wxThread::Resume()
596 {
597 wxCriticalSectionLocker lock(m_critsect);
598
599 if ( p_internal->GetState() == STATE_PAUSED )
600 {
601 m_critsect.Leave();
602 p_internal->Resume();
603 m_critsect.Enter();
604
605 return wxTHREAD_NO_ERROR;
606 }
607 else
608 {
609 wxLogDebug(_T("Attempt to resume a thread which is not paused."));
610
611 return wxTHREAD_MISC_ERROR;
612 }
613 }
614
615 // -----------------------------------------------------------------------------
616 // exiting thread
617 // -----------------------------------------------------------------------------
618
619 wxThread::ExitCode wxThread::Delete()
620 {
621 m_critsect.Enter();
622 wxThreadState state = p_internal->GetState();
623 m_critsect.Leave();
624
625 // ask the thread to stop
626 p_internal->SetCancelFlag();
627
628 switch ( state )
629 {
630 case STATE_NEW:
631 case STATE_EXITED:
632 // nothing to do
633 break;
634
635 case STATE_PAUSED:
636 // resume the thread first
637 Resume();
638
639 // fall through
640
641 default:
642 // wait until the thread stops
643 p_internal->Wait();
644 }
645
646 return NULL;
647 }
648
649 wxThreadError wxThread::Kill()
650 {
651 switch ( p_internal->GetState() )
652 {
653 case STATE_NEW:
654 case STATE_EXITED:
655 return wxTHREAD_NOT_RUNNING;
656
657 default:
658 #ifdef HAVE_PTHREAD_CANCEL
659 if ( pthread_cancel(p_internal->GetId()) != 0 )
660 #endif
661 {
662 wxLogError(_("Failed to terminate a thread."));
663
664 return wxTHREAD_MISC_ERROR;
665 }
666
667 return wxTHREAD_NO_ERROR;
668 }
669 }
670
671 void wxThread::Exit(void *status)
672 {
673 // first call user-level clean up code
674 OnExit();
675
676 // next wake up the threads waiting for us (OTOH, this function won't return
677 // until someone waited for us!)
678 p_internal->SignalExit();
679
680 p_internal->SetState(STATE_EXITED);
681
682 // delete both C++ thread object and terminate the OS thread object
683 // GL: This is very ugly and buggy ...
684 // delete this;
685 pthread_exit(status);
686 }
687
688 // also test whether we were paused
689 bool wxThread::TestDestroy()
690 {
691 wxCriticalSectionLocker lock(m_critsect);
692
693 if ( p_internal->GetState() == STATE_PAUSED )
694 {
695 // leave the crit section or the other threads will stop too if they try
696 // to call any of (seemingly harmless) IsXXX() functions while we sleep
697 m_critsect.Leave();
698
699 p_internal->Pause();
700
701 // enter it back before it's finally left in lock object dtor
702 m_critsect.Enter();
703 }
704
705 return p_internal->WasCancelled();
706 }
707
708 wxThread::~wxThread()
709 {
710 // remove this thread from the global array
711 gs_allThreads.Remove(this);
712 }
713
714 // -----------------------------------------------------------------------------
715 // state tests
716 // -----------------------------------------------------------------------------
717
718 bool wxThread::IsRunning() const
719 {
720 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
721
722 return p_internal->GetState() == STATE_RUNNING;
723 }
724
725 bool wxThread::IsAlive() const
726 {
727 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
728
729 switch ( p_internal->GetState() )
730 {
731 case STATE_RUNNING:
732 case STATE_PAUSED:
733 return TRUE;
734
735 default:
736 return FALSE;
737 }
738 }
739
740 bool wxThread::IsPaused() const
741 {
742 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
743
744 return (p_internal->GetState() == STATE_PAUSED);
745 }
746
747 //--------------------------------------------------------------------
748 // wxThreadModule
749 //--------------------------------------------------------------------
750
751 class wxThreadModule : public wxModule
752 {
753 public:
754 virtual bool OnInit();
755 virtual void OnExit();
756
757 private:
758 DECLARE_DYNAMIC_CLASS(wxThreadModule)
759 };
760
761 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
762
763 bool wxThreadModule::OnInit()
764 {
765 int rc = pthread_key_create(&gs_keySelf, NULL /* dtor function */);
766 if ( rc != 0 )
767 {
768 wxLogSysError(rc, _("Thread module initialization failed: "
769 "failed to create thread key"));
770
771 return FALSE;
772 }
773
774 #ifndef __WXGTK12__
775 gs_mutexGui = new wxMutex();
776 #endif
777
778 gs_tidMain = pthread_self();
779
780 #ifndef __WXGTK12__
781 gs_mutexGui->Lock();
782 #endif
783
784 return TRUE;
785 }
786
787 void wxThreadModule::OnExit()
788 {
789 wxASSERT_MSG( wxThread::IsMain(), _T("only main thread can be here") );
790
791 // terminate any threads left
792 size_t count = gs_allThreads.GetCount();
793 if ( count != 0u )
794 wxLogDebug(_T("Some threads were not terminated by the application."));
795
796 for ( size_t n = 0u; n < count; n++ )
797 {
798 gs_allThreads[n]->Delete();
799 }
800
801 #ifndef __WXGTK12__
802 // destroy GUI mutex
803 gs_mutexGui->Unlock();
804
805 delete gs_mutexGui;
806 #endif
807
808 // and free TLD slot
809 (void)pthread_key_delete(gs_keySelf);
810 }
811
812 // ----------------------------------------------------------------------------
813 // global functions
814 // ----------------------------------------------------------------------------
815
816 void wxMutexGuiEnter()
817 {
818 #ifdef __WXGTK12__
819 gdk_threads_enter();
820 #else
821 gs_mutexGui->Lock();
822 #endif
823 }
824
825 void wxMutexGuiLeave()
826 {
827 #ifdef __WXGTK12__
828 gdk_threads_leave();
829 #else
830 gs_mutexGui->Unlock();
831 #endif
832 }
833
834 #endif
835 // wxUSE_THREADS