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