]> git.saurik.com Git - wxWidgets.git/blob - src/unix/threadpsx.cpp
more threds fixes, more threads tests - seems to work ok for non GUI case
[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 #include "wx/defs.h"
28
29 #if wxUSE_THREADS
30
31 #include "wx/thread.h"
32 #include "wx/module.h"
33 #include "wx/utils.h"
34 #include "wx/log.h"
35 #include "wx/intl.h"
36 #include "wx/dynarray.h"
37
38 #include <stdio.h>
39 #include <unistd.h>
40 #include <pthread.h>
41 #include <errno.h>
42 #include <time.h>
43
44 #if HAVE_SCHED_H
45 #include <sched.h>
46 #endif
47
48 // ----------------------------------------------------------------------------
49 // constants
50 // ----------------------------------------------------------------------------
51
52 // the possible states of the thread and transitions from them
53 enum wxThreadState
54 {
55 STATE_NEW, // didn't start execution yet (=> RUNNING)
56 STATE_RUNNING, // running (=> PAUSED or EXITED)
57 STATE_PAUSED, // suspended (=> RUNNING or EXITED)
58 STATE_EXITED // thread doesn't exist any more
59 };
60
61 // the exit value of a thread which has been cancelled
62 static const wxThread::ExitCode EXITCODE_CANCELLED = (wxThread::ExitCode)-1;
63
64 // our trace mask
65 #define TRACE_THREADS _T("thread")
66
67 // ----------------------------------------------------------------------------
68 // private functions
69 // ----------------------------------------------------------------------------
70
71 static void ScheduleThreadForDeletion();
72 static void DeleteThread(wxThread *This);
73
74 // ----------------------------------------------------------------------------
75 // private classes
76 // ----------------------------------------------------------------------------
77
78 // same as wxMutexLocker but for "native" mutex
79 class MutexLock
80 {
81 public:
82 MutexLock(pthread_mutex_t& mutex)
83 {
84 m_mutex = &mutex;
85 if ( pthread_mutex_lock(m_mutex) != 0 )
86 {
87 wxLogDebug(_T("pthread_mutex_lock() failed"));
88 }
89 }
90
91 ~MutexLock()
92 {
93 if ( pthread_mutex_unlock(m_mutex) != 0 )
94 {
95 wxLogDebug(_T("pthread_mutex_unlock() failed"));
96 }
97 }
98
99 private:
100 pthread_mutex_t *m_mutex;
101 };
102
103 // ----------------------------------------------------------------------------
104 // types
105 // ----------------------------------------------------------------------------
106
107 WX_DEFINE_ARRAY(wxThread *, wxArrayThread);
108
109 // -----------------------------------------------------------------------------
110 // global data
111 // -----------------------------------------------------------------------------
112
113 // we keep the list of all threads created by the application to be able to
114 // terminate them on exit if there are some left - otherwise the process would
115 // be left in memory
116 static wxArrayThread gs_allThreads;
117
118 // the id of the main thread
119 static pthread_t gs_tidMain;
120
121 // the key for the pointer to the associated wxThread object
122 static pthread_key_t gs_keySelf;
123
124 // the number of threads which are being deleted - the program won't exit
125 // until there are any left
126 static size_t gs_nThreadsBeingDeleted = 0;
127
128 // a mutex to protect gs_nThreadsBeingDeleted
129 static pthread_mutex_t gs_mutexDeleteThread = PTHREAD_MUTEX_INITIALIZER;
130
131 // and a condition variable which will be signaled when all
132 // gs_nThreadsBeingDeleted will have been deleted
133 static wxCondition *gs_condAllDeleted = (wxCondition *)NULL;
134
135 #if wxUSE_GUI
136 // this mutex must be acquired before any call to a GUI function
137 static wxMutex *gs_mutexGui;
138 #endif // wxUSE_GUI
139
140 // ============================================================================
141 // implementation
142 // ============================================================================
143
144 //--------------------------------------------------------------------
145 // wxMutex (Posix implementation)
146 //--------------------------------------------------------------------
147
148 class wxMutexInternal
149 {
150 public:
151 pthread_mutex_t m_mutex;
152 };
153
154 wxMutex::wxMutex()
155 {
156 m_internal = new wxMutexInternal;
157
158 pthread_mutex_init(&(m_internal->m_mutex),
159 (pthread_mutexattr_t*) NULL );
160 m_locked = 0;
161 }
162
163 wxMutex::~wxMutex()
164 {
165 if (m_locked > 0)
166 wxLogDebug(wxT("Freeing a locked mutex (%d locks)"), m_locked);
167
168 pthread_mutex_destroy( &(m_internal->m_mutex) );
169 delete m_internal;
170 }
171
172 wxMutexError wxMutex::Lock()
173 {
174 int err = pthread_mutex_lock( &(m_internal->m_mutex) );
175 if (err == EDEADLK)
176 {
177 wxLogDebug(wxT("Locking this mutex would lead to deadlock!"));
178
179 return wxMUTEX_DEAD_LOCK;
180 }
181
182 m_locked++;
183
184 return wxMUTEX_NO_ERROR;
185 }
186
187 wxMutexError wxMutex::TryLock()
188 {
189 if (m_locked)
190 {
191 return wxMUTEX_BUSY;
192 }
193
194 int err = pthread_mutex_trylock( &(m_internal->m_mutex) );
195 switch (err)
196 {
197 case EBUSY: return wxMUTEX_BUSY;
198 }
199
200 m_locked++;
201
202 return wxMUTEX_NO_ERROR;
203 }
204
205 wxMutexError wxMutex::Unlock()
206 {
207 if (m_locked > 0)
208 {
209 m_locked--;
210 }
211 else
212 {
213 wxLogDebug(wxT("Unlocking not locked mutex."));
214
215 return wxMUTEX_UNLOCKED;
216 }
217
218 pthread_mutex_unlock( &(m_internal->m_mutex) );
219
220 return wxMUTEX_NO_ERROR;
221 }
222
223 //--------------------------------------------------------------------
224 // wxCondition (Posix implementation)
225 //--------------------------------------------------------------------
226
227 // The native POSIX condition variables are dumb: if the condition is signaled
228 // before another thread starts to wait on it, the signal is lost and so this
229 // other thread will be never woken up. It's much more convenient to us to
230 // remember that the condition was signaled and to return from Wait()
231 // immediately in this case (this is more like Win32 automatic event objects)
232
233 class wxConditionInternal
234 {
235 public:
236 wxConditionInternal();
237 ~wxConditionInternal();
238
239 void Wait();
240 bool WaitWithTimeout(const timespec* ts);
241
242 void Signal();
243 void Broadcast();
244
245 void WaitDone();
246 bool ShouldWait();
247 bool HasWaiters();
248
249 private:
250 bool m_wasSignaled; // TRUE if condition was signaled while
251 // nobody waited for it
252 size_t m_nWaiters; // TRUE if someone already waits for us
253
254 pthread_mutex_t m_mutexProtect; // protects access to vars above
255
256 pthread_mutex_t m_mutex; // the mutex used with the condition
257 pthread_cond_t m_condition; // the condition itself
258 };
259
260 wxConditionInternal::wxConditionInternal()
261 {
262 m_wasSignaled = FALSE;
263 m_nWaiters = 0;
264
265 if ( pthread_cond_init(&m_condition, (pthread_condattr_t *)NULL) != 0 )
266 {
267 // this is supposed to never happen
268 wxFAIL_MSG( _T("pthread_cond_init() failed") );
269 }
270
271 if ( pthread_mutex_init(&m_mutex, (pthread_mutexattr_t *)NULL) != 0 ||
272 pthread_mutex_init(&m_mutexProtect, NULL) != 0 )
273 {
274 // neither this
275 wxFAIL_MSG( _T("wxCondition: pthread_mutex_init() failed") );
276 }
277
278 // initially the mutex is locked, so no thread can Signal() or Broadcast()
279 // until another thread starts to Wait()
280 if ( pthread_mutex_lock(&m_mutex) != 0 )
281 {
282 wxFAIL_MSG( _T("wxCondition: pthread_mutex_lock() failed") );
283 }
284 }
285
286 wxConditionInternal::~wxConditionInternal()
287 {
288 if ( pthread_cond_destroy( &m_condition ) != 0 )
289 {
290 wxLogDebug(_T("Failed to destroy condition variable (some "
291 "threads are probably still waiting on it?)"));
292 }
293
294 if ( pthread_mutex_unlock( &m_mutex ) != 0 )
295 {
296 wxLogDebug(_T("wxCondition: failed to unlock the mutex"));
297 }
298
299 if ( pthread_mutex_destroy( &m_mutex ) != 0 ||
300 pthread_mutex_destroy( &m_mutexProtect ) != 0 )
301 {
302 wxLogDebug(_T("Failed to destroy mutex (it is probably locked)"));
303 }
304 }
305
306 void wxConditionInternal::WaitDone()
307 {
308 MutexLock lock(m_mutexProtect);
309
310 m_wasSignaled = FALSE;
311 m_nWaiters--;
312 }
313
314 bool wxConditionInternal::ShouldWait()
315 {
316 MutexLock lock(m_mutexProtect);
317
318 if ( m_wasSignaled )
319 {
320 // the condition was signaled before we started to wait, reset the
321 // flag and return
322 m_wasSignaled = FALSE;
323
324 return FALSE;
325 }
326
327 // we start to wait for it
328 m_nWaiters++;
329
330 return TRUE;
331 }
332
333 bool wxConditionInternal::HasWaiters()
334 {
335 MutexLock lock(m_mutexProtect);
336
337 if ( m_nWaiters )
338 {
339 // someone waits for us, signal the condition normally
340 return TRUE;
341 }
342
343 // nobody waits for us and may be never will - so just remember that the
344 // condition was signaled and don't do anything else
345 m_wasSignaled = TRUE;
346
347 return FALSE;
348 }
349
350 void wxConditionInternal::Wait()
351 {
352 if ( ShouldWait() )
353 {
354 if ( pthread_cond_wait( &m_condition, &m_mutex ) != 0 )
355 {
356 // not supposed to ever happen
357 wxFAIL_MSG( _T("pthread_cond_wait() failed") );
358 }
359 }
360
361 WaitDone();
362 }
363
364 bool wxConditionInternal::WaitWithTimeout(const timespec* ts)
365 {
366 bool ok;
367
368 if ( ShouldWait() )
369 {
370 switch ( pthread_cond_timedwait( &m_condition, &m_mutex, ts ) )
371 {
372 case 0:
373 // condition signaled
374 ok = TRUE;
375 break;
376
377 default:
378 wxLogDebug(_T("pthread_cond_timedwait() failed"));
379
380 // fall through
381
382 case ETIMEDOUT:
383 case EINTR:
384 // wait interrupted or timeout elapsed
385 ok = FALSE;
386 }
387 }
388 else
389 {
390 // the condition had already been signaled before
391 ok = TRUE;
392 }
393
394 WaitDone();
395
396 return ok;
397 }
398
399 void wxConditionInternal::Signal()
400 {
401 if ( HasWaiters() )
402 {
403 MutexLock lock(m_mutex);
404
405 if ( pthread_cond_signal( &m_condition ) != 0 )
406 {
407 // shouldn't ever happen
408 wxFAIL_MSG(_T("pthread_cond_signal() failed"));
409 }
410 }
411 }
412
413 void wxConditionInternal::Broadcast()
414 {
415 if ( HasWaiters() )
416 {
417 MutexLock lock(m_mutex);
418
419 if ( pthread_cond_broadcast( &m_condition ) != 0 )
420 {
421 // shouldn't ever happen
422 wxFAIL_MSG(_T("pthread_cond_broadcast() failed"));
423 }
424 }
425 }
426
427 wxCondition::wxCondition()
428 {
429 m_internal = new wxConditionInternal;
430 }
431
432 wxCondition::~wxCondition()
433 {
434 delete m_internal;
435 }
436
437 void wxCondition::Wait()
438 {
439 m_internal->Wait();
440 }
441
442 bool wxCondition::Wait(unsigned long sec, unsigned long nsec)
443 {
444 timespec tspec;
445
446 tspec.tv_sec = time(0L) + sec; // FIXME is time(0) correct here?
447 tspec.tv_nsec = nsec;
448
449 return m_internal->WaitWithTimeout(&tspec);
450 }
451
452 void wxCondition::Signal()
453 {
454 m_internal->Signal();
455 }
456
457 void wxCondition::Broadcast()
458 {
459 m_internal->Broadcast();
460 }
461
462 //--------------------------------------------------------------------
463 // wxThread (Posix implementation)
464 //--------------------------------------------------------------------
465
466 class wxThreadInternal
467 {
468 public:
469 wxThreadInternal();
470 ~wxThreadInternal();
471
472 // thread entry function
473 static void *PthreadStart(void *ptr);
474
475 #if HAVE_THREAD_CLEANUP_FUNCTIONS
476 // thread exit function
477 static void PthreadCleanup(void *ptr);
478 #endif
479
480 // thread actions
481 // start the thread
482 wxThreadError Run();
483 // ask the thread to terminate
484 void Wait();
485 // wake up threads waiting for our termination
486 void SignalExit();
487 // wake up threads waiting for our start
488 void SignalRun() { m_condRun.Signal(); }
489 // go to sleep until Resume() is called
490 void Pause();
491 // resume the thread
492 void Resume();
493
494 // accessors
495 // priority
496 int GetPriority() const { return m_prio; }
497 void SetPriority(int prio) { m_prio = prio; }
498 // state
499 wxThreadState GetState() const { return m_state; }
500 void SetState(wxThreadState state) { m_state = state; }
501 // id
502 pthread_t GetId() const { return m_threadId; }
503 pthread_t *GetIdPtr() { return &m_threadId; }
504 // "cancelled" flag
505 void SetCancelFlag() { m_cancelled = TRUE; }
506 bool WasCancelled() const { return m_cancelled; }
507 // exit code
508 void SetExitCode(wxThread::ExitCode exitcode) { m_exitcode = exitcode; }
509 wxThread::ExitCode GetExitCode() const { return m_exitcode; }
510
511 // the pause flag
512 void SetReallyPaused(bool paused) { m_isPaused = paused; }
513 bool IsReallyPaused() const { return m_isPaused; }
514
515 // tell the thread that it is a detached one
516 void Detach()
517 {
518 m_shouldBeJoined = m_shouldBroadcast = FALSE;
519 m_isDetached = TRUE;
520 }
521 // but even detached threads need to notifyus about their termination
522 // sometimes - tell the thread that it should do it
523 void Notify() { m_shouldBroadcast = TRUE; }
524
525 private:
526 pthread_t m_threadId; // id of the thread
527 wxThreadState m_state; // see wxThreadState enum
528 int m_prio; // in wxWindows units: from 0 to 100
529
530 // this flag is set when the thread should terminate
531 bool m_cancelled;
532
533 // this flag is set when the thread is blocking on m_condSuspend
534 bool m_isPaused;
535
536 // the thread exit code - only used for joinable (!detached) threads and
537 // is only valid after the thread termination
538 wxThread::ExitCode m_exitcode;
539
540 // many threads may call Wait(), but only one of them should call
541 // pthread_join(), so we have to keep track of this
542 wxCriticalSection m_csJoinFlag;
543 bool m_shouldBeJoined;
544 bool m_shouldBroadcast;
545 bool m_isDetached;
546
547 // VZ: it's possible that we might do with less than three different
548 // condition objects - for example, m_condRun and m_condEnd a priori
549 // won't be used in the same time. But for now I prefer this may be a
550 // bit less efficient but safer solution of having distinct condition
551 // variables for each purpose.
552
553 // this condition is signaled by Run() and the threads Entry() is not
554 // called before it is done
555 wxCondition m_condRun;
556
557 // this one is signaled when the thread should resume after having been
558 // Pause()d
559 wxCondition m_condSuspend;
560
561 // finally this one is signalled when the thread exits
562 wxCondition m_condEnd;
563 };
564
565 // ----------------------------------------------------------------------------
566 // thread startup and exit functions
567 // ----------------------------------------------------------------------------
568
569 void *wxThreadInternal::PthreadStart(void *ptr)
570 {
571 wxThread *thread = (wxThread *)ptr;
572 wxThreadInternal *pthread = thread->m_internal;
573
574 // associate the thread pointer with the newly created thread so that
575 // wxThread::This() will work
576 int rc = pthread_setspecific(gs_keySelf, thread);
577 if ( rc != 0 )
578 {
579 wxLogSysError(rc, _("Cannot start thread: error writing TLS"));
580
581 return (void *)-1;
582 }
583
584 // have to declare this before pthread_cleanup_push() which defines a
585 // block!
586 bool dontRunAtAll;
587
588 #if HAVE_THREAD_CLEANUP_FUNCTIONS
589 // install the cleanup handler which will be called if the thread is
590 // cancelled
591 pthread_cleanup_push(wxThreadInternal::PthreadCleanup, ptr);
592 #endif // HAVE_THREAD_CLEANUP_FUNCTIONS
593
594 // wait for the condition to be signaled from Run()
595 pthread->m_condRun.Wait();
596
597 // test whether we should run the run at all - may be it was deleted
598 // before it started to Run()?
599 {
600 wxCriticalSectionLocker lock(thread->m_critsect);
601
602 dontRunAtAll = pthread->GetState() == STATE_NEW &&
603 pthread->WasCancelled();
604 }
605
606 if ( !dontRunAtAll )
607 {
608 // call the main entry
609 pthread->m_exitcode = thread->Entry();
610
611 wxLogTrace(TRACE_THREADS, _T("Thread %ld left its Entry()."),
612 pthread->GetId());
613
614 {
615 wxCriticalSectionLocker lock(thread->m_critsect);
616
617 wxLogTrace(TRACE_THREADS, _T("Thread %ld changes state to EXITED."),
618 pthread->GetId());
619
620 // change the state of the thread to "exited" so that
621 // PthreadCleanup handler won't do anything from now (if it's
622 // called before we do pthread_cleanup_pop below)
623 pthread->SetState(STATE_EXITED);
624 }
625 }
626
627 // NB: at least under Linux, pthread_cleanup_push/pop are macros and pop
628 // contains the matching '}' for the '{' in push, so they must be used
629 // in the same block!
630 #if HAVE_THREAD_CLEANUP_FUNCTIONS
631 // remove the cleanup handler without executing it
632 pthread_cleanup_pop(FALSE);
633 #endif // HAVE_THREAD_CLEANUP_FUNCTIONS
634
635 if ( dontRunAtAll )
636 {
637 delete thread;
638
639 return EXITCODE_CANCELLED;
640 }
641 else
642 {
643 // terminate the thread
644 thread->Exit(pthread->m_exitcode);
645
646 wxFAIL_MSG(wxT("wxThread::Exit() can't return."));
647
648 return NULL;
649 }
650 }
651
652 #if HAVE_THREAD_CLEANUP_FUNCTIONS
653
654 // this handler is called when the thread is cancelled
655 void wxThreadInternal::PthreadCleanup(void *ptr)
656 {
657 wxThread *thread = (wxThread *) ptr;
658
659 {
660 wxCriticalSectionLocker lock(thread->m_critsect);
661 if ( thread->m_internal->GetState() == STATE_EXITED )
662 {
663 // thread is already considered as finished.
664 return;
665 }
666 }
667
668 // exit the thread gracefully
669 thread->Exit(EXITCODE_CANCELLED);
670 }
671
672 #endif // HAVE_THREAD_CLEANUP_FUNCTIONS
673
674 // ----------------------------------------------------------------------------
675 // wxThreadInternal
676 // ----------------------------------------------------------------------------
677
678 wxThreadInternal::wxThreadInternal()
679 {
680 m_state = STATE_NEW;
681 m_cancelled = FALSE;
682 m_prio = WXTHREAD_DEFAULT_PRIORITY;
683 m_threadId = 0;
684 m_exitcode = 0;
685
686 // set to TRUE only when the thread starts waiting on m_condSuspend
687 m_isPaused = FALSE;
688
689 // defaults for joinable threads
690 m_shouldBeJoined = TRUE;
691 m_shouldBroadcast = TRUE;
692 m_isDetached = FALSE;
693 }
694
695 wxThreadInternal::~wxThreadInternal()
696 {
697 }
698
699 wxThreadError wxThreadInternal::Run()
700 {
701 wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
702 wxT("thread may only be started once after Create()") );
703
704 SignalRun();
705
706 SetState(STATE_RUNNING);
707
708 return wxTHREAD_NO_ERROR;
709 }
710
711 void wxThreadInternal::Wait()
712 {
713 // if the thread we're waiting for is waiting for the GUI mutex, we will
714 // deadlock so make sure we release it temporarily
715 if ( wxThread::IsMain() )
716 wxMutexGuiLeave();
717
718 bool isDetached = m_isDetached;
719 long id = GetId();
720 wxLogTrace(TRACE_THREADS, _T("Starting to wait for thread %ld to exit."),
721 id);
722
723 // wait until the thread terminates (we're blocking in _another_ thread,
724 // of course)
725 m_condEnd.Wait();
726
727 wxLogTrace(TRACE_THREADS, _T("Finished waiting for thread %ld."), id);
728
729 // we can't use any member variables any more if the thread is detached
730 // because it could be already deleted
731 if ( !isDetached )
732 {
733 // to avoid memory leaks we should call pthread_join(), but it must
734 // only be done once
735 wxCriticalSectionLocker lock(m_csJoinFlag);
736
737 if ( m_shouldBeJoined )
738 {
739 // FIXME shouldn't we set cancellation type to DISABLED here? If
740 // we're cancelled inside pthread_join(), things will almost
741 // certainly break - but if we disable the cancellation, we
742 // might deadlock
743 if ( pthread_join(id, &m_exitcode) != 0 )
744 {
745 wxLogError(_("Failed to join a thread, potential memory leak "
746 "detected - please restart the program"));
747 }
748
749 m_shouldBeJoined = FALSE;
750 }
751 }
752
753 // reacquire GUI mutex
754 if ( wxThread::IsMain() )
755 wxMutexGuiEnter();
756 }
757
758 void wxThreadInternal::SignalExit()
759 {
760 wxLogTrace(TRACE_THREADS, _T("Thread %ld about to exit."), GetId());
761
762 SetState(STATE_EXITED);
763
764 // wake up all the threads waiting for our termination - if there are any
765 if ( m_shouldBroadcast )
766 {
767 wxLogTrace(TRACE_THREADS, _T("Thread %ld signals end condition."),
768 GetId());
769
770 m_condEnd.Broadcast();
771 }
772 }
773
774 void wxThreadInternal::Pause()
775 {
776 // the state is set from the thread which pauses us first, this function
777 // is called later so the state should have been already set
778 wxCHECK_RET( m_state == STATE_PAUSED,
779 wxT("thread must first be paused with wxThread::Pause().") );
780
781 wxLogTrace(TRACE_THREADS, _T("Thread %ld goes to sleep."), GetId());
782
783 // wait until the condition is signaled from Resume()
784 m_condSuspend.Wait();
785 }
786
787 void wxThreadInternal::Resume()
788 {
789 wxCHECK_RET( m_state == STATE_PAUSED,
790 wxT("can't resume thread which is not suspended.") );
791
792 // the thread might be not actually paused yet - if there were no call to
793 // TestDestroy() since the last call to Pause() for example
794 if ( IsReallyPaused() )
795 {
796 wxLogTrace(TRACE_THREADS, _T("Waking up thread %ld"), GetId());
797
798 // wake up Pause()
799 m_condSuspend.Signal();
800
801 // reset the flag
802 SetReallyPaused(FALSE);
803 }
804 else
805 {
806 wxLogTrace(TRACE_THREADS, _T("Thread %ld is not yet really paused"),
807 GetId());
808 }
809
810 SetState(STATE_RUNNING);
811 }
812
813 // -----------------------------------------------------------------------------
814 // wxThread static functions
815 // -----------------------------------------------------------------------------
816
817 wxThread *wxThread::This()
818 {
819 return (wxThread *)pthread_getspecific(gs_keySelf);
820 }
821
822 bool wxThread::IsMain()
823 {
824 return (bool)pthread_equal(pthread_self(), gs_tidMain);
825 }
826
827 void wxThread::Yield()
828 {
829 sched_yield();
830 }
831
832 void wxThread::Sleep(unsigned long milliseconds)
833 {
834 wxUsleep(milliseconds);
835 }
836
837 // -----------------------------------------------------------------------------
838 // creating thread
839 // -----------------------------------------------------------------------------
840
841 wxThread::wxThread(wxThreadKind kind)
842 {
843 // add this thread to the global list of all threads
844 gs_allThreads.Add(this);
845
846 m_internal = new wxThreadInternal();
847
848 m_isDetached = kind == wxTHREAD_DETACHED;
849 }
850
851 wxThreadError wxThread::Create()
852 {
853 if ( m_internal->GetState() != STATE_NEW )
854 {
855 // don't recreate thread
856 return wxTHREAD_RUNNING;
857 }
858
859 // set up the thread attribute: right now, we only set thread priority
860 pthread_attr_t attr;
861 pthread_attr_init(&attr);
862
863 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
864 int policy;
865 if ( pthread_attr_getschedpolicy(&attr, &policy) != 0 )
866 {
867 wxLogError(_("Cannot retrieve thread scheduling policy."));
868 }
869
870 int min_prio = sched_get_priority_min(policy),
871 max_prio = sched_get_priority_max(policy),
872 prio = m_internal->GetPriority();
873
874 if ( min_prio == -1 || max_prio == -1 )
875 {
876 wxLogError(_("Cannot get priority range for scheduling policy %d."),
877 policy);
878 }
879 else if ( max_prio == min_prio )
880 {
881 if ( prio != WXTHREAD_DEFAULT_PRIORITY )
882 {
883 // notify the programmer that this doesn't work here
884 wxLogWarning(_("Thread priority setting is ignored."));
885 }
886 //else: we have default priority, so don't complain
887
888 // anyhow, don't do anything because priority is just ignored
889 }
890 else
891 {
892 struct sched_param sp;
893 if ( pthread_attr_getschedparam(&attr, &sp) != 0 )
894 {
895 wxFAIL_MSG(_T("pthread_attr_getschedparam() failed"));
896 }
897
898 sp.sched_priority = min_prio + (prio*(max_prio - min_prio))/100;
899
900 if ( pthread_attr_setschedparam(&attr, &sp) != 0 )
901 {
902 wxFAIL_MSG(_T("pthread_attr_setschedparam(priority) failed"));
903 }
904 }
905 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
906
907 #ifdef HAVE_PTHREAD_ATTR_SETSCOPE
908 // this will make the threads created by this process really concurrent
909 if ( pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) != 0 )
910 {
911 wxFAIL_MSG(_T("pthread_attr_setscope(PTHREAD_SCOPE_SYSTEM) failed"));
912 }
913 #endif // HAVE_PTHREAD_ATTR_SETSCOPE
914
915 // VZ: assume that this one is always available (it's rather fundamental),
916 // if this function is ever missing we should try to use
917 // pthread_detach() instead (after thread creation)
918 if ( m_isDetached )
919 {
920 if ( pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0 )
921 {
922 wxFAIL_MSG(_T("pthread_attr_setdetachstate(DETACHED) failed"));
923 }
924
925 // never try to join detached threads
926 m_internal->Detach();
927 }
928 //else: threads are created joinable by default, it's ok
929
930 // create the new OS thread object
931 int rc = pthread_create
932 (
933 m_internal->GetIdPtr(),
934 &attr,
935 wxThreadInternal::PthreadStart,
936 (void *)this
937 );
938
939 if ( pthread_attr_destroy(&attr) != 0 )
940 {
941 wxFAIL_MSG(_T("pthread_attr_destroy() failed"));
942 }
943
944 if ( rc != 0 )
945 {
946 m_internal->SetState(STATE_EXITED);
947
948 return wxTHREAD_NO_RESOURCE;
949 }
950
951 return wxTHREAD_NO_ERROR;
952 }
953
954 wxThreadError wxThread::Run()
955 {
956 wxCriticalSectionLocker lock(m_critsect);
957
958 wxCHECK_MSG( m_internal->GetId(), wxTHREAD_MISC_ERROR,
959 wxT("must call wxThread::Create() first") );
960
961 return m_internal->Run();
962 }
963
964 // -----------------------------------------------------------------------------
965 // misc accessors
966 // -----------------------------------------------------------------------------
967
968 void wxThread::SetPriority(unsigned int prio)
969 {
970 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY <= (int)prio) &&
971 ((int)prio <= (int)WXTHREAD_MAX_PRIORITY),
972 wxT("invalid thread priority") );
973
974 wxCriticalSectionLocker lock(m_critsect);
975
976 switch ( m_internal->GetState() )
977 {
978 case STATE_NEW:
979 // thread not yet started, priority will be set when it is
980 m_internal->SetPriority(prio);
981 break;
982
983 case STATE_RUNNING:
984 case STATE_PAUSED:
985 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
986 {
987 struct sched_param sparam;
988 sparam.sched_priority = prio;
989
990 if ( pthread_setschedparam(m_internal->GetId(),
991 SCHED_OTHER, &sparam) != 0 )
992 {
993 wxLogError(_("Failed to set thread priority %d."), prio);
994 }
995 }
996 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
997 break;
998
999 case STATE_EXITED:
1000 default:
1001 wxFAIL_MSG(wxT("impossible to set thread priority in this state"));
1002 }
1003 }
1004
1005 unsigned int wxThread::GetPriority() const
1006 {
1007 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
1008
1009 return m_internal->GetPriority();
1010 }
1011
1012 unsigned long wxThread::GetId() const
1013 {
1014 return (unsigned long)m_internal->GetId();
1015 }
1016
1017 // -----------------------------------------------------------------------------
1018 // pause/resume
1019 // -----------------------------------------------------------------------------
1020
1021 wxThreadError wxThread::Pause()
1022 {
1023 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1024 _T("a thread can't pause itself") );
1025
1026 wxCriticalSectionLocker lock(m_critsect);
1027
1028 if ( m_internal->GetState() != STATE_RUNNING )
1029 {
1030 wxLogDebug(wxT("Can't pause thread which is not running."));
1031
1032 return wxTHREAD_NOT_RUNNING;
1033 }
1034
1035 wxLogTrace(TRACE_THREADS, _T("Asking thread %ld to pause."),
1036 GetId());
1037
1038 // just set a flag, the thread will be really paused only during the next
1039 // call to TestDestroy()
1040 m_internal->SetState(STATE_PAUSED);
1041
1042 return wxTHREAD_NO_ERROR;
1043 }
1044
1045 wxThreadError wxThread::Resume()
1046 {
1047 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1048 _T("a thread can't resume itself") );
1049
1050 wxCriticalSectionLocker lock(m_critsect);
1051
1052 wxThreadState state = m_internal->GetState();
1053
1054 switch ( state )
1055 {
1056 case STATE_PAUSED:
1057 wxLogTrace(TRACE_THREADS, _T("Thread %ld suspended, resuming."),
1058 GetId());
1059
1060 m_internal->Resume();
1061
1062 return wxTHREAD_NO_ERROR;
1063
1064 case STATE_EXITED:
1065 wxLogTrace(TRACE_THREADS, _T("Thread %ld exited, won't resume."),
1066 GetId());
1067 return wxTHREAD_NO_ERROR;
1068
1069 default:
1070 wxLogDebug(_T("Attempt to resume a thread which is not paused."));
1071
1072 return wxTHREAD_MISC_ERROR;
1073 }
1074 }
1075
1076 // -----------------------------------------------------------------------------
1077 // exiting thread
1078 // -----------------------------------------------------------------------------
1079
1080 wxThread::ExitCode wxThread::Wait()
1081 {
1082 wxCHECK_MSG( This() != this, (ExitCode)-1,
1083 _T("a thread can't wait for itself") );
1084
1085 wxCHECK_MSG( !m_isDetached, (ExitCode)-1,
1086 _T("can't wait for detached thread") );
1087
1088 m_internal->Wait();
1089
1090 return m_internal->GetExitCode();
1091 }
1092
1093 wxThreadError wxThread::Delete(ExitCode *rc)
1094 {
1095 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1096 _T("a thread can't delete itself") );
1097
1098 m_critsect.Enter();
1099 wxThreadState state = m_internal->GetState();
1100
1101 // ask the thread to stop
1102 m_internal->SetCancelFlag();
1103
1104 if ( m_isDetached )
1105 {
1106 // detached threads won't broadcast about their termination by default
1107 // because usually nobody waits for them - but here we do, so ask the
1108 // thread to notify us
1109 m_internal->Notify();
1110 }
1111
1112 m_critsect.Leave();
1113
1114 switch ( state )
1115 {
1116 case STATE_NEW:
1117 // we need to wake up the thread so that PthreadStart() will
1118 // terminate - right now it's blocking on m_condRun
1119 m_internal->SignalRun();
1120
1121 // fall through
1122
1123 case STATE_EXITED:
1124 // nothing to do
1125 break;
1126
1127 case STATE_PAUSED:
1128 // resume the thread first (don't call our Resume() because this
1129 // would dead lock when it tries to enter m_critsect)
1130 m_internal->Resume();
1131
1132 // fall through
1133
1134 default:
1135 // wait until the thread stops
1136 m_internal->Wait();
1137
1138 if ( rc )
1139 {
1140 wxASSERT_MSG( !m_isDetached,
1141 _T("no return code for detached threads") );
1142
1143 // if it's a joinable thread, it's not deleted yet
1144 *rc = m_internal->GetExitCode();
1145 }
1146 }
1147
1148 return wxTHREAD_NO_ERROR;
1149 }
1150
1151 wxThreadError wxThread::Kill()
1152 {
1153 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1154 _T("a thread can't kill itself") );
1155
1156 switch ( m_internal->GetState() )
1157 {
1158 case STATE_NEW:
1159 case STATE_EXITED:
1160 return wxTHREAD_NOT_RUNNING;
1161
1162 case STATE_PAUSED:
1163 // resume the thread first
1164 Resume();
1165
1166 // fall through
1167
1168 default:
1169 #ifdef HAVE_PTHREAD_CANCEL
1170 if ( pthread_cancel(m_internal->GetId()) != 0 )
1171 #endif
1172 {
1173 wxLogError(_("Failed to terminate a thread."));
1174
1175 return wxTHREAD_MISC_ERROR;
1176 }
1177
1178 if ( m_isDetached )
1179 {
1180 // if we use cleanup function, this will be done from
1181 // PthreadCleanup()
1182 #if !HAVE_THREAD_CLEANUP_FUNCTIONS
1183 ScheduleThreadForDeletion();
1184
1185 OnExit();
1186
1187 DeleteThread(this);
1188 #endif // HAVE_THREAD_CLEANUP_FUNCTIONS
1189 }
1190 else
1191 {
1192 m_internal->SetExitCode(EXITCODE_CANCELLED);
1193 }
1194
1195 return wxTHREAD_NO_ERROR;
1196 }
1197 }
1198
1199 void wxThread::Exit(ExitCode status)
1200 {
1201 wxASSERT_MSG( This() == this,
1202 _T("wxThread::Exit() can only be called in the "
1203 "context of the same thread") );
1204
1205 // from the moment we call OnExit(), the main program may terminate at any
1206 // moment, so mark this thread as being already in process of being
1207 // deleted or wxThreadModule::OnExit() will try to delete it again
1208 ScheduleThreadForDeletion();
1209
1210 // don't enter m_critsect before calling OnExit() because the user code
1211 // might deadlock if, for example, it signals a condition in OnExit() (a
1212 // common case) while the main thread calls any of functions entering
1213 // m_critsect on us (almost all of them do)
1214 OnExit();
1215
1216 // now do enter it because SignalExit() will change our state
1217 m_critsect.Enter();
1218
1219 // next wake up the threads waiting for us (OTOH, this function won't return
1220 // until someone waited for us!)
1221 m_internal->SignalExit();
1222
1223 // leave the critical section before entering the dtor which tries to
1224 // enter it
1225 m_critsect.Leave();
1226
1227 // delete C++ thread object if this is a detached thread - user is
1228 // responsible for doing this for joinable ones
1229 if ( m_isDetached )
1230 {
1231 // FIXME I'm feeling bad about it - what if another thread function is
1232 // called (in another thread context) now? It will try to access
1233 // half destroyed object which will probably result in something
1234 // very bad - but we can't protect this by a crit section unless
1235 // we make it a global object, but this would mean that we can
1236 // only call one thread function at a time :-(
1237 DeleteThread(this);
1238 }
1239
1240 // terminate the thread (pthread_exit() never returns)
1241 pthread_exit(status);
1242
1243 wxFAIL_MSG(_T("pthread_exit() failed"));
1244 }
1245
1246 // also test whether we were paused
1247 bool wxThread::TestDestroy()
1248 {
1249 wxASSERT_MSG( This() == this,
1250 _T("wxThread::TestDestroy() can only be called in the "
1251 "context of the same thread") );
1252
1253 m_critsect.Enter();
1254
1255 if ( m_internal->GetState() == STATE_PAUSED )
1256 {
1257 m_internal->SetReallyPaused(TRUE);
1258
1259 // leave the crit section or the other threads will stop too if they
1260 // try to call any of (seemingly harmless) IsXXX() functions while we
1261 // sleep
1262 m_critsect.Leave();
1263
1264 m_internal->Pause();
1265 }
1266 else
1267 {
1268 // thread wasn't requested to pause, nothing to do
1269 m_critsect.Leave();
1270 }
1271
1272 return m_internal->WasCancelled();
1273 }
1274
1275 wxThread::~wxThread()
1276 {
1277 #ifdef __WXDEBUG__
1278 m_critsect.Enter();
1279
1280 // check that the thread either exited or couldn't be created
1281 if ( m_internal->GetState() != STATE_EXITED &&
1282 m_internal->GetState() != STATE_NEW )
1283 {
1284 wxLogDebug(_T("The thread %ld is being destroyed although it is still "
1285 "running! The application may crash."), GetId());
1286 }
1287
1288 m_critsect.Leave();
1289 #endif // __WXDEBUG__
1290
1291 delete m_internal;
1292
1293 // remove this thread from the global array
1294 gs_allThreads.Remove(this);
1295
1296 // detached thread will decrement this counter in DeleteThread(), but it
1297 // is not called for the joinable threads, so do it here
1298 if ( !m_isDetached )
1299 {
1300 MutexLock lock(gs_mutexDeleteThread);
1301 gs_nThreadsBeingDeleted--;
1302
1303 wxLogTrace(TRACE_THREADS, _T("%u scheduled for deletion threads left."),
1304 gs_nThreadsBeingDeleted - 1);
1305 }
1306 }
1307
1308 // -----------------------------------------------------------------------------
1309 // state tests
1310 // -----------------------------------------------------------------------------
1311
1312 bool wxThread::IsRunning() const
1313 {
1314 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
1315
1316 return m_internal->GetState() == STATE_RUNNING;
1317 }
1318
1319 bool wxThread::IsAlive() const
1320 {
1321 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
1322
1323 switch ( m_internal->GetState() )
1324 {
1325 case STATE_RUNNING:
1326 case STATE_PAUSED:
1327 return TRUE;
1328
1329 default:
1330 return FALSE;
1331 }
1332 }
1333
1334 bool wxThread::IsPaused() const
1335 {
1336 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
1337
1338 return (m_internal->GetState() == STATE_PAUSED);
1339 }
1340
1341 //--------------------------------------------------------------------
1342 // wxThreadModule
1343 //--------------------------------------------------------------------
1344
1345 class wxThreadModule : public wxModule
1346 {
1347 public:
1348 virtual bool OnInit();
1349 virtual void OnExit();
1350
1351 private:
1352 DECLARE_DYNAMIC_CLASS(wxThreadModule)
1353 };
1354
1355 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
1356
1357 bool wxThreadModule::OnInit()
1358 {
1359 int rc = pthread_key_create(&gs_keySelf, NULL /* dtor function */);
1360 if ( rc != 0 )
1361 {
1362 wxLogSysError(rc, _("Thread module initialization failed: "
1363 "failed to create thread key"));
1364
1365 return FALSE;
1366 }
1367
1368 gs_tidMain = pthread_self();
1369
1370 #if wxUSE_GUI
1371 gs_mutexGui = new wxMutex();
1372
1373 gs_mutexGui->Lock();
1374 #endif // wxUSE_GUI
1375
1376 return TRUE;
1377 }
1378
1379 void wxThreadModule::OnExit()
1380 {
1381 wxASSERT_MSG( wxThread::IsMain(), wxT("only main thread can be here") );
1382
1383 // are there any threads left which are being deleted right now?
1384 size_t nThreadsBeingDeleted;
1385 {
1386 MutexLock lock(gs_mutexDeleteThread);
1387 nThreadsBeingDeleted = gs_nThreadsBeingDeleted;
1388 }
1389
1390 if ( nThreadsBeingDeleted > 0 )
1391 {
1392 wxLogTrace(TRACE_THREADS, _T("Waiting for %u threads to disappear"),
1393 nThreadsBeingDeleted);
1394
1395 // have to wait until all of them disappear
1396 gs_condAllDeleted->Wait();
1397 }
1398
1399 // terminate any threads left
1400 size_t count = gs_allThreads.GetCount();
1401 if ( count != 0u )
1402 {
1403 wxLogDebug(wxT("%u threads were not terminated by the application."),
1404 count);
1405 }
1406
1407 for ( size_t n = 0u; n < count; n++ )
1408 {
1409 // Delete calls the destructor which removes the current entry. We
1410 // should only delete the first one each time.
1411 gs_allThreads[0]->Delete();
1412 }
1413
1414 #if wxUSE_GUI
1415 // destroy GUI mutex
1416 gs_mutexGui->Unlock();
1417
1418 delete gs_mutexGui;
1419 #endif // wxUSE_GUI
1420
1421 // and free TLD slot
1422 (void)pthread_key_delete(gs_keySelf);
1423 }
1424
1425 // ----------------------------------------------------------------------------
1426 // global functions
1427 // ----------------------------------------------------------------------------
1428
1429 static void ScheduleThreadForDeletion()
1430 {
1431 MutexLock lock(gs_mutexDeleteThread);
1432
1433 if ( gs_nThreadsBeingDeleted == 0 )
1434 {
1435 gs_condAllDeleted = new wxCondition;
1436 }
1437
1438 gs_nThreadsBeingDeleted++;
1439
1440 wxLogTrace(TRACE_THREADS, _T("%u thread%s waiting to be deleted"),
1441 gs_nThreadsBeingDeleted,
1442 gs_nThreadsBeingDeleted == 1 ? "" : "s");
1443 }
1444
1445 static void DeleteThread(wxThread *This)
1446 {
1447 // gs_mutexDeleteThread should be unlocked before signalling the condition
1448 // or wxThreadModule::OnExit() would deadlock
1449 {
1450 MutexLock lock(gs_mutexDeleteThread);
1451
1452 wxLogTrace(TRACE_THREADS, _T("Thread %ld auto deletes."), This->GetId());
1453
1454 delete This;
1455
1456 wxCHECK_RET( gs_nThreadsBeingDeleted > 0,
1457 _T("no threads scheduled for deletion, yet we delete "
1458 "one?") );
1459 }
1460
1461 wxLogTrace(TRACE_THREADS, _T("%u scheduled for deletion threads left."),
1462 gs_nThreadsBeingDeleted - 1);
1463
1464 if ( !--gs_nThreadsBeingDeleted )
1465 {
1466 // no more threads left, signal it
1467 gs_condAllDeleted->Signal();
1468
1469 delete gs_condAllDeleted;
1470 gs_condAllDeleted = (wxCondition *)NULL;
1471 }
1472 }
1473
1474 void wxMutexGuiEnter()
1475 {
1476 #if wxUSE_GUI
1477 gs_mutexGui->Lock();
1478 #endif // wxUSE_GUI
1479 }
1480
1481 void wxMutexGuiLeave()
1482 {
1483 #if wxUSE_GUI
1484 gs_mutexGui->Unlock();
1485 #endif // wxUSE_GUI
1486 }
1487
1488 #endif
1489 // wxUSE_THREADS