From 696d13ee0e378e3f14eb624cae2335bc05f74d06 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Thu, 8 Mar 2007 00:22:11 +0000
Subject: [PATCH] added wxMutex::LockTimeout() (modified patch 1671637)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@44671 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/changes.txt        |  1 +
 docs/latex/wx/mutex.tex | 26 +++++++++++++++++++++-
 include/wx/thread.h     |  5 +++++
 include/wx/thrimpl.cpp  |  8 +++++++
 src/msw/thread.cpp      | 15 ++++++++++---
 src/unix/threadpsx.cpp  | 49 ++++++++++++++++++++++++++++++++++++++---
 6 files changed, 97 insertions(+), 7 deletions(-)

diff --git a/docs/changes.txt b/docs/changes.txt
index 2ba3c52ce5..05d265ae3d 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -35,6 +35,7 @@ All:
 - Fixed tab-related drawing and hit-testing bugs in wxRichTextCtrl.
 - Implemented background colour in wxRichTextCtrl.
 - Fixed crashes in helpview when opening a file.
+- Added wxMutex::LockTimeout() (Aleksandr Napylov)
 
 wxGTK:
 
diff --git a/docs/latex/wx/mutex.tex b/docs/latex/wx/mutex.tex
index 64c95d8c84..fadf27236b 100644
--- a/docs/latex/wx/mutex.tex
+++ b/docs/latex/wx/mutex.tex
@@ -93,23 +93,27 @@ None.
 
 \latexignore{\rtfignore{\wxheading{Members}}}
 
+
 \membersection{wxMutex::wxMutex}\label{wxmutexctor}
 
 \func{}{wxMutex}{\param{wxMutexType }{type = {\tt wxMUTEX\_DEFAULT}}}
 
 Default constructor.
 
+
 \membersection{wxMutex::\destruct{wxMutex}}\label{wxmutexdtor}
 
 \func{}{\destruct{wxMutex}}{\void}
 
 Destroys the wxMutex object.
 
+
 \membersection{wxMutex::Lock}\label{wxmutexlock}
 
 \func{wxMutexError}{Lock}{\void}
 
-Locks the mutex object.
+Locks the mutex object. This is equivalent to 
+\helpref{LockTimeout}{wxmutexlocktimeout} with infinite timeout.
 
 \wxheading{Return value}
 
@@ -121,6 +125,25 @@ One of:
 \twocolitem{{\bf wxMUTEX\_DEAD\_LOCK}}{A deadlock situation was detected.}
 \end{twocollist}
 
+
+\membersection{wxMutex::LockTimeout}\label{wxmutexlocktimeout}
+
+\func{wxMutexError}{LockTimeout}{\param{unsigned long}{ msec}}
+
+Try to lock the mutex object during the specified time interval.
+
+\wxheading{Return value}
+
+One of:
+
+\twocolwidtha{7cm}
+\begin{twocollist}\itemsep=0pt
+\twocolitem{{\bf wxMUTEX\_NO\_ERROR}}{Mutex successfully locked.}
+\twocolitem{{\bf wxMUTEX\_TIMEOUT}}{Mutex couldn't be acquired before timeout expiration.}
+\twocolitem{{\bf wxMUTEX\_DEAD\_LOCK}}{A deadlock situation was detected.}
+\end{twocollist}
+
+
 \membersection{wxMutex::TryLock}\label{wxmutextrylock}
 
 \func{wxMutexError}{TryLock}{\void}
@@ -137,6 +160,7 @@ One of:
 \twocolitem{{\bf wxMUTEX\_BUSY}}{The mutex is already locked by another thread.}
 \end{twocollist}
 
+
 \membersection{wxMutex::Unlock}\label{wxmutexunlock}
 
 \func{wxMutexError}{Unlock}{\void}
diff --git a/include/wx/thread.h b/include/wx/thread.h
index 036b3d0adb..b95652dcac 100644
--- a/include/wx/thread.h
+++ b/include/wx/thread.h
@@ -38,6 +38,7 @@ enum wxMutexError
     wxMUTEX_DEAD_LOCK,      // mutex is already locked by the calling thread
     wxMUTEX_BUSY,           // mutex is already locked by another thread
     wxMUTEX_UNLOCKED,       // attempt to unlock a mutex which is not locked
+    wxMUTEX_TIMEOUT,        // LockTimeout() has timed out
     wxMUTEX_MISC_ERROR      // any other error
 };
 
@@ -149,6 +150,10 @@ public:
     // The caller must call Unlock() later if Lock() returned wxMUTEX_NO_ERROR.
     wxMutexError Lock();
 
+    // Same as Lock() but return wxMUTEX_TIMEOUT if the mutex can't be locked
+    // during the given number of milliseconds
+    wxMutexError LockTimeout(unsigned long ms);
+
     // Try to lock the mutex: if it is currently locked, return immediately
     // with an error. Otherwise the caller must call Unlock().
     wxMutexError TryLock();
diff --git a/include/wx/thrimpl.cpp b/include/wx/thrimpl.cpp
index ba4aa31bb7..63b837fec6 100644
--- a/include/wx/thrimpl.cpp
+++ b/include/wx/thrimpl.cpp
@@ -44,6 +44,14 @@ wxMutexError wxMutex::Lock()
     return m_internal->Lock();
 }
 
