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/>. */
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; })
32 __pthread_mutex_unlock_full (pthread_mutex_t
*mutex
, int decr
)
33 __attribute_noinline__
;
36 internal_function attribute_hidden
37 __pthread_mutex_unlock_usercnt (mutex
, decr
)
38 pthread_mutex_t
*mutex
;
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. */
51 mutex
->__data
.__owner
= 0;
54 --mutex
->__data
.__nusers
;
57 lll_unlock (mutex
->__data
.__lock
, PTHREAD_MUTEX_PSHARED (mutex
));
59 LIBC_PROBE (mutex_release
, 1, mutex
);
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
))
76 if (--mutex
->__data
.__count
!= 0)
77 /* We still hold the mutex. */
81 else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex
)
82 == PTHREAD_MUTEX_ADAPTIVE_NP
, 1))
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
))
98 __pthread_mutex_unlock_full (pthread_mutex_t
*mutex
, int decr
)
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
;
118 if (mutex
->__data
.__owner
!= THREAD_GETMEM (THREAD_SELF
, tid
))
121 if (--mutex
->__data
.__count
!= 0)
122 /* We still hold the mutex. */
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
))
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))
141 newowner
= PTHREAD_MUTEX_NOTRECOVERABLE
;
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
;
152 --mutex
->__data
.__nusers
;
155 lll_robust_unlock (mutex
->__data
.__lock
,
156 PTHREAD_ROBUST_MUTEX_PSHARED (mutex
));
158 THREAD_SETMEM (THREAD_SELF
, robust_head
.list_op_pending
, NULL
);
161 case PTHREAD_MUTEX_PI_RECURSIVE_NP
:
162 /* Recursive mutex. */
163 if (mutex
->__data
.__owner
!= THREAD_GETMEM (THREAD_SELF
, tid
))
166 if (--mutex
->__data
.__count
!= 0)
167 /* We still hold the mutex. */
169 goto continue_pi_non_robust
;
171 case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP
:
172 /* Recursive mutex. */
173 if ((mutex
->__data
.__lock
& FUTEX_TID_MASK
)
174 == THREAD_GETMEM (THREAD_SELF
, tid
)
175 && __builtin_expect (mutex
->__data
.__owner
176 == PTHREAD_MUTEX_INCONSISTENT
, 0))
178 if (--mutex
->__data
.__count
!= 0)
179 /* We still hold the mutex. */
180 return ENOTRECOVERABLE
;
182 goto pi_notrecoverable
;
185 if (mutex
->__data
.__owner
!= THREAD_GETMEM (THREAD_SELF
, tid
))
188 if (--mutex
->__data
.__count
!= 0)
189 /* We still hold the mutex. */
192 goto continue_pi_robust
;
194 case PTHREAD_MUTEX_PI_ERRORCHECK_NP
:
195 case PTHREAD_MUTEX_PI_NORMAL_NP
:
196 case PTHREAD_MUTEX_PI_ADAPTIVE_NP
:
197 case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP
:
198 case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP
:
199 case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP
:
200 if ((mutex
->__data
.__lock
& FUTEX_TID_MASK
)
201 != THREAD_GETMEM (THREAD_SELF
, tid
)
202 || ! lll_islocked (mutex
->__data
.__lock
))
205 /* If the previous owner died and the caller did not succeed in
206 making the state consistent, mark the mutex as unrecoverable
207 and make all waiters. */
208 if ((mutex
->__data
.__kind
& PTHREAD_MUTEX_ROBUST_NORMAL_NP
) != 0
209 && __builtin_expect (mutex
->__data
.__owner
210 == PTHREAD_MUTEX_INCONSISTENT
, 0))
212 newowner
= PTHREAD_MUTEX_NOTRECOVERABLE
;
214 if ((mutex
->__data
.__kind
& PTHREAD_MUTEX_ROBUST_NORMAL_NP
) != 0)
217 /* Remove mutex from the list.
218 Note: robust PI futexes are signaled by setting bit 0. */
219 THREAD_SETMEM (THREAD_SELF
, robust_head
.list_op_pending
,
220 (void *) (((uintptr_t) &mutex
->__data
.__list
.__next
)
222 DEQUEUE_MUTEX (mutex
);
225 continue_pi_non_robust
:
226 mutex
->__data
.__owner
= newowner
;
229 --mutex
->__data
.__nusers
;
232 if ((mutex
->__data
.__lock
& FUTEX_WAITERS
) != 0
233 || atomic_compare_and_exchange_bool_rel (&mutex
->__data
.__lock
, 0,
234 THREAD_GETMEM (THREAD_SELF
,
237 int robust
= mutex
->__data
.__kind
& PTHREAD_MUTEX_ROBUST_NORMAL_NP
;
238 int private = (robust
239 ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex
)
240 : PTHREAD_MUTEX_PSHARED (mutex
));
241 INTERNAL_SYSCALL_DECL (__err
);
242 INTERNAL_SYSCALL (futex
, __err
, 2, &mutex
->__data
.__lock
,
243 __lll_private_flag (FUTEX_UNLOCK_PI
, private));
246 THREAD_SETMEM (THREAD_SELF
, robust_head
.list_op_pending
, NULL
);
249 case PTHREAD_MUTEX_PP_RECURSIVE_NP
:
250 /* Recursive mutex. */
251 if (mutex
->__data
.__owner
!= THREAD_GETMEM (THREAD_SELF
, tid
))
254 if (--mutex
->__data
.__count
!= 0)
255 /* We still hold the mutex. */
259 case PTHREAD_MUTEX_PP_ERRORCHECK_NP
:
260 /* Error checking mutex. */
261 if (mutex
->__data
.__owner
!= THREAD_GETMEM (THREAD_SELF
, tid
)
262 || (mutex
->__data
.__lock
& ~ PTHREAD_MUTEX_PRIO_CEILING_MASK
) == 0)
266 case PTHREAD_MUTEX_PP_NORMAL_NP
:
267 case PTHREAD_MUTEX_PP_ADAPTIVE_NP
:
268 /* Always reset the owner field. */
270 mutex
->__data
.__owner
= 0;
274 --mutex
->__data
.__nusers
;
280 oldval
= mutex
->__data
.__lock
;
281 newval
= oldval
& PTHREAD_MUTEX_PRIO_CEILING_MASK
;
283 while (atomic_compare_and_exchange_bool_rel (&mutex
->__data
.__lock
,
286 if ((oldval
& ~PTHREAD_MUTEX_PRIO_CEILING_MASK
) > 1)
287 lll_futex_wake (&mutex
->__data
.__lock
, 1,
288 PTHREAD_MUTEX_PSHARED (mutex
));
290 int oldprio
= newval
>> PTHREAD_MUTEX_PRIO_CEILING_SHIFT
;
292 LIBC_PROBE (mutex_release
, 1, mutex
);
294 return __pthread_tpp_change_priority (oldprio
, -1);
297 /* Correct code cannot set any other type. */
301 LIBC_PROBE (mutex_release
, 1, mutex
);
307 __pthread_mutex_unlock (mutex
)
308 pthread_mutex_t
*mutex
;
310 return __pthread_mutex_unlock_usercnt (mutex
, 1);
312 strong_alias (__pthread_mutex_unlock
, pthread_mutex_unlock
)
313 hidden_def (__pthread_mutex_unlock
)