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