]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Remove the limit on the number of pthread read/write locks. This works
authorTom Hughes <tom@compton.nu>
Sat, 16 Oct 2004 14:49:53 +0000 (14:49 +0000)
committerTom Hughes <tom@compton.nu>
Sat, 16 Oct 2004 14:49:53 +0000 (14:49 +0000)
in a similar way to the previous patch that removed the limit on the
number of semaphores and fixes bug 86264.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2776

corecheck/tests/.cvsignore
corecheck/tests/Makefile.am
corecheck/tests/pth_rwlock.c [new file with mode: 0644]
corecheck/tests/pth_rwlock.stderr.exp [new file with mode: 0644]
corecheck/tests/pth_rwlock.vgtest [new file with mode: 0644]
coregrind/core.h
coregrind/vg_libpthread.c

index 5ef412432f58a338f73689580d7d767c61644a0e..bcb560cb6a6cc93ff41e626e31cb174cfa1f1649 100644 (file)
@@ -10,6 +10,7 @@ pth_cvsimple
 pth_empty
 pth_mutexspeed
 pth_once
+pth_rwlock
 res_search
 .ktemp
 *.stdout.diff
index f422e39b7c72a986cbec6020339fbf4bd75f5796..90658326f7320e03a4459f6189d16b5ccbebf2c3 100644 (file)
@@ -28,6 +28,7 @@ EXTRA_DIST = $(noinst_SCRIPTS) \
        pth_mutexspeed.stderr.exp \
        pth_mutexspeed.stdout.exp pth_mutexspeed.vgtest \
        pth_once.stderr.exp pth_once.stdout.exp pth_once.vgtest \
+       pth_rwlock.stderr.exp pth_rwlock.vgtest \
        sigkill.stderr.exp sigkill.vgtest \
        res_search.stderr.exp res_search.stdout.exp res_search.vgtest \
        vgprintf.stderr.exp vgprintf.stdout.exp vgprintf.vgtest
@@ -37,7 +38,7 @@ check_PROGRAMS = \
        fdleak_fcntl fdleak_ipv4 fdleak_open fdleak_pipe \
        fdleak_socketpair sigkill res_search \
        pth_atfork1 pth_cancel1 pth_cancel2 pth_cvsimple pth_empty \
-       pth_exit pth_exit2 pth_mutexspeed pth_once \
+       pth_exit pth_exit2 pth_mutexspeed pth_once pth_rwlock \
        as_mmap as_shm \
        vgprintf
 
@@ -81,6 +82,8 @@ pth_mutexspeed_SOURCES        = pth_mutexspeed.c
 pth_mutexspeed_LDADD   = -lpthread
 pth_once_SOURCES       = pth_once.c
 pth_once_LDADD         = -lpthread
+pth_rwlock_SOURCES     = pth_rwlock.c
+pth_rwlock_LDADD       = -lpthread
 res_search_SOURCES      = res_search.c
 res_search_LDADD        = -lresolv -lpthread
 
diff --git a/corecheck/tests/pth_rwlock.c b/corecheck/tests/pth_rwlock.c
new file mode 100644 (file)
index 0000000..75486ea
--- /dev/null
@@ -0,0 +1,31 @@
+#define _XOPEN_SOURCE 600
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOCKS 2000
+
+int main(int argc, char **argv)
+{
+  pthread_rwlock_t locks[LOCKS];
+  int n;
+  int e;
+  
+  for (n = 0; n < LOCKS; n++) {
+    if ((e = pthread_rwlock_init(locks + n, NULL)) != 0) {
+      fprintf(stderr, "pthread_rwlock_init[%d]: %s\n", n, strerror(e));
+      exit(1);
+    }
+  }
+   
+  for (n = 0; n < LOCKS; n++) {
+    if ((e = pthread_rwlock_destroy(locks + n)) != 0) {
+      fprintf(stderr, "pthread_rwlock_destroy[%d]: %s\n", n, strerror(e));
+      exit(1);
+    }
+  }
+  exit(0);
+}
diff --git a/corecheck/tests/pth_rwlock.stderr.exp b/corecheck/tests/pth_rwlock.stderr.exp
new file mode 100644 (file)
index 0000000..67c7b38
--- /dev/null
@@ -0,0 +1,12 @@
+
+warning: Valgrind's pthread_cond_destroy is incomplete
+         (it doesn't check if the cond is waited on)
+         your program may misbehave as a result
+warning: Valgrind's pthread_cond_destroy is incomplete
+         (it doesn't check if the cond is waited on)
+         your program may misbehave as a result
+warning: Valgrind's pthread_cond_destroy is incomplete
+         (it doesn't check if the cond is waited on)
+         your program may misbehave as a result
+
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/corecheck/tests/pth_rwlock.vgtest b/corecheck/tests/pth_rwlock.vgtest
new file mode 100644 (file)
index 0000000..3a66473
--- /dev/null
@@ -0,0 +1 @@
+prog: pth_rwlock
index afc316177ab9e3554088448db87bc33a488ed3d5..89d93a8925ac7407bdab3a82a5cce5d8ea58410f 100644 (file)
    beyond it. */
 #define VG_PTHREAD_STACK_SIZE (1 << 20)
 
-/* Number of entries in the rwlock-remapping table. */
-#define VG_N_RWLOCKS 500
-
 /* Number of entries in each thread's cleanup stack. */
 #define VG_N_CLEANUPSTACK 16
 
index c5c4bde59c35d26d06132cc99883a1076d228f27..b16038055fe67e26aa79643dd31dee12f39b2122 100644 (file)
@@ -2943,7 +2943,6 @@ int sem_timedwait(sem_t* sem, const struct timespec *abstime)
 
 typedef 
    struct {
-      int             initted;  /* != 0 --> in use; sanity check only */
       int             prefer_w; /* != 0 --> prefer writer */
       int             nwait_r;  /* # of waiting readers */
       int             nwait_w;  /* # of waiting writers */
@@ -2957,18 +2956,14 @@ typedef
    vg_rwlock_t;
 
 
-static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t rw_new_mx = PTHREAD_MUTEX_INITIALIZER;
 
-static int                 rw_remap_used = 0;
-static pthread_rwlock_t*   rw_remap_orig[VG_N_RWLOCKS];
-static vg_rwlock_t         rw_remap_new[VG_N_RWLOCKS];
+#define RWLOCK_CHECK_MAGIC 0xb5d17027
 
 
-static 
-void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
+static void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
 {
    int res = 0;
-   vg_rwl->initted = 1;
    vg_rwl->prefer_w = 1;
    vg_rwl->nwait_r = 0;
    vg_rwl->nwait_w = 0;
@@ -2979,54 +2974,71 @@ void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
    my_assert(res == 0);
 }
 
-
-/* Take the address of a LinuxThreads rwlock_t and return the shadow
-   address of our version.  Further, if the LinuxThreads version
-   appears to have been statically initialised, do the same to the one
-   we allocate here.  The vg_pthread_rwlock_t.__vg_rw_readers field is set
-   to zero by PTHREAD_RWLOCK_INITIALIZER (as are several other fields), so
-   we take zero as meaning uninitialised and non-zero meaning initialised. 
-*/
-static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
+static vg_rwlock_t* rw_new ( pthread_rwlock_t* orig )
 {
-   int          res, i;
-   vg_rwlock_t* vg_rwl;
+   int res;
+   vg_rwlock_t* rwl;
    vg_pthread_rwlock_t* vg_orig;
-   
-   res = __pthread_mutex_lock(&rw_remap_mx);
+   CONVERT(rwlock, orig, vg_orig);
+
+   res = __pthread_mutex_lock(&rw_new_mx);
    my_assert(res == 0);
 
-   for (i = 0; i < rw_remap_used; i++) {
-      if (rw_remap_orig[i] == orig)
-         break;
-   }
-   if (i == rw_remap_used) {
-      if (rw_remap_used == VG_N_RWLOCKS) {
-         res = __pthread_mutex_unlock(&rw_remap_mx);
-         my_assert(res == 0);
-         barf("VG_N_RWLOCKS is too low.  Increase and recompile.");
-      }
-      rw_remap_used++;
-      rw_remap_orig[i] = orig;
-      rw_remap_new[i].initted = 0;
-      if (0) printf("allocated rwlock %d\n", i);
-   }
-   res = __pthread_mutex_unlock(&rw_remap_mx);
+   rwl = my_malloc(sizeof(vg_rwlock_t));
+
+   vg_orig->__vg_rw_writer = rwl;
+   vg_orig->__vg_rw_read_waiting = (void *)((Addr)rwl ^ RWLOCK_CHECK_MAGIC);
+
+   init_vg_rwlock(rwl);
+   if (vg_orig->__vg_rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
+      rwl->prefer_w = 0;
+
+   res = __pthread_mutex_unlock(&rw_new_mx);
    my_assert(res == 0);
-   vg_rwl = &rw_remap_new[i];
+  
+   return rwl;
+}
 
-   /* Initialise the shadow, if required. */
+static vg_rwlock_t* rw_lookup ( pthread_rwlock_t* orig )
+{
+   vg_rwlock_t* rwl;
+   vg_pthread_rwlock_t* vg_orig;
    CONVERT(rwlock, orig, vg_orig);
-   if (vg_orig->__vg_rw_readers == 0) {
-      vg_orig->__vg_rw_readers = 1;
-      init_vg_rwlock(vg_rwl);
-      if (vg_orig->__vg_rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
-         vg_rwl->prefer_w = 0;
-   }
 
-   return vg_rwl;
+   if (vg_orig->__vg_rw_writer == NULL)
+      rwl = rw_new (orig);
+   else if (((Addr)vg_orig->__vg_rw_writer ^ RWLOCK_CHECK_MAGIC) == (Addr)vg_orig->__vg_rw_read_waiting)
+      rwl = vg_orig->__vg_rw_writer;
+   else
+      rwl = NULL;
+
+   return rwl;
 }
 
+static void rw_free ( pthread_rwlock_t* orig )
+{
+   int res;
+   vg_rwlock_t* rwl;
+   vg_pthread_rwlock_t* vg_orig;
+   CONVERT(rwlock, orig, vg_orig);
+
+   rwl = vg_orig->__vg_rw_writer;
+
+   vg_orig->__vg_rw_writer = NULL;
+   vg_orig->__vg_rw_read_waiting = NULL;
+
+   res = __pthread_mutex_unlock(&rwl->mx);
+   my_assert(res == 0);
+
+   res = pthread_cond_destroy(&rwl->cv_w);
+   res |= pthread_cond_destroy(&rwl->cv_r);
+   res |= pthread_mutex_destroy(&rwl->mx);
+   my_assert(res == 0);
+
+   my_free(rwl);
+
+   return;
+}
 
 int pthread_rwlock_init ( pthread_rwlock_t* orig,
                           const pthread_rwlockattr_t* attr )
@@ -3038,13 +3050,13 @@ int pthread_rwlock_init ( pthread_rwlock_t* orig,
    CONVERT(rwlockattr, attr, vg_attr);
 
    if (0) printf ("pthread_rwlock_init\n");
-   /* Force the remapper to initialise the shadow. */
-   vg_orig->__vg_rw_readers = 0;
    /* Install the lock preference; the remapper needs to know it. */
-   vg_orig->__vg_rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
    if (vg_attr)
       vg_orig->__vg_rw_kind = vg_attr->__vg_lockkind;
-   rwl = rw_remap ( (pthread_rwlock_t*)vg_orig );
+   else
+      vg_orig->__vg_rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
+   /* Allocate the shadow */
+   rwl = rw_new ((pthread_rwlock_t *)vg_orig);
    return 0;
 }
 
@@ -3064,14 +3076,13 @@ int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
    vg_rwlock_t* rwl;
 
    if (0) printf ("pthread_rwlock_rdlock\n");
-   rwl = rw_remap ( orig );
-   res = __pthread_mutex_lock(&rwl->mx);
-   my_assert(res == 0);
-   if (!rwl->initted) {
-      res = __pthread_mutex_unlock(&rwl->mx);
-      my_assert(res == 0);
+   rwl = rw_lookup (orig);
+   if(!rwl) {
+      pthread_error("pthread_rwlock_rdlock: lock overwritten or not initialized");
       return EINVAL;
    }
+   res = __pthread_mutex_lock(&rwl->mx);
+   my_assert(res == 0);
    if (rwl->status < 0) {
       my_assert(rwl->status == -1);
       rwl->nwait_r++;
@@ -3098,14 +3109,13 @@ int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
    vg_rwlock_t* rwl;
 
    if (0) printf ("pthread_rwlock_tryrdlock\n");
-   rwl = rw_remap ( orig );
-   res = __pthread_mutex_lock(&rwl->mx);
-   my_assert(res == 0);
-   if (!rwl->initted) {
-      res = __pthread_mutex_unlock(&rwl->mx);
-      my_assert(res == 0);
+   rwl = rw_lookup (orig);
+   if(!rwl) {
+      pthread_error("pthread_rwlock_tryrdlock: lock overwritten or not initialized");
       return EINVAL;
    }
+   res = __pthread_mutex_lock(&rwl->mx);
+   my_assert(res == 0);
    if (rwl->status == -1) {
       /* Writer active; we have to give up. */
       res = __pthread_mutex_unlock(&rwl->mx);
@@ -3136,14 +3146,13 @@ int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
    vg_rwlock_t* rwl;
 
    if (0) printf ("pthread_rwlock_wrlock\n");
-   rwl = rw_remap ( orig );
-   res = __pthread_mutex_lock(&rwl->mx);
-   my_assert(res == 0);
-   if (!rwl->initted) {
-      res = __pthread_mutex_unlock(&rwl->mx);
-      my_assert(res == 0);
+   rwl = rw_lookup (orig);
+   if(!rwl) {
+      pthread_error("pthread_rwlock_wrlock: lock overwritten or not initialized");
       return EINVAL;
    }
+   res = __pthread_mutex_lock(&rwl->mx);
+   my_assert(res == 0);
    if (rwl->status != 0) {
       rwl->nwait_w++;
       pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
@@ -3168,14 +3177,13 @@ int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
    int res;
    vg_rwlock_t* rwl;
    if (0) printf ("pthread_wrlock_trywrlock\n");
-   rwl = rw_remap ( orig );
-   res = __pthread_mutex_lock(&rwl->mx);
-   my_assert(res == 0);
-   if (!rwl->initted) {
-      res = __pthread_mutex_unlock(&rwl->mx);
-      my_assert(res == 0);
+   rwl = rw_lookup (orig);
+   if(!rwl) {
+      pthread_error("pthread_rwlock_trywrlock: lock overwritten or not initialized");
       return EINVAL;
    }
+   res = __pthread_mutex_lock(&rwl->mx);
+   my_assert(res == 0);
    if (rwl->status != 0) {
       /* Reader(s) or a writer active; we have to give up. */
       res = __pthread_mutex_unlock(&rwl->mx);
@@ -3196,14 +3204,13 @@ int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
    int res;
    vg_rwlock_t* rwl;
    if (0) printf ("pthread_rwlock_unlock\n");
-   rwl = rw_remap ( orig );
-   res = __pthread_mutex_lock(&rwl->mx);
-   my_assert(res == 0);
-   if (!rwl->initted) {
-      res = __pthread_mutex_unlock(&rwl->mx);
-      my_assert(res == 0);
+   rwl = rw_lookup (orig);
+   if(!rwl) {
+      pthread_error("pthread_rwlock_unlock: lock overwritten or not initialized");
       return EINVAL;
    }
+   res = __pthread_mutex_lock(&rwl->mx);
+   my_assert(res == 0);
    if (rwl->status == 0) {
       res = __pthread_mutex_unlock(&rwl->mx);
       my_assert(res == 0);
@@ -3271,22 +3278,19 @@ int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
    int res;
    vg_rwlock_t* rwl;
    if (0) printf ("pthread_rwlock_destroy\n");
-   rwl = rw_remap ( orig );
-   res = __pthread_mutex_lock(&rwl->mx);
-   my_assert(res == 0);
-   if (!rwl->initted) {
-      res = __pthread_mutex_unlock(&rwl->mx);
-      my_assert(res == 0);
+   rwl = rw_lookup (orig);
+   if(!rwl) {
+      pthread_error("pthread_rwlock_destroy: lock overwritten or not initialized");
       return EINVAL;
    }
+   res = __pthread_mutex_lock(&rwl->mx);
+   my_assert(res == 0);
    if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
       res = __pthread_mutex_unlock(&rwl->mx);
       my_assert(res == 0);
       return EBUSY;
    }
-   rwl->initted = 0;
-   res = __pthread_mutex_unlock(&rwl->mx);
-   my_assert(res == 0);
+   rw_free (orig);
    return 0;
 }