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