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