Mon Mar 16 01:20:37 2009 UTC ()
Pull up following revision(s) (requested by adrianp in ticket #582):
	sys/compat/linux/common/linux_futex.c: revision 1.24 via patch
fix robust_list pointer mess!


(snj)
diff -r1.18.4.1 -r1.18.4.2 src/sys/compat/linux/common/linux_futex.c

cvs diff -r1.18.4.1 -r1.18.4.2 src/sys/compat/linux/common/Attic/linux_futex.c (switch to unified diff)

--- src/sys/compat/linux/common/Attic/linux_futex.c 2009/02/26 20:40:52 1.18.4.1
+++ src/sys/compat/linux/common/Attic/linux_futex.c 2009/03/16 01:20:37 1.18.4.2
@@ -1,632 +1,634 @@ @@ -1,632 +1,634 @@
1/* $NetBSD: linux_futex.c,v 1.18.4.1 2009/02/26 20:40:52 snj Exp $ */ 1/* $NetBSD: linux_futex.c,v 1.18.4.2 2009/03/16 01:20:37 snj Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved. 4 * Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software 14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement: 15 * must display the following acknowledgement:
16 * This product includes software developed by Emmanuel Dreyfus 16 * This product includes software developed by Emmanuel Dreyfus
17 * 4. The name of the author may not be used to endorse or promote  17 * 4. The name of the author may not be used to endorse or promote
18 * products derived from this software without specific prior written  18 * products derived from this software without specific prior written
19 * permission. 19 * permission.
20 * 20 *
21 * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS''  21 * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS''
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,  22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS  24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE. 31 * POSSIBILITY OF SUCH DAMAGE.
32 */ 32 */
33 33
34#include <sys/cdefs.h> 34#include <sys/cdefs.h>
35__KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.18.4.1 2009/02/26 20:40:52 snj Exp $"); 35__KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.18.4.2 2009/03/16 01:20:37 snj Exp $");
36 36
37#include <sys/param.h> 37#include <sys/param.h>
38#include <sys/time.h> 38#include <sys/time.h>
39#include <sys/systm.h> 39#include <sys/systm.h>
40#include <sys/proc.h> 40#include <sys/proc.h>
41#include <sys/lwp.h> 41#include <sys/lwp.h>
42#include <sys/queue.h> 42#include <sys/queue.h>
43#include <sys/condvar.h> 43#include <sys/condvar.h>
44#include <sys/mutex.h> 44#include <sys/mutex.h>
45#include <sys/once.h> 45#include <sys/once.h>
46#include <sys/kmem.h> 46#include <sys/kmem.h>
47#include <sys/kernel.h> 47#include <sys/kernel.h>
48#include <sys/atomic.h> 48#include <sys/atomic.h>
49 49
50#include <compat/linux/common/linux_types.h> 50#include <compat/linux/common/linux_types.h>
51#include <compat/linux/common/linux_emuldata.h> 51#include <compat/linux/common/linux_emuldata.h>
52#include <compat/linux/common/linux_exec.h> 52#include <compat/linux/common/linux_exec.h>
53#include <compat/linux/common/linux_signal.h> 53#include <compat/linux/common/linux_signal.h>
54#include <compat/linux/common/linux_futex.h> 54#include <compat/linux/common/linux_futex.h>
55#include <compat/linux/common/linux_ipc.h> 55#include <compat/linux/common/linux_ipc.h>
56#include <compat/linux/common/linux_sem.h> 56#include <compat/linux/common/linux_sem.h>
57#include <compat/linux/linux_syscallargs.h> 57#include <compat/linux/linux_syscallargs.h>
58 58
59struct futex; 59struct futex;
60 60
61struct waiting_proc { 61struct waiting_proc {
62 lwp_t *wp_l; 62 lwp_t *wp_l;
63 struct futex *wp_new_futex; 63 struct futex *wp_new_futex;
64 kcondvar_t wp_futex_cv; 64 kcondvar_t wp_futex_cv;
65 TAILQ_ENTRY(waiting_proc) wp_list; 65 TAILQ_ENTRY(waiting_proc) wp_list;
66}; 66};
67struct futex { 67struct futex {
68 void *f_uaddr; 68 void *f_uaddr;
69 int f_refcount; 69 int f_refcount;
70 LIST_ENTRY(futex) f_list; 70 LIST_ENTRY(futex) f_list;
71 TAILQ_HEAD(lf_waiting_proc, waiting_proc) f_waiting_proc; 71 TAILQ_HEAD(lf_waiting_proc, waiting_proc) f_waiting_proc;
72}; 72};
73 73
74static LIST_HEAD(futex_list, futex) futex_list; 74static LIST_HEAD(futex_list, futex) futex_list;
75static kmutex_t futex_lock; 75static kmutex_t futex_lock;
76 76
77#define FUTEX_LOCK mutex_enter(&futex_lock); 77#define FUTEX_LOCK mutex_enter(&futex_lock);
78#define FUTEX_UNLOCK mutex_exit(&futex_lock); 78#define FUTEX_UNLOCK mutex_exit(&futex_lock);
79 79
80#define FUTEX_LOCKED 1 80#define FUTEX_LOCKED 1
81#define FUTEX_UNLOCKED 0 81#define FUTEX_UNLOCKED 0
82 82
83#define FUTEX_SYSTEM_LOCK KERNEL_LOCK(1, NULL); 83#define FUTEX_SYSTEM_LOCK KERNEL_LOCK(1, NULL);
84#define FUTEX_SYSTEM_UNLOCK KERNEL_UNLOCK_ONE(0); 84#define FUTEX_SYSTEM_UNLOCK KERNEL_UNLOCK_ONE(0);
85 85
86#ifdef DEBUG_LINUX_FUTEX 86#ifdef DEBUG_LINUX_FUTEX
87#define FUTEXPRINTF(a) printf a 87#define FUTEXPRINTF(a) printf a
88#else 88#else
89#define FUTEXPRINTF(a) 89#define FUTEXPRINTF(a)
90#endif 90#endif
91 91
92static ONCE_DECL(futex_once); 92static ONCE_DECL(futex_once);
93 93
94static int 94static int
95futex_init(void) 95futex_init(void)
96{ 96{
97 printf("futex_init: initializing futex\n"); 97 printf("futex_init: initializing futex\n");
98 mutex_init(&futex_lock, MUTEX_DEFAULT, IPL_NONE); 98 mutex_init(&futex_lock, MUTEX_DEFAULT, IPL_NONE);
99 return 0; 99 return 0;
100} 100}
101 101
102static struct futex *futex_get(void *, int); 102static struct futex *futex_get(void *, int);
103static void futex_put(struct futex *); 103static void futex_put(struct futex *);
104static int futex_sleep(struct futex *, lwp_t *, unsigned long); 104static int futex_sleep(struct futex *, lwp_t *, unsigned long);
105static int futex_wake(struct futex *, int, struct futex *, int); 105static int futex_wake(struct futex *, int, struct futex *, int);
106static int futex_atomic_op(lwp_t *, int, void *); 106static int futex_atomic_op(lwp_t *, int, void *);
107 107
108int 108int
109linux_sys_futex(struct lwp *l, const struct linux_sys_futex_args *uap, register_t *retval) 109linux_sys_futex(struct lwp *l, const struct linux_sys_futex_args *uap, register_t *retval)
110{ 110{
111 /* { 111 /* {
112 syscallarg(int *) uaddr; 112 syscallarg(int *) uaddr;
113 syscallarg(int) op; 113 syscallarg(int) op;
114 syscallarg(int) val; 114 syscallarg(int) val;
115 syscallarg(const struct timespec *) timeout; 115 syscallarg(const struct timespec *) timeout;
116 syscallarg(int *) uaddr2; 116 syscallarg(int *) uaddr2;
117 syscallarg(int) val3; 117 syscallarg(int) val3;
118 } */ 118 } */
119 int val; 119 int val;
120 int ret; 120 int ret;
121 struct timespec timeout = { 0, 0 }; 121 struct timespec timeout = { 0, 0 };
122 int error = 0; 122 int error = 0;
123 struct futex *f; 123 struct futex *f;
124 struct futex *newf; 124 struct futex *newf;
125 int timeout_hz; 125 int timeout_hz;
126 struct timeval tv = {0, 0}; 126 struct timeval tv = {0, 0};
127 struct futex *f2; 127 struct futex *f2;
128 int op_ret; 128 int op_ret;
129 129
130 RUN_ONCE(&futex_once, futex_init); 130 RUN_ONCE(&futex_once, futex_init);
131 131
132 /* 132 /*
133 * Our implementation provides only private futexes. Most of the apps 133 * Our implementation provides only private futexes. Most of the apps
134 * should use private futexes but don't claim so. Therefore we treat 134 * should use private futexes but don't claim so. Therefore we treat
135 * all futexes as private by clearing the FUTEX_PRIVATE_FLAG. It works 135 * all futexes as private by clearing the FUTEX_PRIVATE_FLAG. It works
136 * in most cases (ie. when futexes are not shared on file descriptor 136 * in most cases (ie. when futexes are not shared on file descriptor
137 * or between different processes). 137 * or between different processes).
138 */ 138 */
139 switch (SCARG(uap, op) & ~LINUX_FUTEX_PRIVATE_FLAG) { 139 switch (SCARG(uap, op) & ~LINUX_FUTEX_PRIVATE_FLAG) {
140 case LINUX_FUTEX_WAIT: 140 case LINUX_FUTEX_WAIT:
141 FUTEX_SYSTEM_LOCK; 141 FUTEX_SYSTEM_LOCK;
142 142
143 if ((error = copyin(SCARG(uap, uaddr),  143 if ((error = copyin(SCARG(uap, uaddr),
144 &val, sizeof(val))) != 0) { 144 &val, sizeof(val))) != 0) {
145 FUTEX_SYSTEM_UNLOCK; 145 FUTEX_SYSTEM_UNLOCK;
146 return error; 146 return error;
147 } 147 }
148 148
149 if (val != SCARG(uap, val)) { 149 if (val != SCARG(uap, val)) {
150 FUTEX_SYSTEM_UNLOCK; 150 FUTEX_SYSTEM_UNLOCK;
151 return EWOULDBLOCK; 151 return EWOULDBLOCK;
152 } 152 }
153 153
154 if (SCARG(uap, timeout) != NULL) { 154 if (SCARG(uap, timeout) != NULL) {
155 if ((error = copyin(SCARG(uap, timeout),  155 if ((error = copyin(SCARG(uap, timeout),
156 &timeout, sizeof(timeout))) != 0) { 156 &timeout, sizeof(timeout))) != 0) {
157 FUTEX_SYSTEM_UNLOCK; 157 FUTEX_SYSTEM_UNLOCK;
158 return error; 158 return error;
159 } 159 }
160 } 160 }
161 161
162 FUTEXPRINTF(("FUTEX_WAIT %d.%d: val = %d, uaddr = %p, " 162 FUTEXPRINTF(("FUTEX_WAIT %d.%d: val = %d, uaddr = %p, "
163 "*uaddr = %d, timeout = %lld.%09ld\n",  163 "*uaddr = %d, timeout = %lld.%09ld\n",
164 l->l_proc->p_pid, l->l_lid, SCARG(uap, val),  164 l->l_proc->p_pid, l->l_lid, SCARG(uap, val),
165 SCARG(uap, uaddr), val, (long long)timeout.tv_sec, 165 SCARG(uap, uaddr), val, (long long)timeout.tv_sec,
166 timeout.tv_nsec)); 166 timeout.tv_nsec));
167 167
168 tv.tv_usec = timeout.tv_sec * 1000000 + timeout.tv_nsec / 1000; 168 tv.tv_usec = timeout.tv_sec * 1000000 + timeout.tv_nsec / 1000;
169 timeout_hz = tvtohz(&tv); 169 timeout_hz = tvtohz(&tv);
170 170
171 if (timeout.tv_sec == 0 && timeout.tv_nsec == 0) 171 if (timeout.tv_sec == 0 && timeout.tv_nsec == 0)
172 timeout_hz = 0; 172 timeout_hz = 0;
173 173
174 /* 174 /*
175 * If the user process requests a non null timeout, 175 * If the user process requests a non null timeout,
176 * make sure we do not turn it into an infinite 176 * make sure we do not turn it into an infinite
177 * timeout because timeout_hz is 0. 177 * timeout because timeout_hz is 0.
178 * 178 *
179 * We use a minimal timeout of 1/hz. Maybe it would make 179 * We use a minimal timeout of 1/hz. Maybe it would make
180 * sense to just return ETIMEDOUT without sleeping. 180 * sense to just return ETIMEDOUT without sleeping.
181 */ 181 */
182 if (((timeout.tv_sec != 0) || (timeout.tv_nsec != 0)) && 182 if (((timeout.tv_sec != 0) || (timeout.tv_nsec != 0)) &&
183 (timeout_hz == 0)) 183 (timeout_hz == 0))
184 timeout_hz = 1; 184 timeout_hz = 1;
185 185
186 f = futex_get(SCARG(uap, uaddr), FUTEX_UNLOCKED); 186 f = futex_get(SCARG(uap, uaddr), FUTEX_UNLOCKED);
187 ret = futex_sleep(f, l, timeout_hz); 187 ret = futex_sleep(f, l, timeout_hz);
188 futex_put(f); 188 futex_put(f);
189 189
190 FUTEXPRINTF(("FUTEX_WAIT %d.%d: uaddr = %p, " 190 FUTEXPRINTF(("FUTEX_WAIT %d.%d: uaddr = %p, "
191 "ret = %d\n", l->l_proc->p_pid, l->l_lid,  191 "ret = %d\n", l->l_proc->p_pid, l->l_lid,
192 SCARG(uap, uaddr), ret)); 192 SCARG(uap, uaddr), ret));
193 193
194 FUTEX_SYSTEM_UNLOCK; 194 FUTEX_SYSTEM_UNLOCK;
195 switch (ret) { 195 switch (ret) {
196 case EWOULDBLOCK: /* timeout */ 196 case EWOULDBLOCK: /* timeout */
197 return ETIMEDOUT; 197 return ETIMEDOUT;
198 break; 198 break;
199 case EINTR: /* signal */ 199 case EINTR: /* signal */
200 return EINTR; 200 return EINTR;
201 break; 201 break;
202 case 0: /* FUTEX_WAKE received */ 202 case 0: /* FUTEX_WAKE received */
203 FUTEXPRINTF(("FUTEX_WAIT %d.%d: uaddr = %p, got it\n", 203 FUTEXPRINTF(("FUTEX_WAIT %d.%d: uaddr = %p, got it\n",
204 l->l_proc->p_pid, l->l_lid, SCARG(uap, uaddr))); 204 l->l_proc->p_pid, l->l_lid, SCARG(uap, uaddr)));
205 return 0; 205 return 0;
206 break; 206 break;
207 default: 207 default:
208 FUTEXPRINTF(("FUTEX_WAIT: unexpected ret = %d\n", ret)); 208 FUTEXPRINTF(("FUTEX_WAIT: unexpected ret = %d\n", ret));
209 break; 209 break;
210 } 210 }
211 211
212 /* NOTREACHED */ 212 /* NOTREACHED */
213 break; 213 break;
214  214
215 case LINUX_FUTEX_WAKE: 215 case LINUX_FUTEX_WAKE:
216 FUTEX_SYSTEM_LOCK; 216 FUTEX_SYSTEM_LOCK;
217 /*  217 /*
218 * XXX: Linux is able cope with different addresses  218 * XXX: Linux is able cope with different addresses
219 * corresponding to the same mapped memory in the sleeping  219 * corresponding to the same mapped memory in the sleeping
220 * and the waker process(es). 220 * and the waker process(es).
221 */ 221 */
222 FUTEXPRINTF(("FUTEX_WAKE %d.%d: uaddr = %p, val = %d\n", 222 FUTEXPRINTF(("FUTEX_WAKE %d.%d: uaddr = %p, val = %d\n",
223 l->l_proc->p_pid, l->l_lid, 223 l->l_proc->p_pid, l->l_lid,
224 SCARG(uap, uaddr), SCARG(uap, val))); 224 SCARG(uap, uaddr), SCARG(uap, val)));
225 225
226 f = futex_get(SCARG(uap, uaddr), FUTEX_UNLOCKED); 226 f = futex_get(SCARG(uap, uaddr), FUTEX_UNLOCKED);
227 *retval = futex_wake(f, SCARG(uap, val), NULL, 0); 227 *retval = futex_wake(f, SCARG(uap, val), NULL, 0);
228 futex_put(f); 228 futex_put(f);
229 229
230 FUTEX_SYSTEM_UNLOCK; 230 FUTEX_SYSTEM_UNLOCK;
231 231
232 break; 232 break;
233 233
234 case LINUX_FUTEX_CMP_REQUEUE: 234 case LINUX_FUTEX_CMP_REQUEUE:
235 FUTEX_SYSTEM_LOCK; 235 FUTEX_SYSTEM_LOCK;
236 236
237 if ((error = copyin(SCARG(uap, uaddr),  237 if ((error = copyin(SCARG(uap, uaddr),
238 &val, sizeof(val))) != 0) { 238 &val, sizeof(val))) != 0) {
239 FUTEX_SYSTEM_UNLOCK; 239 FUTEX_SYSTEM_UNLOCK;
240 return error; 240 return error;
241 } 241 }
242 242
243 if (val != SCARG(uap, val3)) { 243 if (val != SCARG(uap, val3)) {
244 FUTEX_SYSTEM_UNLOCK; 244 FUTEX_SYSTEM_UNLOCK;
245 return EAGAIN; 245 return EAGAIN;
246 } 246 }
247 247
248 f = futex_get(SCARG(uap, uaddr), FUTEX_UNLOCKED); 248 f = futex_get(SCARG(uap, uaddr), FUTEX_UNLOCKED);
249 newf = futex_get(SCARG(uap, uaddr2), FUTEX_UNLOCKED); 249 newf = futex_get(SCARG(uap, uaddr2), FUTEX_UNLOCKED);
250 *retval = futex_wake(f, SCARG(uap, val), newf, 250 *retval = futex_wake(f, SCARG(uap, val), newf,
251 (int)(unsigned long)SCARG(uap, timeout)); 251 (int)(unsigned long)SCARG(uap, timeout));
252 futex_put(f); 252 futex_put(f);
253 futex_put(newf); 253 futex_put(newf);
254 254
255 FUTEX_SYSTEM_UNLOCK; 255 FUTEX_SYSTEM_UNLOCK;
256 break; 256 break;
257 257
258 case LINUX_FUTEX_REQUEUE: 258 case LINUX_FUTEX_REQUEUE:
259 FUTEX_SYSTEM_LOCK; 259 FUTEX_SYSTEM_LOCK;
260 260
261 f = futex_get(SCARG(uap, uaddr), FUTEX_UNLOCKED); 261 f = futex_get(SCARG(uap, uaddr), FUTEX_UNLOCKED);
262 newf = futex_get(SCARG(uap, uaddr2), FUTEX_UNLOCKED); 262 newf = futex_get(SCARG(uap, uaddr2), FUTEX_UNLOCKED);
263 *retval = futex_wake(f, SCARG(uap, val), newf, 263 *retval = futex_wake(f, SCARG(uap, val), newf,
264 (int)(unsigned long)SCARG(uap, timeout)); 264 (int)(unsigned long)SCARG(uap, timeout));
265 futex_put(f); 265 futex_put(f);
266 futex_put(newf); 266 futex_put(newf);
267 267
268 FUTEX_SYSTEM_UNLOCK; 268 FUTEX_SYSTEM_UNLOCK;
269 break; 269 break;
270 270
271 case LINUX_FUTEX_FD: 271 case LINUX_FUTEX_FD:
272 FUTEXPRINTF(("linux_sys_futex: unimplemented op %d\n",  272 FUTEXPRINTF(("linux_sys_futex: unimplemented op %d\n",
273 SCARG(uap, op))); 273 SCARG(uap, op)));
274 return ENOSYS; 274 return ENOSYS;
275 case LINUX_FUTEX_WAKE_OP: 275 case LINUX_FUTEX_WAKE_OP:
276 FUTEX_SYSTEM_LOCK; 276 FUTEX_SYSTEM_LOCK;
277 f = futex_get(SCARG(uap, uaddr), FUTEX_UNLOCKED); 277 f = futex_get(SCARG(uap, uaddr), FUTEX_UNLOCKED);
278 f2 = futex_get(SCARG(uap, uaddr2), FUTEX_UNLOCKED); 278 f2 = futex_get(SCARG(uap, uaddr2), FUTEX_UNLOCKED);
279 /* 279 /*
280 * This function returns positive number as results and 280 * This function returns positive number as results and
281 * negative as errors 281 * negative as errors
282 */ 282 */
283 op_ret = futex_atomic_op(l, SCARG(uap, val3), SCARG(uap, uaddr2)); 283 op_ret = futex_atomic_op(l, SCARG(uap, val3), SCARG(uap, uaddr2));
284 if (op_ret < 0) { 284 if (op_ret < 0) {
285 /* XXX: We don't handle EFAULT yet */ 285 /* XXX: We don't handle EFAULT yet */
286 if (op_ret != -EFAULT) { 286 if (op_ret != -EFAULT) {
287 futex_put(f); 287 futex_put(f);
288 futex_put(f2); 288 futex_put(f2);
289 FUTEX_SYSTEM_UNLOCK; 289 FUTEX_SYSTEM_UNLOCK;
290 return -op_ret; 290 return -op_ret;
291 } 291 }
292 futex_put(f); 292 futex_put(f);
293 futex_put(f2); 293 futex_put(f2);
294 FUTEX_SYSTEM_UNLOCK; 294 FUTEX_SYSTEM_UNLOCK;
295 return EFAULT; 295 return EFAULT;
296 } 296 }
297 297
298 ret = futex_wake(f, SCARG(uap, val), NULL, 0); 298 ret = futex_wake(f, SCARG(uap, val), NULL, 0);
299 futex_put(f); 299 futex_put(f);
300 if (op_ret > 0) { 300 if (op_ret > 0) {
301 op_ret = 0; 301 op_ret = 0;
302 /* 302 /*
303 * Linux abuses the address of the timespec parameter 303 * Linux abuses the address of the timespec parameter
304 * as the number of retries 304 * as the number of retries
305 */ 305 */
306 op_ret += futex_wake(f2, 306 op_ret += futex_wake(f2,
307 (int)(unsigned long)SCARG(uap, timeout), NULL, 0); 307 (int)(unsigned long)SCARG(uap, timeout), NULL, 0);
308 ret += op_ret; 308 ret += op_ret;
309 } 309 }
310 futex_put(f2); 310 futex_put(f2);
311 *retval = ret; 311 *retval = ret;
312 FUTEX_SYSTEM_UNLOCK; 312 FUTEX_SYSTEM_UNLOCK;
313 break; 313 break;
314 default: 314 default:
315 FUTEXPRINTF(("linux_sys_futex: unknown op %d\n",  315 FUTEXPRINTF(("linux_sys_futex: unknown op %d\n",
316 SCARG(uap, op))); 316 SCARG(uap, op)));
317 return ENOSYS; 317 return ENOSYS;
318 } 318 }
319 return 0; 319 return 0;
320} 320}
321 321
322static struct futex * 322static struct futex *
323futex_get(void *uaddr, int locked) 323futex_get(void *uaddr, int locked)
324{ 324{
325 struct futex *f; 325 struct futex *f;
326 326
327 if (locked == FUTEX_UNLOCKED) 327 if (locked == FUTEX_UNLOCKED)
328 FUTEX_LOCK; 328 FUTEX_LOCK;
329 329
330 LIST_FOREACH(f, &futex_list, f_list) { 330 LIST_FOREACH(f, &futex_list, f_list) {
331 if (f->f_uaddr == uaddr) { 331 if (f->f_uaddr == uaddr) {
332 f->f_refcount++; 332 f->f_refcount++;
333 if (locked == FUTEX_UNLOCKED) 333 if (locked == FUTEX_UNLOCKED)
334 FUTEX_UNLOCK; 334 FUTEX_UNLOCK;
335 return f; 335 return f;
336 } 336 }
337 } 337 }
338 338
339 /* Not found, create it */ 339 /* Not found, create it */
340 f = kmem_zalloc(sizeof(*f), KM_SLEEP); 340 f = kmem_zalloc(sizeof(*f), KM_SLEEP);
341 f->f_uaddr = uaddr; 341 f->f_uaddr = uaddr;
342 f->f_refcount = 1; 342 f->f_refcount = 1;
343 TAILQ_INIT(&f->f_waiting_proc); 343 TAILQ_INIT(&f->f_waiting_proc);
344 LIST_INSERT_HEAD(&futex_list, f, f_list); 344 LIST_INSERT_HEAD(&futex_list, f, f_list);
345 if (locked == FUTEX_UNLOCKED) 345 if (locked == FUTEX_UNLOCKED)
346 FUTEX_UNLOCK; 346 FUTEX_UNLOCK;
347 347
348 return f; 348 return f;
349} 349}
350 350
351static void  351static void
352futex_put(struct futex *f) 352futex_put(struct futex *f)
353{ 353{
354 354
355 FUTEX_LOCK; 355 FUTEX_LOCK;
356 f->f_refcount--; 356 f->f_refcount--;
357 if (f->f_refcount == 0) { 357 if (f->f_refcount == 0) {
358 KASSERT(TAILQ_EMPTY(&f->f_waiting_proc)); 358 KASSERT(TAILQ_EMPTY(&f->f_waiting_proc));
359 LIST_REMOVE(f, f_list); 359 LIST_REMOVE(f, f_list);
360 kmem_free(f, sizeof(*f)); 360 kmem_free(f, sizeof(*f));
361 } 361 }
362 FUTEX_UNLOCK; 362 FUTEX_UNLOCK;
363 363
364 return; 364 return;
365} 365}
366 366
367static int  367static int
368futex_sleep(struct futex *f, lwp_t *l, unsigned long timeout) 368futex_sleep(struct futex *f, lwp_t *l, unsigned long timeout)
369{ 369{
370 struct waiting_proc *wp; 370 struct waiting_proc *wp;
371 int ret; 371 int ret;
372 372
373 wp = kmem_zalloc(sizeof(*wp), KM_SLEEP); 373 wp = kmem_zalloc(sizeof(*wp), KM_SLEEP);
374 wp->wp_l = l; 374 wp->wp_l = l;
375 wp->wp_new_futex = NULL; 375 wp->wp_new_futex = NULL;
376 cv_init(&wp->wp_futex_cv, "futex"); 376 cv_init(&wp->wp_futex_cv, "futex");
377 377
378 FUTEX_LOCK; 378 FUTEX_LOCK;
379 TAILQ_INSERT_TAIL(&f->f_waiting_proc, wp, wp_list); 379 TAILQ_INSERT_TAIL(&f->f_waiting_proc, wp, wp_list);
380 ret = cv_timedwait_sig(&wp->wp_futex_cv, &futex_lock, timeout); 380 ret = cv_timedwait_sig(&wp->wp_futex_cv, &futex_lock, timeout);
381 TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list); 381 TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
382 FUTEX_UNLOCK; 382 FUTEX_UNLOCK;
383 383
384 /* if we got woken up in futex_wake */ 384 /* if we got woken up in futex_wake */
385 if ((ret == 0) && (wp->wp_new_futex != NULL)) { 385 if ((ret == 0) && (wp->wp_new_futex != NULL)) {
386 /* suspend us on the new futex */ 386 /* suspend us on the new futex */
387 ret = futex_sleep(wp->wp_new_futex, l, timeout); 387 ret = futex_sleep(wp->wp_new_futex, l, timeout);
388 /* and release the old one */ 388 /* and release the old one */
389 futex_put(wp->wp_new_futex); 389 futex_put(wp->wp_new_futex);
390 } 390 }
391 391
392 cv_destroy(&wp->wp_futex_cv); 392 cv_destroy(&wp->wp_futex_cv);
393 kmem_free(wp, sizeof(*wp)); 393 kmem_free(wp, sizeof(*wp));
394 return ret; 394 return ret;
395} 395}
396 396
397static int 397static int
398futex_wake(struct futex *f, int n, struct futex *newf, int n2) 398futex_wake(struct futex *f, int n, struct futex *newf, int n2)
399{ 399{
400 struct waiting_proc *wp; 400 struct waiting_proc *wp;
401 int count; 401 int count;
402 402
403 count = newf ? 0 : 1; 403 count = newf ? 0 : 1;
404 404
405 FUTEX_LOCK; 405 FUTEX_LOCK;
406 TAILQ_FOREACH(wp, &f->f_waiting_proc, wp_list) { 406 TAILQ_FOREACH(wp, &f->f_waiting_proc, wp_list) {
407 if (count <= n) { 407 if (count <= n) {
408 cv_signal(&wp->wp_futex_cv); 408 cv_signal(&wp->wp_futex_cv);
409 count++; 409 count++;
410 } else { 410 } else {
411 if (newf == NULL) 411 if (newf == NULL)
412 continue; 412 continue;
413 /* futex_put called after tsleep */ 413 /* futex_put called after tsleep */
414 wp->wp_new_futex = futex_get(newf->f_uaddr, 414 wp->wp_new_futex = futex_get(newf->f_uaddr,
415 FUTEX_LOCKED); 415 FUTEX_LOCKED);
416 cv_signal(&wp->wp_futex_cv); 416 cv_signal(&wp->wp_futex_cv);
417 if (count - n >= n2) 417 if (count - n >= n2)
418 break; 418 break;
419 } 419 }
420 } 420 }
421 FUTEX_UNLOCK; 421 FUTEX_UNLOCK;
422 422
423 return count; 423 return count;
424} 424}
425 425
426static int 426static int
427futex_atomic_op(lwp_t *l, int encoded_op, void *uaddr) 427futex_atomic_op(lwp_t *l, int encoded_op, void *uaddr)
428{ 428{
429 const int op = (encoded_op >> 28) & 7; 429 const int op = (encoded_op >> 28) & 7;
430 const int cmp = (encoded_op >> 24) & 15; 430 const int cmp = (encoded_op >> 24) & 15;
431 const int cmparg = (encoded_op << 20) >> 20; 431 const int cmparg = (encoded_op << 20) >> 20;
432 int oparg = (encoded_op << 8) >> 20; 432 int oparg = (encoded_op << 8) >> 20;
433 int error, oldval, cval; 433 int error, oldval, cval;
434 434
435 if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) 435 if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
436 oparg = 1 << oparg; 436 oparg = 1 << oparg;
437 437
438 /* XXX: linux verifies access here and returns EFAULT */ 438 /* XXX: linux verifies access here and returns EFAULT */
439 439
440 if (copyin(uaddr, &cval, sizeof(int)) != 0) 440 if (copyin(uaddr, &cval, sizeof(int)) != 0)
441 return -EFAULT; 441 return -EFAULT;
442 442
443 for (;;) { 443 for (;;) {
444 int nval; 444 int nval;
445 445
446 switch (op) { 446 switch (op) {
447 case FUTEX_OP_SET: 447 case FUTEX_OP_SET:
448 nval = oparg; 448 nval = oparg;
449 break; 449 break;
450 case FUTEX_OP_ADD: 450 case FUTEX_OP_ADD:
451 nval = cval + oparg; 451 nval = cval + oparg;
452 break; 452 break;
453 case FUTEX_OP_OR: 453 case FUTEX_OP_OR:
454 nval = cval | oparg; 454 nval = cval | oparg;
455 break; 455 break;
456 case FUTEX_OP_ANDN: 456 case FUTEX_OP_ANDN:
457 nval = cval & ~oparg; 457 nval = cval & ~oparg;
458 break; 458 break;
459 case FUTEX_OP_XOR: 459 case FUTEX_OP_XOR:
460 nval = cval ^ oparg; 460 nval = cval ^ oparg;
461 break; 461 break;
462 default: 462 default:
463 return -ENOSYS; 463 return -ENOSYS;
464 } 464 }
465 465
466 error = ucas_int(uaddr, cval, nval, &oldval); 466 error = ucas_int(uaddr, cval, nval, &oldval);
467 if (oldval == cval || error) { 467 if (oldval == cval || error) {
468 break; 468 break;
469 } 469 }
470 cval = oldval; 470 cval = oldval;
471 } 471 }
472 472
473 if (error) 473 if (error)
474 return -EFAULT; 474 return -EFAULT;
475 475
476 switch (cmp) { 476 switch (cmp) {
477 case FUTEX_OP_CMP_EQ: 477 case FUTEX_OP_CMP_EQ:
478 return (oldval == cmparg); 478 return (oldval == cmparg);
479 case FUTEX_OP_CMP_NE: 479 case FUTEX_OP_CMP_NE:
480 return (oldval != cmparg); 480 return (oldval != cmparg);
481 case FUTEX_OP_CMP_LT: 481 case FUTEX_OP_CMP_LT:
482 return (oldval < cmparg); 482 return (oldval < cmparg);
483 case FUTEX_OP_CMP_GE: 483 case FUTEX_OP_CMP_GE:
484 return (oldval >= cmparg); 484 return (oldval >= cmparg);
485 case FUTEX_OP_CMP_LE: 485 case FUTEX_OP_CMP_LE:
486 return (oldval <= cmparg); 486 return (oldval <= cmparg);
487 case FUTEX_OP_CMP_GT: 487 case FUTEX_OP_CMP_GT:
488 return (oldval > cmparg); 488 return (oldval > cmparg);
489 default: 489 default:
490 return -ENOSYS; 490 return -ENOSYS;
491 } 491 }
492} 492}
493 493
494int 494int
495linux_sys_set_robust_list(struct lwp *l, 495linux_sys_set_robust_list(struct lwp *l,
496 const struct linux_sys_set_robust_list_args *uap, register_t *retval) 496 const struct linux_sys_set_robust_list_args *uap, register_t *retval)
497{ 497{
498 struct proc *p = l->l_proc; 498 struct proc *p = l->l_proc;
499 struct linux_emuldata *led = p->p_emuldata; 499 struct linux_emuldata *led = p->p_emuldata;
500 500
 501 if (SCARG(uap, len) != sizeof(*(led->robust_futexes)))
 502 return EINVAL;
501 led->robust_futexes = SCARG(uap, head); 503 led->robust_futexes = SCARG(uap, head);
502 *retval = 0; 504 *retval = 0;
503 return 0; 505 return 0;
504} 506}
505 507
506int 508int
507linux_sys_get_robust_list(struct lwp *l, 509linux_sys_get_robust_list(struct lwp *l,
508 const struct linux_sys_get_robust_list_args *uap, register_t *retval) 510 const struct linux_sys_get_robust_list_args *uap, register_t *retval)
509{ 511{
510 struct linux_emuldata *led; 512 struct linux_emuldata *led;
511 struct linux_robust_list_head *head; 513 struct linux_robust_list_head **head;
512 size_t len = sizeof(struct linux_robust_list_head); 514 size_t len = sizeof(*led->robust_futexes);
513 int error = 0; 515 int error = 0;
514 516
515 if (!SCARG(uap, pid)) { 517 if (!SCARG(uap, pid)) {
516 led = l->l_proc->p_emuldata; 518 led = l->l_proc->p_emuldata;
517 head = led->robust_futexes; 519 head = &led->robust_futexes;
518 } else { 520 } else {
519 struct proc *p; 521 struct proc *p;
520 522
521 mutex_enter(proc_lock);  523 mutex_enter(proc_lock);
522 if ((p = p_find(SCARG(uap, pid), PFIND_LOCKED)) == NULL || 524 if ((p = p_find(SCARG(uap, pid), PFIND_LOCKED)) == NULL ||
523 p->p_emul != &emul_linux) { 525 p->p_emul != &emul_linux) {
524 mutex_exit(proc_lock); 526 mutex_exit(proc_lock);
525 return ESRCH; 527 return ESRCH;
526 } 528 }
527 led = p->p_emuldata; 529 led = p->p_emuldata;
528 head = led->robust_futexes; 530 head = &led->robust_futexes;
529 mutex_exit(proc_lock); 531 mutex_exit(proc_lock);
530 } 532 }
531 533
532 error = copyout(&len, SCARG(uap, len), sizeof(size_t)); 534 error = copyout(&len, SCARG(uap, len), sizeof(len));
533 if (error) 535 if (error)
534 return error; 536 return error;
535 return copyout(head, SCARG(uap, head), 537 return copyout(head, SCARG(uap, head), sizeof(*head));
536 sizeof(struct linux_robust_list_head)); 
537} 538}
538 539
539static int 540static int
540handle_futex_death(void *uaddr, pid_t pid, int pi) 541handle_futex_death(void *uaddr, pid_t pid, int pi)
541{ 542{
542 int uval, nval, mval; 543 int uval, nval, mval;
543 struct futex *f; 544 struct futex *f;
544 545
545retry: 546retry:
546 if (copyin(uaddr, &uval, 4)) 547 if (copyin(uaddr, &uval, 4))
547 return EFAULT; 548 return EFAULT;
548 549
549 if ((uval & FUTEX_TID_MASK) == pid) { 550 if ((uval & FUTEX_TID_MASK) == pid) {
550 mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED; 551 mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
551 nval = atomic_cas_32(uaddr, uval, mval); 552 nval = atomic_cas_32(uaddr, uval, mval);
552 553
553 if (nval == -1) 554 if (nval == -1)
554 return EFAULT; 555 return EFAULT;
555 556
556 if (nval != uval) 557 if (nval != uval)
557 goto retry; 558 goto retry;
558 559
559 if (!pi && (uval & FUTEX_WAITERS)) { 560 if (!pi && (uval & FUTEX_WAITERS)) {
560 f = futex_get(uaddr, FUTEX_UNLOCKED); 561 f = futex_get(uaddr, FUTEX_UNLOCKED);
561 futex_wake(f, 1, NULL, 0); 562 futex_wake(f, 1, NULL, 0);
562 } 563 }
563 } 564 }
564 565
565 return 0; 566 return 0;
566} 567}
567 568
568static int 569static int
569fetch_robust_entry(struct linux_robust_list **entry, 570fetch_robust_entry(struct linux_robust_list **entry,
570 struct linux_robust_list **head, int *pi) 571 struct linux_robust_list **head, int *pi)
571{ 572{
572 unsigned long uentry; 573 unsigned long uentry;
573 574
574 if (copyin((const void *)head, &uentry, sizeof(unsigned long))) 575 if (copyin((const void *)head, &uentry, sizeof(unsigned long)))
575 return EFAULT; 576 return EFAULT;
576 577
577 *entry = (void *)(uentry & ~1UL); 578 *entry = (void *)(uentry & ~1UL);
578 *pi = uentry & 1; 579 *pi = uentry & 1;
579 580
580 return 0; 581 return 0;
581} 582}
582 583
583/* This walks the list of robust futexes, releasing them. */ 584/* This walks the list of robust futexes, releasing them. */
584void 585void
585release_futexes(struct proc *p) 586release_futexes(struct proc *p)
586{ 587{
587 struct linux_robust_list_head *head = NULL; 588 struct linux_robust_list_head head;
588 struct linux_robust_list *entry, *next_entry, *pending; 589 struct linux_robust_list *entry, *next_entry, *pending;
589 unsigned int limit = 2048, pi, next_pi, pip; 590 unsigned int limit = 2048, pi, next_pi, pip;
590 struct linux_emuldata *led; 591 struct linux_emuldata *led;
591 unsigned long futex_offset; 592 unsigned long futex_offset;
592 int rc; 593 int rc;
593 594
594 led = p->p_emuldata; 595 led = p->p_emuldata;
595 head = led->robust_futexes; 596 if (led->robust_futexes == NULL)
 597 return;
596 598
597 if (head == NULL) 599 if (copyin(led->robust_futexes, &head, sizeof(head)))
598 return; 600 return;
599 601
600 if (fetch_robust_entry(&entry, &head->list.next, &pi)) 602 if (fetch_robust_entry(&entry, &head.list.next, &pi))
601 return; 603 return;
602 604
603 if (copyin(&head->futex_offset, &futex_offset, sizeof(unsigned long))) 605 if (copyin(&head.futex_offset, &futex_offset, sizeof(unsigned long)))
604 return; 606 return;
605 607
606 if (fetch_robust_entry(&pending, &head->pending_list, &pip)) 608 if (fetch_robust_entry(&pending, &head.pending_list, &pip))
607 return; 609 return;
608 610
609 while (entry != &head->list) { 611 while (entry != &head.list) {
610 rc = fetch_robust_entry(&next_entry, &entry->next, &next_pi); 612 rc = fetch_robust_entry(&next_entry, &entry->next, &next_pi);
611 613
612 if (entry != pending) 614 if (entry != pending)
613 if (handle_futex_death((char *)entry + futex_offset, 615 if (handle_futex_death((char *)entry + futex_offset,
614 p->p_pid, pi)) 616 p->p_pid, pi))
615 return; 617 return;
616 618
617 if (rc) 619 if (rc)
618 return; 620 return;
619 621
620 entry = next_entry; 622 entry = next_entry;
621 pi = next_pi; 623 pi = next_pi;
622 624
623 if (!--limit) 625 if (!--limit)
624 break; 626 break;
625 627
626 yield(); /* XXX why? */ 628 yield(); /* XXX why? */
627 } 629 }
628 630
629 if (pending) 631 if (pending)
630 handle_futex_death((char *)pending + futex_offset, 632 handle_futex_death((char *)pending + futex_offset,
631 p->p_pid, pip); 633 p->p_pid, pip);
632} 634}