Implement semaphore functions.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@295 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_libpthread.c b/coregrind/vg_libpthread.c
index c9956cc..960d301 100644
--- a/coregrind/vg_libpthread.c
+++ b/coregrind/vg_libpthread.c
@@ -1542,6 +1542,153 @@
 
 
 /* ---------------------------------------------------------------------
+   Hacky implementation of semaphores.
+   ------------------------------------------------------------------ */
+
+#include <semaphore.h>
+
+/* This is a terrible way to do the remapping.  Plan is to import an
+   AVL tree at some point. */
+#define VG_N_SEMAPHORES 50
+
+typedef
+   struct {
+      pthread_mutex_t se_mx;
+      pthread_cond_t se_cv;
+      int count;
+   }
+   vg_sem_t;
+
+static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
+
+static int      se_remap_used = 0;
+static sem_t*   se_remap_orig[VG_N_SEMAPHORES];
+static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
+
+static vg_sem_t* se_remap ( sem_t* orig )
+{
+   int res, i;
+   res = __pthread_mutex_lock(&se_remap_mx);
+   assert(res == 0);
+
+   for (i = 0; i < se_remap_used; i++) {
+      if (se_remap_orig[i] == orig)
+         break;
+   }
+   if (i == se_remap_used) {
+      if (se_remap_used == VG_N_SEMAPHORES) {
+         res = pthread_mutex_unlock(&se_remap_mx);
+         assert(res == 0);
+         barf("N_SEMAPHORES is too low.  Increase and recompile.");
+      }
+      se_remap_used++;
+      se_remap_orig[i] = orig;
+      /* printf("allocated semaphore %d\n", i); */
+   }
+   res = __pthread_mutex_unlock(&se_remap_mx);
+   assert(res == 0);
+   return &se_remap_new[i];
+}
+
+
+int sem_init(sem_t *sem, int pshared, unsigned int value)
+{
+   int       res;
+   vg_sem_t* vg_sem;
+   ensure_valgrind("sem_init");
+   if (pshared != 0) {
+      errno = ENOSYS;
+      return -1;
+   }
+   vg_sem = se_remap(sem);
+   res = pthread_mutex_init(&vg_sem->se_mx, NULL);
+   assert(res == 0);
+   res = pthread_cond_init(&vg_sem->se_cv, NULL);
+   assert(res == 0);
+   vg_sem->count = value;
+   return 0;
+}
+
+
+int sem_wait ( sem_t* sem ) 
+{
+   int       res;
+   vg_sem_t* vg_sem;
+   ensure_valgrind("sem_wait");
+   vg_sem = se_remap(sem);
+   res = __pthread_mutex_lock(&vg_sem->se_mx);
+   assert(res == 0);
+   while (vg_sem->count == 0) {
+      res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
+      assert(res == 0);
+   }
+   vg_sem->count--;
+   res = __pthread_mutex_unlock(&vg_sem->se_mx);
+   assert(res == 0);
+   return 0;
+}
+
+int sem_post ( sem_t* sem ) 
+{
+   int       res;
+   vg_sem_t* vg_sem; 
+   ensure_valgrind("sem_post");
+   vg_sem = se_remap(sem);
+   res = __pthread_mutex_lock(&vg_sem->se_mx);
+   assert(res == 0);
+   if (vg_sem->count == 0) {
+      vg_sem->count++;
+      res = pthread_cond_broadcast(&vg_sem->se_cv);
+      assert(res == 0);
+   } else {
+      vg_sem->count++;
+   }
+   res = __pthread_mutex_unlock(&vg_sem->se_mx);
+   assert(res == 0);
+   return 0;
+}
+
+
+int sem_trywait ( sem_t* sem ) 
+{
+   int       ret, res;
+   vg_sem_t* vg_sem; 
+   ensure_valgrind("sem_trywait");
+   vg_sem = se_remap(sem);
+   res = __pthread_mutex_lock(&vg_sem->se_mx);
+   assert(res == 0);
+   if (vg_sem->count > 0) { 
+      vg_sem->count--; 
+      ret = 0; 
+   } else { 
+      ret = -1; 
+      errno = EAGAIN; 
+   }
+   res = __pthread_mutex_unlock(&vg_sem->se_mx);
+   assert(res == 0);
+   return ret;
+}
+
+
+int sem_getvalue(sem_t* sem, int * sval)
+{
+   vg_sem_t* vg_sem; 
+   ensure_valgrind("sem_trywait");
+   vg_sem = se_remap(sem);
+   *sval = vg_sem->count;
+   return 0;
+}
+
+
+int sem_destroy(sem_t * sem)
+{
+   kludged("sem_destroy");
+   /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
+   return 0;
+}
+
+
+/* ---------------------------------------------------------------------
    B'stard.
    ------------------------------------------------------------------ */