Small optimization of STT_GNU_IFUNC handling.
[glibc.git] / nptl / pthread_mutex_unlock.c
blob0028c5583f287c54b8136f04956296b164089128
1 /* Copyright (C) 2002, 2003, 2005-2007, 2008 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, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 #include <assert.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include "pthreadP.h"
24 #include <lowlevellock.h>
26 static int
27 internal_function
28 __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr)
29 __attribute_noinline__;
31 int
32 internal_function attribute_hidden
33 __pthread_mutex_unlock_usercnt (mutex, decr)
34 pthread_mutex_t *mutex;
35 int decr;
37 int type = PTHREAD_MUTEX_TYPE (mutex);
38 if (__builtin_expect (type & ~PTHREAD_MUTEX_KIND_MASK_NP, 0))
39 return __pthread_mutex_unlock_full (mutex, decr);
41 if (__builtin_expect (type, PTHREAD_MUTEX_TIMED_NP)
42 == PTHREAD_MUTEX_TIMED_NP)
44 /* Always reset the owner field. */
45 normal:
46 mutex->__data.__owner = 0;
47 if (decr)
48 /* One less user. */
49 --mutex->__data.__nusers;
51 /* Unlock. */
52 lll_unlock (mutex->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex));
53 return 0;
55 else if (__builtin_expect (type == PTHREAD_MUTEX_RECURSIVE_NP, 1))
57 /* Recursive mutex. */
58 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
59 return EPERM;
61 if (--mutex->__data.__count != 0)
62 /* We still hold the mutex. */
63 return 0;
64 goto normal;
66 else if (__builtin_expect (type == PTHREAD_MUTEX_ADAPTIVE_NP, 1))
67 goto normal;
68 else
70 /* Error checking mutex. */
71 assert (type == PTHREAD_MUTEX_ERRORCHECK_NP);
72 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)
73 || ! lll_islocked (mutex->__data.__lock))
74 return EPERM;
75 goto normal;
80 static int
81 internal_function
82 __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr)
84 int newowner = 0;
86 switch (PTHREAD_MUTEX_TYPE (mutex))
88 case PTHREAD_MUTEX_ROBUST_RECURSIVE_NP:
89 /* Recursive mutex. */
90 if ((mutex->__data.__lock & FUTEX_TID_MASK)
91 == THREAD_GETMEM (THREAD_SELF, tid)
92 && __builtin_expect (mutex->__data.__owner
93 == PTHREAD_MUTEX_INCONSISTENT, 0))
95 if (--mutex->__data.__count != 0)
96 /* We still hold the mutex. */
97 return ENOTRECOVERABLE;
99 goto notrecoverable;
102 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
103 return EPERM;
105 if (--mutex->__data.__count != 0)
106 /* We still hold the mutex. */
107 return 0;
109 goto robust;
111 case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP:
112 case PTHREAD_MUTEX_ROBUST_NORMAL_NP:
113 case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
114 if ((mutex->__data.__lock & FUTEX_TID_MASK)
115 != THREAD_GETMEM (THREAD_SELF, tid)
116 || ! lll_islocked (mutex->__data.__lock))
117 return EPERM;
119 /* If the previous owner died and the caller did not succeed in
120 making the state consistent, mark the mutex as unrecoverable
121 and make all waiters. */
122 if (__builtin_expect (mutex->__data.__owner
123 == PTHREAD_MUTEX_INCONSISTENT, 0))
124 notrecoverable:
125 newowner = PTHREAD_MUTEX_NOTRECOVERABLE;
127 robust:
128 /* Remove mutex from the list. */
129 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
130 &mutex->__data.__list.__next);
131 DEQUEUE_MUTEX (mutex);
133 mutex->__data.__owner = newowner;
134 if (decr)
135 /* One less user. */
136 --mutex->__data.__nusers;
138 /* Unlock. */
139 lll_robust_unlock (mutex->__data.__lock,
140 PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
142 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
143 break;
145 case PTHREAD_MUTEX_PI_RECURSIVE_NP:
146 /* Recursive mutex. */
147 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
148 return EPERM;
150 if (--mutex->__data.__count != 0)
151 /* We still hold the mutex. */
152 return 0;
153 goto continue_pi;
155 case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP:
156 /* Recursive mutex. */
157 if ((mutex->__data.__lock & FUTEX_TID_MASK)
158 == THREAD_GETMEM (THREAD_SELF, tid)
159 && __builtin_expect (mutex->__data.__owner
160 == PTHREAD_MUTEX_INCONSISTENT, 0))
162 if (--mutex->__data.__count != 0)
163 /* We still hold the mutex. */
164 return ENOTRECOVERABLE;
166 goto pi_notrecoverable;
169 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
170 return EPERM;
172 if (--mutex->__data.__count != 0)
173 /* We still hold the mutex. */
174 return 0;
176 goto continue_pi;
178 case PTHREAD_MUTEX_PI_ERRORCHECK_NP:
179 case PTHREAD_MUTEX_PI_NORMAL_NP:
180 case PTHREAD_MUTEX_PI_ADAPTIVE_NP:
181 case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP:
182 case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
183 case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
184 if ((mutex->__data.__lock & FUTEX_TID_MASK)
185 != THREAD_GETMEM (THREAD_SELF, tid)
186 || ! lll_islocked (mutex->__data.__lock))
187 return EPERM;
189 /* If the previous owner died and the caller did not succeed in
190 making the state consistent, mark the mutex as unrecoverable
191 and make all waiters. */
192 if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0
193 && __builtin_expect (mutex->__data.__owner
194 == PTHREAD_MUTEX_INCONSISTENT, 0))
195 pi_notrecoverable:
196 newowner = PTHREAD_MUTEX_NOTRECOVERABLE;
198 continue_pi:
199 if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0)
201 /* Remove mutex from the list.
202 Note: robust PI futexes are signaled by setting bit 0. */
203 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
204 (void *) (((uintptr_t) &mutex->__data.__list.__next)
205 | 1));
206 DEQUEUE_MUTEX (mutex);
209 mutex->__data.__owner = newowner;
210 if (decr)
211 /* One less user. */
212 --mutex->__data.__nusers;
214 /* Unlock. */
215 if ((mutex->__data.__lock & FUTEX_WAITERS) != 0
216 || atomic_compare_and_exchange_bool_acq (&mutex->__data.__lock, 0,
217 THREAD_GETMEM (THREAD_SELF,
218 tid)))
220 int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
221 int private = (robust
222 ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
223 : PTHREAD_MUTEX_PSHARED (mutex));
224 INTERNAL_SYSCALL_DECL (__err);
225 INTERNAL_SYSCALL (futex, __err, 2, &mutex->__data.__lock,
226 __lll_private_flag (FUTEX_UNLOCK_PI, private));
229 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
230 break;
232 case PTHREAD_MUTEX_PP_RECURSIVE_NP:
233 /* Recursive mutex. */
234 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
235 return EPERM;
237 if (--mutex->__data.__count != 0)
238 /* We still hold the mutex. */
239 return 0;
240 goto pp;
242 case PTHREAD_MUTEX_PP_ERRORCHECK_NP:
243 /* Error checking mutex. */
244 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)
245 || (mutex->__data.__lock & ~ PTHREAD_MUTEX_PRIO_CEILING_MASK) == 0)
246 return EPERM;
247 /* FALLTHROUGH */
249 case PTHREAD_MUTEX_PP_NORMAL_NP:
250 case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
251 /* Always reset the owner field. */
253 mutex->__data.__owner = 0;
255 if (decr)
256 /* One less user. */
257 --mutex->__data.__nusers;
259 /* Unlock. */
260 int newval, oldval;
263 oldval = mutex->__data.__lock;
264 newval = oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK;
266 while (atomic_compare_and_exchange_bool_acq (&mutex->__data.__lock,
267 newval, oldval));
269 if ((oldval & ~PTHREAD_MUTEX_PRIO_CEILING_MASK) > 1)
270 lll_futex_wake (&mutex->__data.__lock, 1,
271 PTHREAD_MUTEX_PSHARED (mutex));
273 int oldprio = newval >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
274 return __pthread_tpp_change_priority (oldprio, -1);
276 default:
277 /* Correct code cannot set any other type. */
278 return EINVAL;
281 return 0;
286 __pthread_mutex_unlock (mutex)
287 pthread_mutex_t *mutex;
289 return __pthread_mutex_unlock_usercnt (mutex, 1);
291 strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock)
292 strong_alias (__pthread_mutex_unlock, __pthread_mutex_unlock_internal)