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