|
From: <sv...@va...> - 2012-01-23 17:06:39
|
Author: bart
Date: 2012-01-23 17:01:58 +0000 (Mon, 23 Jan 2012)
New Revision: 12351
Log:
drd, semaphore implementation: Only wake the associated futex if at least one thread is waiting
Modified:
trunk/drd/drd_pthread_intercepts.c
Modified: trunk/drd/drd_pthread_intercepts.c
===================================================================
--- trunk/drd/drd_pthread_intercepts.c 2012-01-22 08:58:31 UTC (rev 12350)
+++ trunk/drd/drd_pthread_intercepts.c 2012-01-23 17:01:58 UTC (rev 12351)
@@ -138,6 +138,7 @@
typedef struct {
pthread_mutex_t mutex;
int counter;
+ int waiters;
} DrdSema;
typedef struct
@@ -183,6 +184,7 @@
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 @@
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 @@
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);
}
|