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