]> git.saurik.com Git - wxWidgets.git/blame - src/unix/threadpsx.cpp
wxRTC: save and load the 'shown' status in case there's a situation where layout...
[wxWidgets.git] / src / unix / threadpsx.cpp
CommitLineData
518b5d2f 1/////////////////////////////////////////////////////////////////////////////
ad9835c9 2// Name: src/unix/threadpsx.cpp
518b5d2f
VZ
3// Purpose: wxThread (Posix) Implementation
4// Author: Original from Wolfram Gloger/Guilhem Lavaux
be809868 5// Modified by: K. S. Sreeram (2002): POSIXified wxCondition, added wxSemaphore
518b5d2f 6// Created: 04/22/98
518b5d2f
VZ
7// Copyright: (c) Wolfram Gloger (1996, 1997)
8// Guilhem Lavaux (1998)
8d5eff60 9// Vadim Zeitlin (1999-2002)
518b5d2f 10// Robert Roebling (1999)
be809868 11// K. S. Sreeram (2002)
65571936 12// Licence: wxWindows licence
518b5d2f
VZ
13/////////////////////////////////////////////////////////////////////////////
14
15// ============================================================================
16// declaration
17// ============================================================================
18
19// ----------------------------------------------------------------------------
20// headers
21// ----------------------------------------------------------------------------
22
14f355c2
VS
23// for compilers that support precompilation, includes "wx.h".
24#include "wx/wxprec.h"
518b5d2f 25
7bcb11d3 26#if wxUSE_THREADS
518b5d2f 27
88a7a4e1 28#include "wx/thread.h"
79b7b95a 29#include "wx/except.h"
88a7a4e1 30
ad9835c9 31#ifndef WX_PRECOMP
79b7b95a 32 #include "wx/app.h"
ad9835c9 33 #include "wx/dynarray.h"
88a7a4e1 34 #include "wx/intl.h"
e4db172a 35 #include "wx/log.h"
de6185e2 36 #include "wx/utils.h"
c0badb70 37 #include "wx/timer.h"
bb90a3e6 38 #include "wx/stopwatch.h"
02761f6c 39 #include "wx/module.h"
ad9835c9
WS
40#endif
41
518b5d2f
VZ
42#include <stdio.h>
43#include <unistd.h>
44#include <pthread.h>
45#include <errno.h>
46#include <time.h>
feedacd8 47#include <sys/time.h> // needed for at least __QNX__
4f66d445 48#ifdef HAVE_SCHED_H
518b5d2f
VZ
49 #include <sched.h>
50#endif
51
ef8d96c2
VZ
52#ifdef HAVE_THR_SETCONCURRENCY
53 #include <thread.h>
54#endif
55
89b3361e 56#ifdef HAVE_ABI_FORCEDUNWIND
e02ea203
VZ
57 #include <cxxabi.h>
58#endif
59
eaf4bde6
VZ
60#ifdef HAVE_SETPRIORITY
61 #include <sys/resource.h> // for setpriority()
62#endif
63
ef8d96c2
VZ
64// we use wxFFile under Linux in GetCPUCount()
65#ifdef __LINUX__
66 #include "wx/ffile.h"
67#endif
68
35e9c131
VS
69#define THR_ID_CAST(id) (reinterpret_cast<void*>(id))
70#define THR_ID(thr) THR_ID_CAST((thr)->GetId())
ef4f69ec 71
518b5d2f
VZ
72// ----------------------------------------------------------------------------
73// constants
74// ----------------------------------------------------------------------------
75
882eefb1
VZ
76// the possible states of the thread and transitions from them
77enum wxThreadState
518b5d2f
VZ
78{
79 STATE_NEW, // didn't start execution yet (=> RUNNING)
882eefb1
VZ
80 STATE_RUNNING, // running (=> PAUSED or EXITED)
81 STATE_PAUSED, // suspended (=> RUNNING or EXITED)
82 STATE_EXITED // thread doesn't exist any more
518b5d2f
VZ
83};
84
9fc3ad34
VZ
85// the exit value of a thread which has been cancelled
86static const wxThread::ExitCode EXITCODE_CANCELLED = (wxThread::ExitCode)-1;
87
9e84b847 88// trace mask for wxThread operations
9a83f860 89#define TRACE_THREADS wxT("thread")
9fc3ad34 90
9e84b847 91// you can get additional debugging messages for the semaphore operations
9a83f860 92#define TRACE_SEMA wxT("semaphore")
9e84b847 93
9fc3ad34
VZ
94// ----------------------------------------------------------------------------
95// private functions
96// ----------------------------------------------------------------------------
97
98static void ScheduleThreadForDeletion();
99static void DeleteThread(wxThread *This);
100
882eefb1 101// ----------------------------------------------------------------------------
9e84b847 102// private classes
882eefb1
VZ
103// ----------------------------------------------------------------------------
104
9e84b847 105// an (non owning) array of pointers to threads
0d2c74c6 106WX_DEFINE_ARRAY_PTR(wxThread *, wxArrayThread);
518b5d2f 107
9e84b847
VZ
108// an entry for a thread we can wait for
109
518b5d2f
VZ
110// -----------------------------------------------------------------------------
111// global data
112// -----------------------------------------------------------------------------
113
114// we keep the list of all threads created by the application to be able to
115// terminate them on exit if there are some left - otherwise the process would
116// be left in memory
117static wxArrayThread gs_allThreads;
118
25b34b26
VZ
119// a mutex to protect gs_allThreads
120static wxMutex *gs_mutexAllThreads = NULL;
121
518b5d2f 122// the id of the main thread
f9226383
VZ
123//
124// we suppose that 0 is not a valid pthread_t value but in principle this might
125// be false (e.g. if it's a selector-like value), wxThread::IsMain() would need
126// to be updated in such case
127wxThreadIdType wxThread::ms_idMainThread = 0;
518b5d2f
VZ
128
129// the key for the pointer to the associated wxThread object
130static pthread_key_t gs_keySelf;
131
9fc3ad34
VZ
132// the number of threads which are being deleted - the program won't exit
133// until there are any left
134static size_t gs_nThreadsBeingDeleted = 0;
135
136// a mutex to protect gs_nThreadsBeingDeleted
d3b9f782 137static wxMutex *gs_mutexDeleteThread = NULL;
9fc3ad34
VZ
138
139// and a condition variable which will be signaled when all
140// gs_nThreadsBeingDeleted will have been deleted
d3b9f782 141static wxCondition *gs_condAllDeleted = NULL;
9fc3ad34 142
a94c4b85 143#ifndef __WXOSX__
c80217d1
VS
144// this mutex must be acquired before any call to a GUI function
145// (it's not inside #if wxUSE_GUI because this file is compiled as part
146// of wxBase)
147static wxMutex *gs_mutexGui = NULL;
a94c4b85 148#endif
518b5d2f 149
9e84b847
VZ
150// when we wait for a thread to exit, we're blocking on a condition which the
151// thread signals in its SignalExit() method -- but this condition can't be a
152// member of the thread itself as a detached thread may delete itself at any
153// moment and accessing the condition member of the thread after this would
154// result in a disaster
155//
156// so instead we maintain a global list of the structs below for the threads
157// we're interested in waiting on
158
518b5d2f 159// ============================================================================
8d5eff60 160// wxMutex implementation
518b5d2f
VZ
161// ============================================================================
162
8d5eff60
VZ
163// ----------------------------------------------------------------------------
164// wxMutexInternal
165// ----------------------------------------------------------------------------
518b5d2f 166
9e84b847
VZ
167// this is a simple wrapper around pthread_mutex_t which provides error
168// checking
518b5d2f
VZ
169class wxMutexInternal
170{
171public:
9e84b847 172 wxMutexInternal(wxMutexType mutexType);
8d5eff60
VZ
173 ~wxMutexInternal();
174
175 wxMutexError Lock();
696d13ee 176 wxMutexError Lock(unsigned long ms);
8d5eff60
VZ
177 wxMutexError TryLock();
178 wxMutexError Unlock();
179
9e84b847
VZ
180 bool IsOk() const { return m_isOk; }
181
696d13ee
VZ
182private:
183 // convert the result of pthread_mutex_[timed]lock() call to wx return code
184 wxMutexError HandleLockResult(int err);
185
8d5eff60 186private:
9fc3ad34 187 pthread_mutex_t m_mutex;
9e84b847 188 bool m_isOk;
375f364e
RR
189 wxMutexType m_type;
190 unsigned long m_owningThread;
be809868 191
9e84b847 192 // wxConditionInternal uses our m_mutex
be809868 193 friend class wxConditionInternal;
518b5d2f
VZ
194};
195
123dca7d
VZ
196#if defined(HAVE_PTHREAD_MUTEXATTR_T) && \
197 wxUSE_UNIX && !defined(HAVE_PTHREAD_MUTEXATTR_SETTYPE_DECL)
707a3782
VS
198// on some systems pthread_mutexattr_settype() is not in the headers (but it is
199// in the library, otherwise we wouldn't compile this code at all)
200extern "C" int pthread_mutexattr_settype(pthread_mutexattr_t *, int);
201#endif
202
9e84b847 203wxMutexInternal::wxMutexInternal(wxMutexType mutexType)
518b5d2f 204{
375f364e
RR
205 m_type = mutexType;
206 m_owningThread = 0;
207
9e84b847
VZ
208 int err;
209 switch ( mutexType )
210 {
211 case wxMUTEX_RECURSIVE:
212 // support recursive locks like Win32, i.e. a thread can lock a
213 // mutex which it had itself already locked
214 //
215 // unfortunately initialization of recursive mutexes is non
216 // portable, so try several methods
d9b9876f 217#ifdef HAVE_PTHREAD_MUTEXATTR_T
9e84b847
VZ
218 {
219 pthread_mutexattr_t attr;
220 pthread_mutexattr_init(&attr);
221 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
d9b9876f 222
9e84b847
VZ
223 err = pthread_mutex_init(&m_mutex, &attr);
224 }
d9b9876f 225#elif defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER)
9e84b847
VZ
226 // we can use this only as initializer so we have to assign it
227 // first to a temp var - assigning directly to m_mutex wouldn't
228 // even compile
229 {
230 pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
231 m_mutex = mutex;
232 }
d9b9876f 233#else // no recursive mutexes
9e84b847 234 err = EINVAL;
d9b9876f 235#endif // HAVE_PTHREAD_MUTEXATTR_T/...
9e84b847
VZ
236 break;
237
238 default:
9a83f860 239 wxFAIL_MSG( wxT("unknown mutex type") );
9e84b847
VZ
240 // fall through
241
242 case wxMUTEX_DEFAULT:
243 err = pthread_mutex_init(&m_mutex, NULL);
244 break;
245 }
246
247 m_isOk = err == 0;
248 if ( !m_isOk )
249 {
401eb3de 250 wxLogApiError( wxT("pthread_mutex_init()"), err);
9e84b847 251 }
8d5eff60
VZ
252}
253
254wxMutexInternal::~wxMutexInternal()
255{
9e84b847
VZ
256 if ( m_isOk )
257 {
258 int err = pthread_mutex_destroy(&m_mutex);
259 if ( err != 0 )
260 {
401eb3de 261 wxLogApiError( wxT("pthread_mutex_destroy()"), err);
9e84b847
VZ
262 }
263 }
8d5eff60
VZ
264}
265
266wxMutexError wxMutexInternal::Lock()
267{
375f364e
RR
268 if ((m_type == wxMUTEX_DEFAULT) && (m_owningThread != 0))
269 {
270 if (m_owningThread == wxThread::GetCurrentId())
271 return wxMUTEX_DEAD_LOCK;
272 }
122cf17b 273
696d13ee
VZ
274 return HandleLockResult(pthread_mutex_lock(&m_mutex));
275}
276
277wxMutexError wxMutexInternal::Lock(unsigned long ms)
278{
e55a667c 279#ifdef HAVE_PTHREAD_MUTEX_TIMEDLOCK
696d13ee
VZ
280 static const long MSEC_IN_SEC = 1000;
281 static const long NSEC_IN_MSEC = 1000000;
fd91cec1 282 static const long NSEC_IN_USEC = 1000;
696d13ee
VZ
283 static const long NSEC_IN_SEC = MSEC_IN_SEC * NSEC_IN_MSEC;
284
285 time_t seconds = ms/MSEC_IN_SEC;
286 long nanoseconds = (ms % MSEC_IN_SEC) * NSEC_IN_MSEC;
287 timespec ts = { 0, 0 };
288
fd91cec1
VZ
289 // normally we should use clock_gettime(CLOCK_REALTIME) here but this
290 // function is in librt and we don't link with it currently, so use
291 // gettimeofday() instead -- if it turns out that this is really too
292 // imprecise, we should modify configure to check if clock_gettime() is
293 // available and whether it requires -lrt and use it instead
294#if 0
696d13ee
VZ
295 if ( clock_gettime(CLOCK_REALTIME, &ts) == 0 )
296 {
696d13ee 297 }
fd91cec1
VZ
298#else
299 struct timeval tv;
300 if ( wxGetTimeOfDay(&tv) != -1 )
301 {
302 ts.tv_sec = tv.tv_sec;
303 ts.tv_nsec = tv.tv_usec*NSEC_IN_USEC;
304 }
305#endif
696d13ee
VZ
306 else // fall back on system timer
307 {
fd91cec1
VZ
308 ts.tv_sec = time(NULL);
309 }
310
311 ts.tv_sec += seconds;
312 ts.tv_nsec += nanoseconds;
313 if ( ts.tv_nsec > NSEC_IN_SEC )
314 {
315 ts.tv_sec += 1;
316 ts.tv_nsec -= NSEC_IN_SEC;
696d13ee
VZ
317 }
318
319 return HandleLockResult(pthread_mutex_timedlock(&m_mutex, &ts));
e55a667c
VZ
320#else // !HAVE_PTHREAD_MUTEX_TIMEDLOCK
321 wxUnusedVar(ms);
322
323 return wxMUTEX_MISC_ERROR;
324#endif // HAVE_PTHREAD_MUTEX_TIMEDLOCK/!HAVE_PTHREAD_MUTEX_TIMEDLOCK
696d13ee
VZ
325}
326
327wxMutexError wxMutexInternal::HandleLockResult(int err)
328{
375f364e
RR
329 // wxPrintf( "err %d\n", err );
330
8d5eff60
VZ
331 switch ( err )
332 {
333 case EDEADLK:
9e84b847
VZ
334 // only error checking mutexes return this value and so it's an
335 // unexpected situation -- hence use assert, not wxLogDebug
9a83f860 336 wxFAIL_MSG( wxT("mutex deadlock prevented") );
8d5eff60
VZ
337 return wxMUTEX_DEAD_LOCK;
338
8d5eff60 339 case EINVAL:
9a83f860 340 wxLogDebug(wxT("pthread_mutex_[timed]lock(): mutex not initialized"));
9e84b847 341 break;
8d5eff60 342
696d13ee
VZ
343 case ETIMEDOUT:
344 return wxMUTEX_TIMEOUT;
345
8d5eff60 346 case 0:
375f364e
RR
347 if (m_type == wxMUTEX_DEFAULT)
348 m_owningThread = wxThread::GetCurrentId();
8d5eff60 349 return wxMUTEX_NO_ERROR;
9e84b847
VZ
350
351 default:
9a83f860 352 wxLogApiError(wxT("pthread_mutex_[timed]lock()"), err);
8d5eff60 353 }
9e84b847
VZ
354
355 return wxMUTEX_MISC_ERROR;
8d5eff60
VZ
356}
357
696d13ee 358
8d5eff60
VZ
359wxMutexError wxMutexInternal::TryLock()
360{
361 int err = pthread_mutex_trylock(&m_mutex);
362 switch ( err )
363 {
364 case EBUSY:
9e84b847
VZ
365 // not an error: mutex is already locked, but we're prepared for
366 // this
8d5eff60
VZ
367 return wxMUTEX_BUSY;
368
8d5eff60 369 case EINVAL:
9a83f860 370 wxLogDebug(wxT("pthread_mutex_trylock(): mutex not initialized."));
9e84b847 371 break;
8d5eff60
VZ
372
373 case 0:
375f364e
RR
374 if (m_type == wxMUTEX_DEFAULT)
375 m_owningThread = wxThread::GetCurrentId();
8d5eff60 376 return wxMUTEX_NO_ERROR;
9e84b847
VZ
377
378 default:
9a83f860 379 wxLogApiError(wxT("pthread_mutex_trylock()"), err);
8d5eff60 380 }
9e84b847
VZ
381
382 return wxMUTEX_MISC_ERROR;
8d5eff60
VZ
383}
384
385wxMutexError wxMutexInternal::Unlock()
386{
375f364e 387 m_owningThread = 0;
122cf17b 388
8d5eff60
VZ
389 int err = pthread_mutex_unlock(&m_mutex);
390 switch ( err )
391 {
392 case EPERM:
393 // we don't own the mutex
394 return wxMUTEX_UNLOCKED;
395
8d5eff60 396 case EINVAL:
9a83f860 397 wxLogDebug(wxT("pthread_mutex_unlock(): mutex not initialized."));
9e84b847 398 break;
8d5eff60
VZ
399
400 case 0:
401 return wxMUTEX_NO_ERROR;
518b5d2f 402
9e84b847 403 default:
9a83f860 404 wxLogApiError(wxT("pthread_mutex_unlock()"), err);
518b5d2f
VZ
405 }
406
9e84b847 407 return wxMUTEX_MISC_ERROR;
518b5d2f
VZ
408}
409
be809868 410// ===========================================================================
8d5eff60 411// wxCondition implementation
be809868 412// ===========================================================================
8d5eff60 413
be809868 414// ---------------------------------------------------------------------------
8d5eff60 415// wxConditionInternal
be809868 416// ---------------------------------------------------------------------------
518b5d2f 417
9e84b847
VZ
418// this is a wrapper around pthread_cond_t associated with a wxMutex (and hence
419// with a pthread_mutex_t)
518b5d2f
VZ
420class wxConditionInternal
421{
422public:
c112e100 423 wxConditionInternal(wxMutex& mutex);
9fc3ad34
VZ
424 ~wxConditionInternal();
425
9e84b847 426 bool IsOk() const { return m_isOk && m_mutex.IsOk(); }
4c460b34 427
9e84b847
VZ
428 wxCondError Wait();
429 wxCondError WaitTimeout(unsigned long milliseconds);
547b93ab 430
9e84b847
VZ
431 wxCondError Signal();
432 wxCondError Broadcast();
4c460b34 433
be809868 434private:
c112e100 435 // get the POSIX mutex associated with us
9e84b847 436 pthread_mutex_t *GetPMutex() const { return &m_mutex.m_internal->m_mutex; }
518b5d2f 437
c112e100 438 wxMutex& m_mutex;
be809868 439 pthread_cond_t m_cond;
9e84b847
VZ
440
441 bool m_isOk;
8d5eff60 442};
547b93ab 443
c112e100
VZ
444wxConditionInternal::wxConditionInternal(wxMutex& mutex)
445 : m_mutex(mutex)
9fc3ad34 446{
9e84b847 447 int err = pthread_cond_init(&m_cond, NULL /* default attributes */);
9fc3ad34 448
9e84b847 449 m_isOk = err == 0;
9fc3ad34 450
9e84b847 451 if ( !m_isOk )
9fc3ad34 452 {
9a83f860 453 wxLogApiError(wxT("pthread_cond_init()"), err);
9fc3ad34
VZ
454 }
455}
456
9e84b847 457wxConditionInternal::~wxConditionInternal()
4c460b34 458{
9e84b847 459 if ( m_isOk )
c112e100 460 {
9e84b847
VZ
461 int err = pthread_cond_destroy(&m_cond);
462 if ( err != 0 )
463 {
9a83f860 464 wxLogApiError(wxT("pthread_cond_destroy()"), err);
9e84b847 465 }
c112e100 466 }
be809868 467}
4c460b34 468
9e84b847 469wxCondError wxConditionInternal::Wait()
be809868 470{
9e84b847
VZ
471 int err = pthread_cond_wait(&m_cond, GetPMutex());
472 if ( err != 0 )
473 {
9a83f860 474 wxLogApiError(wxT("pthread_cond_wait()"), err);
4c460b34 475
9e84b847 476 return wxCOND_MISC_ERROR;
be809868 477 }
4c460b34 478
9e84b847 479 return wxCOND_NO_ERROR;
be809868 480}
60ce696e 481
9e84b847 482wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds)
be809868 483{
e60defcb 484 wxLongLong curtime = wxGetUTCTimeMillis();
9e84b847 485 curtime += milliseconds;
be809868
VZ
486 wxLongLong temp = curtime / 1000;
487 int sec = temp.GetLo();
9e84b847 488 temp *= 1000;
be809868
VZ
489 temp = curtime - temp;
490 int millis = temp.GetLo();
491
492 timespec tspec;
493
494 tspec.tv_sec = sec;
495 tspec.tv_nsec = millis * 1000L * 1000L;
4c460b34 496
9e84b847
VZ
497 int err = pthread_cond_timedwait( &m_cond, GetPMutex(), &tspec );
498 switch ( err )
499 {
500 case ETIMEDOUT:
501 return wxCOND_TIMEOUT;
502
503 case 0:
504 return wxCOND_NO_ERROR;
505
506 default:
9a83f860 507 wxLogApiError(wxT("pthread_cond_timedwait()"), err);
9e84b847
VZ
508 }
509
510 return wxCOND_MISC_ERROR;
9fc3ad34
VZ
511}
512
9e84b847 513wxCondError wxConditionInternal::Signal()
9fc3ad34 514{
9e84b847
VZ
515 int err = pthread_cond_signal(&m_cond);
516 if ( err != 0 )
517 {
9a83f860 518 wxLogApiError(wxT("pthread_cond_signal()"), err);
9e84b847
VZ
519
520 return wxCOND_MISC_ERROR;
521 }
522
523 return wxCOND_NO_ERROR;
be809868 524}
547b93ab 525
9e84b847 526wxCondError wxConditionInternal::Broadcast()
be809868 527{
9e84b847
VZ
528 int err = pthread_cond_broadcast(&m_cond);
529 if ( err != 0 )
530 {
9a83f860 531 wxLogApiError(wxT("pthread_cond_broadcast()"), err);
9e84b847
VZ
532
533 return wxCOND_MISC_ERROR;
534 }
535
536 return wxCOND_NO_ERROR;
be809868
VZ
537}
538
539// ===========================================================================
540// wxSemaphore implementation
541// ===========================================================================
9fc3ad34 542
be809868
VZ
543// ---------------------------------------------------------------------------
544// wxSemaphoreInternal
545// ---------------------------------------------------------------------------
546
9e84b847
VZ
547// we implement the semaphores using mutexes and conditions instead of using
548// the sem_xxx() POSIX functions because they're not widely available and also
549// because it's impossible to implement WaitTimeout() using them
be809868
VZ
550class wxSemaphoreInternal
551{
552public:
9e84b847 553 wxSemaphoreInternal(int initialcount, int maxcount);
be809868 554
9e84b847 555 bool IsOk() const { return m_isOk; }
be809868 556
9e84b847
VZ
557 wxSemaError Wait();
558 wxSemaError TryWait();
559 wxSemaError WaitTimeout(unsigned long milliseconds);
be809868 560
9e84b847 561 wxSemaError Post();
be809868
VZ
562
563private:
564 wxMutex m_mutex;
565 wxCondition m_cond;
566
9e84b847
VZ
567 size_t m_count,
568 m_maxcount;
569
570 bool m_isOk;
be809868
VZ
571};
572
9e84b847 573wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
c112e100 574 : m_cond(m_mutex)
be809868
VZ
575{
576
9e84b847
VZ
577 if ( (initialcount < 0 || maxcount < 0) ||
578 ((maxcount > 0) && (initialcount > maxcount)) )
579 {
9a83f860 580 wxFAIL_MSG( wxT("wxSemaphore: invalid initial or maximal count") );
9e84b847 581
ad9835c9 582 m_isOk = false;
9e84b847
VZ
583 }
584 else
be809868 585 {
9e84b847
VZ
586 m_maxcount = (size_t)maxcount;
587 m_count = (size_t)initialcount;
547b93ab 588 }
547b93ab 589
9e84b847 590 m_isOk = m_mutex.IsOk() && m_cond.IsOk();
be809868 591}
547b93ab 592
9e84b847 593wxSemaError wxSemaphoreInternal::Wait()
be809868 594{
cd10339a 595 wxMutexLocker locker(m_mutex);
60ce696e 596
9e84b847 597 while ( m_count == 0 )
9fc3ad34 598 {
9e84b847 599 wxLogTrace(TRACE_SEMA,
9a83f860 600 wxT("Thread %p waiting for semaphore to become signalled"),
35e9c131 601 THR_ID_CAST(wxThread::GetCurrentId()));
9e84b847
VZ
602
603 if ( m_cond.Wait() != wxCOND_NO_ERROR )
604 return wxSEMA_MISC_ERROR;
605
606 wxLogTrace(TRACE_SEMA,
9a83f860 607 wxT("Thread %p finished waiting for semaphore, count = %lu"),
35e9c131 608 THR_ID_CAST(wxThread::GetCurrentId()), (unsigned long)m_count);
9fc3ad34 609 }
be809868 610
9e84b847
VZ
611 m_count--;
612
613 return wxSEMA_NO_ERROR;
be809868
VZ
614}
615
9e84b847 616wxSemaError wxSemaphoreInternal::TryWait()
be809868 617{
cd10339a 618 wxMutexLocker locker(m_mutex);
be809868 619
9e84b847
VZ
620 if ( m_count == 0 )
621 return wxSEMA_BUSY;
be809868 622
9e84b847 623 m_count--;
be809868 624
9e84b847 625 return wxSEMA_NO_ERROR;
be809868
VZ
626}
627
9e84b847 628wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds)
be809868 629{
cd10339a 630 wxMutexLocker locker(m_mutex);
be809868
VZ
631
632 wxLongLong startTime = wxGetLocalTimeMillis();
633
9e84b847 634 while ( m_count == 0 )
9fc3ad34 635 {
be809868 636 wxLongLong elapsed = wxGetLocalTimeMillis() - startTime;
9e84b847 637 long remainingTime = (long)milliseconds - (long)elapsed.GetLo();
be809868 638 if ( remainingTime <= 0 )
9e84b847
VZ
639 {
640 // timeout
641 return wxSEMA_TIMEOUT;
642 }
be809868 643
918dc519
VZ
644 switch ( m_cond.WaitTimeout(remainingTime) )
645 {
646 case wxCOND_TIMEOUT:
647 return wxSEMA_TIMEOUT;
648
649 default:
650 return wxSEMA_MISC_ERROR;
651
652 case wxCOND_NO_ERROR:
653 ;
654 }
9fc3ad34 655 }
8d5eff60 656
9e84b847 657 m_count--;
be809868 658
9e84b847 659 return wxSEMA_NO_ERROR;
be809868
VZ
660}
661
9e84b847 662wxSemaError wxSemaphoreInternal::Post()
be809868 663{
cd10339a 664 wxMutexLocker locker(m_mutex);
be809868 665
9e84b847 666 if ( m_maxcount > 0 && m_count == m_maxcount )
60ce696e 667 {
9e84b847 668 return wxSEMA_OVERFLOW;
60ce696e 669 }
be809868 670
9e84b847 671 m_count++;
518b5d2f 672
9e84b847 673 wxLogTrace(TRACE_SEMA,
9a83f860 674 wxT("Thread %p about to signal semaphore, count = %lu"),
35e9c131 675 THR_ID_CAST(wxThread::GetCurrentId()), (unsigned long)m_count);
2b5f62a0 676
9e84b847
VZ
677 return m_cond.Signal() == wxCOND_NO_ERROR ? wxSEMA_NO_ERROR
678 : wxSEMA_MISC_ERROR;
518b5d2f
VZ
679}
680
be809868 681// ===========================================================================
8d5eff60 682// wxThread implementation
be809868 683// ===========================================================================
518b5d2f 684
295272bd
VZ
685// the thread callback functions must have the C linkage
686extern "C"
687{
688
816a7358 689#ifdef wxHAVE_PTHREAD_CLEANUP
295272bd
VZ
690 // thread exit function
691 void wxPthreadCleanup(void *ptr);
816a7358 692#endif // wxHAVE_PTHREAD_CLEANUP
90350682 693
295272bd 694void *wxPthreadStart(void *ptr);
90350682 695
295272bd 696} // extern "C"
90350682 697
8d5eff60
VZ
698// ----------------------------------------------------------------------------
699// wxThreadInternal
700// ----------------------------------------------------------------------------
701
518b5d2f
VZ
702class wxThreadInternal
703{
704public:
705 wxThreadInternal();
706 ~wxThreadInternal();
707
708 // thread entry function
295272bd 709 static void *PthreadStart(wxThread *thread);
518b5d2f
VZ
710
711 // thread actions
0dd300ca
VS
712 // create the thread
713 wxThreadError Create(wxThread *thread, unsigned int stackSize);
518b5d2f
VZ
714 // start the thread
715 wxThreadError Run();
9e84b847
VZ
716 // unblock the thread allowing it to run
717 void SignalRun() { m_semRun.Post(); }
518b5d2f 718 // ask the thread to terminate
882eefb1 719 void Wait();
518b5d2f
VZ
720 // go to sleep until Resume() is called
721 void Pause();
722 // resume the thread
723 void Resume();
724
725 // accessors
726 // priority
727 int GetPriority() const { return m_prio; }
728 void SetPriority(int prio) { m_prio = prio; }
729 // state
882eefb1 730 wxThreadState GetState() const { return m_state; }
9e84b847
VZ
731 void SetState(wxThreadState state)
732 {
711f12ef 733#if wxUSE_LOG_TRACE
a243da29 734 static const wxChar *const stateNames[] =
9e84b847 735 {
9a83f860
VZ
736 wxT("NEW"),
737 wxT("RUNNING"),
738 wxT("PAUSED"),
739 wxT("EXITED"),
9e84b847
VZ
740 };
741
9a83f860 742 wxLogTrace(TRACE_THREADS, wxT("Thread %p: %s => %s."),
35e9c131 743 THR_ID(this), stateNames[m_state], stateNames[state]);
711f12ef 744#endif // wxUSE_LOG_TRACE
9e84b847
VZ
745
746 m_state = state;
747 }
518b5d2f 748 // id
882eefb1
VZ
749 pthread_t GetId() const { return m_threadId; }
750 pthread_t *GetIdPtr() { return &m_threadId; }
2e57ca64
VS
751 // "created" flag
752 bool WasCreated() const { return m_created; }
518b5d2f 753 // "cancelled" flag
ad9835c9 754 void SetCancelFlag() { m_cancelled = true; }
518b5d2f 755 bool WasCancelled() const { return m_cancelled; }
9fc3ad34
VZ
756 // exit code
757 void SetExitCode(wxThread::ExitCode exitcode) { m_exitcode = exitcode; }
758 wxThread::ExitCode GetExitCode() const { return m_exitcode; }
759
4c460b34
VZ
760 // the pause flag
761 void SetReallyPaused(bool paused) { m_isPaused = paused; }
762 bool IsReallyPaused() const { return m_isPaused; }
763
9fc3ad34 764 // tell the thread that it is a detached one
4c460b34
VZ
765 void Detach()
766 {
9e84b847
VZ
767 wxCriticalSectionLocker lock(m_csJoinFlag);
768
ad9835c9
WS
769 m_shouldBeJoined = false;
770 m_isDetached = true;
4c460b34 771 }
518b5d2f 772
816a7358 773#ifdef wxHAVE_PTHREAD_CLEANUP
90350682
VZ
774 // this is used by wxPthreadCleanup() only
775 static void Cleanup(wxThread *thread);
816a7358 776#endif // wxHAVE_PTHREAD_CLEANUP
90350682 777
518b5d2f 778private:
882eefb1
VZ
779 pthread_t m_threadId; // id of the thread
780 wxThreadState m_state; // see wxThreadState enum
77ffb593 781 int m_prio; // in wxWidgets units: from 0 to 100
518b5d2f 782
2e57ca64
VS
783 // this flag is set when the thread was successfully created
784 bool m_created;
785
9fc3ad34 786 // this flag is set when the thread should terminate
518b5d2f
VZ
787 bool m_cancelled;
788
be809868 789 // this flag is set when the thread is blocking on m_semSuspend
4c460b34
VZ
790 bool m_isPaused;
791
9fc3ad34
VZ
792 // the thread exit code - only used for joinable (!detached) threads and
793 // is only valid after the thread termination
794 wxThread::ExitCode m_exitcode;
795
796 // many threads may call Wait(), but only one of them should call
797 // pthread_join(), so we have to keep track of this
798 wxCriticalSection m_csJoinFlag;
799 bool m_shouldBeJoined;
4c460b34 800 bool m_isDetached;
9fc3ad34 801
be809868 802 // this semaphore is posted by Run() and the threads Entry() is not
9fc3ad34 803 // called before it is done
be809868 804 wxSemaphore m_semRun;
9fc3ad34
VZ
805
806 // this one is signaled when the thread should resume after having been
807 // Pause()d
be809868 808 wxSemaphore m_semSuspend;
518b5d2f
VZ
809};
810
9fc3ad34
VZ
811// ----------------------------------------------------------------------------
812// thread startup and exit functions
813// ----------------------------------------------------------------------------
814
295272bd
VZ
815void *wxPthreadStart(void *ptr)
816{
817 return wxThreadInternal::PthreadStart((wxThread *)ptr);
818}
819
820void *wxThreadInternal::PthreadStart(wxThread *thread)
518b5d2f 821{
9fc3ad34 822 wxThreadInternal *pthread = thread->m_internal;
518b5d2f 823
9a83f860 824 wxLogTrace(TRACE_THREADS, wxT("Thread %p started."), THR_ID(pthread));
ef4f69ec 825
9fc3ad34
VZ
826 // associate the thread pointer with the newly created thread so that
827 // wxThread::This() will work
862cc6f9
VZ
828 int rc = pthread_setspecific(gs_keySelf, thread);
829 if ( rc != 0 )
518b5d2f 830 {
b82f92a8 831 wxLogSysError(rc, _("Cannot start thread: error writing TLS."));
518b5d2f
VZ
832
833 return (void *)-1;
834 }
9fc3ad34 835
4c460b34
VZ
836 // have to declare this before pthread_cleanup_push() which defines a
837 // block!
838 bool dontRunAtAll;
839
816a7358 840#ifdef wxHAVE_PTHREAD_CLEANUP
9fc3ad34
VZ
841 // install the cleanup handler which will be called if the thread is
842 // cancelled
295272bd 843 pthread_cleanup_push(wxPthreadCleanup, thread);
816a7358 844#endif // wxHAVE_PTHREAD_CLEANUP
518b5d2f 845
be809868
VZ
846 // wait for the semaphore to be posted from Run()
847 pthread->m_semRun.Wait();
518b5d2f 848
4c460b34
VZ
849 // test whether we should run the run at all - may be it was deleted
850 // before it started to Run()?
851 {
852 wxCriticalSectionLocker lock(thread->m_critsect);
9fc3ad34 853
4c460b34
VZ
854 dontRunAtAll = pthread->GetState() == STATE_NEW &&
855 pthread->WasCancelled();
856 }
9fc3ad34 857
4c460b34 858 if ( !dontRunAtAll )
9fc3ad34 859 {
4c460b34 860 // call the main entry
ef4f69ec 861 wxLogTrace(TRACE_THREADS,
9a83f860 862 wxT("Thread %p about to enter its Entry()."),
ef4f69ec
VZ
863 THR_ID(pthread));
864
79b7b95a
VS
865 wxTRY
866 {
52784696 867 pthread->m_exitcode = thread->CallEntry();
5092b3ad 868
79b7b95a 869 wxLogTrace(TRACE_THREADS,
9a83f860 870 wxT("Thread %p Entry() returned %lu."),
79b7b95a
VS
871 THR_ID(pthread), wxPtrToUInt(pthread->m_exitcode));
872 }
89b3361e 873#ifdef HAVE_ABI_FORCEDUNWIND
e02ea203
VZ
874 // When using common C++ ABI under Linux we must always rethrow this
875 // special exception used to unwind the stack when the thread was
876 // cancelled, otherwise the thread library would simply terminate the
877 // program, see http://udrepper.livejournal.com/21541.html
878 catch ( abi::__forced_unwind& )
879 {
880 wxCriticalSectionLocker lock(thread->m_critsect);
881 pthread->SetState(STATE_EXITED);
882 throw;
883 }
89b3361e 884#endif // HAVE_ABI_FORCEDUNWIND
79b7b95a 885 wxCATCH_ALL( wxTheApp->OnUnhandledException(); )
ef4f69ec 886
4c460b34
VZ
887 {
888 wxCriticalSectionLocker lock(thread->m_critsect);
889
4c460b34 890 // change the state of the thread to "exited" so that
90350682 891 // wxPthreadCleanup handler won't do anything from now (if it's
4c460b34
VZ
892 // called before we do pthread_cleanup_pop below)
893 pthread->SetState(STATE_EXITED);
894 }
9fc3ad34
VZ
895 }
896
741d91c5
VZ
897 // NB: pthread_cleanup_push/pop() are macros and pop contains the matching
898 // '}' for the '{' in push, so they must be used in the same block!
816a7358 899#ifdef wxHAVE_PTHREAD_CLEANUP
741d91c5
VZ
900 #ifdef __DECCXX
901 // under Tru64 we get a warning from macro expansion
902 #pragma message save
903 #pragma message disable(declbutnotref)
904 #endif
905
9fc3ad34 906 // remove the cleanup handler without executing it
062c4861 907 pthread_cleanup_pop(FALSE);
741d91c5
VZ
908
909 #ifdef __DECCXX
910 #pragma message restore
911 #endif
816a7358 912#endif // wxHAVE_PTHREAD_CLEANUP
518b5d2f 913
4c460b34
VZ
914 if ( dontRunAtAll )
915 {
9e84b847 916 // FIXME: deleting a possibly joinable thread here???
4c460b34 917 delete thread;
518b5d2f 918
4c460b34
VZ
919 return EXITCODE_CANCELLED;
920 }
921 else
922 {
923 // terminate the thread
924 thread->Exit(pthread->m_exitcode);
925
926 wxFAIL_MSG(wxT("wxThread::Exit() can't return."));
518b5d2f 927
4c460b34
VZ
928 return NULL;
929 }
518b5d2f
VZ
930}
931
816a7358 932#ifdef wxHAVE_PTHREAD_CLEANUP
5092b3ad 933
9fc3ad34 934// this handler is called when the thread is cancelled
90350682 935extern "C" void wxPthreadCleanup(void *ptr)
5092b3ad 936{
90350682
VZ
937 wxThreadInternal::Cleanup((wxThread *)ptr);
938}
5092b3ad 939
90350682
VZ
940void wxThreadInternal::Cleanup(wxThread *thread)
941{
b4866582 942 if (pthread_getspecific(gs_keySelf) == 0) return;
9fc3ad34
VZ
943 {
944 wxCriticalSectionLocker lock(thread->m_critsect);
945 if ( thread->m_internal->GetState() == STATE_EXITED )
946 {
947 // thread is already considered as finished.
948 return;
949 }
950 }
5092b3ad 951
9fc3ad34
VZ
952 // exit the thread gracefully
953 thread->Exit(EXITCODE_CANCELLED);
954}
5092b3ad 955
816a7358 956#endif // wxHAVE_PTHREAD_CLEANUP
5092b3ad 957
9fc3ad34
VZ
958// ----------------------------------------------------------------------------
959// wxThreadInternal
960// ----------------------------------------------------------------------------
5092b3ad 961
518b5d2f
VZ
962wxThreadInternal::wxThreadInternal()
963{
964 m_state = STATE_NEW;
2e57ca64 965 m_created = false;
ad9835c9 966 m_cancelled = false;
90e95e61 967 m_prio = wxPRIORITY_DEFAULT;
bbfa0322 968 m_threadId = 0;
9fc3ad34 969 m_exitcode = 0;
518b5d2f 970
ad9835c9
WS
971 // set to true only when the thread starts waiting on m_semSuspend
972 m_isPaused = false;
4c460b34 973
9fc3ad34 974 // defaults for joinable threads
ad9835c9
WS
975 m_shouldBeJoined = true;
976 m_isDetached = false;
518b5d2f
VZ
977}
978
979wxThreadInternal::~wxThreadInternal()
980{
518b5d2f
VZ
981}
982
0dd300ca
VS
983#ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
984 #define WXUNUSED_STACKSIZE(identifier) identifier
985#else
986 #define WXUNUSED_STACKSIZE(identifier) WXUNUSED(identifier)
987#endif
988
989wxThreadError wxThreadInternal::Create(wxThread *thread,
990 unsigned int WXUNUSED_STACKSIZE(stackSize))
991{
992 if ( GetState() != STATE_NEW )
993 {
994 // don't recreate thread
995 return wxTHREAD_RUNNING;
996 }
997
998 // set up the thread attribute: right now, we only set thread priority
999 pthread_attr_t attr;
1000 pthread_attr_init(&attr);
1001
1002#ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
1003 if (stackSize)
1004 pthread_attr_setstacksize(&attr, stackSize);
1005#endif
1006
1007#ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
1008 int policy;
1009 if ( pthread_attr_getschedpolicy(&attr, &policy) != 0 )
1010 {
1011 wxLogError(_("Cannot retrieve thread scheduling policy."));
1012 }
1013
1014#ifdef __VMS__
1015 /* the pthread.h contains too many spaces. This is a work-around */
1016# undef sched_get_priority_max
1017#undef sched_get_priority_min
1018#define sched_get_priority_max(_pol_) \
1019 (_pol_ == SCHED_OTHER ? PRI_FG_MAX_NP : PRI_FIFO_MAX)
1020#define sched_get_priority_min(_pol_) \
1021 (_pol_ == SCHED_OTHER ? PRI_FG_MIN_NP : PRI_FIFO_MIN)
1022#endif
1023
1024 int max_prio = sched_get_priority_max(policy),
1025 min_prio = sched_get_priority_min(policy),
1026 prio = GetPriority();
1027
1028 if ( min_prio == -1 || max_prio == -1 )
1029 {
1030 wxLogError(_("Cannot get priority range for scheduling policy %d."),
1031 policy);
1032 }
1033 else if ( max_prio == min_prio )
1034 {
1035 if ( prio != wxPRIORITY_DEFAULT )
1036 {
1037 // notify the programmer that this doesn't work here
1038 wxLogWarning(_("Thread priority setting is ignored."));
1039 }
1040 //else: we have default priority, so don't complain
1041
1042 // anyhow, don't do anything because priority is just ignored
1043 }
1044 else
1045 {
1046 struct sched_param sp;
1047 if ( pthread_attr_getschedparam(&attr, &sp) != 0 )
1048 {
1049 wxFAIL_MSG(wxT("pthread_attr_getschedparam() failed"));
1050 }
1051
1052 sp.sched_priority = min_prio + (prio*(max_prio - min_prio))/100;
1053
1054 if ( pthread_attr_setschedparam(&attr, &sp) != 0 )
1055 {
1056 wxFAIL_MSG(wxT("pthread_attr_setschedparam(priority) failed"));
1057 }
1058 }
1059#endif // HAVE_THREAD_PRIORITY_FUNCTIONS
1060
1061#ifdef HAVE_PTHREAD_ATTR_SETSCOPE
1062 // this will make the threads created by this process really concurrent
1063 if ( pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) != 0 )
1064 {
1065 wxFAIL_MSG(wxT("pthread_attr_setscope(PTHREAD_SCOPE_SYSTEM) failed"));
1066 }
1067#endif // HAVE_PTHREAD_ATTR_SETSCOPE
1068
1069 // VZ: assume that this one is always available (it's rather fundamental),
1070 // if this function is ever missing we should try to use
1071 // pthread_detach() instead (after thread creation)
1072 if ( thread->IsDetached() )
1073 {
1074 if ( pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0 )
1075 {
1076 wxFAIL_MSG(wxT("pthread_attr_setdetachstate(DETACHED) failed"));
1077 }
1078
1079 // never try to join detached threads
1080 Detach();
1081 }
1082 //else: threads are created joinable by default, it's ok
1083
1084 // create the new OS thread object
1085 int rc = pthread_create
1086 (
1087 GetIdPtr(),
1088 &attr,
1089 wxPthreadStart,
1090 (void *)thread
1091 );
1092
1093 if ( pthread_attr_destroy(&attr) != 0 )
1094 {
1095 wxFAIL_MSG(wxT("pthread_attr_destroy() failed"));
1096 }
1097
1098 if ( rc != 0 )
1099 {
1100 SetState(STATE_EXITED);
1101
1102 return wxTHREAD_NO_RESOURCE;
1103 }
1104
2e57ca64 1105 m_created = true;
0dd300ca
VS
1106 return wxTHREAD_NO_ERROR;
1107}
1108
518b5d2f
VZ
1109wxThreadError wxThreadInternal::Run()
1110{
1111 wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
9fc3ad34 1112 wxT("thread may only be started once after Create()") );
518b5d2f 1113
9fc3ad34 1114 SetState(STATE_RUNNING);
518b5d2f 1115
9e84b847
VZ
1116 // wake up threads waiting for our start
1117 SignalRun();
1118
518b5d2f 1119 return wxTHREAD_NO_ERROR;
518b5d2f
VZ
1120}
1121
882eefb1 1122void wxThreadInternal::Wait()
518b5d2f 1123{
9a83f860 1124 wxCHECK_RET( !m_isDetached, wxT("can't wait for a detached thread") );
9e84b847 1125
518b5d2f
VZ
1126 // if the thread we're waiting for is waiting for the GUI mutex, we will
1127 // deadlock so make sure we release it temporarily
1128 if ( wxThread::IsMain() )
827833e2
SC
1129 {
1130#ifdef __WXOSX__
1131 // give the thread we're waiting for chance to do the GUI call
1132 // it might be in, we don't do this conditionally as the to be waited on
1133 // thread might have to acquire the mutex later but before terminating
1134 if ( wxGuiOwnedByMainThread() )
1135 wxMutexGuiLeave();
1136#else
518b5d2f 1137 wxMutexGuiLeave();
827833e2
SC
1138#endif
1139 }
518b5d2f 1140
547b93ab 1141 wxLogTrace(TRACE_THREADS,
9a83f860 1142 wxT("Starting to wait for thread %p to exit."),
ef4f69ec
VZ
1143 THR_ID(this));
1144
9e84b847
VZ
1145 // to avoid memory leaks we should call pthread_join(), but it must only be
1146 // done once so use a critical section to serialize the code below
9fc3ad34 1147 {
4c460b34
VZ
1148 wxCriticalSectionLocker lock(m_csJoinFlag);
1149
1150 if ( m_shouldBeJoined )
9fc3ad34 1151 {
4c460b34
VZ
1152 // FIXME shouldn't we set cancellation type to DISABLED here? If
1153 // we're cancelled inside pthread_join(), things will almost
1154 // certainly break - but if we disable the cancellation, we
1155 // might deadlock
2b5f62a0 1156 if ( pthread_join(GetId(), &m_exitcode) != 0 )
4c460b34 1157 {
9e84b847
VZ
1158 // this is a serious problem, so use wxLogError and not
1159 // wxLogDebug: it is possible to bring the system to its knees
1160 // by creating too many threads and not joining them quite
1161 // easily
76a6e803 1162 wxLogError(_("Failed to join a thread, potential memory leak detected - please restart the program"));
4c460b34 1163 }
9fc3ad34 1164
ad9835c9 1165 m_shouldBeJoined = false;
4c460b34 1166 }
9fc3ad34 1167 }
9111db68 1168
827833e2 1169#ifndef __WXOSX__
518b5d2f
VZ
1170 // reacquire GUI mutex
1171 if ( wxThread::IsMain() )
1172 wxMutexGuiEnter();
827833e2 1173#endif
518b5d2f
VZ
1174}
1175
518b5d2f
VZ
1176void wxThreadInternal::Pause()
1177{
882eefb1
VZ
1178 // the state is set from the thread which pauses us first, this function
1179 // is called later so the state should have been already set
518b5d2f 1180 wxCHECK_RET( m_state == STATE_PAUSED,
223d09f6 1181 wxT("thread must first be paused with wxThread::Pause().") );
518b5d2f 1182
ef4f69ec 1183 wxLogTrace(TRACE_THREADS,
9a83f860 1184 wxT("Thread %p goes to sleep."), THR_ID(this));
ef4f69ec 1185
be809868
VZ
1186 // wait until the semaphore is Post()ed from Resume()
1187 m_semSuspend.Wait();
518b5d2f
VZ
1188}
1189
1190void wxThreadInternal::Resume()
1191{
1192 wxCHECK_RET( m_state == STATE_PAUSED,
223d09f6 1193 wxT("can't resume thread which is not suspended.") );
518b5d2f 1194
4c460b34
VZ
1195 // the thread might be not actually paused yet - if there were no call to
1196 // TestDestroy() since the last call to Pause() for example
1197 if ( IsReallyPaused() )
1198 {
ef4f69ec 1199 wxLogTrace(TRACE_THREADS,
9a83f860 1200 wxT("Waking up thread %p"), THR_ID(this));
ef4f69ec 1201
4c460b34 1202 // wake up Pause()
be809868 1203 m_semSuspend.Post();
4c460b34
VZ
1204
1205 // reset the flag
ad9835c9 1206 SetReallyPaused(false);
4c460b34
VZ
1207 }
1208 else
1209 {
ef4f69ec 1210 wxLogTrace(TRACE_THREADS,
9a83f860 1211 wxT("Thread %p is not yet really paused"), THR_ID(this));
4c460b34 1212 }
518b5d2f
VZ
1213
1214 SetState(STATE_RUNNING);
1215}
1216
1217// -----------------------------------------------------------------------------
9fc3ad34 1218// wxThread static functions
518b5d2f
VZ
1219// -----------------------------------------------------------------------------
1220
1221wxThread *wxThread::This()
1222{
1223 return (wxThread *)pthread_getspecific(gs_keySelf);
1224}
1225
518b5d2f
VZ
1226void wxThread::Yield()
1227{
6f837e5c 1228#ifdef HAVE_SCHED_YIELD
518b5d2f 1229 sched_yield();
6f837e5c 1230#endif
518b5d2f
VZ
1231}
1232
ef8d96c2
VZ
1233int wxThread::GetCPUCount()
1234{
85bf679a
VZ
1235#if defined(_SC_NPROCESSORS_ONLN)
1236 // this works for Solaris and Linux 2.6
1237 int rc = sysconf(_SC_NPROCESSORS_ONLN);
1238 if ( rc != -1 )
1239 {
1240 return rc;
1241 }
1242#elif defined(__LINUX__) && wxUSE_FFILE
ef8d96c2
VZ
1243 // read from proc (can't use wxTextFile here because it's a special file:
1244 // it has 0 size but still can be read from)
1245 wxLogNull nolog;
1246
9a83f860 1247 wxFFile file(wxT("/proc/cpuinfo"));
ef8d96c2
VZ
1248 if ( file.IsOpened() )
1249 {
1250 // slurp the whole file
1251 wxString s;
1252 if ( file.ReadAll(&s) )
1253 {
9ec1ed2a 1254 // (ab)use Replace() to find the number of "processor: num" strings
9a83f860 1255 size_t count = s.Replace(wxT("processor\t:"), wxT(""));
ef8d96c2
VZ
1256 if ( count > 0 )
1257 {
1258 return count;
1259 }
1260
9a83f860 1261 wxLogDebug(wxT("failed to parse /proc/cpuinfo"));
ef8d96c2
VZ
1262 }
1263 else
1264 {
9a83f860 1265 wxLogDebug(wxT("failed to read /proc/cpuinfo"));
ef8d96c2
VZ
1266 }
1267 }
ef8d96c2
VZ
1268#endif // different ways to get number of CPUs
1269
1270 // unknown
1271 return -1;
1272}
1273
f9226383 1274wxThreadIdType wxThread::GetCurrentId()
1fcfb40d 1275{
f9226383 1276 return (wxThreadIdType)pthread_self();
1fcfb40d
RD
1277}
1278
ef4f69ec 1279
ef8d96c2
VZ
1280bool wxThread::SetConcurrency(size_t level)
1281{
32632baf
VZ
1282#ifdef HAVE_PTHREAD_SET_CONCURRENCY
1283 int rc = pthread_setconcurrency( level );
1284#elif defined(HAVE_THR_SETCONCURRENCY)
ef8d96c2 1285 int rc = thr_setconcurrency(level);
32632baf
VZ
1286#else // !HAVE_THR_SETCONCURRENCY
1287 // ok only for the default value
1288 int rc = level == 0 ? 0 : -1;
1289#endif // HAVE_THR_SETCONCURRENCY/!HAVE_THR_SETCONCURRENCY
1290
ef8d96c2
VZ
1291 if ( rc != 0 )
1292 {
32632baf
VZ
1293 wxLogSysError(rc, _("Failed to set thread concurrency level to %lu"),
1294 static_cast<unsigned long>(level));
1295 return false;
ef8d96c2
VZ
1296 }
1297
32632baf 1298 return true;
ef8d96c2
VZ
1299}
1300
518b5d2f
VZ
1301// -----------------------------------------------------------------------------
1302// creating thread
1303// -----------------------------------------------------------------------------
1304
acb8423c 1305wxThread::wxThread(wxThreadKind kind)
518b5d2f
VZ
1306{
1307 // add this thread to the global list of all threads
25b34b26
VZ
1308 {
1309 wxMutexLocker lock(*gs_mutexAllThreads);
1310
1311 gs_allThreads.Add(this);
1312 }
518b5d2f 1313
9fc3ad34 1314 m_internal = new wxThreadInternal();
acb8423c
VZ
1315
1316 m_isDetached = kind == wxTHREAD_DETACHED;
518b5d2f
VZ
1317}
1318
0dd300ca 1319wxThreadError wxThread::Create(unsigned int stackSize)
518b5d2f 1320{
5063450e
VS
1321 wxCriticalSectionLocker lock(m_critsect);
1322
0dd300ca 1323 return m_internal->Create(this, stackSize);
518b5d2f
VZ
1324}
1325
1326wxThreadError wxThread::Run()
1327{
9fc3ad34
VZ
1328 wxCriticalSectionLocker lock(m_critsect);
1329
2e57ca64
VS
1330 // Create the thread if it wasn't created yet with an explicit
1331 // Create() call:
1332 if ( !m_internal->WasCreated() )
1333 {
1334 wxThreadError rv = m_internal->Create(this, 0);
1335 if ( rv != wxTHREAD_NO_ERROR )
1336 return rv;
1337 }
bbfa0322 1338
9fc3ad34 1339 return m_internal->Run();
518b5d2f
VZ
1340}
1341
1342// -----------------------------------------------------------------------------
1343// misc accessors
1344// -----------------------------------------------------------------------------
1345
1346void wxThread::SetPriority(unsigned int prio)
1347{
90e95e61 1348 wxCHECK_RET( wxPRIORITY_MIN <= prio && prio <= wxPRIORITY_MAX,
223d09f6 1349 wxT("invalid thread priority") );
518b5d2f
VZ
1350
1351 wxCriticalSectionLocker lock(m_critsect);
1352
9fc3ad34 1353 switch ( m_internal->GetState() )
518b5d2f
VZ
1354 {
1355 case STATE_NEW:
1356 // thread not yet started, priority will be set when it is
9fc3ad34 1357 m_internal->SetPriority(prio);
518b5d2f
VZ
1358 break;
1359
1360 case STATE_RUNNING:
1361 case STATE_PAUSED:
34f8c26e 1362#ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
7bfe6a32 1363#if defined(__LINUX__)
17a1ebd1
VZ
1364 // On Linux, pthread_setschedparam with SCHED_OTHER does not allow
1365 // a priority other than 0. Instead, we use the BSD setpriority
1366 // which alllows us to set a 'nice' value between 20 to -20. Only
1367 // super user can set a value less than zero (more negative yields
1368 // higher priority). setpriority set the static priority of a
1369 // process, but this is OK since Linux is configured as a thread
1370 // per process.
1371 //
1372 // FIXME this is not true for 2.6!!
7bfe6a32 1373
90e95e61 1374 // map wx priorites 0..100 to Unix priorities 20..-20
a07bf2d0 1375 if ( setpriority(PRIO_PROCESS, 0, -(2*(int)prio)/5 + 20) == -1 )
17a1ebd1
VZ
1376 {
1377 wxLogError(_("Failed to set thread priority %d."), prio);
7bfe6a32
JS
1378 }
1379#else // __LINUX__
518b5d2f
VZ
1380 {
1381 struct sched_param sparam;
1382 sparam.sched_priority = prio;
1383
9fc3ad34 1384 if ( pthread_setschedparam(m_internal->GetId(),
518b5d2f
VZ
1385 SCHED_OTHER, &sparam) != 0 )
1386 {
1387 wxLogError(_("Failed to set thread priority %d."), prio);
1388 }
1389 }
7bfe6a32 1390#endif // __LINUX__
34f8c26e 1391#endif // HAVE_THREAD_PRIORITY_FUNCTIONS
518b5d2f
VZ
1392 break;
1393
1394 case STATE_EXITED:
1395 default:
223d09f6 1396 wxFAIL_MSG(wxT("impossible to set thread priority in this state"));
518b5d2f
VZ
1397 }
1398}
1399
1400unsigned int wxThread::GetPriority() const
1401{
1402 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
1403
9fc3ad34 1404 return m_internal->GetPriority();
518b5d2f
VZ
1405}
1406
547b93ab 1407wxThreadIdType wxThread::GetId() const
13d068d9 1408{
df744f4d 1409 return (wxThreadIdType) m_internal->GetId();
518b5d2f
VZ
1410}
1411
1412// -----------------------------------------------------------------------------
1413// pause/resume
1414// -----------------------------------------------------------------------------
1415
1416wxThreadError wxThread::Pause()
1417{
4c460b34 1418 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
9a83f860 1419 wxT("a thread can't pause itself") );
4c460b34 1420
518b5d2f
VZ
1421 wxCriticalSectionLocker lock(m_critsect);
1422
9fc3ad34 1423 if ( m_internal->GetState() != STATE_RUNNING )
518b5d2f 1424 {
223d09f6 1425 wxLogDebug(wxT("Can't pause thread which is not running."));
518b5d2f
VZ
1426
1427 return wxTHREAD_NOT_RUNNING;
1428 }
1429
9fc3ad34
VZ
1430 // just set a flag, the thread will be really paused only during the next
1431 // call to TestDestroy()
1432 m_internal->SetState(STATE_PAUSED);
518b5d2f
VZ
1433
1434 return wxTHREAD_NO_ERROR;
1435}
1436
1437wxThreadError wxThread::Resume()
1438{
4c460b34 1439 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
9a83f860 1440 wxT("a thread can't resume itself") );
518b5d2f 1441
4c460b34 1442 wxCriticalSectionLocker lock(m_critsect);
518b5d2f 1443
4c460b34 1444 wxThreadState state = m_internal->GetState();
9fc3ad34
VZ
1445
1446 switch ( state )
518b5d2f 1447 {
9fc3ad34 1448 case STATE_PAUSED:
9a83f860 1449 wxLogTrace(TRACE_THREADS, wxT("Thread %p suspended, resuming."),
35e9c131 1450 THR_ID(this));
9fc3ad34
VZ
1451
1452 m_internal->Resume();
1453
1454 return wxTHREAD_NO_ERROR;
1455
1456 case STATE_EXITED:
9a83f860 1457 wxLogTrace(TRACE_THREADS, wxT("Thread %p exited, won't resume."),
35e9c131 1458 THR_ID(this));
9fc3ad34 1459 return wxTHREAD_NO_ERROR;
518b5d2f 1460
9fc3ad34 1461 default:
9a83f860 1462 wxLogDebug(wxT("Attempt to resume a thread which is not paused."));
9fc3ad34
VZ
1463
1464 return wxTHREAD_MISC_ERROR;
518b5d2f
VZ
1465 }
1466}
1467
1468// -----------------------------------------------------------------------------
1469// exiting thread
1470// -----------------------------------------------------------------------------
1471
b95a7c31 1472wxThread::ExitCode wxThread::Wait(wxThreadWait WXUNUSED(waitMode))
b568d04f 1473{
9fc3ad34 1474 wxCHECK_MSG( This() != this, (ExitCode)-1,
9a83f860 1475 wxT("a thread can't wait for itself") );
9fc3ad34
VZ
1476
1477 wxCHECK_MSG( !m_isDetached, (ExitCode)-1,
9a83f860 1478 wxT("can't wait for detached thread") );
9fc3ad34
VZ
1479
1480 m_internal->Wait();
b568d04f 1481
9fc3ad34 1482 return m_internal->GetExitCode();
b568d04f
VZ
1483}
1484
b95a7c31 1485wxThreadError wxThread::Delete(ExitCode *rc, wxThreadWait WXUNUSED(waitMode))
518b5d2f 1486{
4c460b34 1487 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
9a83f860 1488 wxT("a thread can't delete itself") );
4c460b34 1489
9e84b847
VZ
1490 bool isDetached = m_isDetached;
1491
518b5d2f 1492 m_critsect.Enter();
9fc3ad34 1493 wxThreadState state = m_internal->GetState();
518b5d2f 1494
882eefb1 1495 // ask the thread to stop
9fc3ad34
VZ
1496 m_internal->SetCancelFlag();
1497
9111db68
GL
1498 m_critsect.Leave();
1499
df191bfe
VZ
1500 OnDelete();
1501
518b5d2f
VZ
1502 switch ( state )
1503 {
1504 case STATE_NEW:
4c460b34 1505 // we need to wake up the thread so that PthreadStart() will
9e84b847
VZ
1506 // terminate - right now it's blocking on run semaphore in
1507 // PthreadStart()
4c460b34
VZ
1508 m_internal->SignalRun();
1509
1510 // fall through
1511
518b5d2f
VZ
1512 case STATE_EXITED:
1513 // nothing to do
1514 break;
1515
1516 case STATE_PAUSED:
9e84b847 1517 // resume the thread first
9fc3ad34 1518 m_internal->Resume();
518b5d2f
VZ
1519
1520 // fall through
1521
1522 default:
9e84b847 1523 if ( !isDetached )
9fc3ad34 1524 {
9e84b847
VZ
1525 // wait until the thread stops
1526 m_internal->Wait();
9fc3ad34 1527
9e84b847
VZ
1528 if ( rc )
1529 {
1530 // return the exit code of the thread
1531 *rc = m_internal->GetExitCode();
1532 }
9fc3ad34 1533 }
9e84b847 1534 //else: can't wait for detached threads
518b5d2f 1535 }
ce00f59b 1536
363daf0b
FM
1537 if (state == STATE_NEW)
1538 return wxTHREAD_MISC_ERROR;
ce00f59b 1539 // for coherency with the MSW implementation, signal the user that
363daf0b 1540 // Delete() was called on a thread which didn't start to run yet.
518b5d2f 1541
acb8423c 1542 return wxTHREAD_NO_ERROR;
518b5d2f
VZ
1543}
1544
1545wxThreadError wxThread::Kill()
1546{
9fc3ad34 1547 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
9a83f860 1548 wxT("a thread can't kill itself") );
9fc3ad34 1549
df191bfe
VZ
1550 OnKill();
1551
9fc3ad34 1552 switch ( m_internal->GetState() )
518b5d2f
VZ
1553 {
1554 case STATE_NEW:
1555 case STATE_EXITED:
1556 return wxTHREAD_NOT_RUNNING;
1557
9fc3ad34
VZ
1558 case STATE_PAUSED:
1559 // resume the thread first
1560 Resume();
1561
1562 // fall through
1563
518b5d2f 1564 default:
9fc3ad34
VZ
1565#ifdef HAVE_PTHREAD_CANCEL
1566 if ( pthread_cancel(m_internal->GetId()) != 0 )
741d91c5 1567#endif // HAVE_PTHREAD_CANCEL
518b5d2f
VZ
1568 {
1569 wxLogError(_("Failed to terminate a thread."));
1570
1571 return wxTHREAD_MISC_ERROR;
1572 }
9fc3ad34 1573
741d91c5 1574#ifdef HAVE_PTHREAD_CANCEL
9fc3ad34
VZ
1575 if ( m_isDetached )
1576 {
1577 // if we use cleanup function, this will be done from
90350682 1578 // wxPthreadCleanup()
816a7358 1579#ifndef wxHAVE_PTHREAD_CLEANUP
9fc3ad34
VZ
1580 ScheduleThreadForDeletion();
1581
b18cfdd9
VZ
1582 // don't call OnExit() here, it can only be called in the
1583 // threads context and we're in the context of another thread
9fc3ad34
VZ
1584
1585 DeleteThread(this);
816a7358 1586#endif // wxHAVE_PTHREAD_CLEANUP
9fc3ad34
VZ
1587 }
1588 else
1589 {
1590 m_internal->SetExitCode(EXITCODE_CANCELLED);
1591 }
518b5d2f
VZ
1592
1593 return wxTHREAD_NO_ERROR;
741d91c5 1594#endif // HAVE_PTHREAD_CANCEL
518b5d2f
VZ
1595 }
1596}
1597
b568d04f 1598void wxThread::Exit(ExitCode status)
518b5d2f 1599{
4c460b34 1600 wxASSERT_MSG( This() == this,
9a83f860 1601 wxT("wxThread::Exit() can only be called in the context of the same thread") );
4c460b34 1602
9e84b847
VZ
1603 if ( m_isDetached )
1604 {
1605 // from the moment we call OnExit(), the main program may terminate at
1606 // any moment, so mark this thread as being already in process of being
1607 // deleted or wxThreadModule::OnExit() will try to delete it again
1608 ScheduleThreadForDeletion();
1609 }
9fc3ad34
VZ
1610
1611 // don't enter m_critsect before calling OnExit() because the user code
1612 // might deadlock if, for example, it signals a condition in OnExit() (a
1613 // common case) while the main thread calls any of functions entering
1614 // m_critsect on us (almost all of them do)
79b7b95a
VS
1615 wxTRY
1616 {
1617 OnExit();
1618 }
1619 wxCATCH_ALL( wxTheApp->OnUnhandledException(); )
518b5d2f 1620
9fc3ad34
VZ
1621 // delete C++ thread object if this is a detached thread - user is
1622 // responsible for doing this for joinable ones
1623 if ( m_isDetached )
1624 {
1625 // FIXME I'm feeling bad about it - what if another thread function is
1626 // called (in another thread context) now? It will try to access
1627 // half destroyed object which will probably result in something
1628 // very bad - but we can't protect this by a crit section unless
1629 // we make it a global object, but this would mean that we can
1630 // only call one thread function at a time :-(
1631 DeleteThread(this);
b4866582 1632 pthread_setspecific(gs_keySelf, 0);
9fc3ad34 1633 }
343b1669
RR
1634 else
1635 {
1636 m_critsect.Enter();
1637 m_internal->SetState(STATE_EXITED);
1638 m_critsect.Leave();
1639 }
9fc3ad34
VZ
1640
1641 // terminate the thread (pthread_exit() never returns)
518b5d2f 1642 pthread_exit(status);
9fc3ad34 1643
9a83f860 1644 wxFAIL_MSG(wxT("pthread_exit() failed"));
518b5d2f
VZ
1645}
1646
1647// also test whether we were paused
1648bool wxThread::TestDestroy()
1649{
4c460b34 1650 wxASSERT_MSG( This() == this,
9a83f860 1651 wxT("wxThread::TestDestroy() can only be called in the context of the same thread") );
4c460b34 1652
9fc3ad34 1653 m_critsect.Enter();
518b5d2f 1654
9fc3ad34 1655 if ( m_internal->GetState() == STATE_PAUSED )
518b5d2f 1656 {
ad9835c9 1657 m_internal->SetReallyPaused(true);
4c460b34 1658
9fc3ad34
VZ
1659 // leave the crit section or the other threads will stop too if they
1660 // try to call any of (seemingly harmless) IsXXX() functions while we
1661 // sleep
518b5d2f
VZ
1662 m_critsect.Leave();
1663
9fc3ad34
VZ
1664 m_internal->Pause();
1665 }
1666 else
1667 {
1668 // thread wasn't requested to pause, nothing to do
1669 m_critsect.Leave();
518b5d2f
VZ
1670 }
1671
9fc3ad34 1672 return m_internal->WasCancelled();
518b5d2f
VZ
1673}
1674
1675wxThread::~wxThread()
1676{
062c4861 1677 m_critsect.Enter();
9fc3ad34
VZ
1678
1679 // check that the thread either exited or couldn't be created
1680 if ( m_internal->GetState() != STATE_EXITED &&
1681 m_internal->GetState() != STATE_NEW )
bbfa0322 1682 {
35e9c131
VS
1683 wxLogDebug(wxT("The thread %p is being destroyed although it is still running! The application may crash."),
1684 THR_ID(this));
bbfa0322 1685 }
062c4861
GL
1686
1687 m_critsect.Leave();
1688
9fc3ad34 1689 delete m_internal;
bbfa0322 1690
518b5d2f 1691 // remove this thread from the global array
25b34b26
VZ
1692 {
1693 wxMutexLocker lock(*gs_mutexAllThreads);
1694
1695 gs_allThreads.Remove(this);
1696 }
518b5d2f
VZ
1697}
1698
1699// -----------------------------------------------------------------------------
1700// state tests
1701// -----------------------------------------------------------------------------
1702
1703bool wxThread::IsRunning() const
1704{
1705 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
1706
9fc3ad34 1707 return m_internal->GetState() == STATE_RUNNING;
518b5d2f
VZ
1708}
1709
1710bool wxThread::IsAlive() const
1711{
1712 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
1713
9fc3ad34 1714 switch ( m_internal->GetState() )
518b5d2f
VZ
1715 {
1716 case STATE_RUNNING:
1717 case STATE_PAUSED:
ad9835c9 1718 return true;
518b5d2f
VZ
1719
1720 default:
ad9835c9 1721 return false;
518b5d2f
VZ
1722 }
1723}
1724
a737331d
GL
1725bool wxThread::IsPaused() const
1726{
1727 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
1728
9fc3ad34 1729 return (m_internal->GetState() == STATE_PAUSED);
a737331d
GL
1730}
1731
518b5d2f
VZ
1732//--------------------------------------------------------------------
1733// wxThreadModule
1734//--------------------------------------------------------------------
1735
a94c4b85
SC
1736#ifdef __WXOSX__
1737void wxOSXThreadModuleOnInit();
1738void wxOSXThreadModuleOnExit();
1739#endif
1740
518b5d2f
VZ
1741class wxThreadModule : public wxModule
1742{
1743public:
1744 virtual bool OnInit();
1745 virtual void OnExit();
1746
1747private:
1748 DECLARE_DYNAMIC_CLASS(wxThreadModule)
1749};
1750
1751IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
1752
1753bool wxThreadModule::OnInit()
1754{
58230fb1
VZ
1755 int rc = pthread_key_create(&gs_keySelf, NULL /* dtor function */);
1756 if ( rc != 0 )
518b5d2f 1757 {
76a6e803 1758 wxLogSysError(rc, _("Thread module initialization failed: failed to create thread key"));
518b5d2f 1759
ad9835c9 1760 return false;
518b5d2f
VZ
1761 }
1762
f9226383 1763 wxThread::ms_idMainThread = wxThread::GetCurrentId();
19da4326 1764
25b34b26
VZ
1765 gs_mutexAllThreads = new wxMutex();
1766
a94c4b85
SC
1767#ifdef __WXOSX__
1768 wxOSXThreadModuleOnInit();
1769#else
9fc3ad34 1770 gs_mutexGui = new wxMutex();
518b5d2f 1771 gs_mutexGui->Lock();
a94c4b85 1772#endif
518b5d2f 1773
be809868 1774 gs_mutexDeleteThread = new wxMutex();
25b34b26 1775 gs_condAllDeleted = new wxCondition(*gs_mutexDeleteThread);
88e243b2 1776
ad9835c9 1777 return true;
518b5d2f
VZ
1778}
1779
1780void wxThreadModule::OnExit()
1781{
223d09f6 1782 wxASSERT_MSG( wxThread::IsMain(), wxT("only main thread can be here") );
518b5d2f 1783
9fc3ad34
VZ
1784 // are there any threads left which are being deleted right now?
1785 size_t nThreadsBeingDeleted;
be809868 1786
9fc3ad34 1787 {
be809868 1788 wxMutexLocker lock( *gs_mutexDeleteThread );
9fc3ad34 1789 nThreadsBeingDeleted = gs_nThreadsBeingDeleted;
9fc3ad34 1790
be809868 1791 if ( nThreadsBeingDeleted > 0 )
9e84b847 1792 {
2b5f62a0 1793 wxLogTrace(TRACE_THREADS,
9a83f860 1794 wxT("Waiting for %lu threads to disappear"),
2b5f62a0 1795 (unsigned long)nThreadsBeingDeleted);
9fc3ad34 1796
be809868
VZ
1797 // have to wait until all of them disappear
1798 gs_condAllDeleted->Wait();
1799 }
9fc3ad34
VZ
1800 }
1801
25b34b26
VZ
1802 size_t count;
1803
4c460b34 1804 {
25b34b26
VZ
1805 wxMutexLocker lock(*gs_mutexAllThreads);
1806
1807 // terminate any threads left
1808 count = gs_allThreads.GetCount();
1809 if ( count != 0u )
1810 {
1811 wxLogDebug(wxT("%lu threads were not terminated by the application."),
1812 (unsigned long)count);
1813 }
1814 } // unlock mutex before deleting the threads as they lock it in their dtor
518b5d2f
VZ
1815
1816 for ( size_t n = 0u; n < count; n++ )
1817 {
bbfa0322
VZ
1818 // Delete calls the destructor which removes the current entry. We
1819 // should only delete the first one each time.
0ac77ef5 1820 gs_allThreads[0]->Delete();
518b5d2f
VZ
1821 }
1822
25b34b26
VZ
1823 delete gs_mutexAllThreads;
1824
a94c4b85
SC
1825#ifdef __WXOSX__
1826 wxOSXThreadModuleOnExit();
1827#else
518b5d2f
VZ
1828 // destroy GUI mutex
1829 gs_mutexGui->Unlock();
518b5d2f 1830 delete gs_mutexGui;
a94c4b85 1831#endif
518b5d2f
VZ
1832
1833 // and free TLD slot
1834 (void)pthread_key_delete(gs_keySelf);
be809868
VZ
1835
1836 delete gs_condAllDeleted;
1837 delete gs_mutexDeleteThread;
518b5d2f
VZ
1838}
1839
1840// ----------------------------------------------------------------------------
1841// global functions
1842// ----------------------------------------------------------------------------
1843
9fc3ad34
VZ
1844static void ScheduleThreadForDeletion()
1845{
be809868 1846 wxMutexLocker lock( *gs_mutexDeleteThread );
9fc3ad34
VZ
1847
1848 gs_nThreadsBeingDeleted++;
1849
9a83f860 1850 wxLogTrace(TRACE_THREADS, wxT("%lu thread%s waiting to be deleted"),
2b5f62a0 1851 (unsigned long)gs_nThreadsBeingDeleted,
9a83f860 1852 gs_nThreadsBeingDeleted == 1 ? wxT("") : wxT("s"));
9fc3ad34
VZ
1853}
1854
1855static void DeleteThread(wxThread *This)
1856{
35e9c131 1857 wxLogTrace(TRACE_THREADS, wxT("Thread %p auto deletes."), THR_ID(This));
9fc3ad34 1858
be809868 1859 delete This;
9fc3ad34 1860
2450225e
VZ
1861 // only lock gs_mutexDeleteThread after deleting the thread to avoid
1862 // calling out into user code with it locked as this may result in
1863 // deadlocks if the thread dtor deletes another thread (see #11501)
1864 wxMutexLocker locker( *gs_mutexDeleteThread );
1865
be809868 1866 wxCHECK_RET( gs_nThreadsBeingDeleted > 0,
9a83f860 1867 wxT("no threads scheduled for deletion, yet we delete one?") );
9fc3ad34 1868
9a83f860 1869 wxLogTrace(TRACE_THREADS, wxT("%lu threads remain scheduled for deletion."),
2b5f62a0 1870 (unsigned long)gs_nThreadsBeingDeleted - 1);
4c460b34 1871
9fc3ad34
VZ
1872 if ( !--gs_nThreadsBeingDeleted )
1873 {
1874 // no more threads left, signal it
1875 gs_condAllDeleted->Signal();
9fc3ad34
VZ
1876 }
1877}
1878
da0ee16e 1879#ifndef __DARWIN__
a94c4b85 1880
d254213e 1881void wxMutexGuiEnterImpl()
518b5d2f 1882{
9fc3ad34 1883 gs_mutexGui->Lock();
518b5d2f
VZ
1884}
1885
d254213e 1886void wxMutexGuiLeaveImpl()
518b5d2f 1887{
9fc3ad34 1888 gs_mutexGui->Unlock();
518b5d2f 1889}
80cb83be 1890
a94c4b85
SC
1891#endif
1892
9e84b847
VZ
1893// ----------------------------------------------------------------------------
1894// include common implementation code
1895// ----------------------------------------------------------------------------
1896
1897#include "wx/thrimpl.cpp"
1898
1899#endif // wxUSE_THREADS