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