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