Make rwlock try and timed functions optional.
authorMarcus Brinkmann <marcus.brinkmann@ruhr-uni-bochum.de>
Tue, 28 Feb 2012 15:52:07 +0000 (16:52 +0100)
committerMarcus Brinkmann <marcus.brinkmann@ruhr-uni-bochum.de>
Tue, 28 Feb 2012 15:52:07 +0000 (16:52 +0100)
* configure.ac: Check for pthread_rwlock_rdlock, pthread_rwlock_wrlock,
pthread_rwlock_timedrdlock, pthread_rwlock_timedwrlock,
pthread_rwlock_tryrdlock, pthread_rwlock_trywrlock.
* src/npth.c (trylock_func_t): New type.
(busy_wait_for): New function.
(npth_mutex_timedlock) [!HAVE_PTHREAD_MUTEX_TIMEDLOCK]: Reimplement
in terms of busy_wait_for.
(npth_rwlock_rdlock, npth_rwlock_timedrdlock)
[!HAVE_PTHREAD_RWLOCK_TRYRDLOCK]: Skip trylock.
(npth_rwlock_wrlock, npth_rwlock_timedwrlock)
[!HAVE_PTHREAD_RWLOCK_TRYWRLOCK]: Skip trylock call.
(npth_rwlock_timedrdlock) [!HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK]:
Use busy_wait_for.
(npth_rwlock_timedwrlock) [!HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK]:
Use busy_wait_for.

configure.ac
src/npth.c

index c32480e..ad73027 100644 (file)
@@ -216,6 +216,9 @@ if test "$have_w32_system" = no; then
     AC_DEFINE(HAVE_PTHREAD,1,[Define if we have pthread.])
     AC_CHECK_FUNCS([pthread_tryjoin_np pthread_setname_np pthread_getname_np])
     AC_CHECK_FUNCS([pthread_mutex_timedlock])
+    AC_CHECK_FUNCS([pthread_rwlock_rdlock pthread_rwlock_wrlock])
+    AC_CHECK_FUNCS([pthread_rwlock_timedrdlock pthread_rwlock_timedwrlock])
+    AC_CHECK_FUNCS([pthread_rwlock_tryrdlock pthread_rwlock_trywrlock])
   fi
 fi
 
index 07d228b..fb63f13 100644 (file)
@@ -66,6 +66,47 @@ static pthread_t main_thread;
    milliseconds.  */
 #define BUSY_WAIT_INTERVAL 200
 
+typedef int (*trylock_func_t) (void *);
+
+static int
+busy_wait_for (trylock_func_t trylock, void *lock,
+              const struct timespec *abstime)
+{
+  int err;
+
+  /* This is not great, but better than nothing.  Only works for locks
+     which are mostly uncontested.  Provides absolutely no fairness at
+     all.  Creates many wake-ups.  */
+  while (1)
+    {
+      struct timespec ts;
+      err = npth_clock_gettime (&ts);
+      if (err < 0)
+       {
+         /* Just for safety make sure we return some error.  */
+         err = errno ? errno : EINVAL;
+         break;
+       }
+
+      if (! npth_timercmp (abstime, &ts, <))
+       {
+         err = ETIMEDOUT;
+         break;
+       }
+
+      err = (*trylock) (lock);
+      if (err != EBUSY)
+       break;
+
+      /* Try again after waiting a bit.  We could calculate the
+        maximum wait time from ts and abstime, but we don't
+        bother, as our granularity is pretty fine.  */
+      usleep (BUSY_WAIT_INTERVAL * 1000);
+    }
+
+  return err;
+}
+
 \f
 static void
 enter_npth (const char *function)
@@ -257,42 +298,11 @@ npth_mutex_timedlock (npth_mutex_t *mutex, const struct timespec *abstime)
     return err;
 
   ENTER();
-
 #if HAVE_PTHREAD_MUTEX_TIMEDLOCK
   err = pthread_mutex_timedlock (mutex, abstime);
 #else
-  /* This is not great, but better than nothing.  Only works for locks
-     which are mostly uncontested.  Provides absolutely no fairness at
-     all.  Creates many wake-ups.  */
-  while (1)
-    {
-      struct timespec ts;
-      err = npth_clock_gettime (&ts);
-      if (err < 0)
-       {
-         /* Just for safety make sure we return some error.  */
-         err = errno ? errno : EINVAL;
-         break;
-       }
-
-      if (! npth_timercmp (abstime, &ts, <))
-       {
-         err = ETIMEDOUT;
-         break;
-       }
-
-      err = pthread_mutex_trylock (mutex);
-      if (err != EBUSY)
-       break;
-
-      /* Try again after waiting a bit.  We could calculate the
-        maximum wait time from ts and abstime, but we don't
-        bother, as our granularity is pretty fine.  */
-      usleep (BUSY_WAIT_INTERVAL * 1000);
-    }
-
+  err = busy_wait_for ((trylock_func_t) pthread_mutex_trylock, mutex, abstime);
 #endif
-
   LEAVE();
   return err;
 }
@@ -303,11 +313,13 @@ npth_rwlock_rdlock (npth_rwlock_t *rwlock)
 {
   int err;
 
+#ifdef HAVE_PTHREAD_RWLOCK_TRYRDLOCK
   /* No need to allow competing threads to enter when we can get the
      lock immediately.  */
   err = pthread_rwlock_tryrdlock (rwlock);
   if (err != EBUSY)
     return err;
+#endif
 
   ENTER();
   err = pthread_rwlock_rdlock (rwlock);
@@ -321,14 +333,21 @@ npth_rwlock_timedrdlock (npth_rwlock_t *rwlock, const struct timespec *abstime)
 {
   int err;
 
+#ifdef HAVE_PTHREAD_RWLOCK_TRYRDLOCK
   /* No need to allow competing threads to enter when we can get the
      lock immediately.  */
   err = pthread_rwlock_tryrdlock (rwlock);
   if (err != EBUSY)
     return err;
+#endif
 
   ENTER();
+#if HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK
   err = pthread_rwlock_timedrdlock (rwlock, abstime);
+#else
+  err = busy_wait_for ((trylock_func_t) pthread_rwlock_tryrdlock, rwlock,
+                      abstime);
+#endif
   LEAVE();
   return err;
 }
@@ -339,11 +358,13 @@ npth_rwlock_wrlock (npth_rwlock_t *rwlock)
 {
   int err;
 
+#ifdef HAVE_PTHREAD_RWLOCK_TRYWRLOCK
   /* No need to allow competing threads to enter when we can get the
      lock immediately.  */
   err = pthread_rwlock_trywrlock (rwlock);
   if (err != EBUSY)
     return err;
+#endif
 
   ENTER();
   err = pthread_rwlock_wrlock (rwlock);
@@ -357,14 +378,21 @@ npth_rwlock_timedwrlock (npth_rwlock_t *rwlock, const struct timespec *abstime)
 {
   int err;
 
+#ifdef HAVE_PTHREAD_RWLOCK_TRYWRLOCK
   /* No need to allow competing threads to enter when we can get the
      lock immediately.  */
   err = pthread_rwlock_trywrlock (rwlock);
   if (err != EBUSY)
     return err;
+#endif
 
   ENTER();
+#if HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
   err = pthread_rwlock_timedwrlock (rwlock, abstime);
+#elif HAVE_PTHREAD_RWLOCK_TRYRDLOCK
+  err = busy_wait_for ((trylock_func_t) pthread_rwlock_trywrlock, rwlock,
+                      abstime);
+#endif
   LEAVE();
   return err;
 }