[RFC] MIPS: Add VDSO support
Commit Message
From: Alex Smith <alex.smith@imgtec.com>
This patch adds support for using the implementations of gettimeofday()
and clock_gettime() provided by the kernel in the VDSO. The VDSO will
always provide clock_gettime() as CLOCK_{REALTIME,MONOTONIC}_COARSE can
be implemented regardless of platform. CLOCK_{REALTIME,MONOTONIC}, along
with gettimeofday(), are only implemented on platforms which make use of
either the CP0 count or GIC as their clocksource. On other platforms,
the VDSO does not provide the __vdso_gettimeofday symbol, as it is
never useful.
The VDSO functions return ENOSYS when they encounter an unsupported
request, in which case glibc should fall back to the standard syscall.
* sysdeps/unix/sysv/linux/mips/Makefile (sysdep_routines):
Include dl-vdso.
* sysdeps/unix/sysv/linux/mips/Versions: Add
__vdso_clock_gettime.
* sysdeps/unix/sysv/linux/mips/init-first.c: New file.
* sysdeps/unix/sysv/linux/mips/libc-vdso.h: New file.
* sysdeps/unix/sysv/linux/mips/mips32/sysdep.h:
(INTERNAL_VSYSCALL_CALL): Define to be compatible with MIPS
definitions of INTERNAL_SYSCALL_{ERROR_P,ERRNO}.
(HAVE_CLOCK_GETTIME_VSYSCALL): Define.
(HAVE_GETTIMEOFDAY_VSYSCALL): Define.
* sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h: Likewise.
* sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h: Likewise.
---
Hi,
The kernel patches for vdso support are already upstream.
I'm picking up this patch to upstream vdso support for MIPS in glibc.
Rebased this patch on glibc-2.23
Tested with upstream kernel 4.5 and QEMU emulating Malta.
./vdsotest gettimeofday bench
gettimeofday: syscall: 1021 nsec/call
gettimeofday: libc: 262 nsec/call
gettimeofday: vdso: 174 nsec/call
Regards,
ZubairLK
---
sysdeps/unix/sysv/linux/mips/Makefile | 2 ++
sysdeps/unix/sysv/linux/mips/Versions | 4 +++
sysdeps/unix/sysv/linux/mips/init-first.c | 44 ++++++++++++++++++++++++
sysdeps/unix/sysv/linux/mips/libc-vdso.h | 33 ++++++++++++++++++
sysdeps/unix/sysv/linux/mips/mips32/sysdep.h | 16 +++++++++
sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h | 17 +++++++++
sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h | 17 +++++++++
7 files changed, 133 insertions(+)
create mode 100644 sysdeps/unix/sysv/linux/mips/init-first.c
create mode 100644 sysdeps/unix/sysv/linux/mips/libc-vdso.h
Comments
On 30 Mar 2016 16:10, Zubair Lutfullah Kakakhel wrote:
> The kernel patches for vdso support are already upstream.
can you make sure the vdso(7) man page is updated then ?
-mike
Hi,
On 30/03/16 21:02, Mike Frysinger wrote:
> On 30 Mar 2016 16:10, Zubair Lutfullah Kakakhel wrote:
>> The kernel patches for vdso support are already upstream.
>
> can you make sure the vdso(7) man page is updated then ?
> -mike
>
Thanks.
I've sent a patch for man-pages.
http://thread.gmane.org/gmane.linux.man/10349
Regards,
ZubairLK
+ Joseph.
Apologies. I forgot to cc you initially.
Regards,
ZubairLK
On 30/03/16 16:10, Zubair Lutfullah Kakakhel wrote:
> From: Alex Smith <alex.smith@imgtec.com>
>
> This patch adds support for using the implementations of gettimeofday()
> and clock_gettime() provided by the kernel in the VDSO. The VDSO will
> always provide clock_gettime() as CLOCK_{REALTIME,MONOTONIC}_COARSE can
> be implemented regardless of platform. CLOCK_{REALTIME,MONOTONIC}, along
> with gettimeofday(), are only implemented on platforms which make use of
> either the CP0 count or GIC as their clocksource. On other platforms,
> the VDSO does not provide the __vdso_gettimeofday symbol, as it is
> never useful.
>
> The VDSO functions return ENOSYS when they encounter an unsupported
> request, in which case glibc should fall back to the standard syscall.
>
> * sysdeps/unix/sysv/linux/mips/Makefile (sysdep_routines):
> Include dl-vdso.
> * sysdeps/unix/sysv/linux/mips/Versions: Add
> __vdso_clock_gettime.
> * sysdeps/unix/sysv/linux/mips/init-first.c: New file.
> * sysdeps/unix/sysv/linux/mips/libc-vdso.h: New file.
> * sysdeps/unix/sysv/linux/mips/mips32/sysdep.h:
> (INTERNAL_VSYSCALL_CALL): Define to be compatible with MIPS
> definitions of INTERNAL_SYSCALL_{ERROR_P,ERRNO}.
> (HAVE_CLOCK_GETTIME_VSYSCALL): Define.
> (HAVE_GETTIMEOFDAY_VSYSCALL): Define.
> * sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h: Likewise.
> * sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h: Likewise.
>
> ---
> Hi,
>
> The kernel patches for vdso support are already upstream.
>
> I'm picking up this patch to upstream vdso support for MIPS in glibc.
>
> Rebased this patch on glibc-2.23
>
> Tested with upstream kernel 4.5 and QEMU emulating Malta.
>
> ./vdsotest gettimeofday bench
> gettimeofday: syscall: 1021 nsec/call
> gettimeofday: libc: 262 nsec/call
> gettimeofday: vdso: 174 nsec/call
>
> Regards,
> ZubairLK
>
> ---
> sysdeps/unix/sysv/linux/mips/Makefile | 2 ++
> sysdeps/unix/sysv/linux/mips/Versions | 4 +++
> sysdeps/unix/sysv/linux/mips/init-first.c | 44 ++++++++++++++++++++++++
> sysdeps/unix/sysv/linux/mips/libc-vdso.h | 33 ++++++++++++++++++
> sysdeps/unix/sysv/linux/mips/mips32/sysdep.h | 16 +++++++++
> sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h | 17 +++++++++
> sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h | 17 +++++++++
> 7 files changed, 133 insertions(+)
> create mode 100644 sysdeps/unix/sysv/linux/mips/init-first.c
> create mode 100644 sysdeps/unix/sysv/linux/mips/libc-vdso.h
>
> diff --git a/sysdeps/unix/sysv/linux/mips/Makefile b/sysdeps/unix/sysv/linux/mips/Makefile
> index 8127025..c6729c1 100644
> --- a/sysdeps/unix/sysv/linux/mips/Makefile
> +++ b/sysdeps/unix/sysv/linux/mips/Makefile
> @@ -96,6 +96,8 @@ ifeq ($(subdir),elf)
> ifeq ($(build-shared),yes)
> # This is needed for DSO loading from static binaries.
> sysdep-dl-routines += dl-static
> +
> +sysdep_routines += dl-vdso
> endif
> endif
>
> diff --git a/sysdeps/unix/sysv/linux/mips/Versions b/sysdeps/unix/sysv/linux/mips/Versions
> index a56322a..453f276 100644
> --- a/sysdeps/unix/sysv/linux/mips/Versions
> +++ b/sysdeps/unix/sysv/linux/mips/Versions
> @@ -37,4 +37,8 @@ libc {
> GLIBC_2.11 {
> fallocate64;
> }
> + GLIBC_PRIVATE {
> + # nptl/pthread_cond_timedwait.c uses INTERNAL_VSYSCALL(clock_gettime).
> + __vdso_clock_gettime;
> + }
> }
> diff --git a/sysdeps/unix/sysv/linux/mips/init-first.c b/sysdeps/unix/sysv/linux/mips/init-first.c
> new file mode 100644
> index 0000000..46dba69
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/mips/init-first.c
> @@ -0,0 +1,44 @@
> +/* Initialization code run first thing by the ELF startup code.
> + Copyright (C) 2015 Free Software Foundation, Inc.
> +
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public License as
> + published by the Free Software Foundation; either version 2.1 of the
> + License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <http://www.gnu.org/licenses/>. */
> +
> +#ifdef SHARED
> +# include <dl-vdso.h>
> +# include <libc-vdso.h>
> +
> +int (*VDSO_SYMBOL(gettimeofday)) (struct timeval *, void *) attribute_hidden;
> +int (*VDSO_SYMBOL(clock_gettime)) (clockid_t, struct timespec *);
> +
> +static inline void
> +_libc_vdso_platform_setup (void)
> +{
> + PREPARE_VERSION_KNOWN (linux26, LINUX_2_6);
> +
> + void *p = _dl_vdso_vsym ("__vdso_gettimeofday", &linux26);
> + PTR_MANGLE (p);
> + VDSO_SYMBOL (gettimeofday) = p;
> +
> + p = _dl_vdso_vsym ("__vdso_clock_gettime", &linux26);
> + PTR_MANGLE (p);
> + VDSO_SYMBOL (clock_gettime) = p;
> +}
> +
> +# define VDSO_SETUP _libc_vdso_platform_setup
> +#endif
> +
> +#include <csu/init-first.c>
> diff --git a/sysdeps/unix/sysv/linux/mips/libc-vdso.h b/sysdeps/unix/sysv/linux/mips/libc-vdso.h
> new file mode 100644
> index 0000000..1580de8
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/mips/libc-vdso.h
> @@ -0,0 +1,33 @@
> +/* VDSO function pointer declarations.
> + Copyright (C) 2015 Free Software Foundation, Inc.
> +
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library. If not, see
> + <http://www.gnu.org/licenses/>. */
> +
> +#ifndef _LIBC_VDSO_H
> +#define _LIBC_VDSO_H
> +
> +#ifdef SHARED
> +
> +# include <sysdep-vdso.h>
> +
> +extern int (*VDSO_SYMBOL(gettimeofday)) (struct timeval *, void *)
> + attribute_hidden;
> +extern int (*VDSO_SYMBOL(clock_gettime)) (clockid_t, struct timespec *);
> +
> +#endif
> +
> +#endif /* _LIBC_VDSO_H */
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h b/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
> index 2160df7..2335409 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
> @@ -371,6 +371,22 @@
> #define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \
> "$14", "$15", "$24", "$25", "hi", "lo", "memory"
>
> +/* Standard MIPS syscalls have an error flag, and return a positive errno
> + when the error flag is set. Emulate this behaviour for vsyscalls so that
> + the INTERNAL_SYSCALL_{ERROR_P,ERRNO} macros work correctly. */
> +#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...) \
> + ({ \
> + long _ret = funcptr (args); \
> + err = ((unsigned long) (_ret) >= (unsigned long) -4095L); \
> + if (err) \
> + _ret = -_ret; \
> + _ret; \
> + })
> +
> +/* List of system calls which are supported as vsyscalls. */
> +#define HAVE_CLOCK_GETTIME_VSYSCALL 1
> +#define HAVE_GETTIMEOFDAY_VSYSCALL 1
> +
> #endif /* __ASSEMBLER__ */
>
> /* Pointer mangling is not yet supported for MIPS. */
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h b/sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h
> index 466dcde..661b3dc 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h
> @@ -295,6 +295,23 @@
>
> #define __SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", "$13", \
> "$14", "$15", "$24", "$25", "hi", "lo", "memory"
> +
> +/* Standard MIPS syscalls have an error flag, and return a positive errno
> + when the error flag is set. Emulate this behaviour for vsyscalls so that
> + the INTERNAL_SYSCALL_{ERROR_P,ERRNO} macros work correctly. */
> +#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...) \
> + ({ \
> + long _ret = funcptr (args); \
> + err = ((unsigned long) (_ret) >= (unsigned long) -4095L); \
> + if (err) \
> + _ret = -_ret; \
> + _ret; \
> + })
> +
> +/* List of system calls which are supported as vsyscalls. */
> +#define HAVE_CLOCK_GETTIME_VSYSCALL 1
> +#define HAVE_GETTIMEOFDAY_VSYSCALL 1
> +
> #endif /* __ASSEMBLER__ */
>
> /* Pointer mangling is not yet supported for MIPS. */
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h b/sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h
> index db8b237..476eca3 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h
> @@ -291,6 +291,23 @@
>
> #define __SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", "$13", \
> "$14", "$15", "$24", "$25", "hi", "lo", "memory"
> +
> +/* Standard MIPS syscalls have an error flag, and return a positive errno
> + when the error flag is set. Emulate this behaviour for vsyscalls so that
> + the INTERNAL_SYSCALL_{ERROR_P,ERRNO} macros work correctly. */
> +#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...) \
> + ({ \
> + long _ret = funcptr (args); \
> + err = ((unsigned long) (_ret) >= (unsigned long) -4095L); \
> + if (err) \
> + _ret = -_ret; \
> + _ret; \
> + })
> +
> +/* List of system calls which are supported as vsyscalls. */
> +#define HAVE_CLOCK_GETTIME_VSYSCALL 1
> +#define HAVE_GETTIMEOFDAY_VSYSCALL 1
> +
> #endif /* __ASSEMBLER__ */
>
> /* Pointer mangling is not yet supported for MIPS. */
>
On Wed, 30 Mar 2016, Zubair Lutfullah Kakakhel wrote:
> +/* Initialization code run first thing by the ELF startup code.
> + Copyright (C) 2015 Free Software Foundation, Inc.
Copyright notices for all new files should include 2016. OK with that
fixed for all affected files in this patch.
@@ -96,6 +96,8 @@ ifeq ($(subdir),elf)
ifeq ($(build-shared),yes)
# This is needed for DSO loading from static binaries.
sysdep-dl-routines += dl-static
+
+sysdep_routines += dl-vdso
endif
endif
@@ -37,4 +37,8 @@ libc {
GLIBC_2.11 {
fallocate64;
}
+ GLIBC_PRIVATE {
+ # nptl/pthread_cond_timedwait.c uses INTERNAL_VSYSCALL(clock_gettime).
+ __vdso_clock_gettime;
+ }
}
new file mode 100644
@@ -0,0 +1,44 @@
+/* Initialization code run first thing by the ELF startup code.
+ Copyright (C) 2015 Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef SHARED
+# include <dl-vdso.h>
+# include <libc-vdso.h>
+
+int (*VDSO_SYMBOL(gettimeofday)) (struct timeval *, void *) attribute_hidden;
+int (*VDSO_SYMBOL(clock_gettime)) (clockid_t, struct timespec *);
+
+static inline void
+_libc_vdso_platform_setup (void)
+{
+ PREPARE_VERSION_KNOWN (linux26, LINUX_2_6);
+
+ void *p = _dl_vdso_vsym ("__vdso_gettimeofday", &linux26);
+ PTR_MANGLE (p);
+ VDSO_SYMBOL (gettimeofday) = p;
+
+ p = _dl_vdso_vsym ("__vdso_clock_gettime", &linux26);
+ PTR_MANGLE (p);
+ VDSO_SYMBOL (clock_gettime) = p;
+}
+
+# define VDSO_SETUP _libc_vdso_platform_setup
+#endif
+
+#include <csu/init-first.c>
new file mode 100644
@@ -0,0 +1,33 @@
+/* VDSO function pointer declarations.
+ Copyright (C) 2015 Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _LIBC_VDSO_H
+#define _LIBC_VDSO_H
+
+#ifdef SHARED
+
+# include <sysdep-vdso.h>
+
+extern int (*VDSO_SYMBOL(gettimeofday)) (struct timeval *, void *)
+ attribute_hidden;
+extern int (*VDSO_SYMBOL(clock_gettime)) (clockid_t, struct timespec *);
+
+#endif
+
+#endif /* _LIBC_VDSO_H */
@@ -371,6 +371,22 @@
#define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \
"$14", "$15", "$24", "$25", "hi", "lo", "memory"
+/* Standard MIPS syscalls have an error flag, and return a positive errno
+ when the error flag is set. Emulate this behaviour for vsyscalls so that
+ the INTERNAL_SYSCALL_{ERROR_P,ERRNO} macros work correctly. */
+#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...) \
+ ({ \
+ long _ret = funcptr (args); \
+ err = ((unsigned long) (_ret) >= (unsigned long) -4095L); \
+ if (err) \
+ _ret = -_ret; \
+ _ret; \
+ })
+
+/* List of system calls which are supported as vsyscalls. */
+#define HAVE_CLOCK_GETTIME_VSYSCALL 1
+#define HAVE_GETTIMEOFDAY_VSYSCALL 1
+
#endif /* __ASSEMBLER__ */
/* Pointer mangling is not yet supported for MIPS. */
@@ -295,6 +295,23 @@
#define __SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", "$13", \
"$14", "$15", "$24", "$25", "hi", "lo", "memory"
+
+/* Standard MIPS syscalls have an error flag, and return a positive errno
+ when the error flag is set. Emulate this behaviour for vsyscalls so that
+ the INTERNAL_SYSCALL_{ERROR_P,ERRNO} macros work correctly. */
+#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...) \
+ ({ \
+ long _ret = funcptr (args); \
+ err = ((unsigned long) (_ret) >= (unsigned long) -4095L); \
+ if (err) \
+ _ret = -_ret; \
+ _ret; \
+ })
+
+/* List of system calls which are supported as vsyscalls. */
+#define HAVE_CLOCK_GETTIME_VSYSCALL 1
+#define HAVE_GETTIMEOFDAY_VSYSCALL 1
+
#endif /* __ASSEMBLER__ */
/* Pointer mangling is not yet supported for MIPS. */
@@ -291,6 +291,23 @@
#define __SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", "$13", \
"$14", "$15", "$24", "$25", "hi", "lo", "memory"
+
+/* Standard MIPS syscalls have an error flag, and return a positive errno
+ when the error flag is set. Emulate this behaviour for vsyscalls so that
+ the INTERNAL_SYSCALL_{ERROR_P,ERRNO} macros work correctly. */
+#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...) \
+ ({ \
+ long _ret = funcptr (args); \
+ err = ((unsigned long) (_ret) >= (unsigned long) -4095L); \
+ if (err) \
+ _ret = -_ret; \
+ _ret; \
+ })
+
+/* List of system calls which are supported as vsyscalls. */
+#define HAVE_CLOCK_GETTIME_VSYSCALL 1
+#define HAVE_GETTIMEOFDAY_VSYSCALL 1
+
#endif /* __ASSEMBLER__ */
/* Pointer mangling is not yet supported for MIPS. */