]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - nptl/pthread_rwlock_timedrdlock.c
S390: Increase function alignment to 16 bytes.
[thirdparty/glibc.git] / nptl / pthread_rwlock_timedrdlock.c
index 0212b49adb3aa1fe45446fef0501f96224784d48..aa0053094dddfe5eeee81306f6f0bb15f6341f49 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2015 Free Software Foundation, Inc.
+/* Copyright (C) 2003-2019 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <errno.h>
-#include <sysdep.h>
-#include <lowlevellock.h>
-#include <pthread.h>
-#include <pthreadP.h>
-#include <sys/time.h>
-#include <kernel-features.h>
+#include "pthread_rwlock_common.c"
 
-
-/* Try to acquire read lock for RWLOCK or return after specfied time.  */
+/* See pthread_rwlock_common.c.  */
 int
-pthread_rwlock_timedrdlock (rwlock, abstime)
-     pthread_rwlock_t *rwlock;
-     const struct timespec *abstime;
+pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
+    const struct timespec *abstime)
 {
-  int result = 0;
-
-  /* Make sure we are alone.  */
-  lll_lock(rwlock->__data.__lock, rwlock->__data.__shared);
-
-  while (1)
-    {
-      int err;
-
-      /* Get the rwlock if there is no writer...  */
-      if (rwlock->__data.__writer == 0
-         /* ...and if either no writer is waiting or we prefer readers.  */
-         && (!rwlock->__data.__nr_writers_queued
-             || PTHREAD_RWLOCK_PREFER_READER_P (rwlock)))
-       {
-         /* Increment the reader counter.  Avoid overflow.  */
-         if (++rwlock->__data.__nr_readers == 0)
-           {
-             /* Overflow on number of readers.  */
-             --rwlock->__data.__nr_readers;
-             result = EAGAIN;
-           }
-
-         break;
-       }
-
-      /* Make sure we are not holding the rwlock as a writer.  This is
-        a deadlock situation we recognize and report.  */
-      if (__builtin_expect (rwlock->__data.__writer
-                           == THREAD_GETMEM (THREAD_SELF, tid), 0))
-       {
-         result = EDEADLK;
-         break;
-       }
-
-      /* Make sure the passed in timeout value is valid.  Ideally this
-        test would be executed once.  But since it must not be
-        performed if we would not block at all simply moving the test
-        to the front is no option.  Replicating all the code is
-        costly while this test is not.  */
-      if (__builtin_expect (abstime->tv_nsec >= 1000000000
-                            || abstime->tv_nsec < 0, 0))
-       {
-         result = EINVAL;
-         break;
-       }
-
-      /* Work around the fact that the kernel rejects negative timeout values
-        despite them being valid.  */
-      if (__glibc_unlikely (abstime->tv_sec < 0))
-       {
-         result = ETIMEDOUT;
-         break;
-       }
-
-#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
-     || !defined lll_futex_timed_wait_bitset)
-      /* Get the current time.  So far we support only one clock.  */
-      struct timeval tv;
-      (void) __gettimeofday (&tv, NULL);
-
-      /* Convert the absolute timeout value to a relative timeout.  */
-      struct timespec rt;
-      rt.tv_sec = abstime->tv_sec - tv.tv_sec;
-      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
-      if (rt.tv_nsec < 0)
-       {
-         rt.tv_nsec += 1000000000;
-         --rt.tv_sec;
-       }
-      /* Did we already time out?  */
-      if (rt.tv_sec < 0)
-       {
-         /* Yep, return with an appropriate error.  */
-         result = ETIMEDOUT;
-         break;
-       }
-#endif
-
-      /* Remember that we are a reader.  */
-      if (++rwlock->__data.__nr_readers_queued == 0)
-       {
-         /* Overflow on number of queued readers.  */
-         --rwlock->__data.__nr_readers_queued;
-         result = EAGAIN;
-         break;
-       }
-
-      int waitval = rwlock->__data.__readers_wakeup;
-
-      /* Free the lock.  */
-      lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
-
-      /* Wait for the writer to finish.  */
-#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
-     || !defined lll_futex_timed_wait_bitset)
-      err = lll_futex_timed_wait (&rwlock->__data.__readers_wakeup,
-                                 waitval, &rt, rwlock->__data.__shared);
-#else
-      err = lll_futex_timed_wait_bitset (&rwlock->__data.__readers_wakeup,
-                                        waitval, abstime,
-                                        FUTEX_CLOCK_REALTIME,
-                                        rwlock->__data.__shared);
-#endif
-
-      /* Get the lock.  */
-      lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
-
-      --rwlock->__data.__nr_readers_queued;
-
-      /* Did the futex call time out?  */
-      if (err == -ETIMEDOUT)
-       {
-         /* Yep, report it.  */
-         result = ETIMEDOUT;
-         break;
-       }
-    }
-
-  /* We are done, free the lock.  */
-  lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
-
-  return result;
+  /* Make sure the passed in timeout value is valid.  Note that the previous
+     implementation assumed that this check *must* not be performed if there
+     would in fact be no blocking; however, POSIX only requires that "the
+     validity of the abstime parameter need not be checked if the lock can be
+     immediately acquired" (i.e., we need not but may check it).  */
+  /* ??? Just move this to __pthread_rwlock_rdlock_full?  */
+  if (__glibc_unlikely (abstime->tv_nsec >= 1000000000
+      || abstime->tv_nsec < 0))
+    return EINVAL;
+
+  return __pthread_rwlock_rdlock_full (rwlock, abstime);
 }