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