]> git.saurik.com Git - wxWidgets.git/blobdiff - src/unix/threadpsx.cpp
moved toolbar adjustments for the client size from wxTLWMSW to wxFrameMSW to fix...
[wxWidgets.git] / src / unix / threadpsx.cpp
index fad73a2df9fb83bd6f923e0707dd7adf4e12d270..fd9b12c7313d37038187ffddb9ff6db8db336e59 100644 (file)
     #include <sched.h>
 #endif
 
+#ifdef HAVE_THR_SETCONCURRENCY
+    #include <thread.h>
+#endif
+
+// we use wxFFile under Linux in GetCPUCount()
+#ifdef __LINUX__
+    #include "wx/ffile.h"
+#endif
+
 // ----------------------------------------------------------------------------
 // constants
 // ----------------------------------------------------------------------------
@@ -126,7 +135,7 @@ static pthread_key_t gs_keySelf;
 static size_t gs_nThreadsBeingDeleted = 0;
 
 // a mutex to protect gs_nThreadsBeingDeleted
-static pthread_mutex_t gs_mutexDeleteThread = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t gs_mutexDeleteThread;
 
 // and a condition variable which will be signaled when all
 // gs_nThreadsBeingDeleted will have been deleted
@@ -155,8 +164,26 @@ wxMutex::wxMutex()
 {
     m_internal = new wxMutexInternal;
 
-    pthread_mutex_init(&(m_internal->m_mutex),
-                       (pthread_mutexattr_t*) NULL );
+    // support recursive locks like Win32, i.e. a thread can lock a mutex which
+    // it had itself already locked
+    //
+    // but initialization of recursive mutexes is non portable <sigh>, so try
+    // several methods
+#ifdef HAVE_PTHREAD_MUTEXATTR_T
+    pthread_mutexattr_t attr;
+    pthread_mutexattr_init(&attr);
+    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+
+    pthread_mutex_init(&(m_internal->m_mutex), &attr);
+#elif defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER)
+    // we can use this only as initializer so we have to assign it first to a
+    // temp var - assigning directly to m_mutex wouldn't even compile
+    pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+    m_internal->m_mutex = mutex;
+#else // no recursive mutexes
+    pthread_mutex_init(&(m_internal->m_mutex), NULL);
+#endif // HAVE_PTHREAD_MUTEXATTR_T/...
+
     m_locked = 0;
 }
 
@@ -463,6 +490,13 @@ void wxCondition::Broadcast()
 // wxThread (Posix implementation)
 //--------------------------------------------------------------------
 
+#if HAVE_THREAD_CLEANUP_FUNCTIONS
+
+// thread exit function
+extern "C" void wxPthreadCleanup(void *ptr);
+
+#endif // HAVE_THREAD_CLEANUP_FUNCTIONS
+
 class wxThreadInternal
 {
 public:
@@ -472,11 +506,6 @@ public:
     // thread entry function
     static void *PthreadStart(void *ptr);
 
-#if HAVE_THREAD_CLEANUP_FUNCTIONS
-    // thread exit function
-    static void PthreadCleanup(void *ptr);
-#endif
-
     // thread actions
         // start the thread
     wxThreadError Run();
@@ -522,6 +551,11 @@ public:
         // sometimes - tell the thread that it should do it
     void Notify() { m_shouldBroadcast = TRUE; }
 
+#if HAVE_THREAD_CLEANUP_FUNCTIONS
+    // this is used by wxPthreadCleanup() only
+    static void Cleanup(wxThread *thread);
+#endif // HAVE_THREAD_CLEANUP_FUNCTIONS
+
 private:
     pthread_t     m_threadId;   // id of the thread
     wxThreadState m_state;      // see wxThreadState enum
@@ -588,7 +622,7 @@ void *wxThreadInternal::PthreadStart(void *ptr)
 #if HAVE_THREAD_CLEANUP_FUNCTIONS
     // install the cleanup handler which will be called if the thread is
     // cancelled
-    pthread_cleanup_push(wxThreadInternal::PthreadCleanup, ptr);
+    pthread_cleanup_push(wxPthreadCleanup, ptr);
 #endif // HAVE_THREAD_CLEANUP_FUNCTIONS
 
     // wait for the condition to be signaled from Run()
@@ -618,7 +652,7 @@ void *wxThreadInternal::PthreadStart(void *ptr)
                        pthread->GetId());
 
             // change the state of the thread to "exited" so that
-            // PthreadCleanup handler won't do anything from now (if it's
+            // wxPthreadCleanup handler won't do anything from now (if it's
             // called before we do pthread_cleanup_pop below)
             pthread->SetState(STATE_EXITED);
         }
@@ -652,10 +686,13 @@ void *wxThreadInternal::PthreadStart(void *ptr)
 #if HAVE_THREAD_CLEANUP_FUNCTIONS
 
 // this handler is called when the thread is cancelled
-void wxThreadInternal::PthreadCleanup(void *ptr)
+extern "C" void wxPthreadCleanup(void *ptr)
 {
-    wxThread *thread = (wxThread *) ptr;
+    wxThreadInternal::Cleanup((wxThread *)ptr);
+}
 
