]> git.saurik.com Git - wxWidgets.git/blob - src/unix/threadpsx.cpp
Compilation fix.
[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: K. S. Sreeram (2002): POSIXified wxCondition, added wxSemaphore
6 // Created: 04/22/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Wolfram Gloger (1996, 1997)
9 // Guilhem Lavaux (1998)
10 // Vadim Zeitlin (1999-2002)
11 // Robert Roebling (1999)
12 // K. S. Sreeram (2002)
13 // Licence: wxWindows licence
14 /////////////////////////////////////////////////////////////////////////////
15
16 // ============================================================================
17 // declaration
18 // ============================================================================
19
20 // ----------------------------------------------------------------------------
21 // headers
22 // ----------------------------------------------------------------------------
23
24 #ifdef __GNUG__
25 #pragma implementation "thread.h"
26 #endif
27
28 #include "wx/defs.h"
29
30 #if wxUSE_THREADS
31
32 #include "wx/thread.h"
33 #include "wx/module.h"
34 #include "wx/utils.h"
35 #include "wx/log.h"
36 #include "wx/intl.h"
37 #include "wx/dynarray.h"
38 #include "wx/timer.h"
39
40 #include <stdio.h>
41 #include <unistd.h>
42 #include <pthread.h>
43 #include <errno.h>
44 #include <time.h>
45 #if HAVE_SCHED_H
46 #include <sched.h>
47 #endif
48
49 #ifdef HAVE_THR_SETCONCURRENCY
50 #include <thread.h>
51 #endif
52
53 // we use wxFFile under Linux in GetCPUCount()
54 #ifdef __LINUX__
55 #include "wx/ffile.h"
56 // For setpriority.
57 #include <sys/time.h>
58 #include <sys/resource.h>
59 #endif
60
61 // ----------------------------------------------------------------------------
62 // constants
63 // ----------------------------------------------------------------------------
64
65 // the possible states of the thread and transitions from them
66 enum wxThreadState
67 {
68 STATE_NEW, // didn't start execution yet (=> RUNNING)
69 STATE_RUNNING, // running (=> PAUSED or EXITED)
70 STATE_PAUSED, // suspended (=> RUNNING or EXITED)
71 STATE_EXITED // thread doesn't exist any more
72 };
73
74 // the exit value of a thread which has been cancelled
75 static const wxThread::ExitCode EXITCODE_CANCELLED = (wxThread::ExitCode)-1;
76
77 // trace mask for wxThread operations
78 #define TRACE_THREADS _T("thread")
79
80 // you can get additional debugging messages for the semaphore operations
81 #define TRACE_SEMA _T("semaphore")
82
83 // ----------------------------------------------------------------------------
84 // private functions
85 // ----------------------------------------------------------------------------
86
87 static void ScheduleThreadForDeletion();
88 static void DeleteThread(wxThread *This);
89
90 // ----------------------------------------------------------------------------
91 // private classes
92 // ----------------------------------------------------------------------------
93
94 // an (non owning) array of pointers to threads
95 WX_DEFINE_ARRAY(wxThread *, wxArrayThread);
96
97 // an entry for a thread we can wait for
98
99 // -----------------------------------------------------------------------------
100 // global data
101 // -----------------------------------------------------------------------------
102
103 // we keep the list of all threads created by the application to be able to
104 // terminate them on exit if there are some left - otherwise the process would
105 // be left in memory
106 static wxArrayThread gs_allThreads;
107
108 // the id of the main thread
109 static pthread_t gs_tidMain;
110
111 // the key for the pointer to the associated wxThread object
112 static pthread_key_t gs_keySelf;
113
114 // the number of threads which are being deleted - the program won't exit
115 // until there are any left
116 static size_t gs_nThreadsBeingDeleted = 0;
117
118 // a mutex to protect gs_nThreadsBeingDeleted
119 static wxMutex *gs_mutexDeleteThread = (wxMutex *)NULL;
120
121 // and a condition variable which will be signaled when all
122 // gs_nThreadsBeingDeleted will have been deleted
123 static wxCondition *gs_condAllDeleted = (wxCondition *)NULL;
124
125 #if wxUSE_GUI
126 // this mutex must be acquired before any call to a GUI function
127 static wxMutex *gs_mutexGui;
128 #endif // wxUSE_GUI
129
130 // when we wait for a thread to exit, we're blocking on a condition which the
131 // thread signals in its SignalExit() method -- but this condition can't be a
132 // member of the thread itself as a detached thread may delete itself at any
133 // moment and accessing the condition member of the thread after this would
134 // result in a disaster
135 //
136 // so instead we maintain a global list of the structs below for the threads
137 // we're interested in waiting on
138
139 // ============================================================================
140 // wxMutex implementation
141 // ============================================================================
142
143 // ----------------------------------------------------------------------------
144 // wxMutexInternal
145 // ----------------------------------------------------------------------------
146
147 // this is a simple wrapper around pthread_mutex_t which provides error
148 // checking
149 class wxMutexInternal
150 {
151 public:
152 wxMutexInternal(wxMutexType mutexType);
153 ~wxMutexInternal();
154
155 wxMutexError Lock();
156 wxMutexError TryLock();
157 wxMutexError Unlock();
158
159 bool IsOk() const { return m_isOk; }
160
161 private:
162 pthread_mutex_t m_mutex;
163 bool m_isOk;
164
165 // wxConditionInternal uses our m_mutex
166 friend class wxConditionInternal;
167 };
168
169 #ifdef HAVE_PTHREAD_MUTEXATTR_T
170 // on some systems pthread_mutexattr_settype() is not in the headers (but it is
171 // in the library, otherwise we wouldn't compile this code at all)
172 extern "C" int pthread_mutexattr_settype(pthread_mutexattr_t *, int);
173 #endif
174
175 wxMutexInternal::wxMutexInternal(wxMutexType mutexType)
176 {
177 int err;
178 switch ( mutexType )
179 {
180 case wxMUTEX_RECURSIVE:
181 // support recursive locks like Win32, i.e. a thread can lock a
182 // mutex which it had itself already locked
183 //
184 // unfortunately initialization of recursive mutexes is non
185 // portable, so try several methods
186 #ifdef HAVE_PTHREAD_MUTEXATTR_T
187 {
188 pthread_mutexattr_t attr;
189 pthread_mutexattr_init(&attr);
190 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
191
192 err = pthread_mutex_init(&m_mutex, &attr);
193 }
194 #elif defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER)
195 // we can use this only as initializer so we have to assign it
196 // first to a temp var - assigning directly to m_mutex wouldn't
197 // even compile
198 {
199 pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
200 m_mutex = mutex;
201 }
202 #else // no recursive mutexes
203 err = EINVAL;
204 #endif // HAVE_PTHREAD_MUTEXATTR_T/...
205 break;
206
207 default:
208 wxFAIL_MSG( _T("unknown mutex type") );
209 // fall through
210
211 case wxMUTEX_DEFAULT:
212 err = pthread_mutex_init(&m_mutex, NULL);
213 break;
214 }
215
216 m_isOk = err == 0;
217 if ( !m_isOk )
218 {
219 wxLogApiError( wxT("pthread_mutex_init()"), err);
220 }
221 }
222
223 wxMutexInternal::~wxMutexInternal()
224 {
225 if ( m_isOk )
226 {
227 int err = pthread_mutex_destroy(&m_mutex);
228 if ( err != 0 )
229 {
230 wxLogApiError( wxT("pthread_mutex_destroy()"), err);
231 }
232 }
233 }
234
235 wxMutexError wxMutexInternal::Lock()
236 {
237 int err = pthread_mutex_lock(&m_mutex);
238 switch ( err )
239 {
240 case EDEADLK:
241 // only error checking mutexes return this value and so it's an
242 // unexpected situation -- hence use assert, not wxLogDebug
243 wxFAIL_MSG( _T("mutex deadlock prevented") );
244 return wxMUTEX_DEAD_LOCK;
245
246 case EINVAL:
247 wxLogDebug(_T("pthread_mutex_lock(): mutex not initialized."));
248 break;
249
250 case 0:
251 return wxMUTEX_NO_ERROR;
252
253 default:
254 wxLogApiError(_T("pthread_mutex_lock()"), err);
255 }
256
257 return wxMUTEX_MISC_ERROR;
258 }
259
260 wxMutexError wxMutexInternal::TryLock()
261 {
262 int err = pthread_mutex_trylock(&m_mutex);
263 switch ( err )
264 {
265 case EBUSY:
266 // not an error: mutex is already locked, but we're prepared for
267 // this
268 return wxMUTEX_BUSY;
269
270 case EINVAL:
271 wxLogDebug(_T("pthread_mutex_trylock(): mutex not initialized."));
272 break;
273
274 case 0:
275 return wxMUTEX_NO_ERROR;
276
277 default:
278 wxLogApiError(_T("pthread_mutex_trylock()"), err);
279 }
280
281 return wxMUTEX_MISC_ERROR;
282 }
283
284 wxMutexError wxMutexInternal::Unlock()
285 {
286 int err = pthread_mutex_unlock(&m_mutex);
287 switch ( err )
288 {
289 case EPERM:
290 // we don't own the mutex
291 return wxMUTEX_UNLOCKED;
292
293 case EINVAL:
294 wxLogDebug(_T("pthread_mutex_unlock(): mutex not initialized."));
295 break;
296
297 case 0:
298 return wxMUTEX_NO_ERROR;
299
300 default:
301 wxLogApiError(_T("pthread_mutex_unlock()"), err);
302 }
303
304 return wxMUTEX_MISC_ERROR;
305 }
306
307 // ===========================================================================
308 // wxCondition implementation
309 // ===========================================================================
310
311 // ---------------------------------------------------------------------------
312 // wxConditionInternal
313 // ---------------------------------------------------------------------------
314
315 // this is a wrapper around pthread_cond_t associated with a wxMutex (and hence
316 // with a pthread_mutex_t)
317 class wxConditionInternal
318 {
319 public:
320 wxConditionInternal(wxMutex& mutex);
321 ~wxConditionInternal();
322
323 bool IsOk() const { return m_isOk && m_mutex.IsOk(); }
324
325 wxCondError Wait();
326 wxCondError WaitTimeout(unsigned long milliseconds);
327
328 wxCondError Signal();
329 wxCondError Broadcast();
330
331 private:
332 // get the POSIX mutex associated with us
333 pthread_mutex_t *GetPMutex() const { return &m_mutex.m_internal->m_mutex; }
334
335 wxMutex& m_mutex;
336 pthread_cond_t m_cond;
337
338 bool m_isOk;
339 };
340
341 wxConditionInternal::wxConditionInternal(wxMutex& mutex)
342 : m_mutex(mutex)
343 {
344 int err = pthread_cond_init(&m_cond, NULL /* default attributes */);
345
346 m_isOk = err == 0;
347
348 if ( !m_isOk )
349 {
350 wxLogApiError(_T("pthread_cond_init()"), err);
351 }
352 }
353
354 wxConditionInternal::~wxConditionInternal()
355 {
356 if ( m_isOk )
357 {
358 int err = pthread_cond_destroy(&m_cond);
359 if ( err != 0 )
360 {
361 wxLogApiError(_T("pthread_cond_destroy()"), err);
362 }
363 }
364 }
365
366 wxCondError wxConditionInternal::Wait()
367 {
368 int err = pthread_cond_wait(&m_cond, GetPMutex());
369 if ( err != 0 )
370 {
371 wxLogApiError(_T("pthread_cond_wait()"), err);
372
373 return wxCOND_MISC_ERROR;
374 }
375
376 return wxCOND_NO_ERROR;
377 }
378
379 wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds)
380 {
381 wxLongLong curtime = wxGetLocalTimeMillis();
382 curtime += milliseconds;
383 wxLongLong temp = curtime / 1000;
384 int sec = temp.GetLo();
385 temp *= 1000;
386 temp = curtime - temp;
387 int millis = temp.GetLo();
388
389 timespec tspec;
390
391 tspec.tv_sec = sec;
392 tspec.tv_nsec = millis * 1000L * 1000L;
393
394 int err = pthread_cond_timedwait( &m_cond, GetPMutex(), &tspec );
395 switch ( err )
396 {
397 case ETIMEDOUT:
398 return wxCOND_TIMEOUT;
399
400 case 0:
401 return wxCOND_NO_ERROR;
402
403 default:
404 wxLogApiError(_T("pthread_cond_timedwait()"), err);
405 }
406
407 return wxCOND_MISC_ERROR;
408 }
409
410 wxCondError wxConditionInternal::Signal()
411 {
412 int err = pthread_cond_signal(&m_cond);
413 if ( err != 0 )
414 {
415 wxLogApiError(_T("pthread_cond_signal()"), err);
416
417 return wxCOND_MISC_ERROR;
418 }
419
420 return wxCOND_NO_ERROR;
421 }
422
423 wxCondError wxConditionInternal::Broadcast()
424 {
425 int err = pthread_cond_broadcast(&m_cond);
426 if ( err != 0 )
427 {
428 wxLogApiError(_T("pthread_cond_broadcast()"), err);
429
430 return wxCOND_MISC_ERROR;
431 }
432
433 return wxCOND_NO_ERROR;
434 }
435
436 // ===========================================================================
437 // wxSemaphore implementation
438 // ===========================================================================
439
440 // ---------------------------------------------------------------------------
441 // wxSemaphoreInternal
442 // ---------------------------------------------------------------------------
443
444 // we implement the semaphores using mutexes and conditions instead of using
445 // the sem_xxx() POSIX functions because they're not widely available and also
446 // because it's impossible to implement WaitTimeout() using them
447 class wxSemaphoreInternal
448 {
449 public:
450 wxSemaphoreInternal(int initialcount, int maxcount);
451
452 bool IsOk() const { return m_isOk; }
453
454 wxSemaError Wait();
455 wxSemaError TryWait();
456 wxSemaError WaitTimeout(unsigned long milliseconds);
457
458 wxSemaError Post();
459
460 private:
461 wxMutex m_mutex;
462 wxCondition m_cond;
463
464 size_t m_count,
465 m_maxcount;
466
467 bool m_isOk;
468 };
469
470 wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
471 : m_cond(m_mutex)
472 {
473
474 if ( (initialcount < 0 || maxcount < 0) ||
475 ((maxcount > 0) && (initialcount > maxcount)) )
476 {
477 wxFAIL_MSG( _T("wxSemaphore: invalid initial or maximal count") );
478
479 m_isOk = FALSE;
480 }
481 else
482 {
483 m_maxcount = (size_t)maxcount;
484 m_count = (size_t)initialcount;
485 }
486
487 m_isOk = m_mutex.IsOk() && m_cond.IsOk();
488 }
489
490 wxSemaError wxSemaphoreInternal::Wait()
491 {
492 wxMutexLocker locker(m_mutex);
493
494 while ( m_count == 0 )
495 {
496 wxLogTrace(TRACE_SEMA,
497 "Thread %ld waiting for semaphore to become signalled",
498 wxThread::GetCurrentId());
499
500 if ( m_cond.Wait() != wxCOND_NO_ERROR )
501 return wxSEMA_MISC_ERROR;
502
503 wxLogTrace(TRACE_SEMA,
504 "Thread %ld finished waiting for semaphore, count = %lu",
505 wxThread::GetCurrentId(), (unsigned long)m_count);
506 }
507
508 m_count--;
509
510 return wxSEMA_NO_ERROR;
511 }
512
513 wxSemaError wxSemaphoreInternal::TryWait()
514 {
515 wxMutexLocker locker(m_mutex);
516
517 if ( m_count == 0 )
518 return wxSEMA_BUSY;
519
520 m_count--;
521
522 return wxSEMA_NO_ERROR;
523 }
524
525 wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds)
526 {
527 wxMutexLocker locker(m_mutex);
528
529 wxLongLong startTime = wxGetLocalTimeMillis();
530
531 while ( m_count == 0 )
532 {
533 wxLongLong elapsed = wxGetLocalTimeMillis() - startTime;
534 long remainingTime = (long)milliseconds - (long)elapsed.GetLo();
535 if ( remainingTime <= 0 )
536 {
537 // timeout
538 return wxSEMA_TIMEOUT;
539 }
540
541 switch ( m_cond.WaitTimeout(remainingTime) )
542 {
543 case wxCOND_TIMEOUT:
544 return wxSEMA_TIMEOUT;
545
546 default:
547 return wxSEMA_MISC_ERROR;
548
549 case wxCOND_NO_ERROR:
550 ;
551 }
552 }
553
554 m_count--;
555
556 return wxSEMA_NO_ERROR;
557 }
558
559 wxSemaError wxSemaphoreInternal::Post()
560 {
561 wxMutexLocker locker(m_mutex);
562
563 if ( m_maxcount > 0 && m_count == m_maxcount )
564 {
565 return wxSEMA_OVERFLOW;
566 }
567
568 m_count++;
569
570 wxLogTrace(TRACE_SEMA,
571 "Thread %ld about to signal semaphore, count = %lu",
572 wxThread::GetCurrentId(), (unsigned long)m_count);
573
574 return m_cond.Signal() == wxCOND_NO_ERROR ? wxSEMA_NO_ERROR
575 : wxSEMA_MISC_ERROR;
576 }
577
578 // ===========================================================================
579 // wxThread implementation
580 // ===========================================================================
581
582 // the thread callback functions must have the C linkage
583 extern "C"
584 {
585
586 #if HAVE_THREAD_CLEANUP_FUNCTIONS
587 // thread exit function
588 void wxPthreadCleanup(void *ptr);
589 #endif // HAVE_THREAD_CLEANUP_FUNCTIONS
590
591 void *wxPthreadStart(void *ptr);
592
593 } // extern "C"
594
595 // ----------------------------------------------------------------------------
596 // wxThreadInternal
597 // ----------------------------------------------------------------------------
598
599 class wxThreadInternal
600 {
601 public:
602 wxThreadInternal();
603 ~wxThreadInternal();
604
605 // thread entry function
606 static void *PthreadStart(wxThread *thread);
607
608 // thread actions
609 // start the thread
610 wxThreadError Run();
611 // unblock the thread allowing it to run
612 void SignalRun() { m_semRun.Post(); }
613 // ask the thread to terminate
614 void Wait();
615 // go to sleep until Resume() is called
616 void Pause();
617 // resume the thread
618 void Resume();
619
620 // accessors
621 // priority
622 int GetPriority() const { return m_prio; }
623 void SetPriority(int prio) { m_prio = prio; }
624 // state
625 wxThreadState GetState() const { return m_state; }
626 void SetState(wxThreadState state)
627 {
628 #ifdef __WXDEBUG__
629 static const wxChar *stateNames[] =
630 {
631 _T("NEW"),
632 _T("RUNNING"),
633 _T("PAUSED"),
634 _T("EXITED"),
635 };
636
637 wxLogTrace(TRACE_THREADS, _T("Thread %ld: %s => %s."),
638 (long)GetId(), stateNames[m_state], stateNames[state]);
639 #endif // __WXDEBUG__
640
641 m_state = state;
642 }
643 // id
644 pthread_t GetId() const { return m_threadId; }
645 pthread_t *GetIdPtr() { return &m_threadId; }
646 // "cancelled" flag
647 void SetCancelFlag() { m_cancelled = TRUE; }
648 bool WasCancelled() const { return m_cancelled; }
649 // exit code
650 void SetExitCode(wxThread::ExitCode exitcode) { m_exitcode = exitcode; }
651 wxThread::ExitCode GetExitCode() const { return m_exitcode; }
652
653 // the pause flag
654 void SetReallyPaused(bool paused) { m_isPaused = paused; }
655 bool IsReallyPaused() const { return m_isPaused; }
656
657 // tell the thread that it is a detached one
658 void Detach()
659 {
660 wxCriticalSectionLocker lock(m_csJoinFlag);
661
662 m_shouldBeJoined = FALSE;
663 m_isDetached = TRUE;
664 }
665
666 #if HAVE_THREAD_CLEANUP_FUNCTIONS
667 // this is used by wxPthreadCleanup() only
668 static void Cleanup(wxThread *thread);
669 #endif // HAVE_THREAD_CLEANUP_FUNCTIONS
670
671 private:
672 pthread_t m_threadId; // id of the thread
673 wxThreadState m_state; // see wxThreadState enum
674 int m_prio; // in wxWindows units: from 0 to 100
675
676 // this flag is set when the thread should terminate
677 bool m_cancelled;
678
679 // this flag is set when the thread is blocking on m_semSuspend
680 bool m_isPaused;
681
682 // the thread exit code - only used for joinable (!detached) threads and
683 // is only valid after the thread termination
684 wxThread::ExitCode m_exitcode;
685
686 // many threads may call Wait(), but only one of them should call
687 // pthread_join(), so we have to keep track of this
688 wxCriticalSection m_csJoinFlag;
689 bool m_shouldBeJoined;
690 bool m_isDetached;
691
692 // this semaphore is posted by Run() and the threads Entry() is not
693 // called before it is done
694 wxSemaphore m_semRun;
695
696 // this one is signaled when the thread should resume after having been
697 // Pause()d
698 wxSemaphore m_semSuspend;
699 };
700
701 // ----------------------------------------------------------------------------
702 // thread startup and exit functions
703 // ----------------------------------------------------------------------------
704
705 void *wxPthreadStart(void *ptr)
706 {
707 return wxThreadInternal::PthreadStart((wxThread *)ptr);
708 }
709
710 void *wxThreadInternal::PthreadStart(wxThread *thread)
711 {
712 wxThreadInternal *pthread = thread->m_internal;
713
714 #ifdef __VMS
715 wxLogTrace(TRACE_THREADS, _T("Thread %ld started."), (long long)pthread->GetId());
716 #else
717 wxLogTrace(TRACE_THREADS, _T("Thread %ld started."), (long)pthread->GetId());
718 #endif
719
720 // associate the thread pointer with the newly created thread so that
721 // wxThread::This() will work
722 int rc = pthread_setspecific(gs_keySelf, thread);
723 if ( rc != 0 )
724 {
725 wxLogSysError(rc, _("Cannot start thread: error writing TLS"));
726
727 return (void *)-1;
728 }
729
730 // have to declare this before pthread_cleanup_push() which defines a
731 // block!
732 bool dontRunAtAll;
733
734 #if HAVE_THREAD_CLEANUP_FUNCTIONS
735 // install the cleanup handler which will be called if the thread is
736 // cancelled
737 pthread_cleanup_push(wxPthreadCleanup, thread);
738 #endif // HAVE_THREAD_CLEANUP_FUNCTIONS
739
740 // wait for the semaphore to be posted from Run()
741 pthread->m_semRun.Wait();
742
743 // test whether we should run the run at all - may be it was deleted
744 // before it started to Run()?
745 {
746 wxCriticalSectionLocker lock(thread->m_critsect);
747
748 dontRunAtAll = pthread->GetState() == STATE_NEW &&
749 pthread->WasCancelled();
750 }
751
752 if ( !dontRunAtAll )
753 {
754 // call the main entry
755 wxLogTrace(TRACE_THREADS, _T("Thread %ld about to enter its Entry()."),
756 #ifdef __VMS
757 (long long)pthread->GetId());
758 #else
759 (long)pthread->GetId());
760 #endif
761
762 pthread->m_exitcode = thread->Entry();
763
764 wxLogTrace(TRACE_THREADS, _T("Thread %ld Entry() returned %lu."),
765 #ifdef __VMS
766 (long long)pthread->GetId(), (unsigned long)pthread->m_exitcode);
767 #else
768 (long)pthread->GetId(), (unsigned long)pthread->m_exitcode);
769 #endif
770
771 {
772 wxCriticalSectionLocker lock(thread->m_critsect);
773
774 // change the state of the thread to "exited" so that
775 // wxPthreadCleanup handler won't do anything from now (if it's
776 // called before we do pthread_cleanup_pop below)
777 pthread->SetState(STATE_EXITED);
778 }
779 }
780
781 // NB: at least under Linux, pthread_cleanup_push/pop are macros and pop
782 // contains the matching '}' for the '{' in push, so they must be used
783 // in the same block!
784 #if HAVE_THREAD_CLEANUP_FUNCTIONS
785 // remove the cleanup handler without executing it
786 pthread_cleanup_pop(FALSE);
787 #endif // HAVE_THREAD_CLEANUP_FUNCTIONS
788
789 if ( dontRunAtAll )
790 {
791 // FIXME: deleting a possibly joinable thread here???
792 delete thread;
793
794 return EXITCODE_CANCELLED;
795 }
796 else
797 {
798 // terminate the thread
799 thread->Exit(pthread->m_exitcode);
800
801 wxFAIL_MSG(wxT("wxThread::Exit() can't return."));
802
803 return NULL;
804 }
805 }
806
807 #if HAVE_THREAD_CLEANUP_FUNCTIONS
808
809 // this handler is called when the thread is cancelled
810 extern "C" void wxPthreadCleanup(void *ptr)
811 {
812 wxThreadInternal::Cleanup((wxThread *)ptr);
813 }
814
815 void wxThreadInternal::Cleanup(wxThread *thread)
816 {
817 {
818 wxCriticalSectionLocker lock(thread->m_critsect);
819 if ( thread->m_internal->GetState() == STATE_EXITED )
820 {
821 // thread is already considered as finished.
822 return;
823 }
824 }
825
826 // exit the thread gracefully
827 thread->Exit(EXITCODE_CANCELLED);
828 }
829
830 #endif // HAVE_THREAD_CLEANUP_FUNCTIONS
831
832 // ----------------------------------------------------------------------------
833 // wxThreadInternal
834 // ----------------------------------------------------------------------------
835
836 wxThreadInternal::wxThreadInternal()
837 {
838 m_state = STATE_NEW;
839 m_cancelled = FALSE;
840 m_prio = WXTHREAD_DEFAULT_PRIORITY;
841 m_threadId = 0;
842 m_exitcode = 0;
843
844 // set to TRUE only when the thread starts waiting on m_semSuspend
845 m_isPaused = FALSE;
846
847 // defaults for joinable threads
848 m_shouldBeJoined = TRUE;
849 m_isDetached = FALSE;
850 }
851
852 wxThreadInternal::~wxThreadInternal()
853 {
854 }
855
856 wxThreadError wxThreadInternal::Run()
857 {
858 wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
859 wxT("thread may only be started once after Create()") );
860
861 SetState(STATE_RUNNING);
862
863 // wake up threads waiting for our start
864 SignalRun();
865
866 return wxTHREAD_NO_ERROR;
867 }
868
869 void wxThreadInternal::Wait()
870 {
871 wxCHECK_RET( !m_isDetached, _T("can't wait for a detached thread") );
872
873 // if the thread we're waiting for is waiting for the GUI mutex, we will
874 // deadlock so make sure we release it temporarily
875 if ( wxThread::IsMain() )
876 wxMutexGuiLeave();
877
878 wxLogTrace(TRACE_THREADS,
879 #ifdef __VMS
880 _T("Starting to wait for thread %ld to exit."), (long long)GetId());
881 #else
882 _T("Starting to wait for thread %ld to exit."), (long)GetId());
883 #endif
884
885 // to avoid memory leaks we should call pthread_join(), but it must only be
886 // done once so use a critical section to serialize the code below
887 {
888 wxCriticalSectionLocker lock(m_csJoinFlag);
889
890 if ( m_shouldBeJoined )
891 {
892 // FIXME shouldn't we set cancellation type to DISABLED here? If
893 // we're cancelled inside pthread_join(), things will almost
894 // certainly break - but if we disable the cancellation, we
895 // might deadlock
896 if ( pthread_join(GetId(), &m_exitcode) != 0 )
897 {
898 // this is a serious problem, so use wxLogError and not
899 // wxLogDebug: it is possible to bring the system to its knees
900 // by creating too many threads and not joining them quite
901 // easily
902 wxLogError(_("Failed to join a thread, potential memory leak "
903 "detected - please restart the program"));
904 }
905
906 m_shouldBeJoined = FALSE;
907 }
908 }
909
910 // reacquire GUI mutex
911 if ( wxThread::IsMain() )
912 wxMutexGuiEnter();
913 }
914
915 void wxThreadInternal::Pause()
916 {
917 // the state is set from the thread which pauses us first, this function
918 // is called later so the state should have been already set
919 wxCHECK_RET( m_state == STATE_PAUSED,
920 wxT("thread must first be paused with wxThread::Pause().") );
921
922 #ifdef __VMS
923 wxLogTrace(TRACE_THREADS, _T("Thread %ld goes to sleep."), (long long)GetId());
924 #else
925 wxLogTrace(TRACE_THREADS, _T("Thread %ld goes to sleep."), (long)GetId());
926 #endif
927
928 // wait until the semaphore is Post()ed from Resume()
929 m_semSuspend.Wait();
930 }
931
932 void wxThreadInternal::Resume()
933 {
934 wxCHECK_RET( m_state == STATE_PAUSED,
935 wxT("can't resume thread which is not suspended.") );
936
937 // the thread might be not actually paused yet - if there were no call to
938 // TestDestroy() since the last call to Pause() for example
939 if ( IsReallyPaused() )
940 {
941 #ifdef __VMS
942 wxLogTrace(TRACE_THREADS, _T("Waking up thread %ld"), (long long)GetId());
943 #else
944 wxLogTrace(TRACE_THREADS, _T("Waking up thread %ld"), (long)GetId());
945 #endif
946
947 // wake up Pause()
948 m_semSuspend.Post();
949
950 // reset the flag
951 SetReallyPaused(FALSE);
952 }
953 else
954 {
955 wxLogTrace(TRACE_THREADS, _T("Thread %ld is not yet really paused"),
956 #ifdef __VMS
957 (long long)GetId());
958 #else
959 (long)GetId());
960 #endif
961 }
962
963 SetState(STATE_RUNNING);
964 }
965
966 // -----------------------------------------------------------------------------
967 // wxThread static functions
968 // -----------------------------------------------------------------------------
969
970 wxThread *wxThread::This()
971 {
972 return (wxThread *)pthread_getspecific(gs_keySelf);
973 }
974
975 bool wxThread::IsMain()
976 {
977 return (bool)pthread_equal(pthread_self(), gs_tidMain);
978 }
979
980 void wxThread::Yield()
981 {
982 #ifdef HAVE_SCHED_YIELD
983 sched_yield();
984 #endif
985 }
986
987 void wxThread::Sleep(unsigned long milliseconds)
988 {
989 wxUsleep(milliseconds);
990 }
991
992 int wxThread::GetCPUCount()
993 {
994 #if defined(__LINUX__) && wxUSE_FFILE
995 // read from proc (can't use wxTextFile here because it's a special file:
996 // it has 0 size but still can be read from)
997 wxLogNull nolog;
998
999 wxFFile file(_T("/proc/cpuinfo"));
1000 if ( file.IsOpened() )
1001 {
1002 // slurp the whole file
1003 wxString s;
1004 if ( file.ReadAll(&s) )
1005 {
1006 // (ab)use Replace() to find the number of "processor: num" strings
1007 size_t count = s.Replace(_T("processor\t:"), _T(""));
1008 if ( count > 0 )
1009 {
1010 return count;
1011 }
1012
1013 wxLogDebug(_T("failed to parse /proc/cpuinfo"));
1014 }
1015 else
1016 {
1017 wxLogDebug(_T("failed to read /proc/cpuinfo"));
1018 }
1019 }
1020 #elif defined(_SC_NPROCESSORS_ONLN)
1021 // this works for Solaris
1022 int rc = sysconf(_SC_NPROCESSORS_ONLN);
1023 if ( rc != -1 )
1024 {
1025 return rc;
1026 }
1027 #endif // different ways to get number of CPUs
1028
1029 // unknown
1030 return -1;
1031 }
1032
1033 #ifdef __VMS
1034 // VMS is a 64 bit system and threads have 64 bit pointers.
1035 // ??? also needed for other systems????
1036 unsigned long long wxThread::GetCurrentId()
1037 {
1038 return (unsigned long long)pthread_self();
1039 #else
1040 unsigned long wxThread::GetCurrentId()
1041 {
1042 return (unsigned long)pthread_self();
1043 #endif
1044 }
1045
1046 bool wxThread::SetConcurrency(size_t level)
1047 {
1048 #ifdef HAVE_THR_SETCONCURRENCY
1049 int rc = thr_setconcurrency(level);
1050 if ( rc != 0 )
1051 {
1052 wxLogSysError(rc, _T("thr_setconcurrency() failed"));
1053 }
1054
1055 return rc == 0;
1056 #else // !HAVE_THR_SETCONCURRENCY
1057 // ok only for the default value
1058 return level == 0;
1059 #endif // HAVE_THR_SETCONCURRENCY/!HAVE_THR_SETCONCURRENCY
1060 }
1061
1062 // -----------------------------------------------------------------------------
1063 // creating thread
1064 // -----------------------------------------------------------------------------
1065
1066 wxThread::wxThread(wxThreadKind kind)
1067 {
1068 // add this thread to the global list of all threads
1069 gs_allThreads.Add(this);
1070
1071 m_internal = new wxThreadInternal();
1072
1073 m_isDetached = kind == wxTHREAD_DETACHED;
1074 }
1075
1076 wxThreadError wxThread::Create(unsigned int WXUNUSED(stackSize))
1077 {
1078 if ( m_internal->GetState() != STATE_NEW )
1079 {
1080 // don't recreate thread
1081 return wxTHREAD_RUNNING;
1082 }
1083
1084 // set up the thread attribute: right now, we only set thread priority
1085 pthread_attr_t attr;
1086 pthread_attr_init(&attr);
1087
1088 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
1089 int policy;
1090 if ( pthread_attr_getschedpolicy(&attr, &policy) != 0 )
1091 {
1092 wxLogError(_("Cannot retrieve thread scheduling policy."));
1093 }
1094
1095 #ifdef __VMS__
1096 /* the pthread.h contains too many spaces. This is a work-around */
1097 # undef sched_get_priority_max
1098 #undef sched_get_priority_min
1099 #define sched_get_priority_max(_pol_) \
1100 (_pol_ == SCHED_OTHER ? PRI_FG_MAX_NP : PRI_FIFO_MAX)
1101 #define sched_get_priority_min(_pol_) \
1102 (_pol_ == SCHED_OTHER ? PRI_FG_MIN_NP : PRI_FIFO_MIN)
1103 #endif
1104
1105 int max_prio = sched_get_priority_max(policy),
1106 min_prio = sched_get_priority_min(policy),
1107 prio = m_internal->GetPriority();
1108
1109 if ( min_prio == -1 || max_prio == -1 )
1110 {
1111 wxLogError(_("Cannot get priority range for scheduling policy %d."),
1112 policy);
1113 }
1114 else if ( max_prio == min_prio )
1115 {
1116 if ( prio != WXTHREAD_DEFAULT_PRIORITY )
1117 {
1118 // notify the programmer that this doesn't work here
1119 wxLogWarning(_("Thread priority setting is ignored."));
1120 }
1121 //else: we have default priority, so don't complain
1122
1123 // anyhow, don't do anything because priority is just ignored
1124 }
1125 else
1126 {
1127 struct sched_param sp;
1128 if ( pthread_attr_getschedparam(&attr, &sp) != 0 )
1129 {
1130 wxFAIL_MSG(_T("pthread_attr_getschedparam() failed"));
1131 }
1132
1133 sp.sched_priority = min_prio + (prio*(max_prio - min_prio))/100;
1134
1135 if ( pthread_attr_setschedparam(&attr, &sp) != 0 )
1136 {
1137 wxFAIL_MSG(_T("pthread_attr_setschedparam(priority) failed"));
1138 }
1139 }
1140 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
1141
1142 #ifdef HAVE_PTHREAD_ATTR_SETSCOPE
1143 // this will make the threads created by this process really concurrent
1144 if ( pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) != 0 )
1145 {
1146 wxFAIL_MSG(_T("pthread_attr_setscope(PTHREAD_SCOPE_SYSTEM) failed"));
1147 }
1148 #endif // HAVE_PTHREAD_ATTR_SETSCOPE
1149
1150 // VZ: assume that this one is always available (it's rather fundamental),
1151 // if this function is ever missing we should try to use
1152 // pthread_detach() instead (after thread creation)
1153 if ( m_isDetached )
1154 {
1155 if ( pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0 )
1156 {
1157 wxFAIL_MSG(_T("pthread_attr_setdetachstate(DETACHED) failed"));
1158 }
1159
1160 // never try to join detached threads
1161 m_internal->Detach();
1162 }
1163 //else: threads are created joinable by default, it's ok
1164
1165 // create the new OS thread object
1166 int rc = pthread_create
1167 (
1168 m_internal->GetIdPtr(),
1169 &attr,
1170 wxPthreadStart,
1171 (void *)this
1172 );
1173
1174 if ( pthread_attr_destroy(&attr) != 0 )
1175 {
1176 wxFAIL_MSG(_T("pthread_attr_destroy() failed"));
1177 }
1178
1179 if ( rc != 0 )
1180 {
1181 m_internal->SetState(STATE_EXITED);
1182
1183 return wxTHREAD_NO_RESOURCE;
1184 }
1185
1186 return wxTHREAD_NO_ERROR;
1187 }
1188
1189 wxThreadError wxThread::Run()
1190 {
1191 wxCriticalSectionLocker lock(m_critsect);
1192
1193 wxCHECK_MSG( m_internal->GetId(), wxTHREAD_MISC_ERROR,
1194 wxT("must call wxThread::Create() first") );
1195
1196 return m_internal->Run();
1197 }
1198
1199 // -----------------------------------------------------------------------------
1200 // misc accessors
1201 // -----------------------------------------------------------------------------
1202
1203 void wxThread::SetPriority(unsigned int prio)
1204 {
1205 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY <= (int)prio) &&
1206 ((int)prio <= (int)WXTHREAD_MAX_PRIORITY),
1207 wxT("invalid thread priority") );
1208
1209 wxCriticalSectionLocker lock(m_critsect);
1210
1211 switch ( m_internal->GetState() )
1212 {
1213 case STATE_NEW:
1214 // thread not yet started, priority will be set when it is
1215 m_internal->SetPriority(prio);
1216 break;
1217
1218 case STATE_RUNNING:
1219 case STATE_PAUSED:
1220 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
1221 #if defined(__LINUX__)
1222 // On Linux, pthread_setschedparam with SCHED_OTHER does not allow
1223 // a priority other than 0. Instead, we use the BSD setpriority
1224 // which alllows us to set a 'nice' value between 20 to -20. Only
1225 // super user can set a value less than zero (more negative yields
1226 // higher priority). setpriority set the static priority of a process,
1227 // but this is OK since Linux is configured as a thread per process.
1228 {
1229 float fPrio;
1230 float pSpan;
1231 int iPrio;
1232
1233 // Map Wx priorites (WXTHREAD_MIN_PRIORITY -
1234 // WXTHREAD_MAX_PRIORITY) into BSD priorities (20 - -20).
1235 // Do calculation of values instead of hard coding them
1236 // to make maintenance easier.
1237
1238 pSpan = ((float)(WXTHREAD_MAX_PRIORITY - WXTHREAD_MIN_PRIORITY)) / 2.0;
1239
1240 // prio starts as ................... // value => (0) >= p <= (n)
1241
1242 fPrio = ((float)prio) - pSpan; // value => (-n) >= p <= (+n)
1243
1244 fPrio = 0.0 - fPrio; // value => (+n) <= p >= (-n)
1245
1246 fPrio = fPrio * (20. / pSpan) + .5; // value => (20) <= p >= (-20)
1247
1248 iPrio = (int)fPrio;
1249
1250 // Clamp prio from 20 - -20;
1251 iPrio = (iPrio > 20) ? 20 : iPrio;
1252 iPrio = (iPrio < -20) ? -20 : iPrio;
1253
1254 if (setpriority(PRIO_PROCESS, 0, iPrio) == -1)
1255 {
1256 wxLogError(_("Failed to set thread priority %d."), prio);
1257 }
1258 }
1259 #else // __LINUX__
1260 {
1261 struct sched_param sparam;
1262 sparam.sched_priority = prio;
1263
1264 if ( pthread_setschedparam(m_internal->GetId(),
1265 SCHED_OTHER, &sparam) != 0 )
1266 {
1267 wxLogError(_("Failed to set thread priority %d."), prio);
1268 }
1269 }
1270 #endif // __LINUX__
1271 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
1272 break;
1273
1274 case STATE_EXITED:
1275 default:
1276 wxFAIL_MSG(wxT("impossible to set thread priority in this state"));
1277 }
1278 }
1279
1280 unsigned int wxThread::GetPriority() const
1281 {
1282 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
1283
1284 return m_internal->GetPriority();
1285 }
1286
1287 wxThreadIdType wxThread::GetId() const
1288 {
1289 return (wxThreadIdType) m_internal->GetId();
1290 }
1291
1292 // -----------------------------------------------------------------------------
1293 // pause/resume
1294 // -----------------------------------------------------------------------------
1295
1296 wxThreadError wxThread::Pause()
1297 {
1298 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1299 _T("a thread can't pause itself") );
1300
1301 wxCriticalSectionLocker lock(m_critsect);
1302
1303 if ( m_internal->GetState() != STATE_RUNNING )
1304 {
1305 wxLogDebug(wxT("Can't pause thread which is not running."));
1306
1307 return wxTHREAD_NOT_RUNNING;
1308 }
1309
1310 // just set a flag, the thread will be really paused only during the next
1311 // call to TestDestroy()
1312 m_internal->SetState(STATE_PAUSED);
1313
1314 return wxTHREAD_NO_ERROR;
1315 }
1316
1317 wxThreadError wxThread::Resume()
1318 {
1319 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1320 _T("a thread can't resume itself") );
1321
1322 wxCriticalSectionLocker lock(m_critsect);
1323
1324 wxThreadState state = m_internal->GetState();
1325
1326 switch ( state )
1327 {
1328 case STATE_PAUSED:
1329 wxLogTrace(TRACE_THREADS, _T("Thread %ld suspended, resuming."),
1330 GetId());
1331
1332 m_internal->Resume();
1333
1334 return wxTHREAD_NO_ERROR;
1335
1336 case STATE_EXITED:
1337 wxLogTrace(TRACE_THREADS, _T("Thread %ld exited, won't resume."),
1338 GetId());
1339 return wxTHREAD_NO_ERROR;
1340
1341 default:
1342 wxLogDebug(_T("Attempt to resume a thread which is not paused."));
1343
1344 return wxTHREAD_MISC_ERROR;
1345 }
1346 }
1347
1348 // -----------------------------------------------------------------------------
1349 // exiting thread
1350 // -----------------------------------------------------------------------------
1351
1352 wxThread::ExitCode wxThread::Wait()
1353 {
1354 wxCHECK_MSG( This() != this, (ExitCode)-1,
1355 _T("a thread can't wait for itself") );
1356
1357 wxCHECK_MSG( !m_isDetached, (ExitCode)-1,
1358 _T("can't wait for detached thread") );
1359
1360 m_internal->Wait();
1361
1362 return m_internal->GetExitCode();
1363 }
1364
1365 wxThreadError wxThread::Delete(ExitCode *rc)
1366 {
1367 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1368 _T("a thread can't delete itself") );
1369
1370 bool isDetached = m_isDetached;
1371
1372 m_critsect.Enter();
1373 wxThreadState state = m_internal->GetState();
1374
1375 // ask the thread to stop
1376 m_internal->SetCancelFlag();
1377
1378 m_critsect.Leave();
1379
1380 switch ( state )
1381 {
1382 case STATE_NEW:
1383 // we need to wake up the thread so that PthreadStart() will
1384 // terminate - right now it's blocking on run semaphore in
1385 // PthreadStart()
1386 m_internal->SignalRun();
1387
1388 // fall through
1389
1390 case STATE_EXITED:
1391 // nothing to do
1392 break;
1393
1394 case STATE_PAUSED:
1395 // resume the thread first
1396 m_internal->Resume();
1397
1398 // fall through
1399
1400 default:
1401 if ( !isDetached )
1402 {
1403 // wait until the thread stops
1404 m_internal->Wait();
1405
1406 if ( rc )
1407 {
1408 // return the exit code of the thread
1409 *rc = m_internal->GetExitCode();
1410 }
1411 }
1412 //else: can't wait for detached threads
1413 }
1414
1415 return wxTHREAD_NO_ERROR;
1416 }
1417
1418 wxThreadError wxThread::Kill()
1419 {
1420 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1421 _T("a thread can't kill itself") );
1422
1423 switch ( m_internal->GetState() )
1424 {
1425 case STATE_NEW:
1426 case STATE_EXITED:
1427 return wxTHREAD_NOT_RUNNING;
1428
1429 case STATE_PAUSED:
1430 // resume the thread first
1431 Resume();
1432
1433 // fall through
1434
1435 default:
1436 #ifdef HAVE_PTHREAD_CANCEL
1437 if ( pthread_cancel(m_internal->GetId()) != 0 )
1438 #endif
1439 {
1440 wxLogError(_("Failed to terminate a thread."));
1441
1442 return wxTHREAD_MISC_ERROR;
1443 }
1444
1445 if ( m_isDetached )
1446 {
1447 // if we use cleanup function, this will be done from
1448 // wxPthreadCleanup()
1449 #if !HAVE_THREAD_CLEANUP_FUNCTIONS
1450 ScheduleThreadForDeletion();
1451
1452 // don't call OnExit() here, it can only be called in the
1453 // threads context and we're in the context of another thread
1454
1455 DeleteThread(this);
1456 #endif // HAVE_THREAD_CLEANUP_FUNCTIONS
1457 }
1458 else
1459 {
1460 m_internal->SetExitCode(EXITCODE_CANCELLED);
1461 }
1462
1463 return wxTHREAD_NO_ERROR;
1464 }
1465 }
1466
1467 void wxThread::Exit(ExitCode status)
1468 {
1469 wxASSERT_MSG( This() == this,
1470 _T("wxThread::Exit() can only be called in the "
1471 "context of the same thread") );
1472
1473 if ( m_isDetached )
1474 {
1475 // from the moment we call OnExit(), the main program may terminate at
1476 // any moment, so mark this thread as being already in process of being
1477 // deleted or wxThreadModule::OnExit() will try to delete it again
1478 ScheduleThreadForDeletion();
1479 }
1480
1481 // don't enter m_critsect before calling OnExit() because the user code
1482 // might deadlock if, for example, it signals a condition in OnExit() (a
1483 // common case) while the main thread calls any of functions entering
1484 // m_critsect on us (almost all of them do)
1485 OnExit();
1486
1487 // delete C++ thread object if this is a detached thread - user is
1488 // responsible for doing this for joinable ones
1489 if ( m_isDetached )
1490 {
1491 // FIXME I'm feeling bad about it - what if another thread function is
1492 // called (in another thread context) now? It will try to access
1493 // half destroyed object which will probably result in something
1494 // very bad - but we can't protect this by a crit section unless
1495 // we make it a global object, but this would mean that we can
1496 // only call one thread function at a time :-(
1497 DeleteThread(this);
1498 }
1499
1500 // terminate the thread (pthread_exit() never returns)
1501 pthread_exit(status);
1502
1503 wxFAIL_MSG(_T("pthread_exit() failed"));
1504 }
1505
1506 // also test whether we were paused
1507 bool wxThread::TestDestroy()
1508 {
1509 wxASSERT_MSG( This() == this,
1510 _T("wxThread::TestDestroy() can only be called in the "
1511 "context of the same thread") );
1512
1513 m_critsect.Enter();
1514
1515 if ( m_internal->GetState() == STATE_PAUSED )
1516 {
1517 m_internal->SetReallyPaused(TRUE);
1518
1519 // leave the crit section or the other threads will stop too if they
1520 // try to call any of (seemingly harmless) IsXXX() functions while we
1521 // sleep
1522 m_critsect.Leave();
1523
1524 m_internal->Pause();
1525 }
1526 else
1527 {
1528 // thread wasn't requested to pause, nothing to do
1529 m_critsect.Leave();
1530 }
1531
1532 return m_internal->WasCancelled();
1533 }
1534
1535 wxThread::~wxThread()
1536 {
1537 #ifdef __WXDEBUG__
1538 m_critsect.Enter();
1539
1540 // check that the thread either exited or couldn't be created
1541 if ( m_internal->GetState() != STATE_EXITED &&
1542 m_internal->GetState() != STATE_NEW )
1543 {
1544 wxLogDebug(_T("The thread %ld is being destroyed although it is still "
1545 "running! The application may crash."), GetId());
1546 }
1547
1548 m_critsect.Leave();
1549 #endif // __WXDEBUG__
1550
1551 delete m_internal;
1552
1553 // remove this thread from the global array
1554 gs_allThreads.Remove(this);
1555 }
1556
1557 // -----------------------------------------------------------------------------
1558 // state tests
1559 // -----------------------------------------------------------------------------
1560
1561 bool wxThread::IsRunning() const
1562 {
1563 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
1564
1565 return m_internal->GetState() == STATE_RUNNING;
1566 }
1567
1568 bool wxThread::IsAlive() const
1569 {
1570 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
1571
1572 switch ( m_internal->GetState() )
1573 {
1574 case STATE_RUNNING:
1575 case STATE_PAUSED:
1576 return TRUE;
1577
1578 default:
1579 return FALSE;
1580 }
1581 }
1582
1583 bool wxThread::IsPaused() const
1584 {
1585 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
1586
1587 return (m_internal->GetState() == STATE_PAUSED);
1588 }
1589
1590 //--------------------------------------------------------------------
1591 // wxThreadModule
1592 //--------------------------------------------------------------------
1593
1594 class wxThreadModule : public wxModule
1595 {
1596 public:
1597 virtual bool OnInit();
1598 virtual void OnExit();
1599
1600 private:
1601 DECLARE_DYNAMIC_CLASS(wxThreadModule)
1602 };
1603
1604 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
1605
1606 bool wxThreadModule::OnInit()
1607 {
1608 int rc = pthread_key_create(&gs_keySelf, NULL /* dtor function */);
1609 if ( rc != 0 )
1610 {
1611 wxLogSysError(rc, _("Thread module initialization failed: "
1612 "failed to create thread key"));
1613
1614 return FALSE;
1615 }
1616
1617 gs_tidMain = pthread_self();
1618
1619 #if wxUSE_GUI
1620 gs_mutexGui = new wxMutex();
1621
1622 gs_mutexGui->Lock();
1623 #endif // wxUSE_GUI
1624
1625 gs_mutexDeleteThread = new wxMutex();
1626 gs_condAllDeleted = new wxCondition( *gs_mutexDeleteThread );
1627
1628 return TRUE;
1629 }
1630
1631 void wxThreadModule::OnExit()
1632 {
1633 wxASSERT_MSG( wxThread::IsMain(), wxT("only main thread can be here") );
1634
1635 // are there any threads left which are being deleted right now?
1636 size_t nThreadsBeingDeleted;
1637
1638 {
1639 wxMutexLocker lock( *gs_mutexDeleteThread );
1640 nThreadsBeingDeleted = gs_nThreadsBeingDeleted;
1641
1642 if ( nThreadsBeingDeleted > 0 )
1643 {
1644 wxLogTrace(TRACE_THREADS,
1645 _T("Waiting for %lu threads to disappear"),
1646 (unsigned long)nThreadsBeingDeleted);
1647
1648 // have to wait until all of them disappear
1649 gs_condAllDeleted->Wait();
1650 }
1651 }
1652
1653 // terminate any threads left
1654 size_t count = gs_allThreads.GetCount();
1655 if ( count != 0u )
1656 {
1657 wxLogDebug(wxT("%lu threads were not terminated by the application."),
1658 (unsigned long)count);
1659 }
1660
1661 for ( size_t n = 0u; n < count; n++ )
1662 {
1663 // Delete calls the destructor which removes the current entry. We
1664 // should only delete the first one each time.
1665 gs_allThreads[0]->Delete();
1666 }
1667
1668 #if wxUSE_GUI
1669 // destroy GUI mutex
1670 gs_mutexGui->Unlock();
1671
1672 delete gs_mutexGui;
1673 #endif // wxUSE_GUI
1674
1675 // and free TLD slot
1676 (void)pthread_key_delete(gs_keySelf);
1677
1678 delete gs_condAllDeleted;
1679 delete gs_mutexDeleteThread;
1680 }
1681
1682 // ----------------------------------------------------------------------------
1683 // global functions
1684 // ----------------------------------------------------------------------------
1685
1686 static void ScheduleThreadForDeletion()
1687 {
1688 wxMutexLocker lock( *gs_mutexDeleteThread );
1689
1690 gs_nThreadsBeingDeleted++;
1691
1692 wxLogTrace(TRACE_THREADS, _T("%lu thread%s waiting to be deleted"),
1693 (unsigned long)gs_nThreadsBeingDeleted,
1694 gs_nThreadsBeingDeleted == 1 ? "" : "s");
1695 }
1696
1697 static void DeleteThread(wxThread *This)
1698 {
1699 // gs_mutexDeleteThread should be unlocked before signalling the condition
1700 // or wxThreadModule::OnExit() would deadlock
1701 wxMutexLocker locker( *gs_mutexDeleteThread );
1702
1703 wxLogTrace(TRACE_THREADS, _T("Thread %ld auto deletes."), This->GetId());
1704
1705 delete This;
1706
1707 wxCHECK_RET( gs_nThreadsBeingDeleted > 0,
1708 _T("no threads scheduled for deletion, yet we delete one?") );
1709
1710 wxLogTrace(TRACE_THREADS, _T("%lu scheduled for deletion threads left."),
1711 (unsigned long)gs_nThreadsBeingDeleted - 1);
1712
1713 if ( !--gs_nThreadsBeingDeleted )
1714 {
1715 // no more threads left, signal it
1716 gs_condAllDeleted->Signal();
1717 }
1718 }
1719
1720 void wxMutexGuiEnter()
1721 {
1722 #if wxUSE_GUI
1723 gs_mutexGui->Lock();
1724 #endif // wxUSE_GUI
1725 }
1726
1727 void wxMutexGuiLeave()
1728 {
1729 #if wxUSE_GUI
1730 gs_mutexGui->Unlock();
1731 #endif // wxUSE_GUI
1732 }
1733
1734 // ----------------------------------------------------------------------------
1735 // include common implementation code
1736 // ----------------------------------------------------------------------------
1737
1738 #include "wx/thrimpl.cpp"
1739
1740 #endif // wxUSE_THREADS
1741