]> git.saurik.com Git - wxWidgets.git/blobdiff - src/unix/threadpsx.cpp
[ 1509599 ] 'Split pickers page in widgets sample' with more icons and rebaking.
[wxWidgets.git] / src / unix / threadpsx.cpp
index 1d32055350cf84481c9ce065fe27e427f7129cd0..1e538342f7561a88b268fa22064067f561535842 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        threadpsx.cpp
+// Name:        src/unix/threadpsx.cpp
 // Purpose:     wxThread (Posix) Implementation
 // Author:      Original from Wolfram Gloger/Guilhem Lavaux
 // Modified by: K. S. Sreeram (2002): POSIXified wxCondition, added wxSemaphore
 // headers
 // ----------------------------------------------------------------------------
 
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
-    #pragma implementation "thread.h"
-#endif
-
 // for compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
 #if wxUSE_THREADS
 
 #include "wx/thread.h"
+
+#ifndef WX_PRECOMP
+    #include "wx/dynarray.h"
+    #include "wx/intl.h"
+    #include "wx/log.h"
+    #include "wx/utils.h"
+    #include "wx/timer.h"
+#endif
+
 #include "wx/module.h"
-#include "wx/utils.h"
-#include "wx/log.h"
-#include "wx/intl.h"
-#include "wx/dynarray.h"
-#include "wx/timer.h"
+#include "wx/stopwatch.h"
 
 #include <stdio.h>
 #include <unistd.h>
 #include <pthread.h>
 #include <errno.h>
 #include <time.h>
-#if HAVE_SCHED_H
+#ifdef HAVE_SCHED_H
     #include <sched.h>
 #endif
 
@@ -99,7 +100,7 @@ static void DeleteThread(wxThread *This);
 // ----------------------------------------------------------------------------
 
 // an (non owning) array of pointers to threads
-WX_DEFINE_ARRAY(wxThread *, wxArrayThread);
+WX_DEFINE_ARRAY_PTR(wxThread *, wxArrayThread);
 
 // an entry for a thread we can wait for
 
@@ -113,7 +114,7 @@ WX_DEFINE_ARRAY(wxThread *, wxArrayThread);
 static wxArrayThread gs_allThreads;
 
 // the id of the main thread
-static pthread_t gs_tidMain;
+static pthread_t gs_tidMain = (pthread_t)-1;
 
 // the key for the pointer to the associated wxThread object
 static pthread_key_t gs_keySelf;
@@ -173,7 +174,8 @@ private:
     friend class wxConditionInternal;
 };
 
-#ifdef HAVE_PTHREAD_MUTEXATTR_T
+#if defined(HAVE_PTHREAD_MUTEXATTR_T) && \
+        wxUSE_UNIX && !defined(HAVE_PTHREAD_MUTEXATTR_SETTYPE_DECL)
 // on some systems pthread_mutexattr_settype() is not in the headers (but it is
 // in the library, otherwise we wouldn't compile this code at all)
 extern "C" int pthread_mutexattr_settype(pthread_mutexattr_t *, int);