+wxMutexError wxMutex::LockTimeout(unsigned long ms)
+{
+    wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
+                 _T("wxMutex::Lock(): not initialized") );
+
+    return m_internal->Lock(ms);
+}
+
 wxMutexError wxMutex::TryLock()
 {
     wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
diff --git a/src/msw/thread.cpp b/src/msw/thread.cpp
index 74ab15f4c9..9fe2deef2c 100644
--- a/src/msw/thread.cpp
+++ b/src/msw/thread.cpp
@@ -178,7 +178,8 @@ public:
     bool IsOk() const { return m_mutex != NULL; }
 
     wxMutexError Lock() { return LockTimeout(INFINITE); }
-    wxMutexError TryLock() { return LockTimeout(0); }
+    wxMutexError Lock(unsigned long ms) { return LockTimeout(ms); }
+    wxMutexError TryLock();
     wxMutexError Unlock();
 
 private:
@@ -196,7 +197,7 @@ wxMutexInternal::wxMutexInternal(wxMutexType WXUNUSED(mutexType))
     m_mutex = ::CreateMutex
                 (
                     NULL,       // default secutiry attributes
-                    false,      // not initially locked
+                    FALSE,      // not initially locked
                     NULL        // no name
                 );
 
@@ -217,6 +218,14 @@ wxMutexInternal::~wxMutexInternal()
     }
 }
 
+wxMutexError wxMutexInternal::TryLock()
+{
+    const wxMutexError rc = LockTimeout(0);
+
+    // we have a special return code for timeout in this case
+    return rc == wxMUTEX_TIMEOUT ? wxMUTEX_BUSY : rc;
+}
+
 wxMutexError wxMutexInternal::LockTimeout(DWORD milliseconds)
 {
     DWORD rc = ::WaitForSingleObject(m_mutex, milliseconds);
@@ -237,7 +246,7 @@ wxMutexError wxMutexInternal::LockTimeout(DWORD milliseconds)
             break;
 
         case WAIT_TIMEOUT:
-            return wxMUTEX_BUSY;
+            return wxMUTEX_TIMEOUT;
 
         case WAIT_ABANDONED:        // checked for above
         default:
diff --git a/src/unix/threadpsx.cpp b/src/unix/threadpsx.cpp
index 983ac3632a..36943023ce 100644
--- a/src/unix/threadpsx.cpp
+++ b/src/unix/threadpsx.cpp
@@ -163,11 +163,16 @@ public:
     ~wxMutexInternal();
 
     wxMutexError Lock();
+    wxMutexError Lock(unsigned long ms);
     wxMutexError TryLock();
     wxMutexError Unlock();
 
     bool IsOk() const { return m_isOk; }
 
+private:
+    // convert the result of pthread_mutex_[timed]lock() call to wx return code
+    wxMutexError HandleLockResult(int err);
+
 private:
     pthread_mutex_t m_mutex;
     bool m_isOk;
@@ -245,7 +250,41 @@ wxMutexInternal::~wxMutexInternal()
 
 wxMutexError wxMutexInternal::Lock()
 {
-    int err = pthread_mutex_lock(&m_mutex);
+    return HandleLockResult(pthread_mutex_lock(&m_mutex));
+}
+
+wxMutexError wxMutexInternal::Lock(unsigned long ms)
+{
+    static const long MSEC_IN_SEC   = 1000;
+    static const long NSEC_IN_MSEC  = 1000000;
+    static const long NSEC_IN_SEC   = MSEC_IN_SEC * NSEC_IN_MSEC;
+
+    time_t seconds = ms/MSEC_IN_SEC;
+    long nanoseconds = (ms % MSEC_IN_SEC) * NSEC_IN_MSEC;
+    timespec ts = { 0, 0 };
+
+    if ( clock_gettime(CLOCK_REALTIME, &ts) == 0 )
+    {
+        ts.tv_sec += seconds;
+        ts.tv_nsec += nanoseconds;
+        if ( ts.tv_nsec > NSEC_IN_SEC )
+        {
+            ts.tv_sec += 1;
+            ts.tv_nsec -= NSEC_IN_SEC;
+        }
+    }
+    else // fall back on system timer
+    {
+        wxLogDebug(_T("clock_gettime(CLOCK_REALTIME) failed"));
+        ts.tv_sec = time(NULL) + seconds;
+        ts.tv_nsec = nanoseconds;
+    }
+
+    return HandleLockResult(pthread_mutex_timedlock(&m_mutex, &ts));
+}
+
+wxMutexError wxMutexInternal::HandleLockResult(int err)
+{
     switch ( err )
     {
         case EDEADLK:
@@ -255,19 +294,23 @@ wxMutexError wxMutexInternal::Lock()
             return wxMUTEX_DEAD_LOCK;
 
         case EINVAL:
-            wxLogDebug(_T("pthread_mutex_lock(): mutex not initialized."));
+            wxLogDebug(_T("pthread_mutex_[timed]lock(): mutex not initialized"));
             break;
 
+        case ETIMEDOUT:
+            return wxMUTEX_TIMEOUT;
+
         case 0:
             return wxMUTEX_NO_ERROR;
 
         default:
-            wxLogApiError(_T("pthread_mutex_lock()"), err);
+            wxLogApiError(_T("pthread_mutex_[timed]lock()"), err);
     }
 
     return wxMUTEX_MISC_ERROR;
 }
 
+
 wxMutexError wxMutexInternal::TryLock()
 {
     int err = pthread_mutex_trylock(&m_mutex);
-- 
2.50.0

