Do not allow multiple threads to acquire a QMutex
authorBradley T. Hughes <bradley.hughes@nokia.com>
Thu, 5 May 2011 15:03:54 +0000 (17:03 +0200)
committerOlivier Goffart <olivier.goffart@nokia.com>
Tue, 10 May 2011 10:54:56 +0000 (12:54 +0200)
After the mutex optimizations on Mac, we did not handle the case where
semaphore_wait() could return KERN_ABORTED. Under heavy contention, this
happens, and when running in release mode, the assert in qmutex.cpp is not
executed. The code silently allows multiple threads to continue as if it
had acquired the mutex exclusively.

Fix this by checking for KERN_ABORTED from semaphore_wait(), and retry the
wait. We do not handle KERN_ABORTED for timed waits, simply return false and
let the code doing the tryLock() handle it how it deems best.

Reviewed-by: joao
(cherry picked from commit b54af0a9d6406356616889826e31925d2fa05718)

src/corelib/thread/qmutex_unix.cpp

index 11e2060..b584ae5 100644 (file)
@@ -107,18 +107,21 @@ bool QMutexPrivate::wait(int timeout)
         // lock acquired without waiting
         return true;
     }
-    bool returnValue;
+    kern_return_t r;
     if (timeout < 0) {
-        returnValue = semaphore_wait(mach_semaphore) == KERN_SUCCESS;
+        do {
+            r = semaphore_wait(mach_semaphore);
+        } while (r == KERN_ABORTED);
+       if (r != KERN_SUCCESS)
+            qWarning("QMutex: infinite wait failed, error %d", r);
     } else {
         mach_timespec_t ts;
         ts.tv_nsec = ((timeout % 1000) * 1000) * 1000;
         ts.tv_sec = (timeout / 1000);
-        kern_return_t r = semaphore_timedwait(mach_semaphore, ts);
-        returnValue = r == KERN_SUCCESS;
+        r = semaphore_timedwait(mach_semaphore, ts);
     }
     contenders.deref();
-    return returnValue;
+    return r == KERN_SUCCESS;
 }
 
 void QMutexPrivate::wakeUp()