@@ -483,7 +485,7 @@ wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
     {
         wxFAIL_MSG( _T("wxSemaphore: invalid initial or maximal count") );
 
-        m_isOk = FALSE;
+        m_isOk = false;
     }
     else
     {
@@ -590,10 +592,10 @@ wxSemaError wxSemaphoreInternal::Post()
 extern "C"
 {
 
-#if HAVE_THREAD_CLEANUP_FUNCTIONS
+#ifdef wxHAVE_PTHREAD_CLEANUP
     // thread exit function
     void wxPthreadCleanup(void *ptr);
-#endif // HAVE_THREAD_CLEANUP_FUNCTIONS
+#endif // wxHAVE_PTHREAD_CLEANUP
 
 void *wxPthreadStart(void *ptr);
 
@@ -651,7 +653,7 @@ public:
     pthread_t GetId() const { return m_threadId; }
     pthread_t *GetIdPtr() { return &m_threadId; }
         // "cancelled" flag
-    void SetCancelFlag() { m_cancelled = TRUE; }
+    void SetCancelFlag() { m_cancelled = true; }
     bool WasCancelled() const { return m_cancelled; }
         // exit code
     void SetExitCode(wxThread::ExitCode exitcode) { m_exitcode = exitcode; }
@@ -666,19 +668,19 @@ public:
     {
         wxCriticalSectionLocker lock(m_csJoinFlag);
 
-        m_shouldBeJoined = FALSE;
-        m_isDetached = TRUE;
+        m_shouldBeJoined = false;
+        m_isDetached = true;
     }
 
-#if HAVE_THREAD_CLEANUP_FUNCTIONS
+#ifdef wxHAVE_PTHREAD_CLEANUP
     // this is used by wxPthreadCleanup() only
     static void Cleanup(wxThread *thread);
-#endif // HAVE_THREAD_CLEANUP_FUNCTIONS
+#endif // wxHAVE_PTHREAD_CLEANUP
 
 private:
     pthread_t     m_threadId;   // id of the thread
     wxThreadState m_state;      // see wxThreadState enum
-    int           m_prio;       // in wxWindows units: from 0 to 100
+    int           m_prio;       // in wxWidgets units: from 0 to 100
 
     // this flag is set when the thread should terminate
     bool m_cancelled;
@@ -734,11 +736,11 @@ void *wxThreadInternal::PthreadStart(wxThread *thread)
     // block!
     bool dontRunAtAll;
 
-#if HAVE_THREAD_CLEANUP_FUNCTIONS
+#ifdef wxHAVE_PTHREAD_CLEANUP
     // install the cleanup handler which will be called if the thread is
     // cancelled
     pthread_cleanup_push(wxPthreadCleanup, thread);
-#endif // HAVE_THREAD_CLEANUP_FUNCTIONS
+#endif // wxHAVE_PTHREAD_CLEANUP
 
     // wait for the semaphore to be posted from Run()
     pthread->m_semRun.Wait();
@@ -763,7 +765,7 @@ void *wxThreadInternal::PthreadStart(wxThread *thread)
 
         wxLogTrace(TRACE_THREADS,
                    _T("Thread %ld Entry() returned %lu."),
-                   THR_ID(pthread), (unsigned long)pthread->m_exitcode);
+                   THR_ID(pthread), wxPtrToUInt(pthread->m_exitcode));
 
         {
             wxCriticalSectionLocker lock(thread->m_critsect);
@@ -775,13 +777,22 @@ void *wxThreadInternal::PthreadStart(wxThread *thread)
         }
     }
 
-    // NB: at least under Linux, pthread_cleanup_push/pop are macros and pop
-    //     contains the matching '}' for the '{' in push, so they must be used
-    //     in the same block!
-#if HAVE_THREAD_CLEANUP_FUNCTIONS
+    // NB: pthread_cleanup_push/pop() are macros and pop contains the matching
+    //     '}' for the '{' in push, so they must be used in the same block!
+#ifdef wxHAVE_PTHREAD_CLEANUP
+    #ifdef __DECCXX
+        // under Tru64 we get a warning from macro expansion
+        #pragma message save
+        #pragma message disable(declbutnotref)
+    #endif
+
     // remove the cleanup handler without executing it
     pthread_cleanup_pop(FALSE);
-#endif // HAVE_THREAD_CLEANUP_FUNCTIONS
+
+    #ifdef __DECCXX
+        #pragma message restore
+    #endif
+#endif // wxHAVE_PTHREAD_CLEANUP
 
     if ( dontRunAtAll )
     {
@@ -801,7 +812,7 @@ void *wxThreadInternal::PthreadStart(wxThread *thread)
     }
 }
 
