]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
drd, semaphore implementation: Only wake the associated futex if at least one thread...
authorBart Van Assche <bvanassche@acm.org>
Mon, 23 Jan 2012 17:01:58 +0000 (17:01 +0000)
committerBart Van Assche <bvanassche@acm.org>
Mon, 23 Jan 2012 17:01:58 +0000 (17:01 +0000)
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@12351

drd/drd_pthread_intercepts.c

index a7c28f6b8cb2883e02ddf6eb1cd7289992cf9899..b9bc28e615f72e321e4abf772d137d6fb9b20372 100644 (file)
@@ -138,6 +138,7 @@ static int never_true;
 typedef struct {
    pthread_mutex_t mutex;
    int counter;
+   int waiters;
 } DrdSema;
 
 typedef struct
@@ -183,6 +184,7 @@ static void DRD_(sema_init)(DrdSema* sema)
    DRD_IGNORE_VAR(sema->counter);
    pthread_mutex_init(&sema->mutex, NULL);
    sema->counter = 0;
+   sema->waiters = 0;
 }
 
 static void DRD_(sema_destroy)(DrdSema* sema)
@@ -195,24 +197,28 @@ static void DRD_(sema_down)(DrdSema* sema)
    int res = ENOSYS;
 
    pthread_mutex_lock(&sema->mutex);
-   while (sema->counter == 0) {
-      pthread_mutex_unlock(&sema->mutex);
+   if (sema->counter == 0) {
+      sema->waiters++;
+      while (sema->counter == 0) {
+         pthread_mutex_unlock(&sema->mutex);
 #ifdef HAVE_USABLE_LINUX_FUTEX_H
-      if (syscall(__NR_futex, (UWord)&sema->counter,
-                  FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0) == 0)
-         res = 0;
-      else
-         res = errno;
+         if (syscall(__NR_futex, (UWord)&sema->counter,
+                     FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0) == 0)
+            res = 0;
+         else
+            res = errno;
 #endif
-      /*
-       * Invoke sched_yield() on non-Linux systems, if the futex syscall has
-       * not been invoked or if this code has been built on a Linux system
-       * where __NR_futex is defined and is run on a Linux system that does
-       * not support the futex syscall.
-       */
-      if (res != 0 && res != EWOULDBLOCK)
-         sched_yield();
-      pthread_mutex_lock(&sema->mutex);
+         /*
+          * Invoke sched_yield() on non-Linux systems, if the futex syscall has
+          * not been invoked or if this code has been built on a Linux system
+          * where __NR_futex is defined and is run on a Linux system that does
+          * not support the futex syscall.
+          */
+         if (res != 0 && res != EWOULDBLOCK)
+            sched_yield();
+         pthread_mutex_lock(&sema->mutex);
+      }
+      sema->waiters--;
    }
    sema->counter--;
    pthread_mutex_unlock(&sema->mutex);
@@ -223,8 +229,9 @@ static void DRD_(sema_up)(DrdSema* sema)
    pthread_mutex_lock(&sema->mutex);
    sema->counter++;
 #ifdef HAVE_USABLE_LINUX_FUTEX_H
-   syscall(__NR_futex, (UWord)&sema->counter,
-           FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1);
+   if (sema->waiters > 0)
+      syscall(__NR_futex, (UWord)&sema->counter,
+              FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1);
 #endif
    pthread_mutex_unlock(&sema->mutex);
 }