]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - nptl/pthread_rwlock_wrlock.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / nptl / pthread_rwlock_wrlock.c
index 6d8fb93c3b7039e6feebf8266e0e1bc7bc2533ee..f061128ff6318dcb6cfd10c2401769e08a204cda 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2012 Free Software Foundation, Inc.
+/* Copyright (C) 2003-2016 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
 
 #include <errno.h>
 #include <sysdep.h>
 #include <lowlevellock.h>
+#include <futex-internal.h>
 #include <pthread.h>
 #include <pthreadP.h>
 #include <stap-probe.h>
+#include <elide.h>
 
 
 /* Acquire write lock for RWLOCK.  */
-int
-__pthread_rwlock_wrlock (rwlock)
-     pthread_rwlock_t *rwlock;
+static int __attribute__((noinline))
+__pthread_rwlock_wrlock_slow (pthread_rwlock_t *rwlock)
 {
   int result = 0;
+  int futex_shared =
+      rwlock->__data.__shared == LLL_PRIVATE ? FUTEX_PRIVATE : FUTEX_SHARED;
 
-  LIBC_PROBE (wrlock_entry, 1, rwlock);
-
-  /* Make sure we are alone.  */
-  lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
+  /* Caller has taken the lock.  */
 
   while (1)
     {
-      /* Get the rwlock if there is no writer and no reader.  */
-      if (rwlock->__data.__writer == 0 && rwlock->__data.__nr_readers == 0)
-       {
-         /* Mark self as writer.  */
-         rwlock->__data.__writer = THREAD_GETMEM (THREAD_SELF, tid);
-
-         LIBC_PROBE (wrlock_acquire_write, 1, rwlock);
-         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
@@ -71,15 +61,27 @@ __pthread_rwlock_wrlock (rwlock)
       /* Free the lock.  */
       lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
 
-      /* Wait for the writer or reader(s) to finish.  */
-      lll_futex_wait (&rwlock->__data.__writer_wakeup, waitval,
-                     rwlock->__data.__shared);
+      /* Wait for the writer or reader(s) to finish.  We do not check the
+        return value because we decide how to continue based on the state of
+        the rwlock.  */
+      futex_wait_simple (&rwlock->__data.__writer_wakeup, waitval,
+                        futex_shared);
 
       /* Get the lock.  */
       lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
 
       /* To start over again, remove the thread from the writer list.  */
       --rwlock->__data.__nr_writers_queued;
+
+      /* Get the rwlock if there is no writer and no reader.  */
+      if (rwlock->__data.__writer == 0 && rwlock->__data.__nr_readers == 0)
+       {
+         /* Mark self as writer.  */
+         rwlock->__data.__writer = THREAD_GETMEM (THREAD_SELF, tid);
+
+         LIBC_PROBE (wrlock_acquire_write, 1, rwlock);
+         break;
+       }
     }
 
   /* We are done, free the lock.  */
@@ -88,5 +90,40 @@ __pthread_rwlock_wrlock (rwlock)
   return result;
 }
 
+/* Fast path of acquiring write lock for RWLOCK.  */
+
+int
+__pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
+{
+  LIBC_PROBE (wrlock_entry, 1, rwlock);
+
+  if (ELIDE_LOCK (rwlock->__data.__rwelision,
+                 rwlock->__data.__lock == 0
+                 && rwlock->__data.__writer == 0
+                 && rwlock->__data.__nr_readers == 0))
+    return 0;
+
+  /* Make sure we are alone.  */
+  lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+  /* Get the rwlock if there is no writer and no reader.  */
+  if (__glibc_likely((rwlock->__data.__writer |
+       rwlock->__data.__nr_readers) == 0))
+    {
+      /* Mark self as writer.  */
+      rwlock->__data.__writer = THREAD_GETMEM (THREAD_SELF, tid);
+
+      LIBC_PROBE (wrlock_acquire_write, 1, rwlock);
+
+      /* We are done, free the lock.  */
+      lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
+
+      return 0;
+    }
+
+  return __pthread_rwlock_wrlock_slow (rwlock);
+}
+
+
 weak_alias (__pthread_rwlock_wrlock, pthread_rwlock_wrlock)
-strong_alias (__pthread_rwlock_wrlock, __pthread_rwlock_wrlock_internal)
+hidden_def (__pthread_rwlock_wrlock)