-#if HAVE_THREAD_CLEANUP_FUNCTIONS
+#ifdef wxHAVE_PTHREAD_CLEANUP
 
 // this handler is called when the thread is cancelled
 extern "C" void wxPthreadCleanup(void *ptr)
@@ -811,6 +822,7 @@ extern "C" void wxPthreadCleanup(void *ptr)
 
 void wxThreadInternal::Cleanup(wxThread *thread)
 {
+    if (pthread_getspecific(gs_keySelf) == 0) return;
     {
         wxCriticalSectionLocker lock(thread->m_critsect);
         if ( thread->m_internal->GetState() == STATE_EXITED )
@@ -824,7 +836,7 @@ void wxThreadInternal::Cleanup(wxThread *thread)
     thread->Exit(EXITCODE_CANCELLED);
 }
 
-#endif // HAVE_THREAD_CLEANUP_FUNCTIONS
+#endif // wxHAVE_PTHREAD_CLEANUP
 
 // ----------------------------------------------------------------------------
 // wxThreadInternal
@@ -833,17 +845,17 @@ void wxThreadInternal::Cleanup(wxThread *thread)
 wxThreadInternal::wxThreadInternal()
 {
     m_state = STATE_NEW;
-    m_cancelled = FALSE;
+    m_cancelled = false;
     m_prio = WXTHREAD_DEFAULT_PRIORITY;
     m_threadId = 0;
     m_exitcode = 0;
 
-    // set to TRUE only when the thread starts waiting on m_semSuspend
-    m_isPaused = FALSE;
+    // set to true only when the thread starts waiting on m_semSuspend
+    m_isPaused = false;
 
     // defaults for joinable threads
-    m_shouldBeJoined = TRUE;
-    m_isDetached = FALSE;
+    m_shouldBeJoined = true;
+    m_isDetached = false;
 }
 
 wxThreadInternal::~wxThreadInternal()
@@ -893,11 +905,10 @@ void wxThreadInternal::Wait()
                 // wxLogDebug: it is possible to bring the system to its knees
                 // by creating too many threads and not joining them quite
                 // easily
-                wxLogError(_("Failed to join a thread, potential memory leak "
-                             "detected - please restart the program"));
+                wxLogError(_("Failed to join a thread, potential memory leak detected - please restart the program"));
             }
 
-            m_shouldBeJoined = FALSE;
+            m_shouldBeJoined = false;
         }
     }
 
@@ -936,7 +947,7 @@ void wxThreadInternal::Resume()
         m_semSuspend.Post();
 
         // reset the flag
-        SetReallyPaused(FALSE);
+        SetReallyPaused(false);
     }
     else
     {
@@ -958,7 +969,7 @@ wxThread *wxThread::This()
 
 bool wxThread::IsMain()
 {
-    return (bool)pthread_equal(pthread_self(), gs_tidMain);
+    return (bool)pthread_equal(pthread_self(), gs_tidMain) || gs_tidMain == (pthread_t)-1;
 }
 
 void wxThread::Yield()
@@ -970,7 +981,7 @@ void wxThread::Yield()
 
 void wxThread::Sleep(unsigned long milliseconds)
 {
-    wxUsleep(milliseconds);
+    wxMilliSleep(milliseconds);
 }
 
 int wxThread::GetCPUCount()
@@ -1062,7 +1073,13 @@ wxThread::wxThread(wxThreadKind kind)
     m_isDetached = kind == wxTHREAD_DETACHED;
 }
 
