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