]> git.saurik.com Git - wxWidgets.git/blame - src/unix/threadpsx.cpp
copy wxImage options when copying the images (replaces patch 780705)
[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
1186 return wxTHREAD_NO_ERROR;
1187}
1188
1189wxThreadError wxThread::Run()
1190{
9fc3ad34
VZ
1191 wxCriticalSectionLocker lock(m_critsect);
1192
1193 wxCHECK_MSG( m_internal->GetId(), wxTHREAD_MISC_ERROR,
223d09f6 1194 wxT("must call wxThread::Create() first") );
bbfa0322 1195
9fc3ad34 1196 return m_internal->Run();
518b5d2f
VZ
1197}
1198
1199// -----------------------------------------------------------------------------
1200// misc accessors
1201// -----------------------------------------------------------------------------
1202
1203void wxThread::SetPriority(unsigned int prio)
1204{
34f8c26e
VZ
1205 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY <= (int)prio) &&
1206 ((int)prio <= (int)WXTHREAD_MAX_PRIORITY),
223d09f6 1207 wxT("invalid thread priority") );
518b5d2f
VZ
1208
1209 wxCriticalSectionLocker lock(m_critsect);
1210
9fc3ad34 1211 switch ( m_internal->GetState() )
518b5d2f
VZ
1212 {
1213 case STATE_NEW:
1214 // thread not yet started, priority will be set when it is
9fc3ad34 1215 m_internal->SetPriority(prio);
518b5d2f
VZ
1216 break;
1217
1218 case STATE_RUNNING:
1219 case STATE_PAUSED:
34f8c26e 1220#ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
7bfe6a32
JS
1221#if defined(__LINUX__)
1222// On Linux, pthread_setschedparam with SCHED_OTHER does not allow
1223// a priority other than 0. Instead, we use the BSD setpriority
1224// which alllows us to set a 'nice' value between 20 to -20. Only
1225// super user can set a value less than zero (more negative yields
1226// higher priority). setpriority set the static priority of a process,
1227// but this is OK since Linux is configured as a thread per process.
1228 {
1229 float fPrio;
1230 float pSpan;
1231 int iPrio;
1232
1233 // Map Wx priorites (WXTHREAD_MIN_PRIORITY -
1234 // WXTHREAD_MAX_PRIORITY) into BSD priorities (20 - -20).
1235 // Do calculation of values instead of hard coding them
1236 // to make maintenance easier.
1237
1238 pSpan = ((float)(WXTHREAD_MAX_PRIORITY - WXTHREAD_MIN_PRIORITY)) / 2.0;
1239
1240 // prio starts as ................... // value => (0) >= p <= (n)
1241
1242 fPrio = ((float)prio) - pSpan; // value => (-n) >= p <= (+n)
1243
1244 fPrio = 0.0 - fPrio; // value => (+n) <= p >= (-n)
1245
1246 fPrio = fPrio * (20. / pSpan) + .5; // value => (20) <= p >= (-20)
1247
1248 iPrio = (int)fPrio;
1249
1250 // Clamp prio from 20 - -20;
1251 iPrio = (iPrio > 20) ? 20 : iPrio;
1252 iPrio = (iPrio < -20) ? -20 : iPrio;
1253
1254 if (setpriority(PRIO_PROCESS, 0, iPrio) == -1)
1255 {
1256 wxLogError(_("Failed to set thread priority %d."), prio);
1257 }
1258 }
1259#else // __LINUX__
518b5d2f
VZ
1260 {
1261 struct sched_param sparam;
1262 sparam.sched_priority = prio;
1263
9fc3ad34 1264 if ( pthread_setschedparam(m_internal->GetId(),
518b5d2f
VZ
1265 SCHED_OTHER, &sparam) != 0 )
1266 {
1267 wxLogError(_("Failed to set thread priority %d."), prio);
1268 }
1269 }
7bfe6a32 1270#endif // __LINUX__
34f8c26e 1271#endif // HAVE_THREAD_PRIORITY_FUNCTIONS
518b5d2f
VZ
1272 break;
1273
1274 case STATE_EXITED:
1275 default:
223d09f6 1276 wxFAIL_MSG(wxT("impossible to set thread priority in this state"));
518b5d2f
VZ
1277 }
1278}
1279
1280unsigned int wxThread::GetPriority() const
1281{
1282 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
1283
9fc3ad34 1284 return m_internal->GetPriority();
518b5d2f
VZ
1285}
1286
547b93ab 1287wxThreadIdType wxThread::GetId() const
13d068d9 1288{
df744f4d 1289 return (wxThreadIdType) m_internal->GetId();
518b5d2f
VZ
1290}
1291
1292// -----------------------------------------------------------------------------
1293// pause/resume
1294// -----------------------------------------------------------------------------
1295
1296wxThreadError wxThread::Pause()
1297{
4c460b34
VZ
1298 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1299 _T("a thread can't pause itself") );
1300
518b5d2f
VZ
1301 wxCriticalSectionLocker lock(m_critsect);
1302
9fc3ad34 1303 if ( m_internal->GetState() != STATE_RUNNING )
518b5d2f 1304 {
223d09f6 1305 wxLogDebug(wxT("Can't pause thread which is not running."));
518b5d2f
VZ
1306
1307 return wxTHREAD_NOT_RUNNING;
1308 }
1309
9fc3ad34
VZ
1310 // just set a flag, the thread will be really paused only during the next
1311 // call to TestDestroy()
1312 m_internal->SetState(STATE_PAUSED);
518b5d2f
VZ
1313
1314 return wxTHREAD_NO_ERROR;
1315}
1316
1317wxThreadError wxThread::Resume()
1318{
4c460b34
VZ
1319 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1320 _T("a thread can't resume itself") );
518b5d2f 1321
4c460b34 1322 wxCriticalSectionLocker lock(m_critsect);
518b5d2f 1323
4c460b34 1324 wxThreadState state = m_internal->GetState();
9fc3ad34
VZ
1325
1326 switch ( state )
518b5d2f 1327 {
9fc3ad34 1328 case STATE_PAUSED:
4c460b34 1329 wxLogTrace(TRACE_THREADS, _T("Thread %ld suspended, resuming."),
9fc3ad34
VZ
1330 GetId());
1331
1332 m_internal->Resume();
1333
1334 return wxTHREAD_NO_ERROR;
1335
1336 case STATE_EXITED:
1337 wxLogTrace(TRACE_THREADS, _T("Thread %ld exited, won't resume."),
1338 GetId());
1339 return wxTHREAD_NO_ERROR;
518b5d2f 1340
9fc3ad34
VZ
1341 default:
1342 wxLogDebug(_T("Attempt to resume a thread which is not paused."));
1343
1344 return wxTHREAD_MISC_ERROR;
518b5d2f
VZ
1345 }
1346}
1347
1348// -----------------------------------------------------------------------------
1349// exiting thread
1350// -----------------------------------------------------------------------------
1351
9fc3ad34 1352wxThread::ExitCode wxThread::Wait()
b568d04f 1353{
9fc3ad34
VZ
1354 wxCHECK_MSG( This() != this, (ExitCode)-1,
1355 _T("a thread can't wait for itself") );
1356
1357 wxCHECK_MSG( !m_isDetached, (ExitCode)-1,
1358 _T("can't wait for detached thread") );
1359
1360 m_internal->Wait();
b568d04f 1361
9fc3ad34 1362 return m_internal->GetExitCode();
b568d04f
VZ
1363}
1364
1365wxThreadError wxThread::Delete(ExitCode *rc)
518b5d2f 1366{
4c460b34
VZ
1367 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1368 _T("a thread can't delete itself") );
1369
9e84b847
VZ
1370 bool isDetached = m_isDetached;
1371
518b5d2f 1372 m_critsect.Enter();
9fc3ad34 1373 wxThreadState state = m_internal->GetState();
518b5d2f 1374
882eefb1 1375 // ask the thread to stop
9fc3ad34
VZ
1376 m_internal->SetCancelFlag();
1377
9111db68
GL
1378 m_critsect.Leave();
1379
518b5d2f
VZ
1380 switch ( state )
1381 {
1382 case STATE_NEW:
4c460b34 1383 // we need to wake up the thread so that PthreadStart() will
9e84b847
VZ
1384 // terminate - right now it's blocking on run semaphore in
1385 // PthreadStart()
4c460b34
VZ
1386 m_internal->SignalRun();
1387
1388 // fall through
1389
518b5d2f
VZ
1390 case STATE_EXITED:
1391 // nothing to do
1392 break;
1393
1394 case STATE_PAUSED:
9e84b847 1395 // resume the thread first
9fc3ad34 1396 m_internal->Resume();
518b5d2f
VZ
1397
1398 // fall through
1399
1400 default:
9e84b847 1401 if ( !isDetached )
9fc3ad34 1402 {
9e84b847
VZ
1403 // wait until the thread stops
1404 m_internal->Wait();
9fc3ad34 1405
9e84b847
VZ
1406 if ( rc )
1407 {
1408 // return the exit code of the thread
1409 *rc = m_internal->GetExitCode();
1410 }
9fc3ad34 1411 }
9e84b847 1412 //else: can't wait for detached threads
518b5d2f
VZ
1413 }
1414
acb8423c 1415 return wxTHREAD_NO_ERROR;
518b5d2f
VZ
1416}
1417
1418wxThreadError wxThread::Kill()
1419{
9fc3ad34
VZ
1420 wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
1421 _T("a thread can't kill itself") );
1422
1423 switch ( m_internal->GetState() )
518b5d2f
VZ
1424 {
1425 case STATE_NEW:
1426 case STATE_EXITED:
1427 return wxTHREAD_NOT_RUNNING;
1428
9fc3ad34
VZ
1429 case STATE_PAUSED:
1430 // resume the thread first
1431 Resume();
1432
1433 // fall through
1434
518b5d2f 1435 default:
9fc3ad34
VZ
1436#ifdef HAVE_PTHREAD_CANCEL
1437 if ( pthread_cancel(m_internal->GetId()) != 0 )
34f8c26e 1438#endif
518b5d2f
VZ
1439 {
1440 wxLogError(_("Failed to terminate a thread."));
1441
1442 return wxTHREAD_MISC_ERROR;
1443 }
9fc3ad34
VZ
1444
1445 if ( m_isDetached )
1446 {
1447 // if we use cleanup function, this will be done from
90350682 1448 // wxPthreadCleanup()
9fc3ad34
VZ
1449#if !HAVE_THREAD_CLEANUP_FUNCTIONS
1450 ScheduleThreadForDeletion();
1451
b18cfdd9
VZ
1452 // don't call OnExit() here, it can only be called in the
1453 // threads context and we're in the context of another thread
9fc3ad34
VZ
1454
1455 DeleteThread(this);
1456#endif // HAVE_THREAD_CLEANUP_FUNCTIONS
1457 }
1458 else
1459 {
1460 m_internal->SetExitCode(EXITCODE_CANCELLED);
1461 }
518b5d2f
VZ
1462
1463 return wxTHREAD_NO_ERROR;
1464 }
1465}
1466
b568d04f 1467void wxThread::Exit(ExitCode status)
518b5d2f 1468{
4c460b34
VZ
1469 wxASSERT_MSG( This() == this,
1470 _T("wxThread::Exit() can only be called in the "
1471 "context of the same thread") );
1472
9e84b847
VZ
1473 if ( m_isDetached )
1474 {
1475 // from the moment we call OnExit(), the main program may terminate at
1476 // any moment, so mark this thread as being already in process of being
1477 // deleted or wxThreadModule::OnExit() will try to delete it again
1478 ScheduleThreadForDeletion();
1479 }
9fc3ad34
VZ
1480
1481 // don't enter m_critsect before calling OnExit() because the user code
1482 // might deadlock if, for example, it signals a condition in OnExit() (a
1483 // common case) while the main thread calls any of functions entering
1484 // m_critsect on us (almost all of them do)
518b5d2f
VZ
1485 OnExit();
1486
9fc3ad34
VZ
1487 // delete C++ thread object if this is a detached thread - user is
1488 // responsible for doing this for joinable ones
1489 if ( m_isDetached )
1490 {
1491 // FIXME I'm feeling bad about it - what if another thread function is
1492 // called (in another thread context) now? It will try to access
1493 // half destroyed object which will probably result in something
1494 // very bad - but we can't protect this by a crit section unless
1495 // we make it a global object, but this would mean that we can
1496 // only call one thread function at a time :-(
1497 DeleteThread(this);
1498 }
1499
1500 // terminate the thread (pthread_exit() never returns)
518b5d2f 1501 pthread_exit(status);
9fc3ad34
VZ
1502
1503 wxFAIL_MSG(_T("pthread_exit() failed"));
518b5d2f
VZ
1504}
1505
1506// also test whether we were paused
1507bool wxThread::TestDestroy()
1508{
4c460b34
VZ
1509 wxASSERT_MSG( This() == this,
1510 _T("wxThread::TestDestroy() can only be called in the "
1511 "context of the same thread") );
1512
9fc3ad34 1513 m_critsect.Enter();
518b5d2f 1514
9fc3ad34 1515 if ( m_internal->GetState() == STATE_PAUSED )
518b5d2f 1516 {
4c460b34
VZ
1517 m_internal->SetReallyPaused(TRUE);
1518
9fc3ad34
VZ
1519 // leave the crit section or the other threads will stop too if they
1520 // try to call any of (seemingly harmless) IsXXX() functions while we
1521 // sleep
518b5d2f
VZ
1522 m_critsect.Leave();
1523
9fc3ad34
VZ
1524 m_internal->Pause();
1525 }
1526 else
1527 {
1528 // thread wasn't requested to pause, nothing to do
1529 m_critsect.Leave();
518b5d2f
VZ
1530 }
1531
9fc3ad34 1532 return m_internal->WasCancelled();
518b5d2f
VZ
1533}
1534
1535wxThread::~wxThread()
1536{
9fc3ad34 1537#ifdef __WXDEBUG__
062c4861 1538 m_critsect.Enter();
9fc3ad34
VZ
1539
1540 // check that the thread either exited or couldn't be created
1541 if ( m_internal->GetState() != STATE_EXITED &&
1542 m_internal->GetState() != STATE_NEW )
bbfa0322 1543 {
4c460b34
VZ
1544 wxLogDebug(_T("The thread %ld is being destroyed although it is still "
1545 "running! The application may crash."), GetId());
bbfa0322 1546 }
062c4861
GL
1547
1548 m_critsect.Leave();
9fc3ad34 1549#endif // __WXDEBUG__
062c4861 1550
9fc3ad34 1551 delete m_internal;
bbfa0322 1552
518b5d2f
VZ
1553 // remove this thread from the global array
1554 gs_allThreads.Remove(this);
1555}
1556
1557// -----------------------------------------------------------------------------
1558// state tests
1559// -----------------------------------------------------------------------------
1560
1561bool wxThread::IsRunning() const
1562{
1563 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
1564
9fc3ad34 1565 return m_internal->GetState() == STATE_RUNNING;
518b5d2f
VZ
1566}
1567
1568bool wxThread::IsAlive() const
1569{
1570 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
1571
9fc3ad34 1572 switch ( m_internal->GetState() )
518b5d2f
VZ
1573 {
1574 case STATE_RUNNING:
1575 case STATE_PAUSED:
1576 return TRUE;
1577
1578 default:
1579 return FALSE;
1580 }
1581}
1582
a737331d
GL
1583bool wxThread::IsPaused() const
1584{
1585 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
1586
9fc3ad34 1587 return (m_internal->GetState() == STATE_PAUSED);
a737331d
GL
1588}
1589
518b5d2f
VZ
1590//--------------------------------------------------------------------
1591// wxThreadModule
1592//--------------------------------------------------------------------
1593
1594class wxThreadModule : public wxModule
1595{
1596public:
1597 virtual bool OnInit();
1598 virtual void OnExit();
1599
1600private:
1601 DECLARE_DYNAMIC_CLASS(wxThreadModule)
1602};
1603
1604IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
1605
1606bool wxThreadModule::OnInit()
1607{
58230fb1
VZ
1608 int rc = pthread_key_create(&gs_keySelf, NULL /* dtor function */);
1609 if ( rc != 0 )
518b5d2f 1610 {
58230fb1
VZ
1611 wxLogSysError(rc, _("Thread module initialization failed: "
1612 "failed to create thread key"));
518b5d2f
VZ
1613
1614 return FALSE;
1615 }
1616
518b5d2f 1617 gs_tidMain = pthread_self();
19da4326 1618
9fc3ad34
VZ
1619#if wxUSE_GUI
1620 gs_mutexGui = new wxMutex();
1621
518b5d2f 1622 gs_mutexGui->Lock();
9fc3ad34 1623#endif // wxUSE_GUI
518b5d2f 1624
be809868 1625 gs_mutexDeleteThread = new wxMutex();
c112e100 1626 gs_condAllDeleted = new wxCondition( *gs_mutexDeleteThread );
88e243b2 1627
518b5d2f
VZ
1628 return TRUE;
1629}
1630
1631void wxThreadModule::OnExit()
1632{
223d09f6 1633 wxASSERT_MSG( wxThread::IsMain(), wxT("only main thread can be here") );
518b5d2f 1634
9fc3ad34
VZ
1635 // are there any threads left which are being deleted right now?
1636 size_t nThreadsBeingDeleted;
be809868 1637
9fc3ad34 1638 {
be809868 1639 wxMutexLocker lock( *gs_mutexDeleteThread );
9fc3ad34 1640 nThreadsBeingDeleted = gs_nThreadsBeingDeleted;
9fc3ad34 1641
be809868 1642 if ( nThreadsBeingDeleted > 0 )
9e84b847 1643 {
2b5f62a0
VZ
1644 wxLogTrace(TRACE_THREADS,
1645 _T("Waiting for %lu threads to disappear"),
1646 (unsigned long)nThreadsBeingDeleted);
9fc3ad34 1647
be809868
VZ
1648 // have to wait until all of them disappear
1649 gs_condAllDeleted->Wait();
1650 }
9fc3ad34
VZ
1651 }
1652
518b5d2f
VZ
1653 // terminate any threads left
1654 size_t count = gs_allThreads.GetCount();
1655 if ( count != 0u )
4c460b34 1656 {
2b5f62a0
VZ
1657 wxLogDebug(wxT("%lu threads were not terminated by the application."),
1658 (unsigned long)count);
4c460b34 1659 }
518b5d2f
VZ
1660
1661 for ( size_t n = 0u; n < count; n++ )
1662 {
bbfa0322
VZ
1663 // Delete calls the destructor which removes the current entry. We
1664 // should only delete the first one each time.
0ac77ef5 1665 gs_allThreads[0]->Delete();
518b5d2f
VZ
1666 }
1667
9fc3ad34 1668#if wxUSE_GUI
518b5d2f
VZ
1669 // destroy GUI mutex
1670 gs_mutexGui->Unlock();
1671
518b5d2f 1672 delete gs_mutexGui;
9fc3ad34 1673#endif // wxUSE_GUI
518b5d2f
VZ
1674
1675 // and free TLD slot
1676 (void)pthread_key_delete(gs_keySelf);
be809868
VZ
1677
1678 delete gs_condAllDeleted;
1679 delete gs_mutexDeleteThread;
518b5d2f
VZ
1680}
1681
1682// ----------------------------------------------------------------------------
1683// global functions
1684// ----------------------------------------------------------------------------
1685
9fc3ad34
VZ
1686static void ScheduleThreadForDeletion()
1687{
be809868 1688 wxMutexLocker lock( *gs_mutexDeleteThread );
9fc3ad34
VZ
1689
1690 gs_nThreadsBeingDeleted++;
1691
2b5f62a0
VZ
1692 wxLogTrace(TRACE_THREADS, _T("%lu thread%s waiting to be deleted"),
1693 (unsigned long)gs_nThreadsBeingDeleted,
fcc3d7cb 1694 gs_nThreadsBeingDeleted == 1 ? "" : "s");
9fc3ad34
VZ
1695}
1696
1697static void DeleteThread(wxThread *This)
1698{
1699 // gs_mutexDeleteThread should be unlocked before signalling the condition
1700 // or wxThreadModule::OnExit() would deadlock
be809868 1701 wxMutexLocker locker( *gs_mutexDeleteThread );
9fc3ad34 1702
be809868 1703 wxLogTrace(TRACE_THREADS, _T("Thread %ld auto deletes."), This->GetId());
9fc3ad34 1704
be809868 1705 delete This;
9fc3ad34 1706
be809868 1707 wxCHECK_RET( gs_nThreadsBeingDeleted > 0,
9e84b847 1708 _T("no threads scheduled for deletion, yet we delete one?") );
9fc3ad34 1709
2b5f62a0
VZ
1710 wxLogTrace(TRACE_THREADS, _T("%lu scheduled for deletion threads left."),
1711 (unsigned long)gs_nThreadsBeingDeleted - 1);
4c460b34 1712
9fc3ad34
VZ
1713 if ( !--gs_nThreadsBeingDeleted )
1714 {
1715 // no more threads left, signal it
1716 gs_condAllDeleted->Signal();
9fc3ad34
VZ
1717 }
1718}
1719
518b5d2f
VZ
1720void wxMutexGuiEnter()
1721{
9fc3ad34
VZ
1722#if wxUSE_GUI
1723 gs_mutexGui->Lock();
1724#endif // wxUSE_GUI
518b5d2f
VZ
1725}
1726
1727void wxMutexGuiLeave()
1728{
9fc3ad34
VZ
1729#if wxUSE_GUI
1730 gs_mutexGui->Unlock();
1731#endif // wxUSE_GUI
518b5d2f 1732}
80cb83be 1733
9e84b847
VZ
1734// ----------------------------------------------------------------------------
1735// include common implementation code
1736// ----------------------------------------------------------------------------
1737
1738#include "wx/thrimpl.cpp"
1739
1740#endif // wxUSE_THREADS
1741