]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Added support for sem_open() and sem_close().
authorBart Van Assche <bvanassche@acm.org>
Thu, 23 Jul 2009 16:31:39 +0000 (16:31 +0000)
committerBart Van Assche <bvanassche@acm.org>
Thu, 23 Jul 2009 16:31:39 +0000 (16:31 +0000)
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@10560

13 files changed:
drd/drd_clientreq.c
drd/drd_clientreq.h
drd/drd_pthread_intercepts.c
drd/drd_semaphore.c
drd/drd_semaphore.h
drd/tests/Makefile.am
drd/tests/sem_open.c [new file with mode: 0644]
drd/tests/sem_open.stderr.exp [new file with mode: 0644]
drd/tests/sem_open.vgtest [new file with mode: 0644]
drd/tests/sem_open2.stderr.exp [new file with mode: 0644]
drd/tests/sem_open2.vgtest [new file with mode: 0644]
drd/tests/sem_open3.stderr.exp [new file with mode: 0644]
drd/tests/sem_open3.vgtest [new file with mode: 0644]

index e888e064ed728e00736aff5c8923b9be92c8b502..3aca2d734d04cc3119b2ca0a4db35269d9624a32 100644 (file)
@@ -371,6 +371,24 @@ static Bool handle_client_request(ThreadId vg_tid, UWord* arg, UWord* ret)
          DRD_(semaphore_destroy)(arg[1]);
       break;
 
+   case VG_USERREQ__PRE_SEM_OPEN:
+      DRD_(thread_enter_synchr)(drd_tid);
+      break;
+
+   case VG_USERREQ__POST_SEM_OPEN:
+      if (DRD_(thread_leave_synchr)(drd_tid) == 0)
+         DRD_(semaphore_open)(arg[1], (Char*)arg[2], arg[3], arg[4], arg[5]);
+      break;
+
+   case VG_USERREQ__PRE_SEM_CLOSE:
+      if (DRD_(thread_enter_synchr)(drd_tid) == 0)
+         DRD_(semaphore_close)(arg[1]);
+      break;
+
+   case VG_USERREQ__POST_SEM_CLOSE:
+      DRD_(thread_leave_synchr)(drd_tid);
+      break;
+
    case VG_USERREQ__PRE_SEM_WAIT:
       if (DRD_(thread_enter_synchr)(drd_tid) == 0)
          DRD_(semaphore_pre_wait)(arg[1]);
index 7799b37eb33606a2c3fc8c3fadaf28bcfbb4e4ba..190ead5c49046d8eb39fe55281f2fbb399710949 100644 (file)
@@ -143,6 +143,18 @@ enum {
    /* To notify the drd tool of a sem_destroy call. */
    VG_USERREQ__POST_SEM_DESTROY,
    /* args: Addr sem */
+   /* To notify the drd tool of a sem_open call. */
+   VG_USERREQ__PRE_SEM_OPEN,
+   /* args: Addr name, Word oflag, Word mode, Word value */
+   /* To notify the drd tool of a sem_open call. */
+   VG_USERREQ__POST_SEM_OPEN,
+   /* args: Addr sem, Word oflag, Word mode, Word value */
+   /* To notify the drd tool of a sem_close call. */
+   VG_USERREQ__PRE_SEM_CLOSE,
+   /* args: Addr sem */
+   /* To notify the drd tool of a sem_close call. */
+   VG_USERREQ__POST_SEM_CLOSE,
+   /* args: Addr sem */
    /* To notify the drd tool of a sem_wait call. */
    VG_USERREQ__PRE_SEM_WAIT,
    /* args: Addr sem */
index 4be2e7e5bf762484c4f09721ffa26dcd24fb34fa..b2ef0184afe26e040e1ea8977c70682dd0d35d08 100644 (file)
@@ -838,6 +838,39 @@ PTH_FUNC(int, semZudestroyZa, // sem_destroy*
    return ret;
 }
 
+// sem_open
+PTH_FUNC(sem_t *, semZuopen, // sem_open
+         const char *name, int oflag, mode_t mode, unsigned int value)
+{
+   sem_t *ret;
+   int    res;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_OPEN,
+                              name, oflag, mode, value, 0);
+   CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
+   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_OPEN,
+                              ret != SEM_FAILED ? ret : 0,
+                              name, oflag, mode, value);
+   return ret;
+}
+
+// sem_close
+PTH_FUNC(int, semZuclose, // sem_close
+         sem_t *sem)
+{
+   int   ret;
+   int   res;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_CLOSE,
+                              sem, 0, 0, 0, 0);
+   CALL_FN_W_W(ret, fn, sem);
+   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_CLOSE,
+                              sem, 0, 0, 0, 0);
+   return ret;
+}
+
 // sem_wait
 PTH_FUNC(int, semZuwaitZa, // sem_wait*
          sem_t *sem)