+void wxThreadInternal::Cleanup(wxThread *thread)
+{
     {
         wxCriticalSectionLocker lock(thread->m_critsect);
         if ( thread->m_internal->GetState() == STATE_EXITED )
@@ -716,8 +753,12 @@ void wxThreadInternal::Wait()
         wxMutexGuiLeave();
 
     bool isDetached = m_isDetached;
-    long id = GetId();
-    wxLogTrace(TRACE_THREADS, _T("Starting to wait for thread %ld to exit."),
+#ifdef __VMS
+   long long id = (long long)GetId();
+#else
+   long id = (long)GetId();
+#endif
+   wxLogTrace(TRACE_THREADS, _T("Starting to wait for thread %ld to exit."),
                id);
 
     // wait until the thread terminates (we're blocking in _another_ thread,
@@ -740,7 +781,7 @@ void wxThreadInternal::Wait()
             //       we're cancelled inside pthread_join(), things will almost
             //       certainly break - but if we disable the cancellation, we
             //       might deadlock
-            if ( pthread_join(id, &m_exitcode) != 0 )
+            if ( pthread_join((pthread_t)id, &m_exitcode) != 0 )
             {
                 wxLogError(_("Failed to join a thread, potential memory leak "
                              "detected - please restart the program"));
@@ -826,7 +867,9 @@ bool wxThread::IsMain()
 
 void wxThread::Yield()
 {
+#ifdef HAVE_SCHED_YIELD
     sched_yield();
+#endif
 }
 
 void wxThread::Sleep(unsigned long milliseconds)
@@ -834,6 +877,63 @@ void wxThread::Sleep(unsigned long milliseconds)
     wxUsleep(milliseconds);
 }
 
+int wxThread::GetCPUCount()
+{
+#if defined(__LINUX__) && wxUSE_FFILE
+    // read from proc (can't use wxTextFile here because it's a special file:
+    // it has 0 size but still can be read from)
+    wxLogNull nolog;
+
+    wxFFile file(_T("/proc/cpuinfo"));
+    if ( file.IsOpened() )
+    {
+        // slurp the whole file
+        wxString s;
+        if ( file.ReadAll(&s) )
+        {
+            // (ab)use Replace() to find the number of "processor" strings
+            size_t count = s.Replace(_T("processor"), _T(""));
+            if ( count > 0 )
+            {
+                return count;
+            }
+
+            wxLogDebug(_T("failed to parse /proc/cpuinfo"));
+        }
+        else
+        {
+            wxLogDebug(_T("failed to read /proc/cpuinfo"));
+        }
+    }
+#elif defined(_SC_NPROCESSORS_ONLN)
+    // this works for Solaris
+    int rc = sysconf(_SC_NPROCESSORS_ONLN);
+    if ( rc != -1 )
+    {
+        return rc;
+    }
+#endif // different ways to get number of CPUs
+
+    // unknown
+    return -1;
+}
+
+bool wxThread::SetConcurrency(size_t level)
+{
+#ifdef HAVE_THR_SETCONCURRENCY
+    int rc = thr_setconcurrency(level);
+    if ( rc != 0 )
+    {
+        wxLogSysError(rc, _T("thr_setconcurrency() failed"));
+    }
+
+    return rc == 0;
+#else // !HAVE_THR_SETCONCURRENCY
+    // ok only for the default value
+    return level == 0;
+#endif // HAVE_THR_SETCONCURRENCY/!HAVE_THR_SETCONCURRENCY
+}
+
 // -----------------------------------------------------------------------------
 // creating thread
 // -----------------------------------------------------------------------------
@@ -848,7 +948,7 @@ wxThread::wxThread(wxThreadKind kind)
     m_isDetached = kind == wxTHREAD_DETACHED;
 }
 
-wxThreadError wxThread::Create()
+wxThreadError wxThread::Create(unsigned int WXUNUSED(stackSize))
 {
     if ( m_internal->GetState() != STATE_NEW )
     {
@@ -867,8 +967,18 @@ wxThreadError wxThread::Create()
         wxLogError(_("Cannot retrieve thread scheduling policy."));
     }
 
-    int min_prio = sched_get_priority_min(policy),
-        max_prio = sched_get_priority_max(policy),
+#ifdef __VMS__
+   /* the pthread.h contains too many spaces. This is a work-around */
+# undef sched_get_priority_max
+#undef sched_get_priority_min
+#define sched_get_priority_max(_pol_) \
+     (_pol_ == SCHED_OTHER ? PRI_FG_MAX_NP : PRI_FIFO_MAX)
+#define sched_get_priority_min(_pol_) \
+     (_pol_ == SCHED_OTHER ? PRI_FG_MIN_NP : PRI_FIFO_MIN)
+#endif
+   
+    int max_prio = sched_get_priority_max(policy),
+        min_prio = sched_get_priority_min(policy),
         prio = m_internal->GetPriority();
 
     if ( min_prio == -1 || max_prio == -1 )
@@ -1009,9 +1119,15 @@ unsigned int wxThread::GetPriority() const
     return m_internal->GetPriority();
 }
 
+#ifdef __VMS
+unsigned long long wxThread::GetId() const
+{
+    return (unsigned long long)m_internal->GetId();
+#else
 unsigned long wxThread::GetId() const
 {
     return (unsigned long)m_internal->GetId();
+#endif
 }
 
 // -----------------------------------------------------------------------------
@@ -1178,11 +1294,12 @@ wxThreadError wxThread::Kill()
             if ( m_isDetached )
             {
                 // if we use cleanup function, this will be done from
-                // PthreadCleanup()
+                // wxPthreadCleanup()
 #if !HAVE_THREAD_CLEANUP_FUNCTIONS
                 ScheduleThreadForDeletion();
 
-                OnExit();
+                // 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
@@ -1373,6 +1490,10 @@ bool wxThreadModule::OnInit()
     gs_mutexGui->Lock();
 #endif // wxUSE_GUI
 
+    // under Solaris we get a warning from CC when using
+    // PTHREAD_MUTEX_INITIALIZER, so do it dynamically
+    pthread_mutex_init(&gs_mutexDeleteThread, NULL);
+
     return TRUE;
 }