The patch committed to fix bug #18435 caused regressions on aarch64
[glibc.git] / nptl / pthread_rwlock_rdlock.c
blob004a386fd5ca22ea61475c199604f02902e675e6
1 /* Copyright (C) 2003-2015 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 #include <errno.h>
20 #include <sysdep.h>
21 #include <lowlevellock.h>
22 #include <pthread.h>
23 #include <pthreadP.h>
24 #include <stap-probe.h>
25 #include <elide.h>
26 #include <stdbool.h>
29 /* Acquire read lock for RWLOCK. Slow path. */
30 static int __attribute__((noinline))
31 __pthread_rwlock_rdlock_slow (pthread_rwlock_t *rwlock)
33 int result = 0;
34 bool wake = false;
36 /* Lock is taken in caller. */
38 while (1)
40 /* Make sure we are not holding the rwlock as a writer. This is
41 a deadlock situation we recognize and report. */
42 if (__builtin_expect (rwlock->__data.__writer
43 == THREAD_GETMEM (THREAD_SELF, tid), 0))
45 result = EDEADLK;
46 break;
49 /* Remember that we are a reader. */
50 if (__glibc_unlikely (++rwlock->__data.__nr_readers_queued == 0))
52 /* Overflow on number of queued readers. */
53 --rwlock->__data.__nr_readers_queued;
54 result = EAGAIN;
55 break;
58 int waitval = rwlock->__data.__readers_wakeup;
60 /* Free the lock. */
61 lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
63 /* Wait for the writer to finish. */
64 lll_futex_wait (&rwlock->__data.__readers_wakeup, waitval,
65 rwlock->__data.__shared);
67 /* Get the lock. */
68 lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
70 --rwlock->__data.__nr_readers_queued;
72 /* Get the rwlock if there is no writer... */
73 if (rwlock->__data.__writer == 0
74 /* ...and if either no writer is waiting or we prefer readers. */
75 && (!rwlock->__data.__nr_writers_queued
76 || PTHREAD_RWLOCK_PREFER_READER_P (rwlock)))
78 /* Increment the reader counter. Avoid overflow. */
79 if (__glibc_unlikely (++rwlock->__data.__nr_readers == 0))
81 /* Overflow on number of readers. */
82 --rwlock->__data.__nr_readers;
83 result = EAGAIN;
85 else
87 LIBC_PROBE (rdlock_acquire_read, 1, rwlock);
88 /* See pthread_rwlock_rdlock. */
89 if (rwlock->__data.__nr_readers == 1
90 && rwlock->__data.__nr_readers_queued > 0
91 && rwlock->__data.__nr_writers_queued > 0)
93 ++rwlock->__data.__readers_wakeup;
94 wake = true;
98 break;
102 /* We are done, free the lock. */
103 lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
105 if (wake)
106 lll_futex_wake (&rwlock->__data.__readers_wakeup, INT_MAX,
107 rwlock->__data.__shared);
109 return result;
113 /* Fast path of acquiring read lock on RWLOCK. */
116 __pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
118 int result = 0;
119 bool wake = false;
121 LIBC_PROBE (rdlock_entry, 1, rwlock);
123 if (ELIDE_LOCK (rwlock->__data.__rwelision,
124 rwlock->__data.__lock == 0
125 && rwlock->__data.__writer == 0
126 && rwlock->__data.__nr_readers == 0))
127 return 0;
129 /* Make sure we are alone. */
130 lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
132 /* Get the rwlock if there is no writer... */
133 if (rwlock->__data.__writer == 0
134 /* ...and if either no writer is waiting or we prefer readers. */
135 && (!rwlock->__data.__nr_writers_queued
136 || PTHREAD_RWLOCK_PREFER_READER_P (rwlock)))
138 /* Increment the reader counter. Avoid overflow. */
139 if (__glibc_unlikely (++rwlock->__data.__nr_readers == 0))
141 /* Overflow on number of readers. */
142 --rwlock->__data.__nr_readers;
143 result = EAGAIN;
145 else
147 LIBC_PROBE (rdlock_acquire_read, 1, rwlock);
148 /* If we are the first reader, and there are blocked readers and
149 writers (which we don't prefer, see above), then it can be the
150 case that we stole the lock from a writer that was already woken
151 to acquire it. That means that we need to take over the writer's
152 responsibility to wake all readers (see pthread_rwlock_unlock).
153 Thus, wake all readers in this case. */
154 if (rwlock->__data.__nr_readers == 1
155 && rwlock->__data.__nr_readers_queued > 0
156 && rwlock->__data.__nr_writers_queued > 0)
158 ++rwlock->__data.__readers_wakeup;
159 wake = true;
163 /* We are done, free the lock. */
164 lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
166 if (wake)
167 lll_futex_wake (&rwlock->__data.__readers_wakeup, INT_MAX,
168 rwlock->__data.__shared);
170 return result;
173 return __pthread_rwlock_rdlock_slow (rwlock);
176 weak_alias (__pthread_rwlock_rdlock, pthread_rwlock_rdlock)
177 hidden_def (__pthread_rwlock_rdlock)