diff options
| author | chs <chs@NetBSD.org> | 2010-07-07 01:30:32 +0000 |
|---|---|---|
| committer | chs <chs@NetBSD.org> | 2010-07-07 01:30:32 +0000 |
| commit | 33fa5ccbbf17bc2390e2d136c34926c6f93ac5d1 (patch) | |
| tree | c52fdcf81396fba59fce0a9c410d0dcc8c104091 /sys/compat/linux/common/linux_futex.c | |
| parent | 56acc98394a822ba38a843f6385171e0b1aa5e9a (diff) | |
many changes for COMPAT_LINUX:
- update the linux syscall table for each platform.
- support new-style (NPTL) linux pthreads on all platforms.
clone() with CLONE_THREAD uses 1 process with many LWPs
instead of separate processes.
- move the contents of sys__lwp_setprivate() into a new
lwp_setprivate() and use that everywhere.
- update linux_release[] and linux32_release[] to "2.6.18".
- adjust placement of emul fork/exec/exit hooks as needed
and adjust other emul code to match.
- convert all struct emul definitions to use named initializers.
- change the pid allocator to allow multiple pids to refer to the same proc.
- remove a few fields from struct proc that are no longer needed.
- disable the non-functional "vdso" code in linux32/amd64,
glibc works fine without it.
- fix a race in the futex code where we could miss a wakeup after
a requeue operation.
- redo futex locking to be a little more efficient.
Diffstat (limited to 'sys/compat/linux/common/linux_futex.c')
| -rw-r--r-- | sys/compat/linux/common/linux_futex.c | 410 |
1 files changed, 292 insertions, 118 deletions
diff --git a/sys/compat/linux/common/linux_futex.c b/sys/compat/linux/common/linux_futex.c index 0e2ef7ba8f5..f28d4ac31e9 100644 --- a/sys/compat/linux/common/linux_futex.c +++ b/sys/compat/linux/common/linux_futex.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_futex.c,v 1.25 2010/07/01 02:38:28 rmind Exp $ */ +/* $NetBSD: linux_futex.c,v 1.26 2010/07/07 01:30:35 chs Exp $ */ /*- * Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved. @@ -32,7 +32,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.25 2010/07/01 02:38:28 rmind Exp $"); +__KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.26 2010/07/07 01:30:35 chs Exp $"); #include <sys/param.h> #include <sys/time.h> @@ -52,9 +52,8 @@ __KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.25 2010/07/01 02:38:28 rmind Exp $ #include <compat/linux/common/linux_exec.h> #include <compat/linux/common/linux_signal.h> #include <compat/linux/common/linux_futex.h> -#include <compat/linux/common/linux_ipc.h> #include <compat/linux/common/linux_sched.h> -#include <compat/linux/common/linux_sem.h> +#include <compat/linux/common/linux_machdep.h> #include <compat/linux/linux_syscallargs.h> void linux_to_native_timespec(struct timespec *, struct linux_timespec *); @@ -66,28 +65,29 @@ struct waiting_proc { struct futex *wp_new_futex; kcondvar_t wp_futex_cv; TAILQ_ENTRY(waiting_proc) wp_list; + TAILQ_ENTRY(waiting_proc) wp_rqlist; }; struct futex { void *f_uaddr; int f_refcount; LIST_ENTRY(futex) f_list; - TAILQ_HEAD(lf_waiting_proc, waiting_proc) f_waiting_proc; + TAILQ_HEAD(, waiting_proc) f_waiting_proc; + TAILQ_HEAD(, waiting_proc) f_requeue_proc; }; static LIST_HEAD(futex_list, futex) futex_list; static kmutex_t futex_lock; -#define FUTEX_LOCK mutex_enter(&futex_lock); -#define FUTEX_UNLOCK mutex_exit(&futex_lock); +#define FUTEX_LOCK mutex_enter(&futex_lock) +#define FUTEX_UNLOCK mutex_exit(&futex_lock) +#define FUTEX_LOCKASSERT KASSERT(mutex_owned(&futex_lock)) -#define FUTEX_LOCKED 1 -#define FUTEX_UNLOCKED 0 - -#define FUTEX_SYSTEM_LOCK KERNEL_LOCK(1, NULL); -#define FUTEX_SYSTEM_UNLOCK KERNEL_UNLOCK_ONE(0); +#define FUTEX_SYSTEM_LOCK KERNEL_LOCK(1, NULL) +#define FUTEX_SYSTEM_UNLOCK KERNEL_UNLOCK_ONE(0) #ifdef DEBUG_LINUX_FUTEX -#define FUTEXPRINTF(a) printf a +int debug_futex = 1; +#define FUTEXPRINTF(a) do { if (debug_futex) printf a; } while (0) #else #define FUTEXPRINTF(a) #endif @@ -102,9 +102,12 @@ futex_init(void) return 0; } -static struct futex *futex_get(void *, int); +static struct waiting_proc *futex_wp_alloc(void); +static void futex_wp_free(struct waiting_proc *); +static struct futex *futex_get(void *); +static void futex_ref(struct futex *); static void futex_put(struct futex *); -static int futex_sleep(struct futex *, lwp_t *, unsigned long); +static int futex_sleep(struct futex **, lwp_t *, int, struct waiting_proc *); static int futex_wake(struct futex *, int, struct futex *, int); static int futex_atomic_op(lwp_t *, int, void *); @@ -119,15 +122,40 @@ linux_sys_futex(struct lwp *l, const struct linux_sys_futex_args *uap, register_ syscallarg(int *) uaddr2; syscallarg(int) val3; } */ + struct linux_timespec lts; + struct timespec ts = { 0, 0 }; + int error; + + if ((SCARG(uap, op) & ~LINUX_FUTEX_PRIVATE_FLAG) == LINUX_FUTEX_WAIT && + SCARG(uap, timeout) != NULL) { + if ((error = copyin(SCARG(uap, timeout), + <s, sizeof(lts))) != 0) { + return error; + } + linux_to_native_timespec(&ts, <s); + } + return linux_do_futex(l, uap, retval, &ts); +} + +int +linux_do_futex(struct lwp *l, const struct linux_sys_futex_args *uap, register_t *retval, struct timespec *ts) +{ + /* { + syscallarg(int *) uaddr; + syscallarg(int) op; + syscallarg(int) val; + syscallarg(const struct linux_timespec *) timeout; + syscallarg(int *) uaddr2; + syscallarg(int) val3; + } */ int val; int ret; - struct linux_timespec timeout = { 0, 0 }; int error = 0; struct futex *f; struct futex *newf; int timeout_hz; - struct timespec ts; struct futex *f2; + struct waiting_proc *wp; int op_ret; RUN_ONCE(&futex_once, futex_init); @@ -154,26 +182,17 @@ linux_sys_futex(struct lwp *l, const struct linux_sys_futex_args *uap, register_ return EWOULDBLOCK; } - if (SCARG(uap, timeout) != NULL) { - if ((error = copyin(SCARG(uap, timeout), - &timeout, sizeof(timeout))) != 0) { - FUTEX_SYSTEM_UNLOCK; - return error; - } - } - FUTEXPRINTF(("FUTEX_WAIT %d.%d: val = %d, uaddr = %p, " "*uaddr = %d, timeout = %lld.%09ld\n", l->l_proc->p_pid, l->l_lid, SCARG(uap, val), - SCARG(uap, uaddr), val, (long long)timeout.tv_sec, - timeout.tv_nsec)); + SCARG(uap, uaddr), val, (long long)ts->tv_sec, + ts->tv_nsec)); - linux_to_native_timespec(&ts, &timeout); - if ((error = itimespecfix(&ts)) != 0) { + if ((error = itimespecfix(ts)) != 0) { FUTEX_SYSTEM_UNLOCK; return error; } - timeout_hz = tstohz(&ts); + timeout_hz = tstohz(ts); /* * If the user process requests a non null timeout, @@ -186,9 +205,13 @@ linux_sys_futex(struct lwp *l, const struct linux_sys_futex_args *uap, register_ if (SCARG(uap, timeout) != NULL && timeout_hz == 0) timeout_hz = 1; - f = futex_get(SCARG(uap, uaddr), FUTEX_UNLOCKED); - ret = futex_sleep(f, l, timeout_hz); + wp = futex_wp_alloc(); + FUTEX_LOCK; + f = futex_get(SCARG(uap, uaddr)); + ret = futex_sleep(&f, l, timeout_hz, wp); futex_put(f); + FUTEX_UNLOCK; + futex_wp_free(wp); FUTEXPRINTF(("FUTEX_WAIT %d.%d: uaddr = %p, " "ret = %d\n", l->l_proc->p_pid, l->l_lid, @@ -216,7 +239,6 @@ linux_sys_futex(struct lwp *l, const struct linux_sys_futex_args *uap, register_ break; case LINUX_FUTEX_WAKE: - FUTEX_SYSTEM_LOCK; /* * XXX: Linux is able cope with different addresses * corresponding to the same mapped memory in the sleeping @@ -226,10 +248,12 @@ linux_sys_futex(struct lwp *l, const struct linux_sys_futex_args *uap, register_ l->l_proc->p_pid, l->l_lid, SCARG(uap, uaddr), SCARG(uap, val))); - f = futex_get(SCARG(uap, uaddr), FUTEX_UNLOCKED); + FUTEX_SYSTEM_LOCK; + FUTEX_LOCK; + f = futex_get(SCARG(uap, uaddr)); *retval = futex_wake(f, SCARG(uap, val), NULL, 0); futex_put(f); - + FUTEX_UNLOCK; FUTEX_SYSTEM_UNLOCK; break; @@ -248,12 +272,20 @@ linux_sys_futex(struct lwp *l, const struct linux_sys_futex_args *uap, register_ return EAGAIN; } - f = futex_get(SCARG(uap, uaddr), FUTEX_UNLOCKED); - newf = futex_get(SCARG(uap, uaddr2), FUTEX_UNLOCKED); + FUTEXPRINTF(("FUTEX_CMP_REQUEUE %d.%d: uaddr = %p, val = %d, " + "uaddr2 = %p, val2 = %d\n", + l->l_proc->p_pid, l->l_lid, + SCARG(uap, uaddr), SCARG(uap, val), SCARG(uap, uaddr2), + (int)(unsigned long)SCARG(uap, timeout))); + + FUTEX_LOCK; + f = futex_get(SCARG(uap, uaddr)); + newf = futex_get(SCARG(uap, uaddr2)); *retval = futex_wake(f, SCARG(uap, val), newf, (int)(unsigned long)SCARG(uap, timeout)); futex_put(f); futex_put(newf); + FUTEX_UNLOCK; FUTEX_SYSTEM_UNLOCK; break; @@ -261,12 +293,20 @@ linux_sys_futex(struct lwp *l, const struct linux_sys_futex_args *uap, register_ case LINUX_FUTEX_REQUEUE: FUTEX_SYSTEM_LOCK; - f = futex_get(SCARG(uap, uaddr), FUTEX_UNLOCKED); - newf = futex_get(SCARG(uap, uaddr2), FUTEX_UNLOCKED); + FUTEXPRINTF(("FUTEX_REQUEUE %d.%d: uaddr = %p, val = %d, " + "uaddr2 = %p, val2 = %d\n", + l->l_proc->p_pid, l->l_lid, + SCARG(uap, uaddr), SCARG(uap, val), SCARG(uap, uaddr2), + (int)(unsigned long)SCARG(uap, timeout))); + + FUTEX_LOCK; + f = futex_get(SCARG(uap, uaddr)); + newf = futex_get(SCARG(uap, uaddr2)); *retval = futex_wake(f, SCARG(uap, val), newf, (int)(unsigned long)SCARG(uap, timeout)); futex_put(f); futex_put(newf); + FUTEX_UNLOCK; FUTEX_SYSTEM_UNLOCK; break; @@ -277,25 +317,31 @@ linux_sys_futex(struct lwp *l, const struct linux_sys_futex_args *uap, register_ return ENOSYS; case LINUX_FUTEX_WAKE_OP: FUTEX_SYSTEM_LOCK; - f = futex_get(SCARG(uap, uaddr), FUTEX_UNLOCKED); - f2 = futex_get(SCARG(uap, uaddr2), FUTEX_UNLOCKED); + + FUTEXPRINTF(("FUTEX_WAKE_OP %d.%d: uaddr = %p, op = %d, " + "val = %d, uaddr2 = %p, val2 = %d\n", + l->l_proc->p_pid, l->l_lid, + SCARG(uap, uaddr), SCARG(uap, op), SCARG(uap, val), + SCARG(uap, uaddr2), + (int)(unsigned long)SCARG(uap, timeout))); + + FUTEX_LOCK; + f = futex_get(SCARG(uap, uaddr)); + f2 = futex_get(SCARG(uap, uaddr2)); + FUTEX_UNLOCK; + /* * This function returns positive number as results and * negative as errors */ op_ret = futex_atomic_op(l, SCARG(uap, val3), SCARG(uap, uaddr2)); + FUTEX_LOCK; if (op_ret < 0) { - /* XXX: We don't handle EFAULT yet */ - if (op_ret != -EFAULT) { - futex_put(f); - futex_put(f2); - FUTEX_SYSTEM_UNLOCK; - return -op_ret; - } futex_put(f); futex_put(f2); + FUTEX_UNLOCK; FUTEX_SYSTEM_UNLOCK; - return EFAULT; + return -op_ret; } ret = futex_wake(f, SCARG(uap, val), NULL, 0); @@ -311,8 +357,9 @@ linux_sys_futex(struct lwp *l, const struct linux_sys_futex_args *uap, register_ ret += op_ret; } futex_put(f2); - *retval = ret; + FUTEX_UNLOCK; FUTEX_SYSTEM_UNLOCK; + *retval = ret; break; default: FUTEXPRINTF(("linux_sys_futex: unknown op %d\n", @@ -322,19 +369,34 @@ linux_sys_futex(struct lwp *l, const struct linux_sys_futex_args *uap, register_ return 0; } +static struct waiting_proc * +futex_wp_alloc(void) +{ + struct waiting_proc *wp; + + wp = kmem_zalloc(sizeof(*wp), KM_SLEEP); + cv_init(&wp->wp_futex_cv, "futex"); + return wp; +} + +static void +futex_wp_free(struct waiting_proc *wp) +{ + + cv_destroy(&wp->wp_futex_cv); + kmem_free(wp, sizeof(*wp)); +} + static struct futex * -futex_get(void *uaddr, int locked) +futex_get(void *uaddr) { struct futex *f; - if (locked == FUTEX_UNLOCKED) - FUTEX_LOCK; + FUTEX_LOCKASSERT; LIST_FOREACH(f, &futex_list, f_list) { if (f->f_uaddr == uaddr) { f->f_refcount++; - if (locked == FUTEX_UNLOCKED) - FUTEX_UNLOCK; return f; } } @@ -344,85 +406,140 @@ futex_get(void *uaddr, int locked) f->f_uaddr = uaddr; f->f_refcount = 1; TAILQ_INIT(&f->f_waiting_proc); + TAILQ_INIT(&f->f_requeue_proc); LIST_INSERT_HEAD(&futex_list, f, f_list); - if (locked == FUTEX_UNLOCKED) - FUTEX_UNLOCK; return f; } +static void +futex_ref(struct futex *f) +{ + + FUTEX_LOCKASSERT; + + f->f_refcount++; +} + static void futex_put(struct futex *f) { - FUTEX_LOCK; + FUTEX_LOCKASSERT; + f->f_refcount--; if (f->f_refcount == 0) { KASSERT(TAILQ_EMPTY(&f->f_waiting_proc)); + KASSERT(TAILQ_EMPTY(&f->f_requeue_proc)); LIST_REMOVE(f, f_list); kmem_free(f, sizeof(*f)); } - FUTEX_UNLOCK; - - return; } static int -futex_sleep(struct futex *f, lwp_t *l, unsigned long timeout) +futex_sleep(struct futex **fp, lwp_t *l, int timeout, struct waiting_proc *wp) { - struct waiting_proc *wp; + struct futex *f, *newf; int ret; - wp = kmem_zalloc(sizeof(*wp), KM_SLEEP); + FUTEX_LOCKASSERT; + + f = *fp; wp->wp_l = l; wp->wp_new_futex = NULL; - cv_init(&wp->wp_futex_cv, "futex"); - FUTEX_LOCK; +requeue: TAILQ_INSERT_TAIL(&f->f_waiting_proc, wp, wp_list); ret = cv_timedwait_sig(&wp->wp_futex_cv, &futex_lock, timeout); TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list); - FUTEX_UNLOCK; - - /* if we got woken up in futex_wake */ - if ((ret == 0) && (wp->wp_new_futex != NULL)) { - /* suspend us on the new futex */ - ret = futex_sleep(wp->wp_new_futex, l, timeout); - /* and release the old one */ - futex_put(wp->wp_new_futex); - } - cv_destroy(&wp->wp_futex_cv); - kmem_free(wp, sizeof(*wp)); + /* if futex_wake() tells us to requeue ... */ + newf = wp->wp_new_futex; + if (ret == 0 && newf != NULL) { + /* ... requeue ourselves on the new futex */ + futex_put(f); + wp->wp_new_futex = NULL; + TAILQ_REMOVE(&newf->f_requeue_proc, wp, wp_rqlist); + *fp = f = newf; + goto requeue; + } return ret; } static int futex_wake(struct futex *f, int n, struct futex *newf, int n2) { - struct waiting_proc *wp; + struct waiting_proc *wp, *wpnext; int count; + FUTEX_LOCKASSERT; + count = newf ? 0 : 1; - FUTEX_LOCK; + /* + * first, wake up any threads sleeping on this futex. + * note that sleeping threads are not in the process of requeueing. + */ + TAILQ_FOREACH(wp, &f->f_waiting_proc, wp_list) { + KASSERT(wp->wp_new_futex == NULL); + + FUTEXPRINTF(("futex_wake: signal f %p l %p ref %d\n", + f, wp->wp_l, f->f_refcount)); + cv_signal(&wp->wp_futex_cv); if (count <= n) { - cv_signal(&wp->wp_futex_cv); count++; } else { if (newf == NULL) - continue; - /* futex_put called after tsleep */ - wp->wp_new_futex = futex_get(newf->f_uaddr, - FUTEX_LOCKED); - cv_signal(&wp->wp_futex_cv); + break; + + /* matching futex_put() is called by the other thread. */ + futex_ref(newf); + wp->wp_new_futex = newf; + TAILQ_INSERT_TAIL(&newf->f_requeue_proc, wp, wp_rqlist); + FUTEXPRINTF(("futex_wake: requeue newf %p l %p ref %d\n", + newf, wp->wp_l, newf->f_refcount)); + if (count - n >= n2) + goto out; + } + } + + /* + * next, deal with threads that are requeuing to this futex. + * we don't need to signal these threads, any thread on the + * requeue list has already been signaled but hasn't had a chance + * to run and requeue itself yet. if we would normally wake + * a thread, just remove the requeue info. if we would normally + * requeue a thread, change the requeue target. + */ + + TAILQ_FOREACH_SAFE(wp, &f->f_requeue_proc, wp_rqlist, wpnext) { + KASSERT(wp->wp_new_futex == f); + + FUTEXPRINTF(("futex_wake: unrequeue f %p l %p ref %d\n", + f, wp->wp_l, f->f_refcount)); + wp->wp_new_futex = NULL; + TAILQ_REMOVE(&f->f_requeue_proc, wp, wp_rqlist); + futex_put(f); + + if (count <= n) { + count++; + } else { + if (newf == NULL) + break; + + /* matching futex_put() is called by the other thread. */ + futex_ref(newf); + wp->wp_new_futex = newf; + TAILQ_INSERT_TAIL(&newf->f_requeue_proc, wp, wp_rqlist); + FUTEXPRINTF(("futex_wake: rerequeue newf %p l %p ref %d\n", + newf, wp->wp_l, newf->f_refcount)); if (count - n >= n2) break; } } - FUTEX_UNLOCK; +out: return count; } @@ -498,12 +615,16 @@ int linux_sys_set_robust_list(struct lwp *l, const struct linux_sys_set_robust_list_args *uap, register_t *retval) { - struct proc *p = l->l_proc; - struct linux_emuldata *led = p->p_emuldata; + /* { + syscallarg(struct linux_robust_list_head *) head; + syscallarg(size_t) len; + } */ + struct linux_emuldata *led; - if (SCARG(uap, len) != sizeof(*(led->robust_futexes))) + if (SCARG(uap, len) != sizeof(struct linux_robust_list_head)) return EINVAL; - led->robust_futexes = SCARG(uap, head); + led = l->l_emuldata; + led->led_robust_head = SCARG(uap, head); *retval = 0; return 0; } @@ -512,33 +633,51 @@ int linux_sys_get_robust_list(struct lwp *l, const struct linux_sys_get_robust_list_args *uap, register_t *retval) { + /* { + syscallarg(int) pid; + syscallarg(struct linux_robust_list_head **) head; + syscallarg(size_t *) len; + } */ + struct proc *p; struct linux_emuldata *led; - struct linux_robust_list_head **head; - size_t len = sizeof(*led->robust_futexes); + struct linux_robust_list_head *head; + size_t len; int error = 0; + p = l->l_proc; if (!SCARG(uap, pid)) { - led = l->l_proc->p_emuldata; - head = &led->robust_futexes; + led = l->l_emuldata; + head = led->led_robust_head; } else { - struct proc *p; - - mutex_enter(proc_lock); - p = proc_find(SCARG(uap, pid)); - if (p == NULL || p->p_emul != &emul_linux) { - mutex_exit(proc_lock); + mutex_enter(p->p_lock); + l = lwp_find(p, SCARG(uap, pid)); + if (l != NULL) { + led = l->l_emuldata; + head = led->led_robust_head; + } + mutex_exit(p->p_lock); + if (l == NULL) { return ESRCH; } - led = p->p_emuldata; - head = &led->robust_futexes; - mutex_exit(proc_lock); } +#ifdef __arch64__ + if (p->p_flag & PK_32) { + uint32_t u32; + + u32 = 12; + error = copyout(&u32, SCARG(uap, len), sizeof(u32)); + if (error) + return error; + u32 = (uint32_t)(uintptr_t)head; + return copyout(&u32, SCARG(uap, head), sizeof(u32)); + } +#endif - /* FIXME unlocked */ + len = sizeof(*head); error = copyout(&len, SCARG(uap, len), sizeof(len)); if (error) return error; - return copyout(head, SCARG(uap, head), sizeof(*head)); + return copyout(&head, SCARG(uap, head), sizeof(head)); } static int @@ -548,7 +687,7 @@ handle_futex_death(void *uaddr, pid_t pid, int pi) struct futex *f; retry: - if (copyin(uaddr, &uval, 4)) + if (copyin(uaddr, &uval, sizeof(uval))) return EFAULT; if ((uval & FUTEX_TID_MASK) == pid) { @@ -562,8 +701,10 @@ retry: goto retry; if (!pi && (uval & FUTEX_WAITERS)) { - f = futex_get(uaddr, FUTEX_UNLOCKED); + FUTEX_LOCK; + f = futex_get(uaddr); futex_wake(f, 1, NULL, 0); + FUTEX_UNLOCK; } } @@ -571,12 +712,23 @@ retry: } static int -fetch_robust_entry(struct linux_robust_list **entry, +fetch_robust_entry(struct lwp *l, struct linux_robust_list **entry, struct linux_robust_list **head, int *pi) { + struct linux_emuldata *led; unsigned long uentry; - if (copyin((const void *)head, &uentry, sizeof(unsigned long))) + led = l->l_emuldata; +#ifdef __arch64__ + if (l->l_proc->p_flag & PK_32) { + uint32_t u32; + + if (copyin(head, &u32, sizeof(u32))) + return EFAULT; + uentry = (unsigned long)u32; + } else +#endif + if (copyin(head, &uentry, sizeof(uentry))) return EFAULT; *entry = (void *)(uentry & ~1UL); @@ -587,7 +739,7 @@ fetch_robust_entry(struct linux_robust_list **entry, /* This walks the list of robust futexes, releasing them. */ void -release_futexes(struct proc *p) +release_futexes(struct lwp *l) { struct linux_robust_list_head head; struct linux_robust_list *entry, *next_entry = NULL, *pending; @@ -596,28 +748,50 @@ release_futexes(struct proc *p) unsigned long futex_offset; int rc; - led = p->p_emuldata; - if (led->robust_futexes == NULL) + led = l->l_emuldata; + if (led->led_robust_head == NULL) return; - if (copyin(led->robust_futexes, &head, sizeof(head))) +#ifdef __arch64__ + if (l->l_proc->p_flag & PK_32) { + uint32_t u32s[3]; + + if (copyin(led->led_robust_head, u32s, sizeof(u32s))) + return; + + head.list.next = (void *)(uintptr_t)u32s[0]; + head.futex_offset = (unsigned long)u32s[1]; + head.pending_list = (void *)(uintptr_t)u32s[2]; + } else +#endif + if (copyin(led->led_robust_head, &head, sizeof(head))) return; - if (fetch_robust_entry(&entry, &head.list.next, &pi)) + if (fetch_robust_entry(l, &entry, &head.list.next, &pi)) return; +#ifdef __arch64__ + if (l->l_proc->p_flag & PK_32) { + uint32_t u32; + + if (copyin(led->led_robust_head, &u32, sizeof(u32))) + return; + + head.futex_offset = (unsigned long)u32; + } else +#endif if (copyin(&head.futex_offset, &futex_offset, sizeof(unsigned long))) return; - if (fetch_robust_entry(&pending, &head.pending_list, &pip)) + if (fetch_robust_entry(l, &pending, &head.pending_list, &pip)) return; while (entry != &head.list) { - rc = fetch_robust_entry(&next_entry, &entry->next, &next_pi); + rc = fetch_robust_entry(l, &next_entry, &entry->next, &next_pi); if (entry != pending) if (handle_futex_death((char *)entry + futex_offset, - p->p_pid, pi)) + l->l_lid, pi)) return; if (rc) @@ -634,5 +808,5 @@ release_futexes(struct proc *p) if (pending) handle_futex_death((char *)pending + futex_offset, - p->p_pid, pip); + l->l_lid, pip); } |
