home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / src / unix / threadpsx.cpp < prev    next >
C/C++ Source or Header  |  2002-08-08  |  49KB  |  1,698 lines

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