(David Lee, <david.lee@teracruz.com>)
This patch fixes a semaphore leak within valgrind. If your application
dynamically allocates/releases semaphores, you will very quickly run out.
Also, as a nice side effect, it implements sem_destroy properly.
(me)
Protect sem_getvalue with a lock/unlock of the semaphore's mutex,
like the other routines do.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2153 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/arch/x86-linux/vg_libpthread.c b/coregrind/arch/x86-linux/vg_libpthread.c
index c13063f..5bb198e 100644
--- a/coregrind/arch/x86-linux/vg_libpthread.c
+++ b/coregrind/arch/x86-linux/vg_libpthread.c
@@ -2253,6 +2253,7 @@
pthread_mutex_t se_mx;
pthread_cond_t se_cv;
int count;
+ int waiters;
}
vg_sem_t;
@@ -2287,6 +2288,29 @@
return &se_remap_new[i];
}
+static void se_unmap( sem_t* orig )
+{
+ int res, i;
+ res = __pthread_mutex_lock(&se_remap_mx);
+ my_assert(res == 0);
+
+ for (i = 0; i < se_remap_used; i++) {
+ if (se_remap_orig[i] == orig)
+ break;
+ }
+ if (i == se_remap_used) {
+ res = pthread_mutex_unlock(&se_remap_mx);
+ my_assert(res == 0);
+ barf("se_unmap: unmapping invalid semaphore");
+ } else {
+ se_remap_orig[i] = se_remap_orig[--se_remap_used];
+ se_remap_orig[se_remap_used] = 0;
+ memset(&se_remap_new[se_remap_used], 0,
+ sizeof(se_remap_new[se_remap_used]));
+ }
+ res = pthread_mutex_unlock(&se_remap_mx);
+ my_assert(res == 0);
+}
int sem_init(sem_t *sem, int pshared, unsigned int value)
{
@@ -2317,7 +2341,9 @@
res = __pthread_mutex_lock(&vg_sem->se_mx);
my_assert(res == 0);
while (vg_sem->count == 0) {
+ ++vg_sem->waiters;
res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
+ --vg_sem->waiters;
my_assert(res == 0);
}
vg_sem->count--;
@@ -2370,18 +2396,42 @@
int sem_getvalue(sem_t* sem, int * sval)
{
+ int res;
vg_sem_t* vg_sem;
- ensure_valgrind("sem_trywait");
+ ensure_valgrind("sem_getvalue");
vg_sem = se_remap(sem);
+ res = __pthread_mutex_lock(&vg_sem->se_mx);
+ my_assert(res == 0);
*sval = vg_sem->count;
+ res = __pthread_mutex_unlock(&vg_sem->se_mx);
+ my_assert(res == 0);
return 0;
}
int sem_destroy(sem_t * sem)
{
- kludged("sem_destroy", "(it always succeeds, even if semaphore waited on)");
/* if someone waiting on this semaphore, errno = EBUSY, return -1 */
+ vg_sem_t* vg_sem;
+ int res;
+ ensure_valgrind("sem_destroy");
+ vg_sem = se_remap(sem);
+ res = __pthread_mutex_lock(&vg_sem->se_mx);
+ my_assert(res == 0);
+ if (vg_sem->waiters > 0)
+ {
+ *(__errno_location()) = EBUSY;
+ res = __pthread_mutex_unlock(&vg_sem->se_mx);
+ my_assert(res == 0);
+ return -1;
+ }
+ res = pthread_cond_destroy(&vg_sem->se_cv);
+ my_assert(res == 0);
+ res = __pthread_mutex_unlock(&vg_sem->se_mx);
+ my_assert(res == 0);
+ res = pthread_mutex_destroy(&vg_sem->se_mx);
+ my_assert(res == 0);
+ se_unmap(sem);
return 0;
}
@@ -2395,7 +2445,9 @@
res = __pthread_mutex_lock(&vg_sem->se_mx);
my_assert(res == 0);
while ( vg_sem->count == 0 && res != ETIMEDOUT ) {
+ ++vg_sem->waiters;
res = pthread_cond_timedwait(&vg_sem->se_cv, &vg_sem->se_mx, abstime);
+ --vg_sem->waiters;
}
if ( vg_sem->count > 0 ) {
vg_sem->count--;
diff --git a/coregrind/vg_libpthread.c b/coregrind/vg_libpthread.c
index c13063f..5bb198e 100644
--- a/coregrind/vg_libpthread.c
+++ b/coregrind/vg_libpthread.c
@@ -2253,6 +2253,7 @@
pthread_mutex_t se_mx;
pthread_cond_t se_cv;
int count;
+ int waiters;
}
vg_sem_t;
@@ -2287,6 +2288,29 @@
return &se_remap_new[i];
}
+static void se_unmap( sem_t* orig )
+{
+ int res, i;
+ res = __pthread_mutex_lock(&se_remap_mx);
+ my_assert(res == 0);
+
+ for (i = 0; i < se_remap_used; i++) {
+ if (se_remap_orig[i] == orig)
+ break;
+ }
+ if (i == se_remap_used) {
+ res = pthread_mutex_unlock(&se_remap_mx);
+ my_assert(res == 0);
+ barf("se_unmap: unmapping invalid semaphore");
+ } else {
+ se_remap_orig[i] = se_remap_orig[--se_remap_used];
+ se_remap_orig[se_remap_used] = 0;
+ memset(&se_remap_new[se_remap_used], 0,
+ sizeof(se_remap_new[se_remap_used]));
+ }
+ res = pthread_mutex_unlock(&se_remap_mx);
+ my_assert(res == 0);
+}
int sem_init(sem_t *sem, int pshared, unsigned int value)
{
@@ -2317,7 +2341,9 @@
res = __pthread_mutex_lock(&vg_sem->se_mx);
my_assert(res == 0);
while (vg_sem->count == 0) {
+ ++vg_sem->waiters;
res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
+ --vg_sem->waiters;
my_assert(res == 0);
}
vg_sem->count--;
@@ -2370,18 +2396,42 @@
int sem_getvalue(sem_t* sem, int * sval)
{
+ int res;
vg_sem_t* vg_sem;
- ensure_valgrind("sem_trywait");
+ ensure_valgrind("sem_getvalue");
vg_sem = se_remap(sem);
+ res = __pthread_mutex_lock(&vg_sem->se_mx);
+ my_assert(res == 0);
*sval = vg_sem->count;
+ res = __pthread_mutex_unlock(&vg_sem->se_mx);
+ my_assert(res == 0);
return 0;
}
int sem_destroy(sem_t * sem)
{
- kludged("sem_destroy", "(it always succeeds, even if semaphore waited on)");
/* if someone waiting on this semaphore, errno = EBUSY, return -1 */
+ vg_sem_t* vg_sem;
+ int res;
+ ensure_valgrind("sem_destroy");
+ vg_sem = se_remap(sem);
+ res = __pthread_mutex_lock(&vg_sem->se_mx);
+ my_assert(res == 0);
+ if (vg_sem->waiters > 0)
+ {
+ *(__errno_location()) = EBUSY;
+ res = __pthread_mutex_unlock(&vg_sem->se_mx);
+ my_assert(res == 0);
+ return -1;
+ }
+ res = pthread_cond_destroy(&vg_sem->se_cv);
+ my_assert(res == 0);
+ res = __pthread_mutex_unlock(&vg_sem->se_mx);
+ my_assert(res == 0);
+ res = pthread_mutex_destroy(&vg_sem->se_mx);
+ my_assert(res == 0);
+ se_unmap(sem);
return 0;
}
@@ -2395,7 +2445,9 @@
res = __pthread_mutex_lock(&vg_sem->se_mx);
my_assert(res == 0);
while ( vg_sem->count == 0 && res != ETIMEDOUT ) {
+ ++vg_sem->waiters;
res = pthread_cond_timedwait(&vg_sem->se_cv, &vg_sem->se_mx, abstime);
+ --vg_sem->waiters;
}
if ( vg_sem->count > 0 ) {
vg_sem->count--;