index da3d867b3a500d7de8778fa126b56c224eacf252..f2e38e2f4f6762fac64589f20e4e39c6fd4a0273 100644 (file)
@@ -49,7 +49,7 @@ static ULong s_semaphore_segment_creation_count;
 /* Function definitions. */
 
 /** Push a segment at the end of the queue 'p->last_sem_post_seg'. */
-static void DRD_(segment_push)(struct semaphore_info* p, Segment* sg)
+static void drd_segment_push(struct semaphore_info* p, Segment* sg)
 {
    Word n;
 
@@ -63,7 +63,7 @@ static void DRD_(segment_push)(struct semaphore_info* p, Segment* sg)
 }
 
 /** Pop a segment from the beginning of the queue 'p->last_sem_post_seg'. */
-static Segment* DRD_(segment_pop)(struct semaphore_info* p)
+static Segment* drd_segment_pop(struct semaphore_info* p)
 {
    Word sz;
    Segment* sg;
@@ -94,8 +94,8 @@ void DRD_(semaphore_set_trace)(const Bool trace_semaphore)
  * client semaphore at client addres 'semaphore'.
  */
 static
-void DRD_(semaphore_initialize)(struct semaphore_info* const p,
-                                const Addr semaphore)
+void drd_semaphore_initialize(struct semaphore_info* const p,
+                              const Addr semaphore)
 {
    tl_assert(semaphore != 0);
    tl_assert(p->a1 == semaphore);
@@ -129,7 +129,7 @@ static void semaphore_cleanup(struct semaphore_info* p)
                               " upon",
                               &sei);
    }
-   while ((sg = DRD_(segment_pop)(p)))
+   while ((sg = drd_segment_pop(p)))
       DRD_(sg_put)(sg);
    VG_(deleteXA)(p->last_sem_post_seg);
 }
@@ -141,7 +141,7 @@ static void semaphore_cleanup(struct semaphore_info* p)
  */
 static
 struct semaphore_info*
-DRD_(semaphore_get_or_allocate)(const Addr semaphore)
+drd_semaphore_get_or_allocate(const Addr semaphore)
 {
    struct semaphore_info *p;
 
@@ -151,7 +151,7 @@ DRD_(semaphore_get_or_allocate)(const Addr semaphore)
    {
       tl_assert(offsetof(DrdClientobj, semaphore) == 0);
       p = &(DRD_(clientobj_add)(semaphore, ClientSemaphore)->semaphore);
-      DRD_(semaphore_initialize)(p, semaphore);
+      drd_semaphore_initialize(p, semaphore);
    }
    return p;
 }
@@ -193,14 +193,14 @@ struct semaphore_info* DRD_(semaphore_init)(const Addr semaphore,
                               "Semaphore reinitialization",
                               &SEI);
       // Remove all segments from the segment stack.
-      while ((sg = DRD_(segment_pop)(p)))
+      while ((sg = drd_segment_pop(p)))
       {
          DRD_(sg_put)(sg);
       }
    }
    else
    {
-      p = DRD_(semaphore_get_or_allocate)(semaphore);
+      p = drd_semaphore_get_or_allocate(semaphore);
    }
    tl_assert(p);
    p->waits_to_skip = value;
@@ -238,12 +238,89 @@ void DRD_(semaphore_destroy)(const Addr semaphore)
    DRD_(clientobj_remove)(semaphore, ClientSemaphore);
 }
 
