]> git.ipfire.org Git - thirdparty/glibc.git/blame - nptl/pthread_mutex_unlock.c
Add systemtap static probe points in setjmp/longjmp on x86.
[thirdparty/glibc.git] / nptl / pthread_mutex_unlock.c
CommitLineData
e73e694e 1/* Copyright (C) 2002, 2003, 2005-2008, 2009 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
PE
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
76a50749 18
6de79a49 19#include <assert.h>
76a50749 20#include <errno.h>
1bcfb5a5 21#include <stdlib.h>
76a50749
UD
22#include "pthreadP.h"
23#include <lowlevellock.h>
24
6de79a49
UD
25static int
26internal_function
27__pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr)
28 __attribute_noinline__;
76a50749
UD
29
30int
3a4f2043 31internal_function attribute_hidden
61623643 32__pthread_mutex_unlock_usercnt (mutex, decr)
76a50749 33 pthread_mutex_t *mutex;
8f31c0ef 34 int decr;
76a50749 35{
6de79a49
UD
36 int type = PTHREAD_MUTEX_TYPE (mutex);
37 if (__builtin_expect (type & ~PTHREAD_MUTEX_KIND_MASK_NP, 0))
38 return __pthread_mutex_unlock_full (mutex, decr);
1bcfb5a5 39
6de79a49
UD
40 if (__builtin_expect (type, PTHREAD_MUTEX_TIMED_NP)
41 == PTHREAD_MUTEX_TIMED_NP)
42 {
43 /* Always reset the owner field. */
44 normal:
45 mutex->__data.__owner = 0;
46 if (decr)
47 /* One less user. */
48 --mutex->__data.__nusers;
49
50 /* Unlock. */
51 lll_unlock (mutex->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex));
52 return 0;
53 }
54 else if (__builtin_expect (type == PTHREAD_MUTEX_RECURSIVE_NP, 1))
76a50749 55 {
76a50749 56 /* Recursive mutex. */
61623643 57 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
76a50749
UD
58 return EPERM;
59
60 if (--mutex->__data.__count != 0)
61 /* We still hold the mutex. */
62 return 0;
683040c3 63 goto normal;
6de79a49
UD
64 }
65 else if (__builtin_expect (type == PTHREAD_MUTEX_ADAPTIVE_NP, 1))
66 goto normal;
67 else
68 {
76a50749 69 /* Error checking mutex. */
6de79a49 70 assert (type == PTHREAD_MUTEX_ERRORCHECK_NP);
61623643 71 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)
e51deae7 72 || ! lll_islocked (mutex->__data.__lock))
76a50749 73 return EPERM;
6de79a49
UD
74 goto normal;
75 }
76}
76a50749 77
683040c3 78
6de79a49
UD
79static int
80internal_function
81__pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr)
82{
83 int newowner = 0;
dcc73a8d 84
6de79a49
UD
85 switch (PTHREAD_MUTEX_TYPE (mutex))
86 {
0f6699ea 87 case PTHREAD_MUTEX_ROBUST_RECURSIVE_NP:
1bcfb5a5 88 /* Recursive mutex. */
683040c3 89 if ((mutex->__data.__lock & FUTEX_TID_MASK)
0f6699ea
UD
90 == THREAD_GETMEM (THREAD_SELF, tid)
91 && __builtin_expect (mutex->__data.__owner
92 == PTHREAD_MUTEX_INCONSISTENT, 0))
1bcfb5a5
UD
93 {
94 if (--mutex->__data.__count != 0)
95 /* We still hold the mutex. */
96 return ENOTRECOVERABLE;
97
98 goto notrecoverable;
99 }
100
101 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
102 return EPERM;
103
104 if (--mutex->__data.__count != 0)
105 /* We still hold the mutex. */
106 return 0;
107
108 goto robust;
109
0f6699ea
UD
110 case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP:
111 case PTHREAD_MUTEX_ROBUST_NORMAL_NP:
112 case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
683040c3
UD
113 if ((mutex->__data.__lock & FUTEX_TID_MASK)
114 != THREAD_GETMEM (THREAD_SELF, tid)
e51deae7 115 || ! lll_islocked (mutex->__data.__lock))
1bcfb5a5
UD
116 return EPERM;
117
1bcfb5a5
UD
118 /* If the previous owner died and the caller did not succeed in
119 making the state consistent, mark the mutex as unrecoverable
120 and make all waiters. */
121 if (__builtin_expect (mutex->__data.__owner
683040c3 122 == PTHREAD_MUTEX_INCONSISTENT, 0))
1bcfb5a5
UD
123 notrecoverable:
124 newowner = PTHREAD_MUTEX_NOTRECOVERABLE;
125
126 robust:
127 /* Remove mutex from the list. */
0f6699ea
UD
128 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
129 &mutex->__data.__list.__next);
1bcfb5a5 130 DEQUEUE_MUTEX (mutex);
683040c3
UD
131
132 mutex->__data.__owner = newowner;
133 if (decr)
134 /* One less user. */
135 --mutex->__data.__nusers;
136
137 /* Unlock. */
5bd8a249
UD
138 lll_robust_unlock (mutex->__data.__lock,
139 PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
0f6699ea
UD
140
141 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
1bcfb5a5
UD
142 break;
143
df47504c
UD
144 case PTHREAD_MUTEX_PI_RECURSIVE_NP:
145 /* Recursive mutex. */
146 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
147 return EPERM;
148
149 if (--mutex->__data.__count != 0)
150 /* We still hold the mutex. */
151 return 0;
b0948ffd 152 goto continue_pi_non_robust;
df47504c
UD
153
154 case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP:
155 /* Recursive mutex. */
156 if ((mutex->__data.__lock & FUTEX_TID_MASK)
157 == THREAD_GETMEM (THREAD_SELF, tid)
158 && __builtin_expect (mutex->__data.__owner
159 == PTHREAD_MUTEX_INCONSISTENT, 0))
160 {
161 if (--mutex->__data.__count != 0)
162 /* We still hold the mutex. */
163 return ENOTRECOVERABLE;
164
165 goto pi_notrecoverable;
166 }
167
168 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
169 return EPERM;
170
171 if (--mutex->__data.__count != 0)
172 /* We still hold the mutex. */
173 return 0;
174
b0948ffd 175 goto continue_pi_robust;
df47504c
UD
176
177 case PTHREAD_MUTEX_PI_ERRORCHECK_NP:
178 case PTHREAD_MUTEX_PI_NORMAL_NP:
179 case PTHREAD_MUTEX_PI_ADAPTIVE_NP:
180 case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP:
181 case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
182 case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
183 if ((mutex->__data.__lock & FUTEX_TID_MASK)
184 != THREAD_GETMEM (THREAD_SELF, tid)
e51deae7 185 || ! lll_islocked (mutex->__data.__lock))
df47504c
UD
186 return EPERM;
187
188 /* If the previous owner died and the caller did not succeed in
189 making the state consistent, mark the mutex as unrecoverable
190 and make all waiters. */
191 if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0
192 && __builtin_expect (mutex->__data.__owner
193 == PTHREAD_MUTEX_INCONSISTENT, 0))
194 pi_notrecoverable:
195 newowner = PTHREAD_MUTEX_NOTRECOVERABLE;
196
df47504c
UD
197 if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0)
198 {
b0948ffd 199 continue_pi_robust:
df47504c
UD
200 /* Remove mutex from the list.
201 Note: robust PI futexes are signaled by setting bit 0. */
202 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
203 (void *) (((uintptr_t) &mutex->__data.__list.__next)
204 | 1));
205 DEQUEUE_MUTEX (mutex);
206 }
207
b0948ffd 208 continue_pi_non_robust:
df47504c
UD
209 mutex->__data.__owner = newowner;
210 if (decr)
211 /* One less user. */
212 --mutex->__data.__nusers;
213
214 /* Unlock. */
215 if ((mutex->__data.__lock & FUTEX_WAITERS) != 0
e73e694e 216 || atomic_compare_and_exchange_bool_rel (&mutex->__data.__lock, 0,
df47504c
UD
217 THREAD_GETMEM (THREAD_SELF,
218 tid)))
219 {
efac1fce
UD
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));
df47504c
UD
224 INTERNAL_SYSCALL_DECL (__err);
225 INTERNAL_SYSCALL (futex, __err, 2, &mutex->__data.__lock,
efac1fce 226 __lll_private_flag (FUTEX_UNLOCK_PI, private));
df47504c
UD
227 }
228
229 THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
230 break;
231
f17efcb4
UD
232 case PTHREAD_MUTEX_PP_RECURSIVE_NP:
233 /* Recursive mutex. */
234 if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
235 return EPERM;
236
237 if (--mutex->__data.__count != 0)
238 /* We still hold the mutex. */
239 return 0;
240 goto pp;
241
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 */
248
249 case PTHREAD_MUTEX_PP_NORMAL_NP:
250 case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
251 /* Always reset the owner field. */
252 pp:
253 mutex->__data.__owner = 0;
254
255 if (decr)
256 /* One less user. */
257 --mutex->__data.__nusers;
258
259 /* Unlock. */
260 int newval, oldval;
261 do
262 {
263 oldval = mutex->__data.__lock;
264 newval = oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK;
265 }
e73e694e 266 while (atomic_compare_and_exchange_bool_rel (&mutex->__data.__lock,
f17efcb4
UD
267 newval, oldval));
268
269 if ((oldval & ~PTHREAD_MUTEX_PRIO_CEILING_MASK) > 1)
835abc5c 270 lll_futex_wake (&mutex->__data.__lock, 1,
5bd8a249 271 PTHREAD_MUTEX_PSHARED (mutex));
f17efcb4
UD
272
273 int oldprio = newval >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
274 return __pthread_tpp_change_priority (oldprio, -1);
275
dcc73a8d
UD
276 default:
277 /* Correct code cannot set any other type. */
278 return EINVAL;
a334319f 279 }
0ecb606c 280
76a50749
UD
281 return 0;
282}
61623643
UD
283
284
285int
286__pthread_mutex_unlock (mutex)
287 pthread_mutex_t *mutex;
288{
8f31c0ef 289 return __pthread_mutex_unlock_usercnt (mutex, 1);
61623643 290}
76a50749 291strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock)
db0a052c 292strong_alias (__pthread_mutex_unlock, __pthread_mutex_unlock_internal)