iconv: Suppress array out of bounds warning.
[platform/upstream/glibc.git] / nptl / pthread_mutex_unlock.c
1 /* Copyright (C) 2002-2015 Free Software Foundation, Inc.
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
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
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>
25
26 #ifndef lll_unlock_elision
27 #define lll_unlock_elision(a,b) ({ lll_unlock (a,b); 0; })
28 #endif
29
30 static int
31 internal_function
32 __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr)
33      __attribute_noinline__;
34
35 int
36 internal_function attribute_hidden
37 __pthread_mutex_unlock_usercnt (mutex, decr)
38      pthread_mutex_t *mutex;
39      int decr;
40 {
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);
45
46   if (__builtin_expect (type, PTHREAD_MUTEX_TIMED_NP)
47       == PTHREAD_MUTEX_TIMED_NP)
48     {
49       /* Always reset the owner field.  */
50     normal:
51       mutex->__data.__owner = 0;
52       if (decr)
53         /* One less user.  */
54         --mutex->__data.__nusers;
55
56       /* Unlock.  */
57       lll_unlock (mutex->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex));
58
59       LIBC_PROBE (mutex_release, 1, mutex);
60
61       return 0;
62     }
63   else if (__glibc_likely (type == PTHREAD_MUTEX_TIMED_ELISION_NP))
64     {
65       /* Don't reset the owner/users fields for elision.  */
66       return lll_unlock_elision (mutex->__data.__lock,
67                                       PTHREAD_MUTEX_PSHARED (mutex));
68     }
69   else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex)
70                               == PTHREAD_MUTEX_RECURSIVE_NP, 1))
71     {
72       /* Recursive mutex.  */
73       if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
74         return EPERM;
75
76       if (--mutex->__data.__count != 0)
77         /* We still hold the mutex.  */
78         return 0;
79       goto normal;
80     }
81   else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex)
82                               == PTHREAD_MUTEX_ADAPTIVE_NP, 1))
83     goto normal;
84   else
85     {
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;
92     }
93 }
94
95
96 static int
97 internal_function
98 __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr)
99 {
100   int newowner = 0;
101
102   switch (PTHREAD_MUTEX_TYPE (mutex))
103     {
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))
110         {
111           if (--mutex->__data.__count != 0)
112             /* We still hold the mutex.  */
113             return ENOTRECOVERABLE;
114
115           goto notrecoverable;
116         }
117
118       if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
119         return EPERM;
120
121       if (--mutex->__data.__count != 0)
122         /* We still hold the mutex.  */
123         return 0;
124
125       goto robust;
126
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;
134
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;
142
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);
148
149       mutex->__data.__owner = newowner;
150       if (decr)
151         /* One less user.  */
152         --mutex->__data.__nusers;
153
154       /* Unlock.  */
155       lll_robust_unlock (mutex->__data.__lock,
156                          PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
157
158       THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
159       break;
160
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;
169
170       if (--mutex->__data.__count != 0)
171         /* We still hold the mutex.  */
172         return 0;
173       goto continue_pi_non_robust;
174
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))
181         {
182           if (--mutex->__data.__count != 0)
183             /* We still hold the mutex.  */
184             return ENOTRECOVERABLE;
185
186           goto pi_notrecoverable;
187         }
188
189       if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
190         return EPERM;
191
192       if (--mutex->__data.__count != 0)
193         /* We still hold the mutex.  */
194         return 0;
195
196       goto continue_pi_robust;
197
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;
208
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;
217
218       if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0)
219         {
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);
227         }
228
229     continue_pi_non_robust:
230       mutex->__data.__owner = newowner;
231       if (decr)
232         /* One less user.  */
233         --mutex->__data.__nusers;
234
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)))
240         {
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));
248         }
249
250       THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
251       break;
252 #endif  /* __NR_futex.  */
253
254     case PTHREAD_MUTEX_PP_RECURSIVE_NP:
255       /* Recursive mutex.  */
256       if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
257         return EPERM;
258
259       if (--mutex->__data.__count != 0)
260         /* We still hold the mutex.  */
261         return 0;
262       goto pp;
263
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 */
270
271     case PTHREAD_MUTEX_PP_NORMAL_NP:
272     case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
273       /* Always reset the owner field.  */
274     pp:
275       mutex->__data.__owner = 0;
276
277       if (decr)
278         /* One less user.  */
279         --mutex->__data.__nusers;
280
281       /* Unlock.  */
282       int newval, oldval;
283       do
284         {
285           oldval = mutex->__data.__lock;
286           newval = oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK;
287         }
288       while (atomic_compare_and_exchange_bool_rel (&mutex->__data.__lock,
289                                                    newval, oldval));
290
291       if ((oldval & ~PTHREAD_MUTEX_PRIO_CEILING_MASK) > 1)
292         lll_futex_wake (&mutex->__data.__lock, 1,
293                         PTHREAD_MUTEX_PSHARED (mutex));
294
295       int oldprio = newval >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
296
297       LIBC_PROBE (mutex_release, 1, mutex);
298
299       return __pthread_tpp_change_priority (oldprio, -1);
300
301     default:
302       /* Correct code cannot set any other type.  */
303       return EINVAL;
304     }
305
306   LIBC_PROBE (mutex_release, 1, mutex);
307   return 0;
308 }
309
310
311 int
312 __pthread_mutex_unlock (mutex)
313      pthread_mutex_t *mutex;
314 {
315   return __pthread_mutex_unlock_usercnt (mutex, 1);
316 }
317 strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock)
318 hidden_def (__pthread_mutex_unlock)