]> git.ipfire.org Git - thirdparty/glibc.git/blame - nptl/pthread_rwlock_tryrdlock.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / nptl / pthread_rwlock_tryrdlock.c
CommitLineData
d614a753 1/* Copyright (C) 2002-2020 Free Software Foundation, Inc.
76a50749
UD
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
4
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.
9
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.
14
15 You should have received a copy of the GNU Lesser General Public
59ba27a6 16 License along with the GNU C Library; if not, see
5a82c748 17 <https://www.gnu.org/licenses/>. */
76a50749
UD
18
19#include <errno.h>
20#include "pthreadP.h"
cc25c8b4 21#include <atomic.h>
b634486d 22#include <stdbool.h>
cc25c8b4 23#include "pthread_rwlock_common.c"
76a50749
UD
24
25
cc25c8b4 26/* See pthread_rwlock_common.c for an overview. */
76a50749 27int
c93c5dec 28__pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
76a50749 29{
cc25c8b4
TR
30 /* For tryrdlock, we could speculate that we will succeed and go ahead and
31 register as a reader. However, if we misspeculate, we have to do the
32 same steps as a timed-out rdlock, which will increase contention.
33 Therefore, there is a trade-off between being able to use a combinable
34 read-modify-write operation and a CAS loop as used below; we pick the
35 latter because it simplifies the code, and should perform better when
36 tryrdlock is used in cases where writers are infrequent.
37 Because POSIX does not require a failed trylock to "synchronize memory",
38 relaxed MO is sufficient here and on the failure path of the CAS
39 below. */
40 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers);
41 unsigned int rnew;
42 do
76a50749 43 {
cc25c8b4 44 if ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
76a50749 45 {
cc25c8b4
TR
46 /* If we are in a read phase, try to acquire unless there is a
47 primary writer and we prefer writers and there will be no
48 recursive read locks. */
49 if (((r & PTHREAD_RWLOCK_WRLOCKED) != 0)
50 && (rwlock->__data.__flags
51 == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP))
52 return EBUSY;
53 rnew = r + (1 << PTHREAD_RWLOCK_READER_SHIFT);
76a50749
UD
54 }
55 else
b634486d 56 {
cc25c8b4
TR
57 /* If there is a writer that has acquired the lock and we are in
58 a write phase, fail. */
59 if ((r & PTHREAD_RWLOCK_WRLOCKED) != 0)
60 return EBUSY;
61 else
b634486d 62 {
cc25c8b4
TR
63 /* If we do not care about potentially waiting writers, just
64 try to acquire. */
65 rnew = (r + (1 << PTHREAD_RWLOCK_READER_SHIFT))
66 ^ PTHREAD_RWLOCK_WRPHASE;
b634486d
TR
67 }
68 }
cc25c8b4
TR
69 /* If we could have caused an overflow or take effect during an
70 overflow, we just can / need to return EAGAIN. There is no need to
71 have actually modified the number of readers because we could have
72 done that and cleaned up immediately. */
73 if (rnew >= PTHREAD_RWLOCK_READER_OVERFLOW)
74 return EAGAIN;
75 }
76 /* If the CAS fails, we retry; this prevents that tryrdlock fails spuriously
77 (i.e., fails to acquire the lock although there is no writer), which is
78 fine for C++14 but not currently allowed by POSIX.
79 However, because tryrdlock must not appear to block, we should avoid
80 starving this CAS loop due to constant changes to __readers:
81 While normal rdlock readers that won't be able to acquire will just block
82 (and we expect timeouts on timedrdlock to be longer than one retry of the
83 CAS loop), we can have concurrently failing tryrdlock calls due to
84 readers or writers that acquire and release in the meantime. Using
85 randomized exponential back-off to make a live-lock unlikely should be
86 sufficient.
87 TODO Back-off.
88 Acquire MO so we synchronize with prior writers. */
89 while (!atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers,
90 &r, rnew));
91
92 if ((r & PTHREAD_RWLOCK_WRPHASE) != 0)
93 {
94 /* Same as in __pthread_rwlock_rdlock_full:
95 We started the read phase, so we are also responsible for
96 updating the write-phase futex. Relaxed MO is sufficient.
5fc9ed4c
CD
97 We have to do the same steps as a writer would when handing over the
98 read phase to use because other readers cannot distinguish between
99 us and the writer.
100 Note that __pthread_rwlock_tryrdlock callers will not have to be
101 woken up because they will either see the read phase started by us
102 or they will try to start it themselves; however, callers of
103 __pthread_rwlock_rdlock_full just increase the reader count and then
104 check what state the lock is in, so they cannot distinguish between
105 us and a writer that acquired and released the lock in the
106 meantime. */
107 if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0)
108 & PTHREAD_RWLOCK_FUTEX_USED) != 0)
109 {
110 int private = __pthread_rwlock_get_private (rwlock);
111 futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private);
112 }
76a50749
UD
113 }
114
cc25c8b4 115 return 0;
76a50749 116
b634486d 117
76a50749
UD
118}
119strong_alias (__pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock)