Add a NetBSD native futex implementation, mostly written by riastradh@.
Map the COMPAT_LINUX futex calls to the native ones.
This commit is contained in:
parent
02e6d0f660
commit
276ef22378
@ -1,4 +1,4 @@
|
||||
# $NetBSD: mi,v 1.2321 2020/04/04 19:26:51 christos Exp $
|
||||
# $NetBSD: mi,v 1.2322 2020/04/26 18:53:31 thorpej Exp $
|
||||
#
|
||||
# Note: don't delete entries from here - mark them as "obsolete" instead.
|
||||
./etc/mtree/set.comp comp-sys-root
|
||||
@ -3059,6 +3059,7 @@
|
||||
./usr/include/sys/float_ieee754.h comp-c-include
|
||||
./usr/include/sys/fnv_hash.h comp-obsolete obsolete
|
||||
./usr/include/sys/fstypes.h comp-c-include
|
||||
./usr/include/sys/futex.h comp-c-include
|
||||
./usr/include/sys/gcq.h comp-c-include
|
||||
./usr/include/sys/gmon.h comp-c-include
|
||||
./usr/include/sys/gpio.h comp-c-include
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: mi,v 1.836 2020/04/19 13:22:58 maxv Exp $
|
||||
# $NetBSD: mi,v 1.837 2020/04/26 18:53:32 thorpej Exp $
|
||||
#
|
||||
# Note: don't delete entries from here - mark them as "obsolete" instead.
|
||||
#
|
||||
@ -3120,6 +3120,8 @@
|
||||
./usr/tests/lib/libc/sys/t_dup tests-lib-tests compattestfile,atf
|
||||
./usr/tests/lib/libc/sys/t_fork tests-lib-tests compattestfile,atf
|
||||
./usr/tests/lib/libc/sys/t_fsync tests-lib-tests compattestfile,atf
|
||||
./usr/tests/lib/libc/sys/t_futex_ops tests-lib-tests compattestfile,atf
|
||||
./usr/tests/lib/libc/sys/t_futex_robust tests-lib-tests compattestfile,atf
|
||||
./usr/tests/lib/libc/sys/t_getcontext tests-lib-tests compattestfile,atf
|
||||
./usr/tests/lib/libc/sys/t_getgroups tests-lib-tests compattestfile,atf
|
||||
./usr/tests/lib/libc/sys/t_getitimer tests-lib-tests compattestfile,atf
|
||||
|
64
lib/libc/include/futex_private.h
Normal file
64
lib/libc/include/futex_private.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* $NetBSD: futex_private.h,v 1.1 2020/04/26 18:53:32 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2019 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Jason R. Thorpe.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBC_FUTEX_PRIVATE
|
||||
#define __LIBC_FUTEX_PRIVATE
|
||||
|
||||
#if defined(_LIBC)
|
||||
#include "namespace.h"
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/futex.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static inline int __unused
|
||||
__futex(volatile int *uaddr, int op, int val, const struct timespec *timeout,
|
||||
volatile int *uaddr2, int val2, int val3)
|
||||
{
|
||||
return syscall(SYS___futex, uaddr, op, val, timeout, uaddr2,
|
||||
val2, val3);
|
||||
}
|
||||
|
||||
static inline int __unused
|
||||
__futex_set_robust_list(void *head, size_t len)
|
||||
{
|
||||
return syscall(SYS___futex_set_robust_list, head, len);
|
||||
}
|
||||
|
||||
static inline int __unused
|
||||
__futex_get_robust_list(lwpid_t lwpid, void **headp, size_t *lenp)
|
||||
{
|
||||
return syscall(SYS___futex_get_robust_list, lwpid, headp, lenp);
|
||||
}
|
||||
|
||||
#endif /* __LIBC_FUTEX_PRIVATE */
|
@ -1,4 +1,4 @@
|
||||
$NetBSD: syscalls.master,v 1.96 2019/11/09 23:44:31 jdolecek Exp $
|
||||
$NetBSD: syscalls.master,v 1.97 2020/04/26 18:53:32 thorpej Exp $
|
||||
;
|
||||
; @(#)syscalls.master 8.1 (Berkeley) 7/19/93
|
||||
|
||||
@ -740,11 +740,15 @@
|
||||
struct linux_timespec *timeout, \
|
||||
linux_sigset_t *sigset); }
|
||||
465 UNIMPL unshare
|
||||
466 STD { int|linux_sys||set_robust_list( \
|
||||
struct linux_robust_list_head *head, size_t len); }
|
||||
467 STD { int|linux_sys||get_robust_list(int pid, \
|
||||
struct linux_robust_list_head **head, \
|
||||
size_t *len); }
|
||||
;
|
||||
; The NetBSD native robust list calls have different
|
||||
; argument names / types, but they are ABI-compatible
|
||||
; with Linux.
|
||||
;
|
||||
466 NOARGS { int|sys||__futex_set_robust_list(void *head, \
|
||||
size_t len); }
|
||||
467 NOARGS { int|sys||__futex_get_robust_list(lwpid_t lwpid, \
|
||||
void **headp, size_t *lenp); }
|
||||
468 UNIMPL splice
|
||||
469 UNIMPL sync_file_range
|
||||
470 UNIMPL tee
|
||||
|
@ -1,4 +1,4 @@
|
||||
$NetBSD: syscalls.master,v 1.61 2019/11/09 23:44:31 jdolecek Exp $
|
||||
$NetBSD: syscalls.master,v 1.62 2020/04/26 18:53:32 thorpej Exp $
|
||||
|
||||
; @(#)syscalls.master 8.1 (Berkeley) 7/19/93
|
||||
|
||||
@ -497,11 +497,15 @@
|
||||
struct linux_timespec *timeout, \
|
||||
linux_sigset_t *sigset); }
|
||||
272 UNIMPL unshare
|
||||
273 STD { int|linux_sys||set_robust_list( \
|
||||
struct linux_robust_list_head *head, size_t len); }
|
||||
274 STD { int|linux_sys||get_robust_list(int pid, \
|
||||
struct linux_robust_list_head **head, \
|
||||
size_t *len); }
|
||||
;
|
||||
; The NetBSD native robust list calls have different
|
||||
; argument names / types, but they are ABI-compatible
|
||||
; with Linux.
|
||||
;
|
||||
273 NOARGS { int|sys||__futex_set_robust_list(void *head, \
|
||||
size_t len); }
|
||||
274 NOARGS { int|sys||__futex_get_robust_list(lwpid_t lwpid, \
|
||||
void **headp, size_t *lenp); }
|
||||
275 UNIMPL splice
|
||||
276 UNIMPL tee
|
||||
277 UNIMPL sync_file_range
|
||||
|
@ -1,4 +1,4 @@
|
||||
$NetBSD: syscalls.master,v 1.68 2019/11/09 23:44:31 jdolecek Exp $
|
||||
$NetBSD: syscalls.master,v 1.69 2020/04/26 18:53:32 thorpej Exp $
|
||||
|
||||
; Derived from sys/compat/linux/arch/*/syscalls.master
|
||||
; and from Linux 2.4.12 arch/arm/kernel/calls.S
|
||||
@ -538,11 +538,15 @@
|
||||
struct linux_timespec *timeout, \
|
||||
linux_sigset_t *sigset); }
|
||||
337 UNIMPL unshare
|
||||
338 STD { int|linux_sys||set_robust_list( \
|
||||
struct linux_robust_list_head *head, size_t len); }
|
||||
339 STD { int|linux_sys||get_robust_list(int pid, \
|
||||
struct linux_robust_list_head **head, \
|
||||
size_t *len); }
|
||||
;
|
||||
; The NetBSD native robust list calls have different
|
||||
; argument names / types, but they are ABI-compatible
|
||||
; with Linux.
|
||||
;
|
||||
338 NOARGS { int|sys||__futex_set_robust_list(void *head, \
|
||||
size_t len); }
|
||||
339 NOARGS { int|sys||__futex_get_robust_list(lwpid_t lwpid, \
|
||||
void **headp, size_t *lenp); }
|
||||
340 UNIMPL splice
|
||||
341 UNIMPL sync_file_range2
|
||||
342 UNIMPL tee
|
||||
|
@ -1,4 +1,4 @@
|
||||
$NetBSD: syscalls.master,v 1.123 2019/11/09 23:44:32 jdolecek Exp $
|
||||
$NetBSD: syscalls.master,v 1.124 2020/04/26 18:53:32 thorpej Exp $
|
||||
|
||||
; @(#)syscalls.master 8.1 (Berkeley) 7/19/93
|
||||
|
||||
@ -511,11 +511,10 @@
|
||||
struct linux_timespec *timeout, \
|
||||
linux_sigset_t *sigset); }
|
||||
310 UNIMPL unshare
|
||||
311 STD { int|linux_sys||set_robust_list( \
|
||||
struct linux_robust_list_head *head, size_t len); }
|
||||
312 STD { int|linux_sys||get_robust_list(int pid, \
|
||||
struct linux_robust_list_head **head, \
|
||||
size_t *len); }
|
||||
311 NOARGS { int|sys||__futex_set_robust_list(void *head, \
|
||||
size_t len); }
|
||||
312 NOARGS { int|sys||__futex_get_robust_list(lwpid_t lwpid, \
|
||||
void **headp, size_t *lenp); }
|
||||
313 UNIMPL splice
|
||||
314 UNIMPL sync_file_range
|
||||
315 UNIMPL tee
|
||||
|
@ -1,4 +1,4 @@
|
||||
$NetBSD: syscalls.master,v 1.94 2019/11/09 23:44:32 jdolecek Exp $
|
||||
$NetBSD: syscalls.master,v 1.95 2020/04/26 18:53:32 thorpej Exp $
|
||||
|
||||
; @(#)syscalls.master 8.1 (Berkeley) 7/19/93
|
||||
|
||||
@ -519,11 +519,15 @@
|
||||
struct linux_timespec *timeout, \
|
||||
linux_sigset_t *sigset); }
|
||||
303 UNIMPL unshare
|
||||
304 STD { int|linux_sys||set_robust_list( \
|
||||
struct linux_robust_list_head *head, size_t len); }
|
||||
305 STD { int|linux_sys||get_robust_list(int pid, \
|
||||
struct linux_robust_list_head **head, \
|
||||
size_t *len); }
|
||||
;
|
||||
; The NetBSD native robust list calls have different
|
||||
; argument names / types, but they are ABI-compatible
|
||||
; with Linux.
|
||||
;
|
||||
304 NOARGS { int|sys||__futex_set_robust_list(void *head, \
|
||||
size_t len); }
|
||||
305 NOARGS { int|sys||__futex_get_robust_list(lwpid_t lwpid, \
|
||||
void **headp, size_t *lenp); }
|
||||
306 UNIMPL splice
|
||||
307 UNIMPL sync_file_range
|
||||
308 UNIMPL tee
|
||||
|
@ -1,4 +1,4 @@
|
||||
$NetBSD: syscalls.master,v 1.67 2019/11/09 23:44:32 jdolecek Exp $
|
||||
$NetBSD: syscalls.master,v 1.68 2020/04/26 18:53:32 thorpej Exp $
|
||||
|
||||
; @(#)syscalls.master 8.1 (Berkeley) 7/19/93
|
||||
|
||||
@ -514,11 +514,15 @@
|
||||
306 UNIMPL tee
|
||||
307 UNIMPL vmsplice
|
||||
308 UNIMPL move_pages
|
||||
309 STD { int|linux_sys||set_robust_list( \
|
||||
struct linux_robust_list_head *head, size_t len); }
|
||||
310 STD { int|linux_sys||get_robust_list(int pid, \
|
||||
struct linux_robust_list_head **head, \
|
||||
size_t *len); }
|
||||
;
|
||||
; The NetBSD native robust list calls have different
|
||||
; argument names / types, but they are ABI-compatible
|
||||
; with Linux.
|
||||
;
|
||||
309 NOARGS { int|sys||__futex_set_robust_list(void *head, \
|
||||
size_t len); }
|
||||
310 NOARGS { int|sys||__futex_get_robust_list(lwpid_t lwpid, \
|
||||
void **headp, size_t *lenp); }
|
||||
311 UNIMPL kexec_load
|
||||
312 UNIMPL getcpu
|
||||
313 UNIMPL epoll_pwait
|
||||
|
@ -1,4 +1,4 @@
|
||||
$NetBSD: syscalls.master,v 1.73 2019/11/09 23:44:32 jdolecek Exp $
|
||||
$NetBSD: syscalls.master,v 1.74 2020/04/26 18:53:32 thorpej Exp $
|
||||
|
||||
; @(#)syscalls.master 8.1 (Berkeley) 7/19/93
|
||||
|
||||
@ -514,11 +514,15 @@
|
||||
linux_umode_t mode); }
|
||||
298 STD { int|linux_sys||faccessat(int fd, const char *path, \
|
||||
int amode); }
|
||||
299 STD { int|linux_sys||set_robust_list( \
|
||||
struct linux_robust_list_head *head, size_t len); }
|
||||
300 STD { int|linux_sys||get_robust_list(int pid, \
|
||||
struct linux_robust_list_head **head, \
|
||||
size_t *len); }
|
||||
;
|
||||
; The NetBSD native robust list calls have different
|
||||
; argument names / types, but they are ABI-compatible
|
||||
; with Linux.
|
||||
;
|
||||
299 NOARGS { int|sys||__futex_set_robust_list(void *head, \
|
||||
size_t len); }
|
||||
300 NOARGS { int|sys||__futex_get_robust_list(lwpid_t lwpid, \
|
||||
void **headp, size_t *lenp); }
|
||||
301 UNIMPL move_pages
|
||||
302 UNIMPL getcpu
|
||||
303 UNIMPL epoll_wait
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: linux_emuldata.h,v 1.18 2010/11/02 18:18:07 chs Exp $ */
|
||||
/* $NetBSD: linux_emuldata.h,v 1.19 2020/04/26 18:53:33 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998,2002 The NetBSD Foundation, Inc.
|
||||
@ -29,8 +29,6 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <compat/linux/common/linux_futex.h>
|
||||
|
||||
#ifndef _COMMON_LINUX_EMULDATA_H
|
||||
#define _COMMON_LINUX_EMULDATA_H
|
||||
|
||||
@ -47,7 +45,6 @@ struct linux_emuldata {
|
||||
|
||||
void *led_child_tidptr; /* Used during clone() */
|
||||
void *led_clear_tid; /* Own TID to clear on exit */
|
||||
struct linux_robust_list_head *led_robust_head;
|
||||
long led_personality;
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: linux_exec.c,v 1.122 2020/04/24 03:22:06 thorpej Exp $ */
|
||||
/* $NetBSD: linux_exec.c,v 1.123 2020/04/26 18:53:33 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1994, 1995, 1998, 2000, 2007, 2008, 2020
|
||||
@ -32,7 +32,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.122 2020/04/24 03:22:06 thorpej Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.123 2020/04/26 18:53:33 thorpej Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -44,6 +44,7 @@ __KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.122 2020/04/24 03:22:06 thorpej Exp
|
||||
#include <sys/mount.h>
|
||||
#include <sys/exec.h>
|
||||
#include <sys/exec_elf.h>
|
||||
#include <sys/futex.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscallargs.h>
|
||||
@ -61,7 +62,6 @@ __KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.122 2020/04/24 03:22:06 thorpej Exp
|
||||
#include <compat/linux/common/linux_sched.h>
|
||||
#include <compat/linux/common/linux_machdep.h>
|
||||
#include <compat/linux/common/linux_exec.h>
|
||||
#include <compat/linux/common/linux_futex.h>
|
||||
#include <compat/linux/common/linux_ipc.h>
|
||||
#include <compat/linux/common/linux_sem.h>
|
||||
|
||||
@ -168,32 +168,24 @@ void
|
||||
linux_e_lwp_exit(struct lwp *l)
|
||||
{
|
||||
struct linux_emuldata *led;
|
||||
struct linux_sys_futex_args cup;
|
||||
register_t retval;
|
||||
int error, zero = 0;
|
||||
|
||||
led = l->l_emuldata;
|
||||
if (led->led_clear_tid == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Emulate LINUX_CLONE_CHILD_CLEARTID */
|
||||
error = copyout(&zero, led->led_clear_tid, sizeof(zero));
|
||||
if (led->led_clear_tid != NULL) {
|
||||
/* Emulate LINUX_CLONE_CHILD_CLEARTID */
|
||||
error = copyout(&zero, led->led_clear_tid, sizeof(zero));
|
||||
#ifdef DEBUG_LINUX
|
||||
if (error != 0)
|
||||
printf("%s: cannot clear TID\n", __func__);
|
||||
if (error != 0)
|
||||
printf("%s: cannot clear TID\n", __func__);
|
||||
#endif
|
||||
|
||||
SCARG(&cup, uaddr) = led->led_clear_tid;
|
||||
SCARG(&cup, op) = LINUX_FUTEX_WAKE;
|
||||
SCARG(&cup, val) = 0x7fffffff; /* Awake everyone */
|
||||
SCARG(&cup, timeout) = NULL;
|
||||
SCARG(&cup, uaddr2) = NULL;
|
||||
SCARG(&cup, val3) = 0;
|
||||
if ((error = linux_sys_futex(curlwp, &cup, &retval)) != 0)
|
||||
printf("%s: linux_sys_futex failed\n", __func__);
|
||||
|
||||
release_futexes(l);
|
||||
error = do_futex((int *)led->led_clear_tid, FUTEX_WAKE,
|
||||
INT_MAX, NULL, NULL, 0, 0, &retval);
|
||||
if (error)
|
||||
printf("%s: linux_sys_futex failed\n", __func__);
|
||||
}
|
||||
|
||||
led = l->l_emuldata;
|
||||
l->l_emuldata = NULL;
|
||||
|
@ -1,7 +1,11 @@
|
||||
/* $NetBSD: linux_futex.c,v 1.38 2020/03/14 18:08:38 ad Exp $ */
|
||||
/* $NetBSD: linux_futex.c,v 1.39 2020/04/26 18:53:33 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved.
|
||||
* Copyright (c) 2019 The NetBSD Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Taylor R. Campbell and Jason R. Thorpe.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -11,17 +15,11 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Emmanuel Dreyfus
|
||||
* 4. The name of the author may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
@ -32,86 +30,23 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.38 2020/03/14 18:08:38 ad Exp $");
|
||||
__KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.39 2020/04/26 18:53:33 thorpej Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/lwp.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/condvar.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/kmem.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/atomic.h>
|
||||
#include <sys/sched.h>
|
||||
#include <sys/futex.h>
|
||||
|
||||
#include <compat/linux/common/linux_types.h>
|
||||
#include <compat/linux/common/linux_emuldata.h>
|
||||
#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_sched.h>
|
||||
#include <compat/linux/common/linux_machdep.h>
|
||||
#include <compat/linux/linux_syscallargs.h>
|
||||
|
||||
struct futex;
|
||||
|
||||
struct waiting_proc {
|
||||
struct futex *wp_futex;
|
||||
kcondvar_t wp_futex_cv;
|
||||
TAILQ_ENTRY(waiting_proc) wp_list;
|
||||
bool wp_onlist;
|
||||
};
|
||||
struct futex {
|
||||
void *f_uaddr;
|
||||
int f_refcount;
|
||||
uint32_t f_bitset;
|
||||
LIST_ENTRY(futex) f_list;
|
||||
TAILQ_HEAD(, waiting_proc) f_waiting_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_LOCKASSERT KASSERT(mutex_owned(&futex_lock))
|
||||
|
||||
#define FUTEX_SYSTEM_LOCK KERNEL_LOCK(1, NULL)
|
||||
#define FUTEX_SYSTEM_UNLOCK KERNEL_UNLOCK_ONE(0)
|
||||
|
||||
#ifdef DEBUG_LINUX_FUTEX
|
||||
int debug_futex = 1;
|
||||
#define FUTEXPRINTF(a) do { if (debug_futex) printf a; } while (0)
|
||||
#else
|
||||
#define FUTEXPRINTF(a)
|
||||
#endif
|
||||
|
||||
void
|
||||
linux_futex_init(void)
|
||||
{
|
||||
FUTEXPRINTF(("%s: initializing futex\n", __func__));
|
||||
mutex_init(&futex_lock, MUTEX_DEFAULT, IPL_NONE);
|
||||
}
|
||||
|
||||
void
|
||||
linux_futex_fini(void)
|
||||
{
|
||||
FUTEXPRINTF(("%s: destroying futex\n", __func__));
|
||||
mutex_destroy(&futex_lock);
|
||||
}
|
||||
|
||||
static struct waiting_proc *futex_wp_alloc(void);
|
||||
static void futex_wp_free(struct waiting_proc *);
|
||||
static struct futex *futex_get(void *, uint32_t);
|
||||
static void futex_ref(struct futex *);
|
||||
static void futex_put(struct futex *);
|
||||
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 *);
|
||||
|
||||
int
|
||||
linux_sys_futex(struct lwp *l, const struct linux_sys_futex_args *uap,
|
||||
register_t *retval)
|
||||
@ -125,687 +60,26 @@ linux_sys_futex(struct lwp *l, const struct linux_sys_futex_args *uap,
|
||||
syscallarg(int) val3;
|
||||
} */
|
||||
struct linux_timespec lts;
|
||||
struct timespec ts = { 0, 0 };
|
||||
struct timespec ts, *tsp = NULL;
|
||||
int val2 = 0;
|
||||
int error;
|
||||
|
||||
if ((SCARG(uap, op) & LINUX_FUTEX_CMD_MASK) == LINUX_FUTEX_WAIT &&
|
||||
/*
|
||||
* Linux overlays the "timeout" field and the "val2" field.
|
||||
* "timeout" is only valid for FUTEX_WAIT on Linux.
|
||||
*/
|
||||
if ((SCARG(uap, op) & FUTEX_CMD_MASK) == 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, &ts, retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: TS can't be const because ts2timo destroys it.
|
||||
*/
|
||||
int
|
||||
linux_do_futex(struct lwp *l, const struct linux_sys_futex_args *uap,
|
||||
struct timespec *ts, register_t *retval)
|
||||
{
|
||||
/* {
|
||||
syscallarg(int *) uaddr;
|
||||
syscallarg(int) op;
|
||||
syscallarg(int) val;
|
||||
syscallarg(const struct linux_timespec *) timeout;
|
||||
syscallarg(int *) uaddr2;
|
||||
syscallarg(int) val3;
|
||||
} */
|
||||
int val, val3;
|
||||
int ret;
|
||||
int error = 0;
|
||||
struct futex *f;
|
||||
struct futex *newf;
|
||||
int tout;
|
||||
struct futex *f2;
|
||||
struct waiting_proc *wp;
|
||||
int op_ret, cmd;
|
||||
clockid_t clk;
|
||||
|
||||
cmd = SCARG(uap, op) & LINUX_FUTEX_CMD_MASK;
|
||||
val3 = SCARG(uap, val3);
|
||||
|
||||
if (SCARG(uap, op) & LINUX_FUTEX_CLOCK_REALTIME) {
|
||||
switch (cmd) {
|
||||
case LINUX_FUTEX_WAIT_BITSET:
|
||||
case LINUX_FUTEX_WAIT:
|
||||
clk = CLOCK_REALTIME;
|
||||
break;
|
||||
default:
|
||||
return ENOSYS;
|
||||
}
|
||||
} else
|
||||
clk = CLOCK_MONOTONIC;
|
||||
|
||||
/*
|
||||
* Our implementation provides only private futexes. Most of the apps
|
||||
* should use private futexes but don't claim so. Therefore we treat
|
||||
* all futexes as private by clearing the FUTEX_PRIVATE_FLAG. It works
|
||||
* in most cases (ie. when futexes are not shared on file descriptor
|
||||
* or between different processes).
|
||||
*
|
||||
* Note that we don't handle bitsets at all at the moment. We need
|
||||
* to move from refcounting uaddr's to handling multiple futex entries
|
||||
* pointing to the same uaddr, but having possibly different bitmask.
|
||||
* Perhaps move to an implementation where each uaddr has a list of
|
||||
* futexes.
|
||||
*/
|
||||
switch (cmd) {
|
||||
case LINUX_FUTEX_WAIT:
|
||||
val3 = FUTEX_BITSET_MATCH_ANY;
|
||||
/*FALLTHROUGH*/
|
||||
case LINUX_FUTEX_WAIT_BITSET:
|
||||
if ((error = ts2timo(clk, 0, ts, &tout, NULL)) != 0) {
|
||||
if (error != ETIMEDOUT)
|
||||
return error;
|
||||
/*
|
||||
* If the user process requests a non null
|
||||
* timeout, make sure we do not turn it into
|
||||
* an infinite timeout because tout is 0.
|
||||
*
|
||||
* We use a minimal timeout of 1/hz. Maybe it
|
||||
* would make sense to just return ETIMEDOUT
|
||||
* without sleeping.
|
||||
*/
|
||||
if (SCARG(uap, timeout) != NULL)
|
||||
tout = 1;
|
||||
else
|
||||
tout = 0;
|
||||
}
|
||||
FUTEX_SYSTEM_LOCK;
|
||||
if ((error = copyin(SCARG(uap, uaddr),
|
||||
&val, sizeof(val))) != 0) {
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
return error;
|
||||
}
|
||||
|
||||
if (val != SCARG(uap, val)) {
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
return EWOULDBLOCK;
|
||||
}
|
||||
|
||||
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)ts->tv_sec,
|
||||
ts->tv_nsec));
|
||||
|
||||
|
||||
wp = futex_wp_alloc();
|
||||
FUTEX_LOCK;
|
||||
f = futex_get(SCARG(uap, uaddr), val3);
|
||||
ret = futex_sleep(&f, l, tout, 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,
|
||||
SCARG(uap, uaddr), ret));
|
||||
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
switch (ret) {
|
||||
case EWOULDBLOCK: /* timeout */
|
||||
return ETIMEDOUT;
|
||||
break;
|
||||
case EINTR: /* signal */
|
||||
return EINTR;
|
||||
break;
|
||||
case 0: /* FUTEX_WAKE received */
|
||||
FUTEXPRINTF(("FUTEX_WAIT %d.%d: uaddr = %p, got it\n",
|
||||
l->l_proc->p_pid, l->l_lid, SCARG(uap, uaddr)));
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
FUTEXPRINTF(("FUTEX_WAIT: unexpected ret = %d\n", ret));
|
||||
break;
|
||||
}
|
||||
|
||||
/* NOTREACHED */
|
||||
break;
|
||||
|
||||
case LINUX_FUTEX_WAKE:
|
||||
val = FUTEX_BITSET_MATCH_ANY;
|
||||
/*FALLTHROUGH*/
|
||||
case LINUX_FUTEX_WAKE_BITSET:
|
||||
/*
|
||||
* XXX: Linux is able cope with different addresses
|
||||
* corresponding to the same mapped memory in the sleeping
|
||||
* and the waker process(es).
|
||||
*/
|
||||
FUTEXPRINTF(("FUTEX_WAKE %d.%d: uaddr = %p, val = %d\n",
|
||||
l->l_proc->p_pid, l->l_lid,
|
||||
SCARG(uap, uaddr), SCARG(uap, val)));
|
||||
|
||||
FUTEX_SYSTEM_LOCK;
|
||||
FUTEX_LOCK;
|
||||
f = futex_get(SCARG(uap, uaddr), val3);
|
||||
*retval = futex_wake(f, SCARG(uap, val), NULL, 0);
|
||||
futex_put(f);
|
||||
FUTEX_UNLOCK;
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
|
||||
break;
|
||||
|
||||
case LINUX_FUTEX_CMP_REQUEUE:
|
||||
FUTEX_SYSTEM_LOCK;
|
||||
|
||||
if ((error = copyin(SCARG(uap, uaddr),
|
||||
&val, sizeof(val))) != 0) {
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
return error;
|
||||
}
|
||||
|
||||
if (val != val3) {
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
return EAGAIN;
|
||||
}
|
||||
|
||||
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), val3);
|
||||
newf = futex_get(SCARG(uap, uaddr2), val3);
|
||||
*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;
|
||||
|
||||
case LINUX_FUTEX_REQUEUE:
|
||||
FUTEX_SYSTEM_LOCK;
|
||||
|
||||
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), val3);
|
||||
newf = futex_get(SCARG(uap, uaddr2), val3);
|
||||
*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;
|
||||
|
||||
case LINUX_FUTEX_FD:
|
||||
FUTEXPRINTF(("%s: unimplemented op %d\n", __func__, cmd));
|
||||
return ENOSYS;
|
||||
case LINUX_FUTEX_WAKE_OP:
|
||||
FUTEX_SYSTEM_LOCK;
|
||||
|
||||
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), cmd, SCARG(uap, val),
|
||||
SCARG(uap, uaddr2),
|
||||
(int)(unsigned long)SCARG(uap, timeout)));
|
||||
|
||||
FUTEX_LOCK;
|
||||
f = futex_get(SCARG(uap, uaddr), val3);
|
||||
f2 = futex_get(SCARG(uap, uaddr2), val3);
|
||||
FUTEX_UNLOCK;
|
||||
|
||||
/*
|
||||
* This function returns positive number as results and
|
||||
* negative as errors
|
||||
*/
|
||||
op_ret = futex_atomic_op(l, val3, SCARG(uap, uaddr2));
|
||||
FUTEX_LOCK;
|
||||
if (op_ret < 0) {
|
||||
futex_put(f);
|
||||
futex_put(f2);
|
||||
FUTEX_UNLOCK;
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
return -op_ret;
|
||||
}
|
||||
|
||||
ret = futex_wake(f, SCARG(uap, val), NULL, 0);
|
||||
futex_put(f);
|
||||
if (op_ret > 0) {
|
||||
op_ret = 0;
|
||||
/*
|
||||
* Linux abuses the address of the timespec parameter
|
||||
* as the number of retries
|
||||
*/
|
||||
op_ret += futex_wake(f2,
|
||||
(int)(unsigned long)SCARG(uap, timeout), NULL, 0);
|
||||
ret += op_ret;
|
||||
}
|
||||
futex_put(f2);
|
||||
FUTEX_UNLOCK;
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
*retval = ret;
|
||||
break;
|
||||
default:
|
||||
FUTEXPRINTF(("%s: unknown op %d\n", __func__, cmd));
|
||||
return ENOSYS;
|
||||
}
|
||||
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, uint32_t bitset)
|
||||
{
|
||||
struct futex *f;
|
||||
|
||||
FUTEX_LOCKASSERT;
|
||||
|
||||
LIST_FOREACH(f, &futex_list, f_list) {
|
||||
if (f->f_uaddr == uaddr) {
|
||||
f->f_refcount++;
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found, create it */
|
||||
f = kmem_zalloc(sizeof(*f), KM_SLEEP);
|
||||
f->f_uaddr = uaddr;
|
||||
f->f_bitset = bitset;
|
||||
f->f_refcount = 1;
|
||||
TAILQ_INIT(&f->f_waiting_proc);
|
||||
LIST_INSERT_HEAD(&futex_list, f, f_list);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static void
|
||||
futex_ref(struct futex *f)
|
||||
{
|
||||
|
||||
FUTEX_LOCKASSERT;
|
||||
|
||||
f->f_refcount++;
|
||||
}
|
||||
|
||||
static void
|
||||
futex_put(struct futex *f)
|
||||
{
|
||||
|
||||
FUTEX_LOCKASSERT;
|
||||
|
||||
f->f_refcount--;
|
||||
if (f->f_refcount == 0) {
|
||||
KASSERT(TAILQ_EMPTY(&f->f_waiting_proc));
|
||||
LIST_REMOVE(f, f_list);
|
||||
kmem_free(f, sizeof(*f));
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
futex_sleep(struct futex **fp, lwp_t *l, int timeout, struct waiting_proc *wp)
|
||||
{
|
||||
struct futex *f;
|
||||
int ret;
|
||||
|
||||
FUTEX_LOCKASSERT;
|
||||
|
||||
f = *fp;
|
||||
wp->wp_futex = f;
|
||||
TAILQ_INSERT_TAIL(&f->f_waiting_proc, wp, wp_list);
|
||||
wp->wp_onlist = true;
|
||||
ret = cv_timedwait_sig(&wp->wp_futex_cv, &futex_lock, timeout);
|
||||
|
||||
/*
|
||||
* we may have been requeued to a different futex before we were
|
||||
* woken up, so let the caller know which futex to put. if we were
|
||||
* woken by futex_wake() then it took us off the waiting list,
|
||||
* but if our sleep was interrupted or timed out then we might
|
||||
* need to take ourselves off the waiting list.
|
||||
*/
|
||||
|
||||
f = wp->wp_futex;
|
||||
if (wp->wp_onlist) {
|
||||
TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
|
||||
}
|
||||
*fp = f;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
futex_wake(struct futex *f, int n, struct futex *newf, int n2)
|
||||
{
|
||||
struct waiting_proc *wp;
|
||||
int count = 0;
|
||||
|
||||
FUTEX_LOCKASSERT;
|
||||
|
||||
/*
|
||||
* wake up up to n threads waiting on this futex.
|
||||
*/
|
||||
|
||||
while (n--) {
|
||||
wp = TAILQ_FIRST(&f->f_waiting_proc);
|
||||
if (wp == NULL)
|
||||
return count;
|
||||
|
||||
KASSERT(f == wp->wp_futex);
|
||||
TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
|
||||
wp->wp_onlist = false;
|
||||
cv_signal(&wp->wp_futex_cv);
|
||||
count++;
|
||||
}
|
||||
if (newf == NULL)
|
||||
return count;
|
||||
|
||||
/*
|
||||
* then requeue up to n2 additional threads to newf
|
||||
* (without waking them up).
|
||||
*/
|
||||
|
||||
while (n2--) {
|
||||
wp = TAILQ_FIRST(&f->f_waiting_proc);
|
||||
if (wp == NULL)
|
||||
return count;
|
||||
|
||||
KASSERT(f == wp->wp_futex);
|
||||
TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
|
||||
futex_put(f);
|
||||
|
||||
wp->wp_futex = newf;
|
||||
futex_ref(newf);
|
||||
TAILQ_INSERT_TAIL(&newf->f_waiting_proc, wp, wp_list);
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static int
|
||||
futex_atomic_op(lwp_t *l, int encoded_op, void *uaddr)
|
||||
{
|
||||
const int op = (encoded_op >> 28) & 7;
|
||||
const int cmp = (encoded_op >> 24) & 15;
|
||||
const int cmparg = (encoded_op << 20) >> 20;
|
||||
int oparg = (encoded_op << 8) >> 20;
|
||||
int error, oldval, cval;
|
||||
|
||||
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
||||
oparg = 1 << oparg;
|
||||
|
||||
/* XXX: linux verifies access here and returns EFAULT */
|
||||
|
||||
if (copyin(uaddr, &cval, sizeof(int)) != 0)
|
||||
return -EFAULT;
|
||||
|
||||
for (;;) {
|
||||
int nval;
|
||||
|
||||
switch (op) {
|
||||
case FUTEX_OP_SET:
|
||||
nval = oparg;
|
||||
break;
|
||||
case FUTEX_OP_ADD:
|
||||
nval = cval + oparg;
|
||||
break;
|
||||
case FUTEX_OP_OR:
|
||||
nval = cval | oparg;
|
||||
break;
|
||||
case FUTEX_OP_ANDN:
|
||||
nval = cval & ~oparg;
|
||||
break;
|
||||
case FUTEX_OP_XOR:
|
||||
nval = cval ^ oparg;
|
||||
break;
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
error = ucas_int(uaddr, cval, nval, &oldval);
|
||||
if (error || oldval == cval) {
|
||||
break;
|
||||
}
|
||||
cval = oldval;
|
||||
}
|
||||
|
||||
if (error)
|
||||
return -EFAULT;
|
||||
|
||||
switch (cmp) {
|
||||
case FUTEX_OP_CMP_EQ:
|
||||
return (oldval == cmparg);
|
||||
case FUTEX_OP_CMP_NE:
|
||||
return (oldval != cmparg);
|
||||
case FUTEX_OP_CMP_LT:
|
||||
return (oldval < cmparg);
|
||||
case FUTEX_OP_CMP_GE:
|
||||
return (oldval >= cmparg);
|
||||
case FUTEX_OP_CMP_LE:
|
||||
return (oldval <= cmparg);
|
||||
case FUTEX_OP_CMP_GT:
|
||||
return (oldval > cmparg);
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
linux_sys_set_robust_list(struct lwp *l,
|
||||
const struct linux_sys_set_robust_list_args *uap, register_t *retval)
|
||||
{
|
||||
/* {
|
||||
syscallarg(struct linux_robust_list_head *) head;
|
||||
syscallarg(size_t) len;
|
||||
} */
|
||||
struct linux_emuldata *led;
|
||||
|
||||
if (SCARG(uap, len) != sizeof(struct linux_robust_list_head))
|
||||
return EINVAL;
|
||||
led = l->l_emuldata;
|
||||
led->led_robust_head = SCARG(uap, head);
|
||||
*retval = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
int error = 0;
|
||||
|
||||
p = l->l_proc;
|
||||
if (!SCARG(uap, pid)) {
|
||||
led = l->l_emuldata;
|
||||
head = led->led_robust_head;
|
||||
tsp = &ts;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
#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
|
||||
|
||||
len = sizeof(*head);
|
||||
error = copyout(&len, SCARG(uap, len), sizeof(len));
|
||||
if (error)
|
||||
return error;
|
||||
return copyout(&head, SCARG(uap, head), sizeof(head));
|
||||
}
|
||||
|
||||
static int
|
||||
handle_futex_death(void *uaddr, pid_t pid, int pi)
|
||||
{
|
||||
int uval, nval, mval;
|
||||
struct futex *f;
|
||||
|
||||
retry:
|
||||
if (copyin(uaddr, &uval, sizeof(uval)))
|
||||
return EFAULT;
|
||||
|
||||
if ((uval & FUTEX_TID_MASK) == pid) {
|
||||
mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
|
||||
nval = atomic_cas_32(uaddr, uval, mval);
|
||||
|
||||
if (nval == -1)
|
||||
return EFAULT;
|
||||
|
||||
if (nval != uval)
|
||||
goto retry;
|
||||
|
||||
if (!pi && (uval & FUTEX_WAITERS)) {
|
||||
FUTEX_LOCK;
|
||||
f = futex_get(uaddr, FUTEX_BITSET_MATCH_ANY);
|
||||
futex_wake(f, 1, NULL, 0);
|
||||
FUTEX_UNLOCK;
|
||||
}
|
||||
val2 = (int)(uintptr_t)SCARG(uap, timeout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fetch_robust_entry(struct lwp *l, struct linux_robust_list **entry,
|
||||
struct linux_robust_list **head, int *pi)
|
||||
{
|
||||
unsigned long uentry;
|
||||
|
||||
#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);
|
||||
*pi = uentry & 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This walks the list of robust futexes, releasing them. */
|
||||
void
|
||||
release_futexes(struct lwp *l)
|
||||
{
|
||||
struct linux_robust_list_head head;
|
||||
struct linux_robust_list *entry, *next_entry = NULL, *pending;
|
||||
unsigned int limit = 2048, pi, next_pi, pip;
|
||||
struct linux_emuldata *led;
|
||||
unsigned long futex_offset;
|
||||
int rc;
|
||||
|
||||
led = l->l_emuldata;
|
||||
if (led->led_robust_head == NULL)
|
||||
return;
|
||||
|
||||
#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(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;
|
||||
futex_offset = head.futex_offset;
|
||||
} else
|
||||
#endif
|
||||
if (copyin(&head.futex_offset, &futex_offset, sizeof(unsigned long)))
|
||||
return;
|
||||
|
||||
if (fetch_robust_entry(l, &pending, &head.pending_list, &pip))
|
||||
return;
|
||||
|
||||
while (entry != &head.list) {
|
||||
rc = fetch_robust_entry(l, &next_entry, &entry->next, &next_pi);
|
||||
|
||||
if (entry != pending)
|
||||
if (handle_futex_death((char *)entry + futex_offset,
|
||||
l->l_lid, pi))
|
||||
return;
|
||||
|
||||
if (rc)
|
||||
return;
|
||||
|
||||
entry = next_entry;
|
||||
pi = next_pi;
|
||||
|
||||
if (!--limit)
|
||||
break;
|
||||
|
||||
preempt_point();
|
||||
}
|
||||
|
||||
if (pending)
|
||||
handle_futex_death((char *)pending + futex_offset,
|
||||
l->l_lid, pip);
|
||||
return do_futex(SCARG(uap, uaddr), SCARG(uap, op), SCARG(uap, val),
|
||||
tsp, SCARG(uap, uaddr2), val2, SCARG(uap, val3), retval);
|
||||
}
|
||||
|
@ -1,93 +0,0 @@
|
||||
/* $NetBSD: linux_futex.h,v 1.8 2017/04/10 15:04:32 dholland Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Emmanuel Dreyfus
|
||||
* 4. The name of the author may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FUTEX_H
|
||||
#define _LINUX_FUTEX_H
|
||||
|
||||
#define LINUX_FUTEX_WAIT 0
|
||||
#define LINUX_FUTEX_WAKE 1
|
||||
#define LINUX_FUTEX_FD 2
|
||||
#define LINUX_FUTEX_REQUEUE 3
|
||||
#define LINUX_FUTEX_CMP_REQUEUE 4
|
||||
#define LINUX_FUTEX_WAKE_OP 5
|
||||
#define LINUX_FUTEX_LOCK_PI 6
|
||||
#define LINUX_FUTEX_UNLOCK_PI 7
|
||||
#define LINUX_FUTEX_TRYLOCK_PI 8
|
||||
#define LINUX_FUTEX_WAIT_BITSET 9
|
||||
#define LINUX_FUTEX_WAKE_BITSET 10
|
||||
#define LINUX_FUTEX_WAIT_REQUEUE_PI 11
|
||||
#define LINUX_FUTEX_CMP_REQUEUE_PI 12
|
||||
|
||||
#define LINUX_FUTEX_PRIVATE_FLAG 128
|
||||
#define LINUX_FUTEX_CLOCK_REALTIME 256
|
||||
#define LINUX_FUTEX_CMD_MASK \
|
||||
(~(LINUX_FUTEX_PRIVATE_FLAG|LINUX_FUTEX_CLOCK_REALTIME))
|
||||
|
||||
#define FUTEX_OP_SET 0
|
||||
#define FUTEX_OP_ADD 1
|
||||
#define FUTEX_OP_OR 2
|
||||
#define FUTEX_OP_ANDN 3
|
||||
#define FUTEX_OP_XOR 4
|
||||
#define FUTEX_OP_OPARG_SHIFT 8
|
||||
|
||||
#define FUTEX_OP_CMP_EQ 0
|
||||
#define FUTEX_OP_CMP_NE 1
|
||||
#define FUTEX_OP_CMP_LT 2
|
||||
#define FUTEX_OP_CMP_LE 3
|
||||
#define FUTEX_OP_CMP_GT 4
|
||||
#define FUTEX_OP_CMP_GE 5
|
||||
|
||||
struct linux_robust_list {
|
||||
struct linux_robust_list *next;
|
||||
};
|
||||
|
||||
struct linux_robust_list_head {
|
||||
struct linux_robust_list list;
|
||||
unsigned long futex_offset;
|
||||
struct linux_robust_list *pending_list;
|
||||
};
|
||||
|
||||
#define FUTEX_WAITERS 0x80000000
|
||||
#define FUTEX_OWNER_DIED 0x40000000
|
||||
#define FUTEX_TID_MASK 0x3fffffff
|
||||
|
||||
#define FUTEX_BITSET_MATCH_ANY 0xffffffff
|
||||
|
||||
void release_futexes(struct lwp *);
|
||||
struct linux_sys_futex_args;
|
||||
int linux_do_futex(struct lwp *, const struct linux_sys_futex_args *,
|
||||
struct timespec *, register_t *);
|
||||
void linux_futex_init(void);
|
||||
void linux_futex_fini(void);
|
||||
|
||||
#endif /* !_LINUX_FUTEX_H */
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: linux_mod.c,v 1.13 2020/03/21 16:28:56 pgoyette Exp $ */
|
||||
/* $NetBSD: linux_mod.c,v 1.14 2020/04/26 18:53:33 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008 The NetBSD Foundation, Inc.
|
||||
@ -30,7 +30,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: linux_mod.c,v 1.13 2020/03/21 16:28:56 pgoyette Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: linux_mod.c,v 1.14 2020/04/26 18:53:33 thorpej Exp $");
|
||||
|
||||
#ifdef _KERNEL_OPT
|
||||
#include "opt_execfmt.h"
|
||||
@ -47,7 +47,6 @@ __KERNEL_RCSID(0, "$NetBSD: linux_mod.c,v 1.13 2020/03/21 16:28:56 pgoyette Exp
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <compat/linux/common/linux_sysctl.h>
|
||||
#include <compat/linux/common/linux_futex.h>
|
||||
#include <compat/linux/common/linux_exec.h>
|
||||
|
||||
#if defined(EXEC_ELF32) && ELFSIZE == 32
|
||||
@ -163,7 +162,6 @@ compat_linux_modcmd(modcmd_t cmd, void *arg)
|
||||
|
||||
switch (cmd) {
|
||||
case MODULE_CMD_INIT:
|
||||
linux_futex_init();
|
||||
error = exec_add(linux_execsw, __arraycount(linux_execsw));
|
||||
return error;
|
||||
|
||||
@ -172,7 +170,6 @@ compat_linux_modcmd(modcmd_t cmd, void *arg)
|
||||
if (error)
|
||||
return error;
|
||||
linux_sysctl_fini();
|
||||
linux_futex_fini();
|
||||
return 0;
|
||||
|
||||
default:
|
||||
|
@ -1,4 +1,4 @@
|
||||
$NetBSD: syscalls.master,v 1.70 2019/11/09 23:44:31 jdolecek Exp $
|
||||
$NetBSD: syscalls.master,v 1.71 2020/04/26 18:53:33 thorpej Exp $
|
||||
|
||||
; NetBSD i386 COMPAT_LINUX32 system call name/number "master" file.
|
||||
; (See syscalls.conf to see what it is processed into.)
|
||||
@ -527,10 +527,15 @@
|
||||
309 STD { int|linux32_sys||ppoll(netbsd32_pollfdp_t fds, u_int nfds, \
|
||||
linux32_timespecp_t timeout, linux32_sigsetp_t sigset); }
|
||||
310 UNIMPL unshare
|
||||
311 STD { int|linux32_sys||set_robust_list( \
|
||||
linux32_robust_list_headp_t head, linux32_size_t len); }
|
||||
312 STD { int|linux32_sys||get_robust_list(linux32_pid_t pid, \
|
||||
linux32_robust_list_headpp_t head, linux32_sizep_t len); }
|
||||
;
|
||||
; The netbsd32 native robust list calls have different
|
||||
; argument names / types, but they are ABI-compatible
|
||||
; with linux32.
|
||||
;
|
||||
311 NOARGS { int|netbsd32||__futex_set_robust_list( \
|
||||
netbsd32_voidp head, netbsd32_size_t len); }
|
||||
312 NOARGS { int|netbsd32||__futex_get_robust_list(lwpid_t lwpid, \
|
||||
netbsd32_voidp headp, netbsd32_size_tp lenp); }
|
||||
313 UNIMPL splice
|
||||
314 UNIMPL sync_file_range
|
||||
315 UNIMPL tee
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: linux32_misc.c,v 1.27 2019/08/23 13:49:12 maxv Exp $ */
|
||||
/* $NetBSD: linux32_misc.c,v 1.28 2020/04/26 18:53:33 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1995, 1998, 1999 The NetBSD Foundation, Inc.
|
||||
@ -32,7 +32,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: linux32_misc.c,v 1.27 2019/08/23 13:49:12 maxv Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: linux32_misc.c,v 1.28 2020/04/26 18:53:33 thorpej Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/proc.h>
|
||||
@ -43,6 +43,7 @@ __KERNEL_RCSID(0, "$NetBSD: linux32_misc.c,v 1.27 2019/08/23 13:49:12 maxv Exp $
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/futex.h>
|
||||
|
||||
#include <compat/netbsd32/netbsd32.h>
|
||||
#include <compat/netbsd32/netbsd32_syscallargs.h>
|
||||
@ -61,7 +62,6 @@ __KERNEL_RCSID(0, "$NetBSD: linux32_misc.c,v 1.27 2019/08/23 13:49:12 maxv Exp $
|
||||
#include <compat/linux/common/linux_statfs.h>
|
||||
#include <compat/linux/common/linux_ipc.h>
|
||||
#include <compat/linux/common/linux_sem.h>
|
||||
#include <compat/linux/common/linux_futex.h>
|
||||
#include <compat/linux/linux_syscallargs.h>
|
||||
|
||||
extern const struct linux_mnttypes linux_fstypes[];
|
||||
@ -243,66 +243,30 @@ linux32_sys_futex(struct lwp *l,
|
||||
syscallarg(linux32_intp_t) uaddr2;
|
||||
syscallarg(int) val3;
|
||||
} */
|
||||
struct linux_sys_futex_args ua;
|
||||
struct linux32_timespec lts;
|
||||
struct timespec ts = { 0, 0 };
|
||||
struct timespec ts, *tsp = NULL;
|
||||
int val2 = 0;
|
||||
int error;
|
||||
|
||||
NETBSD32TOP_UAP(uaddr, int);
|
||||
NETBSD32TO64_UAP(op);
|
||||
NETBSD32TO64_UAP(val);
|
||||
NETBSD32TOP_UAP(timeout, struct linux_timespec);
|
||||
NETBSD32TOP_UAP(uaddr2, int);
|
||||
NETBSD32TO64_UAP(val3);
|
||||
if ((SCARG(uap, op) & ~LINUX_FUTEX_PRIVATE_FLAG) == LINUX_FUTEX_WAIT &&
|
||||
/*
|
||||
* Linux overlays the "timeout" field and the "val2" field.
|
||||
* "timeout" is only valid for FUTEX_WAIT on Linux.
|
||||
*/
|
||||
if ((SCARG(uap, op) & FUTEX_CMD_MASK) == FUTEX_WAIT &&
|
||||
SCARG_P32(uap, timeout) != NULL) {
|
||||
if ((error = copyin((void *)SCARG_P32(uap, timeout),
|
||||
if ((error = copyin(SCARG_P32(uap, timeout),
|
||||
<s, sizeof(lts))) != 0) {
|
||||
return error;
|
||||
}
|
||||
linux32_to_native_timespec(&ts, <s);
|
||||
tsp = &ts;
|
||||
} else {
|
||||
val2 = (int)(uintptr_t)SCARG_P32(uap, timeout);
|
||||
}
|
||||
return linux_do_futex(l, &ua, &ts, retval);
|
||||
}
|
||||
|
||||
int
|
||||
linux32_sys_set_robust_list(struct lwp *l,
|
||||
const struct linux32_sys_set_robust_list_args *uap, register_t *retval)
|
||||
{
|
||||
/* {
|
||||
syscallarg(linux32_robust_list_headp_t) head;
|
||||
syscallarg(linux32_size_t) len;
|
||||
} */
|
||||
struct linux_sys_set_robust_list_args ua;
|
||||
struct linux_emuldata *led;
|
||||
|
||||
if (SCARG(uap, len) != 12)
|
||||
return EINVAL;
|
||||
|
||||
NETBSD32TOP_UAP(head, struct robust_list_head);
|
||||
NETBSD32TOX64_UAP(len, size_t);
|
||||
|
||||
led = l->l_emuldata;
|
||||
led->led_robust_head = SCARG(&ua, head);
|
||||
*retval = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
linux32_sys_get_robust_list(struct lwp *l,
|
||||
const struct linux32_sys_get_robust_list_args *uap, register_t *retval)
|
||||
{
|
||||
/* {
|
||||
syscallarg(linux32_pid_t) pid;
|
||||
syscallarg(linux32_robust_list_headpp_t) head;
|
||||
syscallarg(linux32_sizep_t) len;
|
||||
} */
|
||||
struct linux_sys_get_robust_list_args ua;
|
||||
|
||||
NETBSD32TOX_UAP(pid, int);
|
||||
NETBSD32TOP_UAP(head, struct robust_list_head *);
|
||||
NETBSD32TOP_UAP(len, size_t *);
|
||||
return linux_sys_get_robust_list(l, &ua, retval);
|
||||
return do_futex(SCARG_P32(uap, uaddr), SCARG(uap, op),
|
||||
SCARG(uap, val), tsp, SCARG_P32(uap, uaddr2), val2,
|
||||
SCARG(uap, val3), retval);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: files.netbsd32,v 1.50 2020/03/12 15:02:29 pgoyette Exp $
|
||||
# $NetBSD: files.netbsd32,v 1.51 2020/04/26 18:53:33 thorpej Exp $
|
||||
#
|
||||
# config file description for machine-independent netbsd32 compat code.
|
||||
# included by ports that need it.
|
||||
@ -19,6 +19,7 @@ file compat/netbsd32/netbsd32_event.c compat_netbsd32
|
||||
file compat/netbsd32/netbsd32_execve.c compat_netbsd32
|
||||
file compat/netbsd32/netbsd32_fd.c compat_netbsd32
|
||||
file compat/netbsd32/netbsd32_fs.c compat_netbsd32
|
||||
file compat/netbsd32/netbsd32_futex.c compat_netbsd32
|
||||
file compat/netbsd32/netbsd32_kern_proc.c compat_netbsd32
|
||||
file compat/netbsd32/netbsd32_ioctl.c compat_netbsd32
|
||||
file compat/netbsd32/netbsd32_ipc.c compat_netbsd32
|
||||
|
134
sys/compat/netbsd32/netbsd32_futex.c
Normal file
134
sys/compat/netbsd32/netbsd32_futex.c
Normal file
@ -0,0 +1,134 @@
|
||||
/* $NetBSD: netbsd32_futex.c,v 1.1 2020/04/26 18:53:33 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2019 The NetBSD Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Taylor R. Campbell and Jason R. Thorpe.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: netbsd32_futex.c,v 1.1 2020/04/26 18:53:33 thorpej Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/lwp.h>
|
||||
#include <sys/syscallargs.h>
|
||||
#include <sys/futex.h>
|
||||
|
||||
#include <compat/netbsd32/netbsd32.h>
|
||||
#include <compat/netbsd32/netbsd32_syscallargs.h>
|
||||
#include <compat/netbsd32/netbsd32_conv.h>
|
||||
|
||||
/* Sycalls conversion */
|
||||
|
||||
int
|
||||
netbsd32___futex(struct lwp *l, const struct netbsd32___futex_args *uap,
|
||||
register_t *retval)
|
||||
{
|
||||
/* {
|
||||
syscallarg(netbsd32_intp) uaddr;
|
||||
syscallarg(int) op;
|
||||
syscallarg(int) val;
|
||||
syscallarg(netbsd32_timespecp_t) timeout;
|
||||
syscallarg(netbsd32_intp) uaddr2;
|
||||
syscallarg(int) val2;
|
||||
syscallarg(int) val3;
|
||||
} */
|
||||
struct netbsd32_timespec ts32;
|
||||
struct timespec ts, *tsp;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Copy in the timeout argument, if specified.
|
||||
*/
|
||||
if (SCARG_P32(uap, timeout)) {
|
||||
error = copyin(SCARG_P32(uap, timeout), &ts32, sizeof(ts32));
|
||||
if (error)
|
||||
return error;
|
||||
netbsd32_to_timespec(&ts32, &ts);
|
||||
tsp = &ts;
|
||||
} else {
|
||||
tsp = NULL;
|
||||
}
|
||||
|
||||
return do_futex(SCARG_P32(uap, uaddr), SCARG(uap, op),
|
||||
SCARG(uap, val), tsp, SCARG_P32(uap, uaddr2), SCARG(uap, val2),
|
||||
SCARG(uap, val3), retval);
|
||||
}
|
||||
|
||||
int
|
||||
netbsd32___futex_set_robust_list(struct lwp *l,
|
||||
const struct netbsd32___futex_set_robust_list_args *uap, register_t *retval)
|
||||
{
|
||||
/* {
|
||||
syscallarg(netbsd32_voidp) head;
|
||||
syscallarg(netbsd32_size_t) len;
|
||||
} */
|
||||
void *head = SCARG_P32(uap, head);
|
||||
|
||||
if (SCARG(uap, len) != _FUTEX_ROBUST_HEAD_SIZE32)
|
||||
return EINVAL;
|
||||
if ((uintptr_t)head % sizeof(uint32_t))
|
||||
return EINVAL;
|
||||
|
||||
l->l_robust_head = (uintptr_t)head;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
netbsd32___futex_get_robust_list(struct lwp *l,
|
||||
const struct netbsd32___futex_get_robust_list_args *uap, register_t *retval)
|
||||
{
|
||||
/* {
|
||||
syscallarg(lwpid_t) lwpid;
|
||||
syscallarg(netbsd32_voidp) headp;
|
||||
syscallarg(netbsd32_size_tp) lenp;
|
||||
} */
|
||||
void *head;
|
||||
const netbsd32_size_t len = _FUTEX_ROBUST_HEAD_SIZE32;
|
||||
netbsd32_voidp head32;
|
||||
int error;
|
||||
|
||||
error = futex_robust_head_lookup(l, SCARG(uap, lwpid), &head);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
head32.i32 = (uintptr_t)head;
|
||||
if (NETBSD32PTR64(head32) != head)
|
||||
return EFAULT;
|
||||
|
||||
/* Copy out the head pointer and the head structure length. */
|
||||
/* (N.B.: "headp" is actually a "void **". */
|
||||
error = copyout(&head32, SCARG_P32(uap, headp), sizeof(head32));
|
||||
if (__predict_true(error == 0)) {
|
||||
error = copyout(&len, SCARG_P32(uap, lenp), sizeof(len));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
$NetBSD: syscalls.master,v 1.135 2020/04/22 21:22:21 thorpej Exp $
|
||||
$NetBSD: syscalls.master,v 1.136 2020/04/26 18:53:33 thorpej Exp $
|
||||
|
||||
; from: NetBSD: syscalls.master,v 1.81 1998/07/05 08:49:50 jonathan Exp
|
||||
; @(#)syscalls.master 8.2 (Berkeley) 1/13/94
|
||||
@ -1168,3 +1168,10 @@
|
||||
486 STD { int|netbsd32|90|fhstatvfs1(netbsd32_voidp fhp, \
|
||||
netbsd32_size_t fh_size, netbsd32_statvfsp_t buf, \
|
||||
int flags); }
|
||||
487 STD { int|netbsd32||__futex(netbsd32_intp uaddr, int op, \
|
||||
int val, const netbsd32_timespecp_t timeout, \
|
||||
netbsd32_intp uaddr2, int val2, int val3); }
|
||||
488 STD { int|netbsd32||__futex_set_robust_list( \
|
||||
netbsd32_voidp head, netbsd32_size_t len); }
|
||||
489 STD { int|netbsd32||__futex_get_robust_list(lwpid_t lwpid, \
|
||||
netbsd32_voidp headp, netbsd32_size_tp lenp); }
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: files.kern,v 1.45 2020/04/22 09:18:42 rin Exp $
|
||||
# $NetBSD: files.kern,v 1.46 2020/04/26 18:53:33 thorpej Exp $
|
||||
|
||||
#
|
||||
# kernel sources
|
||||
@ -154,6 +154,7 @@ file kern/subr_workqueue.c kern
|
||||
file kern/subr_xcall.c kern
|
||||
file kern/sys_aio.c aio
|
||||
file kern/sys_descrip.c kern
|
||||
file kern/sys_futex.c kern
|
||||
file kern/sys_generic.c kern
|
||||
file kern/sys_module.c kern
|
||||
file kern/sys_mqueue.c mqueue
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: init_main.c,v 1.522 2020/02/24 20:47:47 jdolecek Exp $ */
|
||||
/* $NetBSD: init_main.c,v 1.523 2020/04/26 18:53:33 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008, 2009, 2019 The NetBSD Foundation, Inc.
|
||||
@ -97,7 +97,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.522 2020/02/24 20:47:47 jdolecek Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.523 2020/04/26 18:53:33 thorpej Exp $");
|
||||
|
||||
#include "opt_ddb.h"
|
||||
#include "opt_inet.h"
|
||||
@ -180,6 +180,7 @@ extern void *_binary_splash_image_end;
|
||||
#include <sys/kprintf.h>
|
||||
#include <sys/bufq.h>
|
||||
#include <sys/threadpool.h>
|
||||
#include <sys/futex.h>
|
||||
#ifdef IPSEC
|
||||
#include <netipsec/ipsec.h>
|
||||
#endif
|
||||
@ -550,6 +551,8 @@ main(void)
|
||||
|
||||
ipi_sysinit();
|
||||
|
||||
futex_sys_init();
|
||||
|
||||
/* Now timer is working. Enable preemption. */
|
||||
kpreempt_enable();
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: kern_lwp.c,v 1.235 2020/04/24 03:22:06 thorpej Exp $ */
|
||||
/* $NetBSD: kern_lwp.c,v 1.236 2020/04/26 18:53:33 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001, 2006, 2007, 2008, 2009, 2019, 2020
|
||||
@ -223,7 +223,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.235 2020/04/24 03:22:06 thorpej Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.236 2020/04/26 18:53:33 thorpej Exp $");
|
||||
|
||||
#include "opt_ddb.h"
|
||||
#include "opt_lockdebug.h"
|
||||
@ -258,6 +258,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.235 2020/04/24 03:22:06 thorpej Exp $
|
||||
#include <sys/msan.h>
|
||||
#include <sys/kcov.h>
|
||||
#include <sys/cprng.h>
|
||||
#include <sys/futex.h>
|
||||
|
||||
#include <uvm/uvm_extern.h>
|
||||
#include <uvm/uvm_object.h>
|
||||
@ -2093,6 +2094,7 @@ lwp_thread_cleanup(struct lwp *l)
|
||||
KASSERT(l == curlwp);
|
||||
const lwpid_t tid = l->l_lid;
|
||||
|
||||
KASSERT((tid & FUTEX_TID_MASK) == tid);
|
||||
KASSERT(mutex_owned(l->l_proc->p_lock));
|
||||
|
||||
/*
|
||||
@ -2103,6 +2105,14 @@ lwp_thread_cleanup(struct lwp *l)
|
||||
proc_hide_lwpid(tid);
|
||||
|
||||
mutex_exit(l->l_proc->p_lock);
|
||||
|
||||
/*
|
||||
* If the LWP has robust futexes, release them all
|
||||
* now.
|
||||
*/
|
||||
if (__predict_false(l->l_robust_head != 0)) {
|
||||
futex_release_all_lwp(l, tid);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DDB)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: kern_proc.c,v 1.249 2020/04/26 15:49:10 thorpej Exp $ */
|
||||
/* $NetBSD: kern_proc.c,v 1.250 2020/04/26 18:53:33 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2006, 2007, 2008, 2020 The NetBSD Foundation, Inc.
|
||||
@ -62,7 +62,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_proc.c,v 1.249 2020/04/26 15:49:10 thorpej Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_proc.c,v 1.250 2020/04/26 18:53:33 thorpej Exp $");
|
||||
|
||||
#ifdef _KERNEL_OPT
|
||||
#include "opt_kstack.h"
|
||||
@ -106,6 +106,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_proc.c,v 1.249 2020/04/26 15:49:10 thorpej Exp
|
||||
#include <sys/exec.h>
|
||||
#include <sys/cpu.h>
|
||||
#include <sys/compat_stub.h>
|
||||
#include <sys/futex.h>
|
||||
|
||||
#include <uvm/uvm_extern.h>
|
||||
#include <uvm/uvm.h>
|
||||
@ -889,6 +890,9 @@ expand_pid_table(void)
|
||||
new_pt = kmem_alloc(tsz, KM_SLEEP);
|
||||
new_pt_mask = pt_size * 2 - 1;
|
||||
|
||||
/* XXX For now. The pratical limit is much lower anyway. */
|
||||
KASSERT(new_pt_mask <= FUTEX_TID_MASK);
|
||||
|
||||
rw_enter(&pid_table_lock, RW_WRITER);
|
||||
if (pt_size != pid_tbl_mask + 1) {
|
||||
/* Another process beat us to it... */
|
||||
@ -1039,6 +1043,9 @@ proc_alloc_pid_slot(struct proc *p, uintptr_t slot)
|
||||
pid &= pid_tbl_mask;
|
||||
next_free_pt = nxt & pid_tbl_mask;
|
||||
|
||||
/* XXX For now. The pratical limit is much lower anyway. */
|
||||
KASSERT(pid <= FUTEX_TID_MASK);
|
||||
|
||||
/* Grab table slot */
|
||||
pt->pt_slot = slot;
|
||||
|
||||
|
1977
sys/kern/sys_futex.c
Normal file
1977
sys/kern/sys_futex.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
$NetBSD: syscalls.master,v 1.302 2020/04/22 21:22:21 thorpej Exp $
|
||||
$NetBSD: syscalls.master,v 1.303 2020/04/26 18:53:33 thorpej Exp $
|
||||
|
||||
; @(#)syscalls.master 8.2 (Berkeley) 1/13/94
|
||||
|
||||
@ -1015,3 +1015,10 @@
|
||||
struct statvfs *buf, int flags); }
|
||||
486 STD RUMP { int|sys|90|fhstatvfs1(const void *fhp, \
|
||||
size_t fh_size, struct statvfs *buf, int flags); }
|
||||
487 STD { int|sys||__futex(int *uaddr, int op, int val, \
|
||||
const struct timespec *timeout, \
|
||||
int *uaddr2, int val2, int val3); }
|
||||
488 STD { int|sys||__futex_set_robust_list(void *head, \
|
||||
size_t len); }
|
||||
489 STD { int|sys||__futex_get_robust_list(lwpid_t lwpid, \
|
||||
void **headp, size_t *lenp); }
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: Makefile,v 1.172 2020/03/22 14:27:33 ad Exp $
|
||||
# $NetBSD: Makefile,v 1.173 2020/04/26 18:53:33 thorpej Exp $
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
@ -21,7 +21,7 @@ INCS= acct.h agpio.h aio.h ansi.h aout_mids.h ataio.h atomic.h \
|
||||
endian.h envsys.h errno.h evcnt.h event.h exec.h exec_aout.h \
|
||||
exec_coff.h exec_ecoff.h exec_elf.h exec_script.h extattr.h extent.h \
|
||||
fcntl.h fd_set.h fdio.h featuretest.h file.h filedesc.h filio.h \
|
||||
flashio.h float_ieee754.h fstypes.h gcq.h gmon.h gpio.h hash.h \
|
||||
flashio.h float_ieee754.h fstypes.h futex.h gcq.h gmon.h gpio.h hash.h \
|
||||
idtype.h ieee754.h intr.h intrio.h inttypes.h ioccom.h ioctl.h \
|
||||
ioctl_compat.h iostat.h ipc.h ipmi.h \
|
||||
joystick.h \
|
||||
|
186
sys/sys/futex.h
Normal file
186
sys/sys/futex.h
Normal file
@ -0,0 +1,186 @@
|
||||
/* $NetBSD: futex.h,v 1.1 2020/04/26 18:53:33 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2018, 2019 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Taylor R. Campbell and Jason R. Thorpe.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Emmanuel Dreyfus
|
||||
* 4. The name of the author may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_FUTEX_H_
|
||||
#define _SYS_FUTEX_H_
|
||||
|
||||
/*
|
||||
* Definitions for the __futex(2) synchronization primitive.
|
||||
*
|
||||
* These definitions are intended to be ABI-compatible with the
|
||||
* Linux futex(2) system call.
|
||||
*/
|
||||
|
||||
#include <sys/timespec.h>
|
||||
|
||||
#define FUTEX_WAIT 0
|
||||
#define FUTEX_WAKE 1
|
||||
#define FUTEX_FD 2
|
||||
#define FUTEX_REQUEUE 3
|
||||
#define FUTEX_CMP_REQUEUE 4
|
||||
#define FUTEX_WAKE_OP 5
|
||||
#define FUTEX_LOCK_PI 6
|
||||
#define FUTEX_UNLOCK_PI 7
|
||||
#define FUTEX_TRYLOCK_PI 8
|
||||
#define FUTEX_WAIT_BITSET 9
|
||||
#define FUTEX_WAKE_BITSET 10
|
||||
#define FUTEX_WAIT_REQUEUE_PI 11
|
||||
#define FUTEX_CMP_REQUEUE_PI 12
|
||||
|
||||
#define FUTEX_PRIVATE_FLAG __BIT(7)
|
||||
#define FUTEX_CLOCK_REALTIME __BIT(8)
|
||||
|
||||
#define FUTEX_CMD_MASK \
|
||||
(~(FUTEX_PRIVATE_FLAG|FUTEX_CLOCK_REALTIME))
|
||||
|
||||
#define FUTEX_OP_OP_MASK __BITS(28,31)
|
||||
#define FUTEX_OP_CMP_MASK __BITS(24,27)
|
||||
#define FUTEX_OP_OPARG_MASK __BITS(12,23)
|
||||
#define FUTEX_OP_CMPARG_MASK __BITS(0,11)
|
||||
|
||||
#define FUTEX_OP(op, oparg, cmp, cmparg) \
|
||||
(__SHIFTIN(op, FUTEX_OP_OP_MASK) |\
|
||||
__SHIFTIN(oparg, FUTEX_OP_OPARG_MASK) |\
|
||||
__SHIFTIN(cmp, FUTEX_OP_CMP_MASK) |\
|
||||
__SHIFTIN(cmparg, FUTEX_OP_CMPARG_MASK))
|
||||
|
||||
#define FUTEX_OP_SET 0
|
||||
#define FUTEX_OP_ADD 1
|
||||
#define FUTEX_OP_OR 2
|
||||
#define FUTEX_OP_ANDN 3
|
||||
#define FUTEX_OP_XOR 4
|
||||
#define FUTEX_OP_OPARG_SHIFT 8
|
||||
|
||||
#define FUTEX_OP_CMP_EQ 0
|
||||
#define FUTEX_OP_CMP_NE 1
|
||||
#define FUTEX_OP_CMP_LT 2
|
||||
#define FUTEX_OP_CMP_LE 3
|
||||
#define FUTEX_OP_CMP_GT 4
|
||||
#define FUTEX_OP_CMP_GE 5
|
||||
|
||||
/*
|
||||
* FUTEX_SYNCOBJ_0 and FUTEX_SYNCOBJ_1 are extensions to the Linux
|
||||
* futex API that are reserved for individual consumers of futexes
|
||||
* to define information specific to that synchronzation object.
|
||||
* Note that as a result there is a system-wide upper limit of
|
||||
* 268,435,455 threads (as opposed to 1,073,741,823).
|
||||
*/
|
||||
#define FUTEX_WAITERS ((int)__BIT(31))
|
||||
#define FUTEX_OWNER_DIED ((int)__BIT(30))
|
||||
#define FUTEX_SYNCOBJ_1 ((int)__BIT(29))
|
||||
#define FUTEX_SYNCOBJ_0 ((int)__BIT(28))
|
||||
#define FUTEX_TID_MASK ((int)__BITS(0,27))
|
||||
|
||||
#define FUTEX_BITSET_MATCH_ANY ((int)__BITS(0,31))
|
||||
|
||||
/*
|
||||
* The robust futex ABI consists of an array of 3 longwords, the address
|
||||
* of which is registered with the kernel on a per-thread basis:
|
||||
*
|
||||
* 0: A pointer to a singly-linked list of "lock entries". If the
|
||||
* list is empty, this points back to the list itself.
|
||||
*
|
||||
* 1: An offset from address of the "lock entry" to the 32-bit futex
|
||||
* word associated with that lock entry (may be negative).
|
||||
*
|
||||
* 2: A "pending" pointer, for locks that are in the process of being
|
||||
* acquired or released.
|
||||
*
|
||||
* PI futexes are handled slightly differently. User-space indicates
|
||||
* an entry is for a PI futex by setting the last-significant bit.
|
||||
*/
|
||||
#define _FUTEX_ROBUST_HEAD_LIST 0
|
||||
#define _FUTEX_ROBUST_HEAD_OFFSET 1
|
||||
#define _FUTEX_ROBUST_HEAD_PENDING 2
|
||||
#define _FUTEX_ROBUST_HEAD_NWORDS 3
|
||||
#define _FUTEX_ROBUST_HEAD_SIZE (_FUTEX_ROBUST_HEAD_NWORDS * \
|
||||
sizeof(u_long))
|
||||
#ifdef _LP64
|
||||
#define _FUTEX_ROBUST_HEAD_SIZE32 (_FUTEX_ROBUST_HEAD_NWORDS * \
|
||||
sizeof(uint32_t))
|
||||
#endif /* _LP64 */
|
||||
#define _FUTEX_ROBUST_ENTRY_PI __BIT(0)
|
||||
|
||||
#ifdef __LIBC_FUTEX_PRIVATE
|
||||
struct futex_robust_list {
|
||||
struct futex_robust_list *next;
|
||||
};
|
||||
|
||||
struct futex_robust_list_head {
|
||||
struct futex_robust_list list;
|
||||
long futex_offset;
|
||||
struct futex_robust_list *pending_list;
|
||||
};
|
||||
#endif /* __LIBC_FUTEX_PRIVATE */
|
||||
|
||||
#ifdef _KERNEL
|
||||
struct lwp;
|
||||
|
||||
int futex_robust_head_lookup(struct lwp *, lwpid_t, void **);
|
||||
void futex_release_all_lwp(struct lwp *, lwpid_t);
|
||||
int do_futex(int *, int, int, const struct timespec *, int *, int,
|
||||
int, register_t *);
|
||||
void futex_sys_init(void);
|
||||
void futex_sys_fini(void);
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* ! _SYS_FUTEX_H_ */
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: lwp.h,v 1.207 2020/04/24 03:22:06 thorpej Exp $ */
|
||||
/* $NetBSD: lwp.h,v 1.208 2020/04/26 18:53:33 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001, 2006, 2007, 2008, 2009, 2010, 2019, 2020
|
||||
@ -136,7 +136,7 @@ struct lwp {
|
||||
bool l_vforkwaiting; /* a: vfork() waiting */
|
||||
|
||||
/* User-space synchronization. */
|
||||
uintptr_t l___rsvd0; /* reserved for future use */
|
||||
uintptr_t l_robust_head; /* !: list of robust futexes */
|
||||
uint32_t l___rsvd1; /* reserved for future use */
|
||||
|
||||
#if PCU_UNIT_COUNT > 0
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: Makefile,v 1.62 2020/04/18 17:44:53 christos Exp $
|
||||
# $NetBSD: Makefile,v 1.63 2020/04/26 18:53:33 thorpej Exp $
|
||||
|
||||
MKMAN= no
|
||||
|
||||
@ -18,6 +18,8 @@ TESTS_C+= t_connect
|
||||
TESTS_C+= t_dup
|
||||
TESTS_C+= t_fork
|
||||
TESTS_C+= t_fsync
|
||||
TESTS_C+= t_futex_ops
|
||||
TESTS_C+= t_futex_robust
|
||||
TESTS_C+= t_getcontext
|
||||
TESTS_C+= t_getgroups
|
||||
TESTS_C+= t_getitimer
|
||||
@ -104,6 +106,9 @@ TESTS_C+= t_posix_fadvise
|
||||
LDADD.t_posix_fadvise+= ${LIBRUMPBASE}
|
||||
.endif
|
||||
|
||||
CPPFLAGS.t_futex_ops.c += -I${.CURDIR}/../../../../lib
|
||||
CPPFLAGS.t_futex_robust.c += -I${.CURDIR}/../../../../lib
|
||||
|
||||
CPPFLAGS.t_lwp_create.c += -D_KERNTYPES
|
||||
CPPFLAGS.t_ptrace_wait.c += -D_KERNTYPES -D__TEST_FENV
|
||||
CPPFLAGS.t_ptrace_wait3.c += -D_KERNTYPES -D__TEST_FENV
|
||||
|
1294
tests/lib/libc/sys/t_futex_ops.c
Normal file
1294
tests/lib/libc/sys/t_futex_ops.c
Normal file
File diff suppressed because it is too large
Load Diff
408
tests/lib/libc/sys/t_futex_robust.c
Normal file
408
tests/lib/libc/sys/t_futex_robust.c
Normal file
@ -0,0 +1,408 @@
|
||||
/* $NetBSD: t_futex_robust.c,v 1.1 2020/04/26 18:53:33 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2019 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__COPYRIGHT("@(#) Copyright (c) 2019\
|
||||
The NetBSD Foundation, inc. All rights reserved.");
|
||||
__RCSID("$NetBSD: t_futex_robust.c,v 1.1 2020/04/26 18:53:33 thorpej Exp $");
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include <lwp.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <atf-c.h>
|
||||
|
||||
#include <libc/include/futex_private.h>
|
||||
|
||||
#define STACK_SIZE 65536
|
||||
#define NLOCKS 16
|
||||
|
||||
struct futex_lock_pos {
|
||||
struct futex_robust_list list;
|
||||
int fword;
|
||||
};
|
||||
struct futex_lock_pos pos_locks[NLOCKS];
|
||||
|
||||
struct futex_lock_neg {
|
||||
int fword;
|
||||
struct futex_robust_list list;
|
||||
};
|
||||
struct futex_lock_neg neg_locks[NLOCKS];
|
||||
|
||||
struct lwp_data {
|
||||
ucontext_t context;
|
||||
void *stack_base;
|
||||
lwpid_t lwpid;
|
||||
lwpid_t threadid;
|
||||
struct futex_robust_list_head rhead;
|
||||
|
||||
/* Results to be asserted by main thread. */
|
||||
bool set_robust_list_failed;
|
||||
};
|
||||
|
||||
struct lwp_data lwp_data;
|
||||
|
||||
static void
|
||||
setup_lwp_context(void (*func)(void *))
|
||||
{
|
||||
|
||||
memset(&lwp_data, 0, sizeof(lwp_data));
|
||||
lwp_data.stack_base = mmap(NULL, STACK_SIZE,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_ANON | MAP_STACK | MAP_PRIVATE, -1, 0);
|
||||
ATF_REQUIRE(lwp_data.stack_base != MAP_FAILED);
|
||||
_lwp_makecontext(&lwp_data.context, func,
|
||||
&lwp_data, NULL, lwp_data.stack_base, STACK_SIZE);
|
||||
lwp_data.threadid = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
do_cleanup(void)
|
||||
{
|
||||
if (lwp_data.stack_base != NULL &&
|
||||
lwp_data.stack_base != MAP_FAILED) {
|
||||
(void) munmap(lwp_data.stack_base, STACK_SIZE);
|
||||
}
|
||||
memset(&lwp_data, 0, sizeof(lwp_data));
|
||||
memset(pos_locks, 0, sizeof(pos_locks));
|
||||
memset(neg_locks, 0, sizeof(neg_locks));
|
||||
}
|
||||
|
||||
static void
|
||||
test_pos_robust_list(void *arg)
|
||||
{
|
||||
struct lwp_data *d = arg;
|
||||
int i;
|
||||
|
||||
d->rhead.list.next = &d->rhead.list;
|
||||
d->rhead.futex_offset = offsetof(struct futex_lock_pos, fword) -
|
||||
offsetof(struct futex_lock_pos, list);
|
||||
d->rhead.pending_list = NULL;
|
||||
|
||||
if (__futex_set_robust_list(&d->rhead, sizeof(d->rhead)) != 0) {
|
||||
d->set_robust_list_failed = true;
|
||||
_lwp_exit();
|
||||
}
|
||||
|
||||
memset(pos_locks, 0, sizeof(pos_locks));
|
||||
|
||||
d->threadid = _lwp_self();
|
||||
|
||||
for (i = 0; i < NLOCKS-1; i++) {
|
||||
pos_locks[i].fword = _lwp_self();
|
||||
pos_locks[i].list.next = d->rhead.list.next;
|
||||
d->rhead.list.next = &pos_locks[i].list;
|
||||
}
|
||||
|
||||
pos_locks[i].fword = _lwp_self();
|
||||
d->rhead.pending_list = &pos_locks[i].list;
|
||||
|
||||
_lwp_exit();
|
||||
}
|
||||
|
||||
static void
|
||||
test_neg_robust_list(void *arg)
|
||||
{
|
||||
struct lwp_data *d = arg;
|
||||
int i;
|
||||
|
||||
d->rhead.list.next = &d->rhead.list;
|
||||
d->rhead.futex_offset = offsetof(struct futex_lock_neg, fword) -
|
||||
offsetof(struct futex_lock_neg, list);
|
||||
d->rhead.pending_list = NULL;
|
||||
|
||||
if (__futex_set_robust_list(&d->rhead, sizeof(d->rhead)) != 0) {
|
||||
d->set_robust_list_failed = true;
|
||||
_lwp_exit();
|
||||
}
|
||||
|
||||
memset(neg_locks, 0, sizeof(neg_locks));
|
||||
|
||||
d->threadid = _lwp_self();
|
||||
|
||||
for (i = 0; i < NLOCKS-1; i++) {
|
||||
neg_locks[i].fword = _lwp_self();
|
||||
neg_locks[i].list.next = d->rhead.list.next;
|
||||
d->rhead.list.next = &neg_locks[i].list;
|
||||
}
|
||||
|
||||
neg_locks[i].fword = _lwp_self();
|
||||
d->rhead.pending_list = &neg_locks[i].list;
|
||||
|
||||
_lwp_exit();
|
||||
}
|
||||
|
||||
static void
|
||||
test_unmapped_robust_list(void *arg)
|
||||
{
|
||||
struct lwp_data *d = arg;
|
||||
|
||||
d->rhead.list.next = &d->rhead.list;
|
||||
d->rhead.futex_offset = offsetof(struct futex_lock_pos, fword) -
|
||||
offsetof(struct futex_lock_pos, list);
|
||||
d->rhead.pending_list = NULL;
|
||||
|
||||
if (__futex_set_robust_list((void *)sizeof(d->rhead),
|
||||
sizeof(d->rhead)) != 0) {
|
||||
d->set_robust_list_failed = true;
|
||||
_lwp_exit();
|
||||
}
|
||||
|
||||
memset(pos_locks, 0, sizeof(pos_locks));
|
||||
|
||||
d->threadid = _lwp_self();
|
||||
|
||||
_lwp_exit();
|
||||
}
|
||||
|
||||
static void
|
||||
test_evil_circular_robust_list(void *arg)
|
||||
{
|
||||
struct lwp_data *d = arg;
|
||||
int i;
|
||||
|
||||
d->rhead.list.next = &d->rhead.list;
|
||||
d->rhead.futex_offset = offsetof(struct futex_lock_pos, fword) -
|
||||
offsetof(struct futex_lock_pos, list);
|
||||
d->rhead.pending_list = NULL;
|
||||
|
||||
if (__futex_set_robust_list(&d->rhead, sizeof(d->rhead)) != 0) {
|
||||
d->set_robust_list_failed = true;
|
||||
_lwp_exit();
|
||||
}
|
||||
|
||||
memset(pos_locks, 0, sizeof(pos_locks));
|
||||
|
||||
d->threadid = _lwp_self();
|
||||
|
||||
for (i = 0; i < NLOCKS; i++) {
|
||||
pos_locks[i].fword = _lwp_self();
|
||||
pos_locks[i].list.next = d->rhead.list.next;
|
||||
d->rhead.list.next = &pos_locks[i].list;
|
||||
}
|
||||
|
||||
/* Make a loop. */
|
||||
pos_locks[0].list.next = pos_locks[NLOCKS-1].list.next;
|
||||
|
||||
_lwp_exit();
|
||||
}
|
||||
|
||||
static void
|
||||
test_bad_pending_robust_list(void *arg)
|
||||
{
|
||||
struct lwp_data *d = arg;
|
||||
int i;
|
||||
|
||||
d->rhead.list.next = &d->rhead.list;
|
||||
d->rhead.futex_offset = offsetof(struct futex_lock_pos, fword) -
|
||||
offsetof(struct futex_lock_pos, list);
|
||||
d->rhead.pending_list = NULL;
|
||||
|
||||
if (__futex_set_robust_list(&d->rhead, sizeof(d->rhead)) != 0) {
|
||||
d->set_robust_list_failed = true;
|
||||
_lwp_exit();
|
||||
}
|
||||
|
||||
memset(pos_locks, 0, sizeof(pos_locks));
|
||||
|
||||
d->threadid = _lwp_self();
|
||||
|
||||
for (i = 0; i < NLOCKS; i++) {
|
||||
pos_locks[i].fword = _lwp_self();
|
||||
pos_locks[i].list.next = d->rhead.list.next;
|
||||
d->rhead.list.next = &pos_locks[i].list;
|
||||
}
|
||||
|
||||
d->rhead.pending_list = (void *)sizeof(d->rhead);
|
||||
|
||||
_lwp_exit();
|
||||
}
|
||||
|
||||
ATF_TC_WITH_CLEANUP(futex_robust_positive);
|
||||
ATF_TC_HEAD(futex_robust_positive, tc)
|
||||
{
|
||||
atf_tc_set_md_var(tc, "descr",
|
||||
"checks futex robust list with positive futex word offset");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(futex_robust_positive, tc)
|
||||
{
|
||||
int i;
|
||||
|
||||
setup_lwp_context(test_pos_robust_list);
|
||||
|
||||
ATF_REQUIRE(_lwp_create(&lwp_data.context, 0, &lwp_data.lwpid) == 0);
|
||||
ATF_REQUIRE(_lwp_wait(lwp_data.lwpid, NULL) == 0);
|
||||
|
||||
ATF_REQUIRE(lwp_data.set_robust_list_failed == false);
|
||||
|
||||
for (i = 0; i < NLOCKS; i++) {
|
||||
ATF_REQUIRE((pos_locks[i].fword & FUTEX_TID_MASK) ==
|
||||
lwp_data.threadid);
|
||||
ATF_REQUIRE((pos_locks[i].fword & FUTEX_OWNER_DIED) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TC_CLEANUP(futex_robust_positive, tc)
|
||||
{
|
||||
do_cleanup();
|
||||
}
|
||||
|
||||
ATF_TC_WITH_CLEANUP(futex_robust_negative);
|
||||
ATF_TC_HEAD(futex_robust_negative, tc)
|
||||
{
|
||||
atf_tc_set_md_var(tc, "descr",
|
||||
"checks futex robust list with negative futex word offset");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(futex_robust_negative, tc)
|
||||
{
|
||||
int i;
|
||||
|
||||
setup_lwp_context(test_neg_robust_list);
|
||||
|
||||
ATF_REQUIRE(_lwp_create(&lwp_data.context, 0, &lwp_data.lwpid) == 0);
|
||||
ATF_REQUIRE(_lwp_wait(lwp_data.lwpid, NULL) == 0);
|
||||
|
||||
ATF_REQUIRE(lwp_data.set_robust_list_failed == false);
|
||||
|
||||
for (i = 0; i < NLOCKS; i++) {
|
||||
ATF_REQUIRE((neg_locks[i].fword & FUTEX_TID_MASK) ==
|
||||
lwp_data.threadid);
|
||||
ATF_REQUIRE((neg_locks[i].fword & FUTEX_OWNER_DIED) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TC_CLEANUP(futex_robust_negative, tc)
|
||||
{
|
||||
do_cleanup();
|
||||
}
|
||||
|
||||
ATF_TC_WITH_CLEANUP(futex_robust_unmapped);
|
||||
ATF_TC_HEAD(futex_robust_unmapped, tc)
|
||||
{
|
||||
atf_tc_set_md_var(tc, "descr",
|
||||
"checks futex robust list with unmapped robust list pointer");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(futex_robust_unmapped, tc)
|
||||
{
|
||||
|
||||
setup_lwp_context(test_unmapped_robust_list);
|
||||
|
||||
ATF_REQUIRE(_lwp_create(&lwp_data.context, 0, &lwp_data.lwpid) == 0);
|
||||
ATF_REQUIRE(_lwp_wait(lwp_data.lwpid, NULL) == 0);
|
||||
|
||||
ATF_REQUIRE(lwp_data.set_robust_list_failed == false);
|
||||
|
||||
/*
|
||||
* No additional validation; just exercises a code path
|
||||
* in the kernel.
|
||||
*/
|
||||
}
|
||||
|
||||
ATF_TC_CLEANUP(futex_robust_unmapped, tc)
|
||||
{
|
||||
do_cleanup();
|
||||
}
|
||||
|
||||
ATF_TC_WITH_CLEANUP(futex_robust_evil_circular);
|
||||
ATF_TC_HEAD(futex_robust_evil_circular, tc)
|
||||
{
|
||||
atf_tc_set_md_var(tc, "descr",
|
||||
"checks futex robust list processing faced with a deliberately "
|
||||
"ciruclar list");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(futex_robust_evil_circular, tc)
|
||||
{
|
||||
int i;
|
||||
|
||||
setup_lwp_context(test_evil_circular_robust_list);
|
||||
|
||||
ATF_REQUIRE(_lwp_create(&lwp_data.context, 0, &lwp_data.lwpid) == 0);
|
||||
ATF_REQUIRE(_lwp_wait(lwp_data.lwpid, NULL) == 0);
|
||||
|
||||
ATF_REQUIRE(lwp_data.set_robust_list_failed == false);
|
||||
|
||||
for (i = 0; i < NLOCKS; i++) {
|
||||
ATF_REQUIRE((pos_locks[i].fword & FUTEX_TID_MASK) ==
|
||||
lwp_data.threadid);
|
||||
ATF_REQUIRE((pos_locks[i].fword & FUTEX_OWNER_DIED) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TC_CLEANUP(futex_robust_evil_circular, tc)
|
||||
{
|
||||
do_cleanup();
|
||||
}
|
||||
|
||||
ATF_TC_WITH_CLEANUP(futex_robust_bad_pending);
|
||||
ATF_TC_HEAD(futex_robust_bad_pending, tc)
|
||||
{
|
||||
atf_tc_set_md_var(tc, "descr",
|
||||
"checks futex robust list processing with a bad pending pointer");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(futex_robust_bad_pending, tc)
|
||||
{
|
||||
int i;
|
||||
|
||||
setup_lwp_context(test_bad_pending_robust_list);
|
||||
|
||||
ATF_REQUIRE(_lwp_create(&lwp_data.context, 0, &lwp_data.lwpid) == 0);
|
||||
ATF_REQUIRE(_lwp_wait(lwp_data.lwpid, NULL) == 0);
|
||||
|
||||
ATF_REQUIRE(lwp_data.set_robust_list_failed == false);
|
||||
|
||||
for (i = 0; i < NLOCKS; i++) {
|
||||
ATF_REQUIRE((pos_locks[i].fword & FUTEX_TID_MASK) ==
|
||||
lwp_data.threadid);
|
||||
ATF_REQUIRE((pos_locks[i].fword & FUTEX_OWNER_DIED) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TC_CLEANUP(futex_robust_bad_pending, tc)
|
||||
{
|
||||
do_cleanup();
|
||||
}
|
||||
|
||||
ATF_TP_ADD_TCS(tp)
|
||||
{
|
||||
#if 0
|
||||
ATF_TP_ADD_TC(tp, futex_robust_positive);
|
||||
ATF_TP_ADD_TC(tp, futex_robust_negative);
|
||||
ATF_TP_ADD_TC(tp, futex_robust_unmapped);
|
||||
ATF_TP_ADD_TC(tp, futex_robust_evil_circular);
|
||||
#endif
|
||||
ATF_TP_ADD_TC(tp, futex_robust_bad_pending);
|
||||
|
||||
return atf_no_error();
|
||||
}
|
Loading…
Reference in New Issue
Block a user