* sysdeps/unix/sysv/linux/not-cancel.h (__openat_not_cancel,
[platform/upstream/glibc.git] / nptl / pthread_mutex_timedlock.c
1 /* Copyright (C) 2002, 2003, 2004, 2005, 2006 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 "pthreadP.h"
23 #include <lowlevellock.h>
24
25
26 int
27 pthread_mutex_timedlock (mutex, abstime)
28      pthread_mutex_t *mutex;
29      const struct timespec *abstime;
30 {
31   int oldval;
32   pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
33   int result = 0;
34
35   /* We must not check ABSTIME here.  If the thread does not block
36      abstime must not be checked for a valid value.  */
37
38   switch (mutex->__data.__kind)
39     {
40       /* Recursive mutex.  */
41     case PTHREAD_MUTEX_RECURSIVE_NP:
42       /* Check whether we already hold the mutex.  */
43       if (mutex->__data.__owner == id)
44         {
45           /* Just bump the counter.  */
46           if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
47             /* Overflow of the counter.  */
48             return EAGAIN;
49
50           ++mutex->__data.__count;
51
52           goto out;
53         }
54
55       /* We have to get the mutex.  */
56       result = lll_mutex_timedlock (mutex->__data.__lock, abstime);
57
58       if (result != 0)
59         goto out;
60
61       /* Only locked once so far.  */
62       mutex->__data.__count = 1;
63       break;
64
65       /* Error checking mutex.  */
66     case PTHREAD_MUTEX_ERRORCHECK_NP:
67       /* Check whether we already hold the mutex.  */
68       if (mutex->__data.__owner == id)
69         return EDEADLK;
70
71       /* FALLTHROUGH */
72
73     case PTHREAD_MUTEX_TIMED_NP:
74     simple:
75       /* Normal mutex.  */
76       result = lll_mutex_timedlock (mutex->__data.__lock, abstime);
77       break;
78
79     case PTHREAD_MUTEX_ADAPTIVE_NP:
80       if (! __is_smp)
81         goto simple;
82
83       if (lll_mutex_trylock (mutex->__data.__lock) != 0)
84         {
85           int cnt = 0;
86           int max_cnt = MIN (MAX_ADAPTIVE_COUNT,
87                              mutex->__data.__spins * 2 + 10);
88           do
89             {
90               if (cnt++ >= max_cnt)
91                 {
92                   result = lll_mutex_timedlock (mutex->__data.__lock, abstime);
93                   break;
94                 }
95
96 #ifdef BUSY_WAIT_NOP
97               BUSY_WAIT_NOP;
98 #endif
99             }
100           while (lll_mutex_trylock (mutex->__data.__lock) != 0);
101
102           mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8;
103         }
104       break;
105
106     case PTHREAD_MUTEX_ROBUST_PRIVATE_RECURSIVE_NP:
107     case PTHREAD_MUTEX_ROBUST_PRIVATE_ERRORCHECK_NP:
108     case PTHREAD_MUTEX_ROBUST_PRIVATE_NP:
109     case PTHREAD_MUTEX_ROBUST_PRIVATE_ADAPTIVE_NP:
110       oldval = mutex->__data.__lock;
111       do
112         {
113           if ((oldval & FUTEX_OWNER_DIED) != 0)
114             {
115               /* The previous owner died.  Try locking the mutex.  */
116               int newval;
117               while ((newval
118                       = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
119                                                              id, oldval))
120                      != oldval)
121                 {
122                   if ((newval & FUTEX_OWNER_DIED) == 0)
123                     goto normal;
124                   oldval = newval;
125                 }
126
127               /* We got the mutex.  */
128               mutex->__data.__count = 1;
129               /* But it is inconsistent unless marked otherwise.  */
130               mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
131
132               ENQUEUE_MUTEX (mutex);
133
134               /* Note that we deliberately exist here.  If we fall
135                  through to the end of the function __nusers would be
136                  incremented which is not correct because the old
137                  owner has to be discounted.  */
138               return EOWNERDEAD;
139             }
140
141         normal:
142           /* Check whether we already hold the mutex.  */
143           if (__builtin_expect ((mutex->__data.__lock & FUTEX_TID_MASK)
144                                 == id, 0))
145             {
146               if (mutex->__data.__kind
147                   == PTHREAD_MUTEX_ROBUST_PRIVATE_ERRORCHECK_NP)
148                 return EDEADLK;
149
150               if (mutex->__data.__kind
151                   == PTHREAD_MUTEX_ROBUST_PRIVATE_RECURSIVE_NP)
152                 {
153                   /* Just bump the counter.  */
154                   if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
155                     /* Overflow of the counter.  */
156                     return EAGAIN;
157
158                   ++mutex->__data.__count;
159
160                   return 0;
161                 }
162             }
163
164           result = lll_robust_mutex_timedlock (mutex->__data.__lock, abstime,
165                                                id);
166
167           if (__builtin_expect (mutex->__data.__owner
168                                 == PTHREAD_MUTEX_NOTRECOVERABLE, 0))
169             {
170               /* This mutex is now not recoverable.  */
171               mutex->__data.__count = 0;
172               lll_mutex_unlock (mutex->__data.__lock);
173               return ENOTRECOVERABLE;
174             }
175
176           if (result == ETIMEDOUT || result == EINVAL)
177             goto out;
178
179           oldval = result;
180         }
181       while ((oldval & FUTEX_OWNER_DIED) != 0);
182
183       mutex->__data.__count = 1;
184       ENQUEUE_MUTEX (mutex);
185       break;
186
187     default:
188       /* Correct code cannot set any other type.  */
189       return EINVAL;
190     }
191
192   if (result == 0)
193     {
194       /* Record the ownership.  */
195       mutex->__data.__owner = id;
196       ++mutex->__data.__nusers;
197     }
198
199  out:
200   return result;
201 }