]> git.ipfire.org Git - thirdparty/glibc.git/blame - nptl/pthread_rwlock_timedrdlock.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / nptl / pthread_rwlock_timedrdlock.c
CommitLineData
b168057a 1/* Copyright (C) 2003-2015 Free Software Foundation, Inc.
a88c9263
UD
2 This file is part of the GNU C Library.
3 Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
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
PE
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
a88c9263
UD
18
19#include <errno.h>
20#include <sysdep.h>
21#include <lowlevellock.h>
22#include <pthread.h>
23#include <pthreadP.h>
6af246cf 24#include <sys/time.h>
9bc6103d 25#include <kernel-features.h>
a88c9263
UD
26
27
28/* Try to acquire read lock for RWLOCK or return after specfied time. */
29int
30pthread_rwlock_timedrdlock (rwlock, abstime)
31 pthread_rwlock_t *rwlock;
32 const struct timespec *abstime;
33{
34 int result = 0;
35
c5be0f71 36 /* Make sure we are alone. */
e51deae7 37 lll_lock(rwlock->__data.__lock, rwlock->__data.__shared);
a88c9263
UD
38
39 while (1)
40 {
7ce5c164
UD
41 int err;
42
a88c9263
UD
43 /* Get the rwlock if there is no writer... */
44 if (rwlock->__data.__writer == 0
45 /* ...and if either no writer is waiting or we prefer readers. */
46 && (!rwlock->__data.__nr_writers_queued
546346b6 47 || PTHREAD_RWLOCK_PREFER_READER_P (rwlock)))
a88c9263
UD
48 {
49 /* Increment the reader counter. Avoid overflow. */
50 if (++rwlock->__data.__nr_readers == 0)
51 {
52 /* Overflow on number of readers. */
53 --rwlock->__data.__nr_readers;
54 result = EAGAIN;
55 }
56
57 break;
58 }
59
60 /* Make sure we are not holding the rwlock as a writer. This is
61 a deadlock situation we recognize and report. */
4ad0bbf4
UD
62 if (__builtin_expect (rwlock->__data.__writer
63 == THREAD_GETMEM (THREAD_SELF, tid), 0))
a88c9263
UD
64 {
65 result = EDEADLK;
66 break;
67 }
68
69 /* Make sure the passed in timeout value is valid. Ideally this
70 test would be executed once. But since it must not be
71 performed if we would not block at all simply moving the test
72 to the front is no option. Replicating all the code is
73 costly while this test is not. */
46f4c578 74 if (__builtin_expect (abstime->tv_nsec >= 1000000000
f3a19754 75 || abstime->tv_nsec < 0, 0))
a88c9263
UD
76 {
77 result = EINVAL;
78 break;
79 }
80
8f861542
SP
81 /* Work around the fact that the kernel rejects negative timeout values
82 despite them being valid. */
a1ffb40e 83 if (__glibc_unlikely (abstime->tv_sec < 0))
8f861542
SP
84 {
85 result = ETIMEDOUT;
86 break;
87 }
88
89#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
90 || !defined lll_futex_timed_wait_bitset)
a88c9263
UD
91 /* Get the current time. So far we support only one clock. */
92 struct timeval tv;
c5c2b7c3 93 (void) __gettimeofday (&tv, NULL);
a88c9263
UD
94
95 /* Convert the absolute timeout value to a relative timeout. */
96 struct timespec rt;
97 rt.tv_sec = abstime->tv_sec - tv.tv_sec;
98 rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
99 if (rt.tv_nsec < 0)
100 {
101 rt.tv_nsec += 1000000000;
102 --rt.tv_sec;
103 }
104 /* Did we already time out? */
105 if (rt.tv_sec < 0)
106 {
107 /* Yep, return with an appropriate error. */
108 result = ETIMEDOUT;
109 break;
110 }
8f861542 111#endif
a88c9263
UD
112
113 /* Remember that we are a reader. */
114 if (++rwlock->__data.__nr_readers_queued == 0)
115 {
116 /* Overflow on number of queued readers. */
117 --rwlock->__data.__nr_readers_queued;
118 result = EAGAIN;
119 break;
120 }
121
18a53579
UD
122 int waitval = rwlock->__data.__readers_wakeup;
123
a88c9263 124 /* Free the lock. */
e51deae7 125 lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
a88c9263
UD
126
127 /* Wait for the writer to finish. */
8f861542
SP
128#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
129 || !defined lll_futex_timed_wait_bitset)
7ce5c164 130 err = lll_futex_timed_wait (&rwlock->__data.__readers_wakeup,
e51deae7 131 waitval, &rt, rwlock->__data.__shared);
8f861542
SP
132#else
133 err = lll_futex_timed_wait_bitset (&rwlock->__data.__readers_wakeup,
134 waitval, abstime,
135 FUTEX_CLOCK_REALTIME,
136 rwlock->__data.__shared);
137#endif
a88c9263
UD
138
139 /* Get the lock. */
e51deae7 140 lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
a88c9263 141
644eff0c
UD
142 --rwlock->__data.__nr_readers_queued;
143
a88c9263 144 /* Did the futex call time out? */
7ce5c164 145 if (err == -ETIMEDOUT)
a88c9263
UD
146 {
147 /* Yep, report it. */
148 result = ETIMEDOUT;
149 break;
150 }
151 }
152
153 /* We are done, free the lock. */
e51deae7 154 lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
a88c9263
UD
155
156 return result;
157}