+/** Called after sem_open(). */
+struct semaphore_info* DRD_(semaphore_open)(const Addr semaphore,
+                                            const Char* name, const Word oflag,
+                                            const Word mode, const UInt value)
+{
+   struct semaphore_info* p;
+   Segment* sg;
+
+   if (s_trace_semaphore)
+   {
+      VG_(message)(Vg_UserMsg,
+                   "[%d] semaphore_open      0x%lx name %s"
+                   " oflag %ld mode 0%lo value %u\n",
+                   DRD_(thread_get_running_tid)(),
+                   semaphore, name, oflag, mode, value);
+   }
+
+   /* Return if the sem_open() call failed. */
+   if (! semaphore)
+      return NULL;
+
+   p = semaphore_get(semaphore);
+   if (p)
+   {
+      const ThreadId vg_tid = VG_(get_running_tid)();
+      SemaphoreErrInfo SEI = { DRD_(thread_get_running_tid)(), semaphore };
+      VG_(maybe_record_error)(vg_tid,
+                              SemaphoreErr,
+                              VG_(get_IP)(vg_tid),
+                              "Semaphore reinitialization",
+                              &SEI);
+      // Remove all segments from the segment stack.
+      while ((sg = drd_segment_pop(p)))
+      {
+         DRD_(sg_put)(sg);
+      }
+   }
+   else
+   {
+      p = drd_semaphore_get_or_allocate(semaphore);
+   }
+   tl_assert(p);
+   p->waits_to_skip = value;
+   p->value         = value;
+   return p;
+}
+
+/** Called before sem_close(). */
+void DRD_(semaphore_close)(const Addr semaphore)
+{
+   struct semaphore_info* p;
+
+   p = semaphore_get(semaphore);
+
+   if (s_trace_semaphore)
+   {
+      VG_(message)(Vg_UserMsg,
+                   "[%d] semaphore_close     0x%lx value %u\n",
+                   DRD_(thread_get_running_tid)(),
+                   semaphore,
+                   p ? p->value : 0);
+   }
+
+   if (p == 0)
+   {
+      GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
+      VG_(maybe_record_error)(VG_(get_running_tid)(),
+                              GenericErr,
+                              VG_(get_IP)(VG_(get_running_tid)()),
+                              "Not a semaphore",
+                              &GEI);
+      return;
+   }
+
+   DRD_(clientobj_remove)(semaphore, ClientSemaphore);
+}
+
 /** Called before sem_wait(). */
 void DRD_(semaphore_pre_wait)(const Addr semaphore)
 {
    struct semaphore_info* p;
 
-   p = DRD_(semaphore_get_or_allocate)(semaphore);
+   p = drd_semaphore_get_or_allocate(semaphore);
    tl_assert(p);
    p->waiters++;
 
@@ -289,7 +366,7 @@ void DRD_(semaphore_post_wait)(const DrdThreadId tid, const Addr semaphore,
    /*
     * Note: if another thread destroyed and reinitialized a semaphore while
     * the current thread was waiting in sem_wait, p->waiters may have been
-    * set to zero by DRD_(semaphore_initialize)() after
+    * set to zero by drd_semaphore_initialize() after
     * DRD_(semaphore_pre_wait)() has finished before
     * DRD_(semaphore_post_wait)() has been called.
     */
@@ -308,7 +385,7 @@ void DRD_(semaphore_post_wait)(const DrdThreadId tid, const Addr semaphore,
       p->waits_to_skip--;
    else
    {
-      sg = DRD_(segment_pop)(p);
+      sg = drd_segment_pop(p);
       tl_assert(sg);
       if (sg)
       {
@@ -331,7 +408,7 @@ void DRD_(semaphore_pre_post)(const DrdThreadId tid, const Addr semaphore)
    struct semaphore_info* p;
    Segment* sg;
 
-   p = DRD_(semaphore_get_or_allocate)(semaphore);
+   p = drd_semaphore_get_or_allocate(semaphore);
    p->value++;
 
    if (s_trace_semaphore)
@@ -347,7 +424,7 @@ void DRD_(semaphore_pre_post)(const DrdThreadId tid, const Addr semaphore)
    sg = 0;
    DRD_(thread_get_latest_segment)(&sg, tid);
    tl_assert(sg);
-   DRD_(segment_push)(p, sg);
+   drd_segment_push(p, sg);
    DRD_(thread_new_segment)(tid);
    s_semaphore_segment_creation_count++;
 }
index b9cc1e1c5cd901aaa68d4d610b9b28221c13b6b1..3f2b8051c863ac588ba853b8b9954dabb9d0d58a 100644 (file)
@@ -42,6 +42,10 @@ struct semaphore_info* DRD_(semaphore_init)(const Addr semaphore,
                                             const Word pshared,
                                             const UInt value);
 void DRD_(semaphore_destroy)(const Addr semaphore);
+struct semaphore_info* DRD_(semaphore_open)(const Addr semaphore,
+                                            const Char* name, const Word oflag,
+                                            const Word mode, const UInt value);
+void DRD_(semaphore_close)(const Addr semaphore);
 void DRD_(semaphore_pre_wait)(const Addr semaphore);
 void DRD_(semaphore_post_wait)(const DrdThreadId tid, const Addr semaphore,
                                const Bool waited);
index c030c07daee3166c8607ee9c2b54bc74736a70a4..0bb893d84c4f74aa6dbad1fcf61d6c31d5d58400 100644 (file)
@@ -148,6 +148,12 @@ EXTRA_DIST =                                        \
        sem_as_mutex2.vgtest                        \
        sem_as_mutex3.stderr.exp                    \
        sem_as_mutex3.vgtest                        \
+       sem_open.stderr.exp                         \
+       sem_open.vgtest                             \
+       sem_open2.stderr.exp                        \
+       sem_open2.vgtest                            \
+       sem_open3.stderr.exp                        \
+       sem_open3.vgtest                            \
        sigalrm.stderr.exp                          \
        sigalrm.vgtest                              \
        tc01_simple_race.stderr.exp                 \
@@ -245,6 +251,7 @@ check_PROGRAMS =      \
   rwlock_race         \
   rwlock_test         \
   sem_as_mutex        \
+  sem_open            \
   sigalrm             \
   thread_name         \
   trylock             \
diff --git a/drd/tests/sem_open.c b/drd/tests/sem_open.c
new file mode 100644 (file)
index 0000000..0920001
--- /dev/null
@@ -0,0 +1,118 @@
+/* Use a semaphore to implement mutual exclusion. */
+
+#include <assert.h>
+#include <fcntl.h>     /* O_CREAT */
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>     /* printf() */
+#include <stdlib.h>    /* exit()  */
+#include <unistd.h>    /* sleep() */
+
+/* Local functions declarations. */
+
+static void* thread_func(void*);
+
+
+/* Local variables. */
+
+/* s_sem protects s_d3. */
+static sem_t* s_sem;
+
+static double s_d1; /* accessed before thread creation and in the created */
+                    /* thread (not a race). */
+static double s_d2; /* accessed in the created thread and after the join */
+                    /* (not a race). */
+static double s_d3; /* accessed simultaneously from both threads (race). */
+static int    s_debug     = 0;
+static int    s_do_printf = 0;
+static int    s_do_mutual_exclusion = 0;
+
+
+/* Function definitions. */
+
+int main(int argc, char** argv)
+{
+  int optchar;
+  pthread_t threadid;
+  char semaphore_name[32];
+
+  while ((optchar = getopt(argc, argv, "dmp")) != EOF)
+  {
+    switch (optchar)
+    {
+    case 'd':
+      s_debug = 1;
+      break;
+    case 'm':
+      s_do_mutual_exclusion = 1;
+      break;
+    case 'p':
+      s_do_printf = 1;
+      break;
+    default:
+      assert(0);
+    }
+  }
+
+  /*
+   * Use the ipcs and ipcrm commands to clean up named semaphores left by
+   * aborted instances of this process.
+   */
+  snprintf(semaphore_name, sizeof(semaphore_name), "sem_open-%d", getpid());
+  s_sem = sem_open(semaphore_name, O_CREAT, 0600, 1);
+  if (s_sem == SEM_FAILED)
+  {
+    fprintf(stderr, "Failed to create a semaphore with name %s\n",
+            semaphore_name);
+    exit(1);
+  }
+
+  /*
+   * Switch to line-buffered mode, such that timing information can be 
+   * obtained for each printf() call with strace.
+   */
+  setlinebuf(stdout);
+
+  if (s_debug)
+  {
+    printf("&s_d1 = %p; &s_d2 = %p; &s_d3 = %p\n", &s_d1, &s_d2, &s_d3);
+  }
+
+  s_d1 = 1;
+  s_d3 = 3;
+
+  pthread_create(&threadid, 0, thread_func, 0);
+
+  sleep(1); /* Wait until thread_func() finished. */
+
+  {
+    if (s_do_mutual_exclusion) sem_wait(s_sem);
+    s_d3++;
+    if (s_do_mutual_exclusion) sem_post(s_sem);
+  }
+
+  /* Wait until the thread finished. */
+  pthread_join(threadid, 0);
+  if (s_do_printf) printf("s_d2 = %g (should be 2)\n", s_d2);
+  if (s_do_printf) printf("s_d3 = %g (should be 5)\n", s_d3);
+
+  sem_close(s_sem);
+  sem_unlink(semaphore_name);
+
+  return 0;
+}
+
+static void* thread_func(void* thread_arg)
+{
+  if (s_do_printf)
+  {
+    printf("s_d1 = %g (should be 1)\n", s_d1);
+  }
+  s_d2 = 2;
+  {
+    if (s_do_mutual_exclusion) sem_wait(s_sem);
+    s_d3++;
+    if (s_do_mutual_exclusion) sem_post(s_sem);
+  }
+  return 0;
+}
diff --git a/drd/tests/sem_open.stderr.exp b/drd/tests/sem_open.stderr.exp
new file mode 100644 (file)
index 0000000..b94d77c
--- /dev/null
@@ -0,0 +1,20 @@
+
+Conflicting load by thread 1 at 0x........ size 8
+   at 0x........: main (sem_open.c:?)
+Location 0x........ is 0 bytes inside local var "s_d3"
+declared at sem_open.c:25, in frame #? of thread 1
+Other segment start (thread 2)
+   (thread finished, call stack no longer available)
+Other segment end (thread 2)
+   (thread finished, call stack no longer available)
+
+Conflicting store by thread 1 at 0x........ size 8
+   at 0x........: main (sem_open.c:?)
+Location 0x........ is 0 bytes inside local var "s_d3"
+declared at sem_open.c:25, in frame #? of thread 1
+Other segment start (thread 2)
+   (thread finished, call stack no longer available)
+Other segment end (thread 2)
+   (thread finished, call stack no longer available)
+
+ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
diff --git a/drd/tests/sem_open.vgtest b/drd/tests/sem_open.vgtest
new file mode 100644 (file)
index 0000000..08bb5cc
--- /dev/null
@@ -0,0 +1,3 @@
+prereq: ./supported_libpthread
+vgopts: --check-stack-var=yes --read-var-info=yes
+prog: sem_open
diff --git a/drd/tests/sem_open2.stderr.exp b/drd/tests/sem_open2.stderr.exp
new file mode 100644 (file)
index 0000000..d18786f
--- /dev/null
@@ -0,0 +1,3 @@
+
+
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/drd/tests/sem_open2.vgtest b/drd/tests/sem_open2.vgtest
new file mode 100644 (file)
index 0000000..a1ece0e
--- /dev/null
@@ -0,0 +1,4 @@
+prereq: ./supported_libpthread
+vgopts: --check-stack-var=yes --read-var-info=yes
+prog: sem_open
+args: -m
diff --git a/drd/tests/sem_open3.stderr.exp b/drd/tests/sem_open3.stderr.exp
new file mode 100644 (file)
index 0000000..fb3163d
--- /dev/null
@@ -0,0 +1,11 @@
+
+Conflicting load by thread 1 at 0x........ size 8
+   at 0x........: main (sem_open.c:?)
+Location 0x........ is 0 bytes inside local var "s_d3"
+declared at sem_open.c:25, in frame #? of thread 1
+Other segment start (thread 2)
+   (thread finished, call stack no longer available)
+Other segment end (thread 2)
+   (thread finished, call stack no longer available)
+
+ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
diff --git a/drd/tests/sem_open3.vgtest b/drd/tests/sem_open3.vgtest
new file mode 100644 (file)
index 0000000..02e49d0
--- /dev/null
@@ -0,0 +1,3 @@
+prereq: ./supported_libpthread
+vgopts: --check-stack-var=yes --first-race-only=yes --read-var-info=yes
+prog: sem_open