Make type for spec variable size as size_t
[glibc.git] / nptl / pthread_mutex_unlock.c
blob8064de09c15ceed3a23ae14d04499462e067dc38
1 /* Copyright (C) 2002-2014 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
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 <assert.h>
20 #include <errno.h>
21 #include <stdlib.h>
22 #include "pthreadP.h"
23 #include <lowlevellock.h>
24 #include <stap-probe.h>
26 #ifndef lll_unlock_elision
27 #define lll_unlock_elision(a,b) ({ lll_unlock (a,b); 0; })
28 #endif
30 static int
31 internal_function
32 __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr)
33 __attribute_noinline__;
35 int
36 internal_function attribute_hidden
37 __pthread_mutex_unlock_usercnt (mutex, decr)
38 pthread_mutex_t *mutex;
39 int decr;
41 int type = PTHREAD_MUTEX_TYPE_ELISION (mutex);
42 if (__builtin_expect (type &
43 ~(PTHREAD_MUTEX_KIND_MASK_NP|PTHREAD_MUTEX_ELISION_FLAGS_NP), 0))
44 return __pthread_mutex_unlock_full (mutex, decr);
46 if (__builtin_expect (type, PTHREAD_MUTEX_TIMED_NP)
47 == PTHREAD_MUTEX_TIMED_NP)
49 /* Always reset the owner field. */
50 normal:
51 mutex->__data.__owner = 0;
52 if (decr)
53 /* One less user. */
54 --mutex->__data.__nusers;
56 /* Unlock. */
57 lll_unlock (mutex->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex));
59 LIBC_PROBE (mutex_release, 1, mutex);
61 return 0;
63 else if (__glibc_likely (type == PTHREAD_MUTEX_TIMED_ELISION_NP))
65 /* Don't reset the owner/users fields for elision. */
66 return lll_unlock_elision (mutex->__data.__lock,
67 PTHREAD_MUTEX_PSHARED (mutex));
69 else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex)
70 == PTHREAD_MUTEX_RECURSIVE_NP, 1))
72 /* Recursive mutex. */
73 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
74 return EPERM;
76 if (--mutex->__data.__count != 0)
77 /* We still hold the mutex. */
78 return 0;
79 goto normal;
81 else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex)
82 == PTHREAD_MUTEX_ADAPTIVE_NP, 1))
83 goto normal;
84 else
86 /* Error checking mutex. */
87 assert (type == PTHREAD_MUTEX_ERRORCHECK_NP);
88 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)
89 || ! lll_islocked (mutex->__data.__lock))
90 return EPERM;
91 goto normal;
96 static int
97 internal_function
98 __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr)
100 int newowner = 0;
102 switch (PTHREAD_MUTEX_TYPE (mutex))
104 case PTHREAD_MUTEX_ROBUST_RECURSIVE_NP:
105 /* Recursive mutex. */
106 if ((mutex->__data.__lock & FUTEX_TID_MASK)
107 == THREAD_GETMEM (THREAD_SELF, tid)
108 && __builtin_expect (mutex->__data.__owner
109 == PTHREAD_MUTEX_INCONSISTENT, 0))
111 if (--mutex->__data.__count != 0)
112 /* We still hold the mutex. */
113 return ENOTRECOVERABLE;
115 goto notrecoverable;
118 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
119 return EPERM;
121 if (--mutex->__data.__count != 0)
122 /* We still hold the mutex. */
123 return 0;
125 goto robust;
127 case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP:
128 case PTHREAD_MUTEX_ROBUST_NORMAL_NP:
129 case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
130 if ((mutex->__data.__lock & FUTEX_TID_MASK)
131 != THREAD_GETMEM (THREAD_SELF, tid)
132 || ! lll_islocked (mutex->__data.__lock))
133 return EPERM;
135 /* If the previous owner died and the caller did not succeed in
136 making the state consistent, mark the mutex as unrecoverable
137 and make all waiters. */
138 if (__builtin_expect (mutex->__data.__owner
139 == PTHREAD_MUTEX_INCONSISTENT, 0))
140 notrecoverable:
141 newowner = PTHREAD_MUTEX_NOTRECOVERABLE;
143 robust:
144 /* Remove mutex from the list. */
145 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
146 &mutex->__data.__list.__next);
147 DEQUEUE_MUTEX (mutex);
149 mutex->__data.__owner = newowner;
150 if (decr)
151 /* One less user. */
152 --mutex->__data.__nusers;
154 /* Unlock. */
155 lll_robust_unlock (mutex->__data.__lock,
156 PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
158 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
159 break;
161 /* The PI support requires the Linux futex system call. If that's not
162 available, pthread_mutex_init should never have allowed the type to
163 be set. So it will get the default case for an invalid type. */
164 #ifdef __NR_futex
165 case PTHREAD_MUTEX_PI_RECURSIVE_NP:
166 /* Recursive mutex. */
167 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
168 return EPERM;
170 if (--mutex->__data.__count != 0)
171 /* We still hold the mutex. */
172 return 0;
173 goto continue_pi_non_robust;
175 case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP:
176 /* Recursive mutex. */
177 if ((mutex->__data.__lock & FUTEX_TID_MASK)
178 == THREAD_GETMEM (THREAD_SELF, tid)
179 && __builtin_expect (mutex->__data.__owner
180 == PTHREAD_MUTEX_INCONSISTENT, 0))
182 if (--mutex->__data.__count != 0)
183 /* We still hold the mutex. */
184 return ENOTRECOVERABLE;
186 goto pi_notrecoverable;
189 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
190 return EPERM;
192 if (--mutex->__data.__count != 0)
193 /* We still hold the mutex. */
194 return 0;
196 goto continue_pi_robust;
198 case PTHREAD_MUTEX_PI_ERRORCHECK_NP:
199 case PTHREAD_MUTEX_PI_NORMAL_NP:
200 case PTHREAD_MUTEX_PI_ADAPTIVE_NP:
201 case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP:
202 case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
203 case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
204 if ((mutex->__data.__lock & FUTEX_TID_MASK)
205 != THREAD_GETMEM (THREAD_SELF, tid)
206 || ! lll_islocked (mutex->__data.__lock))
207 return EPERM;
209 /* If the previous owner died and the caller did not succeed in
210 making the state consistent, mark the mutex as unrecoverable
211 and make all waiters. */
212 if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0
213 && __builtin_expect (mutex->__data.__owner
214 == PTHREAD_MUTEX_INCONSISTENT, 0))
215 pi_notrecoverable:
216 newowner = PTHREAD_MUTEX_NOTRECOVERABLE;
218 if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0)
220 continue_pi_robust:
221 /* Remove mutex from the list.
222 Note: robust PI futexes are signaled by setting bit 0. */
223 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
224 (void *) (((uintptr_t) &mutex->__data.__list.__next)
225 | 1));
226 DEQUEUE_MUTEX (mutex);
229 continue_pi_non_robust:
230 mutex->__data.__owner = newowner;
231 if (decr)
232 /* One less user. */
233 --mutex->__data.__nusers;
235 /* Unlock. */
236 if ((mutex->__data.__lock & FUTEX_WAITERS) != 0
237 || atomic_compare_and_exchange_bool_rel (&mutex->__data.__lock, 0,
238 THREAD_GETMEM (THREAD_SELF,
239 tid)))
241 int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
242 int private = (robust
243 ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
244 : PTHREAD_MUTEX_PSHARED (mutex));
245 INTERNAL_SYSCALL_DECL (__err);
246 INTERNAL_SYSCALL (futex, __err, 2, &mutex->__data.__lock,
247 __lll_private_flag (FUTEX_UNLOCK_PI, private));
250 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
251 break;
252 #endif /* __NR_futex. */
254 case PTHREAD_MUTEX_PP_RECURSIVE_NP:
255 /* Recursive mutex. */
256 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
257 return EPERM;
259 if (--mutex->__data.__count != 0)
260 /* We still hold the mutex. */
261 return 0;
262 goto pp;
264 case PTHREAD_MUTEX_PP_ERRORCHECK_NP:
265 /* Error checking mutex. */
266 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)
267 || (mutex->__data.__lock & ~ PTHREAD_MUTEX_PRIO_CEILING_MASK) == 0)
268 return EPERM;
269 /* FALLTHROUGH */
271 case PTHREAD_MUTEX_PP_NORMAL_NP:
272 case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
273 /* Always reset the owner field. */
275 mutex->__data.__owner = 0;
277 if (decr)
278 /* One less user. */
279 --mutex->__data.__nusers;
281 /* Unlock. */
282 int newval, oldval;
285 oldval = mutex->__data.__lock;
286 newval = oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK;
288 while (atomic_compare_and_exchange_bool_rel (&mutex->__data.__lock,
289 newval, oldval));
291 if ((oldval & ~PTHREAD_MUTEX_PRIO_CEILING_MASK) > 1)
292 lll_futex_wake (&mutex->__data.__lock, 1,
293 PTHREAD_MUTEX_PSHARED (mutex));
295 int oldprio = newval >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
297 LIBC_PROBE (mutex_release, 1, mutex);
299 return __pthread_tpp_change_priority (oldprio, -1);
301 default:
302 /* Correct code cannot set any other type. */
303 return EINVAL;
306 LIBC_PROBE (mutex_release, 1, mutex);
307 return 0;
312 __pthread_mutex_unlock (mutex)
313 pthread_mutex_t *mutex;
315 return __pthread_mutex_unlock_usercnt (mutex, 1);
317 strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock)
318 hidden_def (__pthread_mutex_unlock)