OSDN Git Service

3abada235d0cb6d7bf1b0d0a799e39893053f528
[uclinux-h8/uClibc.git] / libpthread / nptl / pthread_mutex_unlock.c
1 /* Copyright (C) 2002, 2003, 2005-2008, 2009 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, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <assert.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include "pthreadP.h"
24 #include <lowlevellock.h>
25
26 static int
27 internal_function
28 __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr)
29      __attribute_noinline__;
30
31 int
32 internal_function attribute_hidden
33 __pthread_mutex_unlock_usercnt (
34      pthread_mutex_t *mutex,
35      int decr)
36 {
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);
40
41   if (__builtin_expect (type, PTHREAD_MUTEX_TIMED_NP)
42       == PTHREAD_MUTEX_TIMED_NP)
43     {
44       /* Always reset the owner field.  */
45     normal:
46       mutex->__data.__owner = 0;
47       if (decr)
48         /* One less user.  */
49         --mutex->__data.__nusers;
50
51       /* Unlock.  */
52       lll_unlock (mutex->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex));
53       return 0;
54     }
55   else if (__builtin_expect (type == PTHREAD_MUTEX_RECURSIVE_NP, 1))
56     {
57       /* Recursive mutex.  */
58       if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
59         return EPERM;
60
61       if (--mutex->__data.__count != 0)
62         /* We still hold the mutex.  */
63         return 0;
64       goto normal;
65     }
66   else if (__builtin_expect (type == PTHREAD_MUTEX_ADAPTIVE_NP, 1))
67     goto normal;
68   else
69     {
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;
76     }
77 }
78
79
80 static int
81 internal_function
82 __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr)
83 {
84   int newowner = 0;
85
86   switch (PTHREAD_MUTEX_TYPE (mutex))
87     {
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))
94         {
95           if (--mutex->__data.__count != 0)
96             /* We still hold the mutex.  */
97             return ENOTRECOVERABLE;
98
99           goto notrecoverable;
100         }
101
102       if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
103         return EPERM;
104
105       if (--mutex->__data.__count != 0)
106         /* We still hold the mutex.  */
107         return 0;
108
109       goto robust;
110
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;
118
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;
126
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);
132
133       mutex->__data.__owner = newowner;
134       if (decr)
135         /* One less user.  */
136         --mutex->__data.__nusers;
137
138       /* Unlock.  */
139       lll_robust_unlock (mutex->__data.__lock,
140                          PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
141
142       THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
143       break;
144
145     case PTHREAD_MUTEX_PI_RECURSIVE_NP:
146       /* Recursive mutex.  */
147       if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
148         return EPERM;
149
150       if (--mutex->__data.__count != 0)
151         /* We still hold the mutex.  */
152         return 0;
153       goto continue_pi_non_robust;
154
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))
161         {
162           if (--mutex->__data.__count != 0)
163             /* We still hold the mutex.  */
164             return ENOTRECOVERABLE;
165
166           goto pi_notrecoverable;
167         }
168
169       if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
170         return EPERM;
171
172       if (--mutex->__data.__count != 0)
173         /* We still hold the mutex.  */
174         return 0;
175
176       goto continue_pi_robust;
177
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;
188
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;
197
198       if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0)
199         {
200         continue_pi_robust:
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);
207         }
208
209     continue_pi_non_robust:
210       mutex->__data.__owner = newowner;
211       if (decr)
212         /* One less user.  */
213         --mutex->__data.__nusers;
214
215       /* Unlock.  */
216       if ((mutex->__data.__lock & FUTEX_WAITERS) != 0
217           || atomic_compare_and_exchange_bool_rel (&mutex->__data.__lock, 0,
218                                                    THREAD_GETMEM (THREAD_SELF,
219                                                                   tid)))
220         {
221           int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
222           int private = (robust
223                          ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
224                          : PTHREAD_MUTEX_PSHARED (mutex));
225           INTERNAL_SYSCALL_DECL (__err);
226           INTERNAL_SYSCALL (futex, __err, 2, &mutex->__data.__lock,
227                             __lll_private_flag (FUTEX_UNLOCK_PI, private));
228         }
229
230       THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
231       break;
232
233     case PTHREAD_MUTEX_PP_RECURSIVE_NP:
234       /* Recursive mutex.  */
235       if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
236         return EPERM;
237
238       if (--mutex->__data.__count != 0)
239         /* We still hold the mutex.  */
240         return 0;
241       goto pp;
242
243     case PTHREAD_MUTEX_PP_ERRORCHECK_NP:
244       /* Error checking mutex.  */
245       if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)
246           || (mutex->__data.__lock & ~ PTHREAD_MUTEX_PRIO_CEILING_MASK) == 0)
247         return EPERM;
248       /* FALLTHROUGH */
249
250     case PTHREAD_MUTEX_PP_NORMAL_NP:
251     case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
252       /* Always reset the owner field.  */
253     pp:
254       mutex->__data.__owner = 0;
255
256       if (decr)
257         /* One less user.  */
258         --mutex->__data.__nusers;
259
260       /* Unlock.  */
261       int newval, oldval;
262       do
263         {
264           oldval = mutex->__data.__lock;
265           newval = oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK;
266         }
267       while (atomic_compare_and_exchange_bool_rel (&mutex->__data.__lock,
268                                                    newval, oldval));
269
270       if ((oldval & ~PTHREAD_MUTEX_PRIO_CEILING_MASK) > 1)
271         lll_futex_wake (&mutex->__data.__lock, 1,
272                         PTHREAD_MUTEX_PSHARED (mutex));
273
274       int oldprio = newval >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
275       return __pthread_tpp_change_priority (oldprio, -1);
276
277     default:
278       /* Correct code cannot set any other type.  */
279       return EINVAL;
280     }
281
282   return 0;
283 }
284
285
286 int
287 attribute_protected
288 __pthread_mutex_unlock (
289      pthread_mutex_t *mutex)
290 {
291   return __pthread_mutex_unlock_usercnt (mutex, 1);
292 }
293 strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock)
294 strong_alias (__pthread_mutex_unlock, __pthread_mutex_unlock_internal)