]>
Commit | Line | Data |
---|---|---|
683040c3 | 1 | /* Copyright (C) 2002, 2003, 2004, 2005, 2006 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 | |
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 | ||
3892d906 | 20 | #include <assert.h> |
76a50749 | 21 | #include <errno.h> |
1bcfb5a5 | 22 | #include <stdlib.h> |
76a50749 UD |
23 | #include "pthreadP.h" |
24 | #include <lowlevellock.h> | |
25 | ||
26 | ||
69431c9a UD |
27 | #ifndef LLL_MUTEX_LOCK |
28 | # define LLL_MUTEX_LOCK(mutex) lll_mutex_lock (mutex) | |
2c0b891a | 29 | # define LLL_MUTEX_TRYLOCK(mutex) lll_mutex_trylock (mutex) |
683040c3 | 30 | # define LLL_ROBUST_MUTEX_LOCK(mutex, id) lll_robust_mutex_lock (mutex, id) |
69431c9a UD |
31 | #endif |
32 | ||
33 | ||
76a50749 UD |
34 | int |
35 | __pthread_mutex_lock (mutex) | |
36 | pthread_mutex_t *mutex; | |
37 | { | |
2c0b891a UD |
38 | assert (sizeof (mutex->__size) >= sizeof (mutex->__data)); |
39 | ||
683040c3 | 40 | int oldval; |
61623643 | 41 | pid_t id = THREAD_GETMEM (THREAD_SELF, tid); |
76a50749 | 42 | |
1bcfb5a5 | 43 | int retval = 0; |
76a50749 UD |
44 | switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP)) |
45 | { | |
46 | /* Recursive mutex. */ | |
47 | case PTHREAD_MUTEX_RECURSIVE_NP: | |
48 | /* Check whether we already hold the mutex. */ | |
9a7178d6 | 49 | if (mutex->__data.__owner == id) |
76a50749 UD |
50 | { |
51 | /* Just bump the counter. */ | |
52 | if (__builtin_expect (mutex->__data.__count + 1 == 0, 0)) | |
53 | /* Overflow of the counter. */ | |
54 | return EAGAIN; | |
55 | ||
56 | ++mutex->__data.__count; | |
76a50749 | 57 | |
3892d906 | 58 | return 0; |
76a50749 | 59 | } |
3892d906 UD |
60 | |
61 | /* We have to get the mutex. */ | |
62 | LLL_MUTEX_LOCK (mutex->__data.__lock); | |
63 | ||
1bcfb5a5 | 64 | assert (mutex->__data.__owner == 0); |
3892d906 | 65 | mutex->__data.__count = 1; |
76a50749 UD |
66 | break; |
67 | ||
68 | /* Error checking mutex. */ | |
69 | case PTHREAD_MUTEX_ERRORCHECK_NP: | |
70 | /* Check whether we already hold the mutex. */ | |
1bcfb5a5 | 71 | if (__builtin_expect (mutex->__data.__owner == id, 0)) |
76a50749 UD |
72 | return EDEADLK; |
73 | ||
74 | /* FALLTHROUGH */ | |
75 | ||
76a50749 | 76 | case PTHREAD_MUTEX_TIMED_NP: |
2c0b891a | 77 | simple: |
76a50749 | 78 | /* Normal mutex. */ |
69431c9a | 79 | LLL_MUTEX_LOCK (mutex->__data.__lock); |
1bcfb5a5 | 80 | assert (mutex->__data.__owner == 0); |
76a50749 | 81 | break; |
2c0b891a UD |
82 | |
83 | case PTHREAD_MUTEX_ADAPTIVE_NP: | |
84 | if (! __is_smp) | |
85 | goto simple; | |
86 | ||
87 | if (LLL_MUTEX_TRYLOCK (mutex->__data.__lock) != 0) | |
88 | { | |
89 | int cnt = 0; | |
90 | int max_cnt = MIN (MAX_ADAPTIVE_COUNT, | |
91 | mutex->__data.__spins * 2 + 10); | |
92 | do | |
93 | { | |
94 | if (cnt++ >= max_cnt) | |
95 | { | |
96 | LLL_MUTEX_LOCK (mutex->__data.__lock); | |
97 | break; | |
98 | } | |
99 | ||
100 | #ifdef BUSY_WAIT_NOP | |
101 | BUSY_WAIT_NOP; | |
102 | #endif | |
103 | } | |
104 | while (LLL_MUTEX_TRYLOCK (mutex->__data.__lock) != 0); | |
105 | ||
106 | mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8; | |
107 | } | |
1bcfb5a5 UD |
108 | assert (mutex->__data.__owner == 0); |
109 | break; | |
110 | ||
0f6699ea UD |
111 | case PTHREAD_MUTEX_ROBUST_RECURSIVE_NP: |
112 | case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP: | |
113 | case PTHREAD_MUTEX_ROBUST_NORMAL_NP: | |
114 | case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP: | |
115 | THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, | |
116 | &mutex->__data.__list.__next); | |
117 | ||
683040c3 UD |
118 | oldval = mutex->__data.__lock; |
119 | do | |
1bcfb5a5 | 120 | { |
0f6699ea | 121 | again: |
683040c3 UD |
122 | if ((oldval & FUTEX_OWNER_DIED) != 0) |
123 | { | |
124 | /* The previous owner died. Try locking the mutex. */ | |
0f6699ea UD |
125 | int newval = id; |
126 | #ifdef NO_INCR | |
127 | newval |= FUTEX_WAITERS; | |
128 | #endif | |
129 | ||
130 | newval | |
131 | = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, | |
132 | newval, oldval); | |
133 | ||
134 | if (newval != oldval) | |
683040c3 | 135 | { |
683040c3 | 136 | oldval = newval; |
0f6699ea | 137 | goto again; |
683040c3 | 138 | } |
1bcfb5a5 | 139 | |
683040c3 UD |
140 | /* We got the mutex. */ |
141 | mutex->__data.__count = 1; | |
142 | /* But it is inconsistent unless marked otherwise. */ | |
143 | mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; | |
144 | ||
145 | ENQUEUE_MUTEX (mutex); | |
0f6699ea | 146 | THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); |
683040c3 UD |
147 | |
148 | /* Note that we deliberately exit here. If we fall | |
149 | through to the end of the function __nusers would be | |
150 | incremented which is not correct because the old | |
151 | owner has to be discounted. If we are not supposed | |
152 | to increment __nusers we actually have to decrement | |
153 | it here. */ | |
154 | #ifdef NO_INCR | |
155 | --mutex->__data.__nusers; | |
156 | #endif | |
1bcfb5a5 | 157 | |
683040c3 UD |
158 | return EOWNERDEAD; |
159 | } | |
1bcfb5a5 | 160 | |
683040c3 | 161 | /* Check whether we already hold the mutex. */ |
0f6699ea | 162 | if (__builtin_expect ((oldval & FUTEX_TID_MASK) == id, 0)) |
683040c3 UD |
163 | { |
164 | if (mutex->__data.__kind | |
0f6699ea UD |
165 | == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP) |
166 | { | |
167 | THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, | |
168 | NULL); | |
169 | return EDEADLK; | |
170 | } | |
1bcfb5a5 | 171 | |
683040c3 | 172 | if (mutex->__data.__kind |
0f6699ea | 173 | == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP) |
683040c3 | 174 | { |
0f6699ea UD |
175 | THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, |
176 | NULL); | |
177 | ||
683040c3 UD |
178 | /* Just bump the counter. */ |
179 | if (__builtin_expect (mutex->__data.__count + 1 == 0, 0)) | |
180 | /* Overflow of the counter. */ | |
181 | return EAGAIN; | |
1bcfb5a5 | 182 | |
683040c3 | 183 | ++mutex->__data.__count; |
1bcfb5a5 | 184 | |
683040c3 UD |
185 | return 0; |
186 | } | |
187 | } | |
1bcfb5a5 | 188 | |
683040c3 | 189 | oldval = LLL_ROBUST_MUTEX_LOCK (mutex->__data.__lock, id); |
1bcfb5a5 | 190 | |
683040c3 UD |
191 | if (__builtin_expect (mutex->__data.__owner |
192 | == PTHREAD_MUTEX_NOTRECOVERABLE, 0)) | |
193 | { | |
194 | /* This mutex is now not recoverable. */ | |
195 | mutex->__data.__count = 0; | |
196 | lll_mutex_unlock (mutex->__data.__lock); | |
0f6699ea | 197 | THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); |
683040c3 UD |
198 | return ENOTRECOVERABLE; |
199 | } | |
1bcfb5a5 | 200 | } |
683040c3 | 201 | while ((oldval & FUTEX_OWNER_DIED) != 0); |
1bcfb5a5 | 202 | |
683040c3 | 203 | mutex->__data.__count = 1; |
1bcfb5a5 | 204 | ENQUEUE_MUTEX (mutex); |
0f6699ea | 205 | THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); |
2c0b891a | 206 | break; |
dcc73a8d UD |
207 | |
208 | default: | |
209 | /* Correct code cannot set any other type. */ | |
210 | return EINVAL; | |
76a50749 UD |
211 | } |
212 | ||
3892d906 | 213 | /* Record the ownership. */ |
3892d906 UD |
214 | mutex->__data.__owner = id; |
215 | #ifndef NO_INCR | |
216 | ++mutex->__data.__nusers; | |
217 | #endif | |
218 | ||
1bcfb5a5 | 219 | return retval; |
76a50749 | 220 | } |
69431c9a | 221 | #ifndef __pthread_mutex_lock |
76a50749 | 222 | strong_alias (__pthread_mutex_lock, pthread_mutex_lock) |
db0a052c | 223 | strong_alias (__pthread_mutex_lock, __pthread_mutex_lock_internal) |
69431c9a | 224 | #endif |