-wxThreadError wxThread::Create(unsigned int WXUNUSED(stackSize))
+#ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
+    #define WXUNUSED_STACKSIZE(identifier)  identifier
+#else
+    #define WXUNUSED_STACKSIZE(identifier)  WXUNUSED(identifier)
+#endif
+
+wxThreadError wxThread::Create(unsigned int WXUNUSED_STACKSIZE(stackSize))
 {
     if ( m_internal->GetState() != STATE_NEW )
     {
@@ -1074,6 +1091,11 @@ wxThreadError wxThread::Create(unsigned int WXUNUSED(stackSize))
     pthread_attr_t attr;
     pthread_attr_init(&attr);
 
+#ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
+    if (stackSize)
+      pthread_attr_setstacksize(&attr, stackSize);
+#endif
+
 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
     int policy;
     if ( pthread_attr_getschedpolicy(&attr, &policy) != 0 )
@@ -1208,42 +1230,21 @@ void wxThread::SetPriority(unsigned int prio)
         case STATE_PAUSED:
 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
 #if defined(__LINUX__)
-// On Linux, pthread_setschedparam with SCHED_OTHER does not allow
-// a priority other than 0.  Instead, we use the BSD setpriority
-// which alllows us to set a 'nice' value between 20 to -20.  Only
-// super user can set a value less than zero (more negative yields
-// higher priority).  setpriority set the static priority of a process,
-// but this is OK since Linux is configured as a thread per process.
-            {
-                float   fPrio;
-                float  pSpan;
-                int            iPrio;
-
-                // Map Wx priorites (WXTHREAD_MIN_PRIORITY -
-                // WXTHREAD_MAX_PRIORITY) into BSD priorities (20 - -20).
-                // Do calculation of values instead of hard coding them
-                // to make maintenance easier.
-
-                pSpan = ((float)(WXTHREAD_MAX_PRIORITY - WXTHREAD_MIN_PRIORITY)) / 2.0;
-
-                // prio starts as ...................  // value =>  (0) >=  p  <=  (n)
-
-                fPrio = ((float)prio) -  pSpan;        // value =>  (-n) >=  p  <=  (+n)
-
-                fPrio = 0.0 - fPrio;                   // value =>  (+n) <=  p  >=  (-n)
-
-                fPrio = fPrio * (20. / pSpan) + .5;    // value =>  (20) <=  p  >=  (-20)
-
-                iPrio = (int)fPrio;
-
-                // Clamp prio from 20 - -20;
-                iPrio = (iPrio > 20)  ?  20 : iPrio;
-                iPrio = (iPrio < -20) ? -20 : iPrio;
+            // On Linux, pthread_setschedparam with SCHED_OTHER does not allow
+            // a priority other than 0.  Instead, we use the BSD setpriority
+            // which alllows us to set a 'nice' value between 20 to -20.  Only
+            // super user can set a value less than zero (more negative yields
+            // higher priority).  setpriority set the static priority of a
+            // process, but this is OK since Linux is configured as a thread
+            // per process.
+            //
+            // FIXME this is not true for 2.6!!
 
-                if (setpriority(PRIO_PROCESS, 0, iPrio) == -1)
-                {
-                    wxLogError(_("Failed to set thread priority %d."), prio);
-                }
+            // map wx priorites WXTHREAD_MIN_PRIORITY..WXTHREAD_MAX_PRIORITY
+            // to Unix priorities 20..-20
+            if ( setpriority(PRIO_PROCESS, 0, -(2*prio)/5 + 20) == -1 )
+            {
+                wxLogError(_("Failed to set thread priority %d."), prio);
             }
 #else // __LINUX__
             {
@@ -1424,25 +1425,26 @@ wxThreadError wxThread::Kill()
         default:
 #ifdef HAVE_PTHREAD_CANCEL
             if ( pthread_cancel(m_internal->GetId()) != 0 )
-#endif
+#endif // HAVE_PTHREAD_CANCEL
             {
                 wxLogError(_("Failed to terminate a thread."));
 
                 return wxTHREAD_MISC_ERROR;
             }
 
+#ifdef HAVE_PTHREAD_CANCEL
             if ( m_isDetached )
             {
                 // if we use cleanup function, this will be done from
                 // wxPthreadCleanup()
-#if !HAVE_THREAD_CLEANUP_FUNCTIONS
+#ifndef wxHAVE_PTHREAD_CLEANUP
                 ScheduleThreadForDeletion();
 
                 // don't call OnExit() here, it can only be called in the
                 // threads context and we're in the context of another thread
 
                 DeleteThread(this);
-#endif // HAVE_THREAD_CLEANUP_FUNCTIONS
+#endif // wxHAVE_PTHREAD_CLEANUP
             }
             else
             {
@@ -1450,14 +1452,14 @@ wxThreadError wxThread::Kill()
             }
 
             return wxTHREAD_NO_ERROR;
+#endif // HAVE_PTHREAD_CANCEL
     }
 }
 
 void wxThread::Exit(ExitCode status)
 {
     wxASSERT_MSG( This() == this,
-                  _T("wxThread::Exit() can only be called in the "
-                     "context of the same thread") );
+                  _T("wxThread::Exit() can only be called in the context of the same thread") );
 
     if ( m_isDetached )
     {
@@ -1484,6 +1486,13 @@ void wxThread::Exit(ExitCode status)
         //       we make it a global object, but this would mean that we can
         //       only call one thread function at a time :-(
         DeleteThread(this);
+        pthread_setspecific(gs_keySelf, 0);
+    }
+    else
+    {
+        m_critsect.Enter();
+        m_internal->SetState(STATE_EXITED);
+        m_critsect.Leave();
     }
 
     // terminate the thread (pthread_exit() never returns)
@@ -1496,14 +1505,13 @@ void wxThread::Exit(ExitCode status)
 bool wxThread::TestDestroy()
 {
     wxASSERT_MSG( This() == this,
-                  _T("wxThread::TestDestroy() can only be called in the "
-                     "context of the same thread") );
+                  _T("wxThread::TestDestroy() can only be called in the context of the same thread") );
 
     m_critsect.Enter();
 
     if ( m_internal->GetState() == STATE_PAUSED )
     {
-        m_internal->SetReallyPaused(TRUE);
+        m_internal->SetReallyPaused(true);
 
         // leave the crit section or the other threads will stop too if they
         // try to call any of (seemingly harmless) IsXXX() functions while we
@@ -1530,8 +1538,8 @@ wxThread::~wxThread()
     if ( m_internal->GetState() != STATE_EXITED &&
          m_internal->GetState() != STATE_NEW )
     {
-        wxLogDebug(_T("The thread %ld is being destroyed although it is still "
-                      "running! The application may crash."), GetId());
+        wxLogDebug(_T("The thread %ld is being destroyed although it is still running! The application may crash."),
+                   (long)GetId());
     }
 
     m_critsect.Leave();
@@ -1562,10 +1570,10 @@ bool wxThread::IsAlive() const
     {
         case STATE_RUNNING:
         case STATE_PAUSED:
-            return TRUE;
+            return true;
 
         default:
-            return FALSE;
+            return false;
     }
 }
 
@@ -1597,10 +1605,9 @@ bool wxThreadModule::OnInit()
     int rc = pthread_key_create(&gs_keySelf, NULL /* dtor function */);
     if ( rc != 0 )
     {
-        wxLogSysError(rc, _("Thread module initialization failed: "
-                            "failed to create thread key"));
+        wxLogSysError(rc, _("Thread module initialization failed: failed to create thread key"));
 
-        return FALSE;
+        return false;
     }
 
     gs_tidMain = pthread_self();
@@ -1611,7 +1618,7 @@ bool wxThreadModule::OnInit()
     gs_mutexDeleteThread = new wxMutex();
     gs_condAllDeleted = new wxCondition( *gs_mutexDeleteThread );
 
-    return TRUE;
+    return true;
 }
 
 void wxThreadModule::OnExit()
@@ -1717,4 +1724,3 @@ void wxMutexGuiLeave()
 #include "wx/thrimpl.cpp"
 
 #endif // wxUSE_THREADS
-