]> git.saurik.com Git - wxWidgets.git/blob - src/unix/threadpsx.cpp
wxMemoryStream doc updated
[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 // With simple makefiles, we must ignore the file body if not using
28 // threads.
29 #include "wx/setup.h"
30
31 #if wxUSE_THREADS
32
33 #include "wx/thread.h"
34 #include "wx/module.h"
35 #include "wx/utils.h"
36 #include "wx/log.h"
37 #include "wx/intl.h"
38 #include "wx/dynarray.h"
39
40 #include <stdio.h>
41 #include <unistd.h>
42 #include <pthread.h>
43 #include <errno.h>
44 #include <time.h>
45
46 #if HAVE_SCHED_H
47 #include <sched.h>
48 #endif
49
50 // ----------------------------------------------------------------------------
51 // constants
52 // ----------------------------------------------------------------------------
53
54 // the possible states of the thread and transitions from them
55 enum wxThreadState
56 {
57 STATE_NEW, // didn't start execution yet (=> RUNNING)
58 STATE_RUNNING, // running (=> PAUSED or EXITED)
59 STATE_PAUSED, // suspended (=> RUNNING or EXITED)
60 STATE_EXITED // thread doesn't exist any more
61 };
62
63 // ----------------------------------------------------------------------------
64 // types
65 // ----------------------------------------------------------------------------
66
67 WX_DEFINE_ARRAY(wxThread *, wxArrayThread);
68
69 // -----------------------------------------------------------------------------
70 // global data
71 // -----------------------------------------------------------------------------
72
73 // we keep the list of all threads created by the application to be able to
74 // terminate them on exit if there are some left - otherwise the process would
75 // be left in memory
76 static wxArrayThread gs_allThreads;
77
78 // the id of the main thread
79 static pthread_t gs_tidMain;
80
81 // the key for the pointer to the associated wxThread object
82 static pthread_key_t gs_keySelf;
83
84 // this mutex must be acquired before any call to a GUI function
85 static wxMutex *gs_mutexGui;
86
87 // ============================================================================
88 // implementation
89 // ============================================================================
90
91 //--------------------------------------------------------------------
92 // wxMutex (Posix implementation)
93 //--------------------------------------------------------------------
94
95 class wxMutexInternal
96 {
97 public:
98 pthread_mutex_t p_mutex;
99 };
100
101 wxMutex::wxMutex()
102 {
103 pthread_mutexattr_t attr_type;
104
105 pthread_mutexattr_settype( &attr_type, PTHREAD_MUTEX_FAST_NP );
106
107 p_internal = new wxMutexInternal;
108 pthread_mutex_init( &(p_internal->p_mutex), (const pthread_mutexattr_t*) &attr_type );
109 m_locked = 0;
110 }
111
112 wxMutex::~wxMutex()
113 {
114 if (m_locked > 0)
115 wxLogDebug(_T("Freeing a locked mutex (%d locks)"), m_locked);
116
117 pthread_mutex_destroy( &(p_internal->p_mutex) );
118 delete p_internal;
119 }
120
121 wxMutexError wxMutex::Lock()
122 {
123 int err = pthread_mutex_lock( &(p_internal->p_mutex) );
124 if (err == EDEADLK)
125 {
126 wxLogDebug(_T("Locking this mutex would lead to deadlock!"));
127
128 return wxMUTEX_DEAD_LOCK;
129 }
130
131 m_locked++;
132
133 return wxMUTEX_NO_ERROR;
134 }
135
136 wxMutexError wxMutex::TryLock()
137 {
138 if (m_locked)
139 {
140 return wxMUTEX_BUSY;
141 }
142
143 int err = pthread_mutex_trylock( &(p_internal->p_mutex) );
144 switch (err)
145 {
146 case EBUSY: return wxMUTEX_BUSY;
147 }
148
149 m_locked++;
150
151 return wxMUTEX_NO_ERROR;
152 }
153
154 wxMutexError wxMutex::Unlock()
155 {
156 if (m_locked > 0)
157 {
158 m_locked--;
159 }
160 else
161 {
162 wxLogDebug(_T("Unlocking not locked mutex."));
163
164 return wxMUTEX_UNLOCKED;
165 }
166
167 pthread_mutex_unlock( &(p_internal->p_mutex) );
168
169 return wxMUTEX_NO_ERROR;
170 }
171
172 //--------------------------------------------------------------------
173 // wxCondition (Posix implementation)
174 //--------------------------------------------------------------------
175
176 class wxConditionInternal
177 {
178 public:
179 pthread_cond_t p_condition;
180 };
181
182 wxCondition::wxCondition()
183 {
184 p_internal = new wxConditionInternal;
185 pthread_cond_init( &(p_internal->p_condition), (const pthread_condattr_t *) NULL );
186 }
187
188 wxCondition::~wxCondition()
189 {
190 pthread_cond_destroy( &(p_internal->p_condition) );
191
192 delete p_internal;
193 }
194
195 void wxCondition::Wait(wxMutex& mutex)
196 {
197 pthread_cond_wait( &(p_internal->p_condition), &(mutex.p_internal->p_mutex) );
198 }
199
200 bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec)
201 {
202 struct timespec tspec;
203
204 tspec.tv_sec = time(0L)+sec;
205 tspec.tv_nsec = nsec;
206 return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT);
207 }
208
209 void wxCondition::Signal()
210 {
211 pthread_cond_signal( &(p_internal->p_condition) );
212 }
213
214 void wxCondition::Broadcast()
215 {
216 pthread_cond_broadcast( &(p_internal->p_condition) );
217 }
218
219 //--------------------------------------------------------------------
220 // wxThread (Posix implementation)
221 //--------------------------------------------------------------------
222
223 class wxThreadInternal
224 {
225 public:
226 wxThreadInternal();
227 ~wxThreadInternal();
228
229 // thread entry function
230 static void *PthreadStart(void *ptr);
231
232 #if HAVE_THREAD_CLEANUP_FUNCTIONS
233 // thread exit function
234 static void PthreadCleanup(void *ptr);
235 #endif
236
237 // thread actions
238 // start the thread
239 wxThreadError Run();
240 // ask the thread to terminate
241 void Wait();
242 // wake up threads waiting for our termination
243 void SignalExit();
244 // go to sleep until Resume() is called
245 void Pause();
246 // resume the thread
247 void Resume();
248
249 // accessors
250 // priority
251 int GetPriority() const { return m_prio; }
252 void SetPriority(int prio) { m_prio = prio; }
253 // state
254 wxThreadState GetState() const { return m_state; }
255 void SetState(wxThreadState state) { m_state = state; }
256 // id
257 pthread_t GetId() const { return m_threadId; }
258 pthread_t *GetIdPtr() { return &m_threadId; }
259 // "cancelled" flag
260 void SetCancelFlag() { m_cancelled = TRUE; }
261 bool WasCancelled() const { return m_cancelled; }
262
263 private:
264 pthread_t m_threadId; // id of the thread
265 wxThreadState m_state; // see wxThreadState enum
266 int m_prio; // in wxWindows units: from 0 to 100
267
268 // set when the thread should terminate
269 bool m_cancelled;
270
271 // this (mutex, cond) pair is used to synchronize the main thread and this
272 // thread in several situations:
273 // 1. The thread function blocks until condition is signaled by Run() when
274 // it's initially created - this allows thread creation in "suspended"
275 // state
276 // 2. The Delete() function blocks until the condition is signaled when the
277 // thread exits.
278 // GL: On Linux, this may fail because we can have a deadlock in either
279 // SignalExit() or Wait(): so we add m_end_mutex for the finalization.
280 wxMutex m_mutex, m_end_mutex;
281 wxCondition m_cond;
282
283 // another (mutex, cond) pair for Pause()/Resume() usage
284 //
285 // VZ: it's possible that we might reuse the mutex and condition from above
286 // for this too, but as I'm not at all sure that it won't create subtle
287 // problems with race conditions between, say, Pause() and Delete() I
288 // prefer this may be a bit less efficient but much safer solution
289 wxMutex m_mutexSuspend;
290 wxCondition m_condSuspend;
291 };
292
293 void *wxThreadInternal::PthreadStart(void *ptr)
294 {
295 wxThread *thread = (wxThread *)ptr;
296 wxThreadInternal *pthread = thread->p_internal;
297 void *status;
298
299 int rc = pthread_setspecific(gs_keySelf, thread);
300 if ( rc != 0 )
301 {
302 wxLogSysError(rc, _("Cannot start thread: error writing TLS"));
303
304 return (void *)-1;
305 }
306 #if HAVE_THREAD_CLEANUP_FUNCTIONS
307 // Install the cleanup handler.
308 pthread_cleanup_push(wxThreadInternal::PthreadCleanup, ptr);
309 #endif
310
311 // wait for the condition to be signaled from Run()
312 // mutex state: currently locked by the thread which created us
313 pthread->m_cond.Wait(pthread->m_mutex);
314 // mutex state: locked again on exit of Wait()
315
316 // call the main entry
317 status = thread->Entry();
318
319 #if HAVE_THREAD_CLEANUP_FUNCTIONS
320 pthread_cleanup_pop(FALSE);
321 #endif
322
323 // terminate the thread
324 thread->Exit(status);
325
326 wxFAIL_MSG(_T("wxThread::Exit() can't return."));
327
328 return NULL;
329 }
330
331 #if HAVE_THREAD_CLEANUP_FUNCTIONS
332 // Only called when the thread is explicitely killed.
333
334 void wxThreadInternal::PthreadCleanup(void *ptr)
335 {
336 wxThread *thread = (wxThread *) ptr;
337
338 // The thread is already considered as finished.
339 if (thread->p_internal->GetState() == STATE_EXITED)
340 return;
341
342 // first call user-level clean up code
343 thread->OnExit();
344
345 // next wake up the threads waiting for us (OTOH, this function won't retur
346 // until someone waited for us!)
347 thread->p_internal->SetState(STATE_EXITED);
348
349 thread->p_internal->SignalExit();
350 }
351 #endif
352
353 wxThreadInternal::wxThreadInternal()
354 {
355 m_state = STATE_NEW;
356 m_cancelled = FALSE;
357
358 // this mutex is locked during almost all thread lifetime - it will only be
359 // unlocked in the very end
360 m_mutex.Lock();
361
362 // this mutex is used by wxThreadInternal::Wait() and by
363 // wxThreadInternal::SignalExit(). We don't use m_mutex because of a
364 // possible deadlock in either Wait() or SignalExit().
365 m_end_mutex.Lock();
366
367 // this mutex is used in Pause()/Resume() and is also locked all the time
368 // unless the thread is paused
369 m_mutexSuspend.Lock();
370 }
371
372 wxThreadInternal::~wxThreadInternal()
373 {
374 // GL: moved to SignalExit
375 // m_mutexSuspend.Unlock();
376
377 // note that m_mutex will be unlocked by the thread which waits for our
378 // termination
379
380 // In the case, we didn't start the thread, all these mutex are locked:
381 // we must unlock them.
382 if (m_mutex.IsLocked())
383 m_mutex.Unlock();
384
385 if (m_end_mutex.IsLocked())
386 m_end_mutex.Unlock();
387
388 if (m_mutexSuspend.IsLocked())
389 m_mutexSuspend.Unlock();
390 }
391
392 wxThreadError wxThreadInternal::Run()
393 {
394 wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
395 _T("thread may only be started once after successful Create()") );
396
397 // the mutex was locked on Create(), so we will be able to lock it again
398 // only when the thread really starts executing and enters the wait -
399 // otherwise we might signal the condition before anybody is waiting for it
400 wxMutexLocker lock(m_mutex);
401 m_cond.Signal();
402
403 m_state = STATE_RUNNING;
404
405 return wxTHREAD_NO_ERROR;
406
407 // now the mutex is unlocked back - but just to allow Wait() function to
408 // terminate by relocking it, so the net result is that the worker thread
409 // starts executing and the mutex is still locked
410 }
411
412 void wxThreadInternal::Wait()
413 {
414 wxCHECK_RET( WasCancelled(), _T("thread should have been cancelled first") );
415
416 // if the thread we're waiting for is waiting for the GUI mutex, we will
417 // deadlock so make sure we release it temporarily
418 if ( wxThread::IsMain() )
419 wxMutexGuiLeave();
420
421 // entering Wait() releases the mutex thus allowing SignalExit() to acquire
422 // it and to signal us its termination
423 m_cond.Wait(m_end_mutex);
424
425 // mutex is still in the locked state - relocked on exit from Wait(), so
426 // unlock it - we don't need it any more, the thread has already terminated
427 m_end_mutex.Unlock();
428
429 // After that, we wait for the real end of the other thread.
430 pthread_join(GetId(), NULL);
431
432 // reacquire GUI mutex
433 if ( wxThread::IsMain() )
434 wxMutexGuiEnter();
435 }
436
437 void wxThreadInternal::SignalExit()
438 {
439 // GL: Unlock mutexSuspend here.
440 m_mutexSuspend.Unlock();
441
442 // as mutex is currently locked, this will block until some other thread
443 // (normally the same which created this one) unlocks it by entering Wait()
444 m_end_mutex.Lock();
445
446 // wake up all the threads waiting for our termination
447 m_cond.Broadcast();
448
449 // after this call mutex will be finally unlocked
450 m_end_mutex.Unlock();
451 }
452
453 void wxThreadInternal::Pause()
454 {
455 // the state is set from the thread which pauses us first, this function
456 // is called later so the state should have been already set
457 wxCHECK_RET( m_state == STATE_PAUSED,
458 _T("thread must first be paused with wxThread::Pause().") );
459
460 // don't pause the thread which is being terminated - this would lead to
461 // deadlock if the thread is paused after Delete() had called Resume() but
462 // before it had time to call Wait()
463 if ( WasCancelled() )
464 return;
465
466 // wait until the condition is signaled from Resume()
467 m_condSuspend.Wait(m_mutexSuspend);
468 }
469
470 void wxThreadInternal::Resume()
471 {
472 wxCHECK_RET( m_state == STATE_PAUSED,
473 _T("can't resume thread which is not suspended.") );
474
475 // we will be able to lock this mutex only when Pause() starts waiting
476 wxMutexLocker lock(m_mutexSuspend);
477 m_condSuspend.Signal();
478
479 SetState(STATE_RUNNING);
480 }
481
482 // -----------------------------------------------------------------------------
483 // static functions
484 // -----------------------------------------------------------------------------
485
486 wxThread *wxThread::This()
487 {
488 return (wxThread *)pthread_getspecific(gs_keySelf);
489 }
490
491 bool wxThread::IsMain()
492 {
493 return (bool)pthread_equal(pthread_self(), gs_tidMain);
494 }
495
496 void wxThread::Yield()
497 {
498 sched_yield();
499 }
500
501 void wxThread::Sleep(unsigned long milliseconds)
502 {
503 wxUsleep(milliseconds);
504 }
505
506 // -----------------------------------------------------------------------------
507 // creating thread
508 // -----------------------------------------------------------------------------
509
510 wxThread::wxThread()
511 {
512 // add this thread to the global list of all threads
513 gs_allThreads.Add(this);
514
515 p_internal = new wxThreadInternal();
516 }
517
518 wxThreadError wxThread::Create()
519 {
520 if (p_internal->GetState() != STATE_NEW)
521 return wxTHREAD_RUNNING;
522
523 // set up the thread attribute: right now, we only set thread priority
524 pthread_attr_t attr;
525 pthread_attr_init(&attr);
526
527 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
528 int prio;
529 if ( pthread_attr_getschedpolicy(&attr, &prio) != 0 )
530 {
531 wxLogError(_("Cannot retrieve thread scheduling policy."));
532 }
533
534 int min_prio = sched_get_priority_min(prio),
535 max_prio = sched_get_priority_max(prio);
536
537 if ( min_prio == -1 || max_prio == -1 )
538 {
539 wxLogError(_("Cannot get priority range for scheduling policy %d."),
540 prio);
541 }
542 else
543 {
544 struct sched_param sp;
545 pthread_attr_getschedparam(&attr, &sp);
546 sp.sched_priority = min_prio +
547 (p_internal->GetPriority()*(max_prio-min_prio))/100;
548 pthread_attr_setschedparam(&attr, &sp);
549 }
550 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
551
552 #ifdef HAVE_PTHREAD_ATTR_SETSCOPE
553 // this will make the threads created by this process really concurrent
554 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
555 #endif // HAVE_PTHREAD_ATTR_SETSCOPE
556
557 // create the new OS thread object
558 int rc = pthread_create(p_internal->GetIdPtr(), &attr,
559 wxThreadInternal::PthreadStart, (void *)this);
560 pthread_attr_destroy(&attr);
561
562 if ( rc != 0 )
563 {
564 p_internal->SetState(STATE_EXITED);
565 return wxTHREAD_NO_RESOURCE;
566 }
567
568 return wxTHREAD_NO_ERROR;
569 }
570
571 wxThreadError wxThread::Run()
572 {
573 return p_internal->Run();
574 }
575
576 // -----------------------------------------------------------------------------
577 // misc accessors
578 // -----------------------------------------------------------------------------
579
580 void wxThread::SetPriority(unsigned int prio)
581 {
582 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY <= (int)prio) &&
583 ((int)prio <= (int)WXTHREAD_MAX_PRIORITY),
584 _T("invalid thread priority") );
585
586 wxCriticalSectionLocker lock(m_critsect);
587
588 switch ( p_internal->GetState() )
589 {
590 case STATE_NEW:
591 // thread not yet started, priority will be set when it is
592 p_internal->SetPriority(prio);
593 break;
594
595 case STATE_RUNNING:
596 case STATE_PAUSED:
597 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
598 {
599 struct sched_param sparam;
600 sparam.sched_priority = prio;
601
602 if ( pthread_setschedparam(p_internal->GetId(),
603 SCHED_OTHER, &sparam) != 0 )
604 {
605 wxLogError(_("Failed to set thread priority %d."), prio);
606 }
607 }
608 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
609 break;
610
611 case STATE_EXITED:
612 default:
613 wxFAIL_MSG(_T("impossible to set thread priority in this state"));
614 }
615 }
616
617 unsigned int wxThread::GetPriority() const
618 {
619 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
620
621 return p_internal->GetPriority();
622 }
623
624 unsigned long wxThread::GetID() const
625 {
626 return (unsigned long)p_internal->GetId();
627 }
628
629 // -----------------------------------------------------------------------------
630 // pause/resume
631 // -----------------------------------------------------------------------------
632
633 wxThreadError wxThread::Pause()
634 {
635 wxCriticalSectionLocker lock(m_critsect);
636
637 if ( p_internal->GetState() != STATE_RUNNING )
638 {
639 wxLogDebug(_T("Can't pause thread which is not running."));
640
641 return wxTHREAD_NOT_RUNNING;
642 }
643
644 p_internal->SetState(STATE_PAUSED);
645
646 return wxTHREAD_NO_ERROR;
647 }
648
649 wxThreadError wxThread::Resume()
650 {
651 wxCriticalSectionLocker lock(m_critsect);
652
653 if ( p_internal->GetState() == STATE_PAUSED )
654 {
655 m_critsect.Leave();
656 p_internal->Resume();
657 m_critsect.Enter();
658
659 return wxTHREAD_NO_ERROR;
660 }
661 else
662 {
663 wxLogDebug(_T("Attempt to resume a thread which is not paused."));
664
665 return wxTHREAD_MISC_ERROR;
666 }
667 }
668
669 // -----------------------------------------------------------------------------
670 // exiting thread
671 // -----------------------------------------------------------------------------
672
673 wxThread::ExitCode wxThread::Delete()
674 {
675 if (IsPaused())
676 Resume();
677
678 m_critsect.Enter();
679 wxThreadState state = p_internal->GetState();
680
681 // ask the thread to stop
682 p_internal->SetCancelFlag();
683
684 m_critsect.Leave();
685
686 switch ( state )
687 {
688 case STATE_NEW:
689 case STATE_EXITED:
690 // nothing to do
691 break;
692
693 case STATE_PAUSED:
694 // resume the thread first
695 Resume();
696
697 // fall through
698
699 default:
700 // wait until the thread stops
701 p_internal->Wait();
702 }
703 //GL: As we must auto-destroy, the destruction must happen here.
704 delete this;
705
706 return NULL;
707 }
708
709 wxThreadError wxThread::Kill()
710 {
711 switch ( p_internal->GetState() )
712 {
713 case STATE_NEW:
714 case STATE_EXITED:
715 return wxTHREAD_NOT_RUNNING;
716
717 default:
718 #ifdef HAVE_PTHREAD_CANCEL
719 if ( pthread_cancel(p_internal->GetId()) != 0 )
720 #endif
721 {
722 wxLogError(_("Failed to terminate a thread."));
723
724 return wxTHREAD_MISC_ERROR;
725 }
726 //GL: As we must auto-destroy, the destruction must happen here (2).
727 delete this;
728
729 return wxTHREAD_NO_ERROR;
730 }
731 }
732
733 void wxThread::Exit(void *status)
734 {
735 // first call user-level clean up code
736 OnExit();
737
738 // next wake up the threads waiting for us (OTOH, this function won't return
739 // until someone waited for us!)
740 p_internal->SignalExit();
741
742 p_internal->SetState(STATE_EXITED);
743
744 // delete both C++ thread object and terminate the OS thread object
745 // GL: This is very ugly and buggy ...
746 // delete this;
747 pthread_exit(status);
748 }
749
750 // also test whether we were paused
751 bool wxThread::TestDestroy()
752 {
753 wxCriticalSectionLocker lock(m_critsect);
754
755 if ( p_internal->GetState() == STATE_PAUSED )
756 {
757 // leave the crit section or the other threads will stop too if they try
758 // to call any of (seemingly harmless) IsXXX() functions while we sleep
759 m_critsect.Leave();
760
761 p_internal->Pause();
762
763 // enter it back before it's finally left in lock object dtor
764 m_critsect.Enter();
765 }
766
767 return p_internal->WasCancelled();
768 }
769
770 wxThread::~wxThread()
771 {
772 m_critsect.Enter();
773 if (p_internal->GetState() != STATE_EXITED &&
774 p_internal->GetState() != STATE_NEW)
775 wxLogDebug(_T("The thread is being destroyed althought it is still running ! The application may crash."));
776
777 m_critsect.Leave();
778
779 delete p_internal;
780 // remove this thread from the global array
781 gs_allThreads.Remove(this);
782 }
783
784 // -----------------------------------------------------------------------------
785 // state tests
786 // -----------------------------------------------------------------------------
787
788 bool wxThread::IsRunning() const
789 {
790 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
791
792 return p_internal->GetState() == STATE_RUNNING;
793 }
794
795 bool wxThread::IsAlive() const
796 {
797 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
798
799 switch ( p_internal->GetState() )
800 {
801 case STATE_RUNNING:
802 case STATE_PAUSED:
803 return TRUE;
804
805 default:
806 return FALSE;
807 }
808 }
809
810 bool wxThread::IsPaused() const
811 {
812 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
813
814 return (p_internal->GetState() == STATE_PAUSED);
815 }
816
817 //--------------------------------------------------------------------
818 // wxThreadModule
819 //--------------------------------------------------------------------
820
821 class wxThreadModule : public wxModule
822 {
823 public:
824 virtual bool OnInit();
825 virtual void OnExit();
826
827 private:
828 DECLARE_DYNAMIC_CLASS(wxThreadModule)
829 };
830
831 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
832
833 bool wxThreadModule::OnInit()
834 {
835 int rc = pthread_key_create(&gs_keySelf, NULL /* dtor function */);
836 if ( rc != 0 )
837 {
838 wxLogSysError(rc, _("Thread module initialization failed: "
839 "failed to create thread key"));
840
841 return FALSE;
842 }
843
844 gs_mutexGui = new wxMutex();
845
846 gs_tidMain = pthread_self();
847
848 gs_mutexGui->Lock();
849
850 return TRUE;
851 }
852
853 void wxThreadModule::OnExit()
854 {
855 wxASSERT_MSG( wxThread::IsMain(), _T("only main thread can be here") );
856
857 // terminate any threads left
858 size_t count = gs_allThreads.GetCount();
859 if ( count != 0u )
860 wxLogDebug(_T("Some threads were not terminated by the application."));
861
862 for ( size_t n = 0u; n < count; n++ )
863 {
864 gs_allThreads[n]->Delete();
865 }
866
867 // destroy GUI mutex
868 gs_mutexGui->Unlock();
869
870 delete gs_mutexGui;
871
872 // and free TLD slot
873 (void)pthread_key_delete(gs_keySelf);
874 }
875
876 // ----------------------------------------------------------------------------
877 // global functions
878 // ----------------------------------------------------------------------------
879
880 void wxMutexGuiEnter()
881 {
882 gs_mutexGui->Lock();
883 }
884
885 void wxMutexGuiLeave()
886 {
887 gs_mutexGui->Unlock();
888 }
889
890 #endif
891 // wxUSE_THREADS