diff mbox series

[v2,7/8] linux: Consolidate time implementation

Message ID 20190905205620.4646-7-adhemerval.zanella@linaro.org
State New
Headers show
Series [v2,1/8] Remove PREPARE_VERSION and PREPARE_VERSION_KNOW | expand

Commit Message

Adhemerval Zanella Sept. 5, 2019, 8:56 p.m. UTC
Changes from previous version:

  - Improve comment about hidden_def_redir.
  - Update due powerpc64 fixes.

--

The time syscall has currently 3 possible implementations:

   1. Wire-up __NR_time with a vDSO implementation (currently only x86 and
      powerpc).
   2. Wire-up __NR_time (hppa, i686, m68k, microblaze, mips, powerpc,
      powerpc64, s390, sh4, sparcv9, x86_64).
   3. Using internal gettimeofday (aarch64, alpha, arm, mips64, mips64-n32,
      nios2, s390x, sparc64).

This patch consolidates all implementation on Linux generic
sysdeps/unix/sysv/linux/time.c.  To simplify the code, some changes are
made:

   * The wire-up with vDSO implementation route external calls directly
     to vDSO through IFUNC.  To enable it the architecture need to
     explicit define USE_TIME_VSYSCALL_IFUNC.

   * Also, powerpc and x86 tries to route internal time usages to
     IFUNC mechanism, which is problematic since powerpc32 and i686 does
     not really support it.  Instead, all internal calls are routed to
     a default internal symbol which in turn calls INTERNAL_VSYSCALL.

   * Static linking also uses the fallback mechanism which calls
     INTERNAL_VSYSCALL, so vDSO is used for this case as well.

The generic implementation issues a syscall as default, calls the
vDSO if the architecture defines HAVE_TIME_VSYSCALL, and route the external
calls to iFUNC if the architecture also defines USE_TIME_VSYSCALL_IFUNC.

Checked on x86_64-linux-gnu, i686-linux-gnu, powerpc-linux-gnu,
powerpc64-linux-gnu, powerpc64le-linux-gnu, and aarch64-linux-gnu.

	* include/libc-symbols.h (hidden_def_redir): New macro.
	* sysdeps/unix/sysv/linux/i386/sysdep.h (HAVE_TIME_VSYSCALL,
	USE_TIME_VSYSCALL_IFUNC): Define.
	* sysdeps/unix/sysv/linux/x86_64/sysdep.h (HAVE_TIME_VSYSCALL,
	USE_TIME_VSYSCALL_IFUNC): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/sysdep.h (USE_TIME_VSYSCALL_IFUNC):
	Likewise.
	* sysdeps/unix/sysv/linux/i386/time.c: Remove file.
	* sysdeps/unix/sysv/linux/x86/time.c: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/time.c: Likewise.
	* sysdeps/unix/sysv/linux/time.c (time): Handle all possible Linux
	implementations (wire-up syscall, vDSO implementation, iFUNC).
	(time_syscall): New function.
---
 include/libc-symbols.h                   | 11 ++++
 sysdeps/unix/sysv/linux/i386/sysdep.h    |  2 +
 sysdeps/unix/sysv/linux/i386/time.c      | 34 ----------
 sysdeps/unix/sysv/linux/powerpc/sysdep.h |  1 +
 sysdeps/unix/sysv/linux/powerpc/time.c   | 83 ------------------------
 sysdeps/unix/sysv/linux/time.c           | 57 +++++++++++++---
 sysdeps/unix/sysv/linux/x86/time.c       | 60 -----------------
 sysdeps/unix/sysv/linux/x86_64/sysdep.h  |  2 +
 8 files changed, 65 insertions(+), 185 deletions(-)
 delete mode 100644 sysdeps/unix/sysv/linux/i386/time.c
 delete mode 100644 sysdeps/unix/sysv/linux/powerpc/time.c
 delete mode 100644 sysdeps/unix/sysv/linux/x86/time.c

-- 
2.17.1
diff mbox series

Patch

diff --git a/include/libc-symbols.h b/include/libc-symbols.h
index b68ec4b7f5..a585a04e63 100644
--- a/include/libc-symbols.h
+++ b/include/libc-symbols.h
@@ -491,6 +491,12 @@  for linking")
    int foo = INITIAL_FOO_VALUE;
    libc_hidden_data_weak (foo)
 
+   If the internal foo should use a different internal symbol (for instance
+   if the symbol is exported as an IFUNC, but internal calls should use a
+   default version) then you may use:
+
+   libc_hidden_def_redir (foo_internal, foo)
+
    If foo is normally just an alias (strong or weak) to some other function,
    you should use the normal strong_alias first, then add libc_hidden_def
    or libc_hidden_weak:
@@ -548,6 +554,7 @@  for linking")
 #  define hidden_ver(local, name)	__hidden_ver1(local, __GI_##name, name);
 #  define hidden_data_ver(local, name)	hidden_ver(local, name)
 #  define hidden_def(name)		__hidden_ver1(__GI_##name, name, name);
+#  define hidden_def_redir(redir, name)	__hidden_ver1(redir, __GI_##name, redir);
 #  define hidden_data_def(name)		hidden_def(name)
 #  define hidden_tls_def(name)				\
   __hidden_ver2 (__thread, __GI_##name, name, name);
@@ -575,6 +582,7 @@  for linking")
    hidden_proto doesn't make sense for assembly but the equivalent
    is to call via the HIDDEN_JUMPTARGET macro instead of JUMPTARGET.  */
 #  define hidden_def(name)	strong_alias (name, __GI_##name)
+#  define hidden_def_redir(redir, name)	strong_alias(redir, __GI_##name);
 #  define hidden_weak(name)	hidden_def (name)
 #  define hidden_ver(local, name) strong_alias (local, __GI_##name)
 #  define hidden_data_def(name)	strong_data_alias (name, __GI_##name)
@@ -605,6 +613,7 @@  for linking")
 # endif /* Not  __ASSEMBLER__ */
 # define hidden_weak(name)
 # define hidden_def(name)
+# define hidden_def_redir(redir, name)
 # define hidden_ver(local, name)
 # define hidden_data_weak(name)
 # define hidden_data_def(name)
@@ -617,6 +626,7 @@  for linking")
 # define libc_hidden_proto(name, attrs...) hidden_proto (name, ##attrs)
 # define libc_hidden_tls_proto(name, attrs...) hidden_tls_proto (name, ##attrs)
 # define libc_hidden_def(name) hidden_def (name)
+# define libc_hidden_def_redir(redir, name) hidden_def_redir (redir, name)
 # define libc_hidden_weak(name) hidden_weak (name)
 # ifdef LINK_OBSOLETE_RPC
    /* libc_hidden_nolink_sunrpc should only get used in sunrpc code.  */
@@ -633,6 +643,7 @@  for linking")
 # define libc_hidden_proto(name, attrs...)
 # define libc_hidden_tls_proto(name, attrs...)
 # define libc_hidden_def(name)
+# define libc_hidden_def_redir(redir, name)
 # define libc_hidden_weak(name)
 # define libc_hidden_ver(local, name)
 # define libc_hidden_data_def(name)
diff --git a/sysdeps/unix/sysv/linux/i386/sysdep.h b/sysdeps/unix/sysv/linux/i386/sysdep.h
index e793fdc936..4f79f25989 100644
--- a/sysdeps/unix/sysv/linux/i386/sysdep.h
+++ b/sysdeps/unix/sysv/linux/i386/sysdep.h
@@ -315,6 +315,8 @@  struct libc_do_syscall_args
 /* List of system calls which are supported as vsyscalls.  */
 # define HAVE_CLOCK_GETTIME_VSYSCALL    "__vdso_clock_gettime"
 # define HAVE_GETTIMEOFDAY_VSYSCALL     "__vdso_gettimeofday"
+# define HAVE_TIME_VSYSCALL             "__vdso_time"
+# define USE_TIME_VSYSCALL_IFUNC	1
 
 /* Define a macro which expands inline into the wrapper code for a system
    call.  This use is for internal calls that do not need to handle errors
diff --git a/sysdeps/unix/sysv/linux/i386/time.c b/sysdeps/unix/sysv/linux/i386/time.c
deleted file mode 100644
index 440e3e6ab4..0000000000
--- a/sysdeps/unix/sysv/linux/i386/time.c
+++ /dev/null
@@ -1,34 +0,0 @@ 
-/* time -- Get number of seconds since Epoch.  Linux/i386 version.
-   Copyright (C) 2015-2019 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
-# define time __redirect_time
-#endif
-
-#include <time.h>
-
-#ifdef SHARED
-# undef time
-# define time_type __redirect_time
-
-# undef libc_hidden_def
-# define libc_hidden_def(name)  \
-  __hidden_ver1 (__time_syscall, __GI_time, __time_syscall);
-#endif
-
-#include <sysdeps/unix/sysv/linux/x86/time.c>
diff --git a/sysdeps/unix/sysv/linux/powerpc/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/sysdep.h
index 357d1b5243..084b6525ca 100644
--- a/sysdeps/unix/sysv/linux/powerpc/sysdep.h
+++ b/sysdeps/unix/sysv/linux/powerpc/sysdep.h
@@ -24,6 +24,7 @@ 
 #define HAVE_CLOCK_GETTIME_VSYSCALL	"__kernel_clock_gettime"
 #define HAVE_GETCPU_VSYSCALL		"__kernel_getcpu"
 #define HAVE_TIME_VSYSCALL		"__kernel_time"
+#define USE_TIME_VSYSCALL_IFUNC		1
 #define HAVE_GETTIMEOFDAY_VSYSCALL	"__kernel_gettimeofday"
 #define HAVE_GET_TBFREQ                 "__kernel_get_tbfreq"
 
diff --git a/sysdeps/unix/sysv/linux/powerpc/time.c b/sysdeps/unix/sysv/linux/powerpc/time.c
deleted file mode 100644
index f0537a2307..0000000000
--- a/sysdeps/unix/sysv/linux/powerpc/time.c
+++ /dev/null
@@ -1,83 +0,0 @@ 
-/* time system call for Linux/PowerPC.
-   Copyright (C) 2013-2019 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
-# ifndef __powerpc64__
-#  define time __redirect_time
-# else
-#  define __redirect_time time
-# endif
-
-# include <time.h>
-# include <sysdep.h>
-# include <dl-vdso.h>
-# include <libc-vdso.h>
-# include <dl-machine.h>
-
-# ifndef __powerpc64__
-#  undef time
-
-time_t
-__time_vsyscall (time_t *t)
-{
-  return INLINE_VSYSCALL (time, 1, t);
-}
-
-/* __GI_time is defined as hidden and for ppc32 it enables the
-   compiler make a local call (symbol@local) for internal GLIBC usage. It
-   means the PLT won't be used and the ifunc resolver will be called directly.
-   For ppc64 a call to a function in another translation unit might use a
-   different toc pointer thus disallowing direct branchess and making internal
-   ifuncs calls safe.  */
-#  undef libc_hidden_def
-#  define libc_hidden_def(name)					\
-  __hidden_ver1 (__time_vsyscall, __GI_time, __time_vsyscall);
-
-# endif /* !__powerpc64__  */
-
-static time_t
-time_syscall (time_t *t)
-{
-  struct timeval tv;
-  time_t result;
-
-  if (INLINE_VSYSCALL (gettimeofday, 2, &tv, NULL) < 0)
-    result = (time_t) -1;
-  else
-    result = (time_t) tv.tv_sec;
-
-  if (t != NULL)
-    *t = result;
-  return result;
-}
-
-# define INIT_ARCH() \
-  void *vdso_time = get_vdso_symbol (HAVE_TIME_VSYSCALL);
-
-/* If the vDSO is not available we fall back to the syscall.  */
-libc_ifunc_hidden (__redirect_time, time,
-		   vdso_time
-		   ? VDSO_IFUNC_RET (vdso_time)
-		   : (void *) time_syscall);
-libc_hidden_def (time)
-
-#else
-
-#include <sysdeps/posix/time.c>
-
-#endif /* !SHARED */
diff --git a/sysdeps/unix/sysv/linux/time.c b/sysdeps/unix/sysv/linux/time.c
index 1978f6d817..9176fe6ed7 100644
--- a/sysdeps/unix/sysv/linux/time.c
+++ b/sysdeps/unix/sysv/linux/time.c
@@ -15,27 +15,68 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <stddef.h>
+/* Currently we have 3 possible time implementations, which is also selected
+   in the order:
+
+   1. Wire-up __NR_time with a vDSO implementation (currently only x86 and
+      powerpc).
+   2. Only wire-up __NR_time (usually old kABIs).
+   3. Using internal gettimeofday (which may call a vDSO as well).  */
+
+#define time __redirect_time
 #include <time.h>
+#undef time
+#include <sys/time.h>
 
 #include <sysdep.h>
+#ifdef HAVE_TIME_VSYSCALL
+# define HAVE_VSYSCALL
+#endif
+#include <sysdep-vdso.h>
+#include <libc-vdso.h>
 
-#ifdef __NR_time
-
-time_t
-time (time_t *t)
+static time_t
+time_syscall (time_t *t)
 {
+  time_t res;
+#ifdef __NR_time
   INTERNAL_SYSCALL_DECL (err);
-  time_t res = INTERNAL_SYSCALL (time, err, 1, NULL);
+  res = INTERNAL_VSYSCALL (time, err, 1, NULL);
   /* There cannot be any error.  */
+#else
+  struct timeval tv;
+  /* gettimeofday does not fail with valid 'tv' and null timezone.  */
+  __gettimeofday (&tv, NULL);
+  res = tv.tv_sec;
+#endif
   if (t != NULL)
     *t = res;
   return res;
 }
-libc_hidden_def (time)
 
+#if HAVE_IFUNC && defined USE_TIME_VSYSCALL_IFUNC
+/* Route externals calls direct to vDSO and static and internal calls to
+   fallback implementation (which also might call the vDSO).  */
+# ifdef SHARED
+#  undef INIT_ARCH
+#  define INIT_ARCH() \
+  void *vdso_time = get_vdso_symbol (HAVE_TIME_VSYSCALL);
+
+libc_ifunc_redirected (__redirect_time, time,
+		       vdso_time
+		       ? VDSO_IFUNC_RET (vdso_time)
+		       : (void *) time_syscall);
+libc_hidden_def_redir (time_syscall, time)
+#  else
+strong_alias (time_syscall, time)
+#  endif /* SHARED  */
 #else
 
-# include <sysdeps/posix/time.c>
+time_t
+time (time_t *t)
+{
+  return time_syscall (t);
+}
+libc_hidden_def_redir (time, time)
 
 #endif
diff --git a/sysdeps/unix/sysv/linux/x86/time.c b/sysdeps/unix/sysv/linux/x86/time.c
deleted file mode 100644
index 60e6d1b7c0..0000000000
--- a/sysdeps/unix/sysv/linux/x86/time.c
+++ /dev/null
@@ -1,60 +0,0 @@ 
-/* time -- Get number of seconds since Epoch.  Linux/x86 version.
-   Copyright (C) 2015-2019 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/>.  */
-
-#include <time.h>
-
-#ifdef SHARED
-
-#include <dl-vdso.h>
-#include <errno.h>
-#include <sysdep-vdso.h>
-
-static time_t
-__time_syscall (time_t *t)
-{
-  INTERNAL_SYSCALL_DECL (err);
-  return INTERNAL_SYSCALL (time, err, 1, t);
-}
-
-# ifndef time_type
-/* The i386 time.c includes this file with a defined time_type macro.
-   For x86_64 we have to define it to time as the internal symbol is the
-   ifunc'ed one.  */
-#  define time_type time
-# endif
-
-#undef INIT_ARCH
-#define INIT_ARCH()
-
-/* If the vDSO is not available we fall back on the syscall.  */
-libc_ifunc_hidden (time_type, time,
-		   (get_vdso_symbol ("__vdso_time") ?: __time_syscall))
-libc_hidden_def (time)
-
-#else
-
-# include <sysdep.h>
-
-time_t
-time (time_t *t)
-{
-  INTERNAL_SYSCALL_DECL (err);
-  return INTERNAL_SYSCALL (time, err, 1, t);
-}
-
-#endif
diff --git a/sysdeps/unix/sysv/linux/x86_64/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
index 4541c0d492..c64fbd1e26 100644
--- a/sysdeps/unix/sysv/linux/x86_64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
@@ -376,6 +376,8 @@ 
 /* List of system calls which are supported as vsyscalls.  */
 # define HAVE_CLOCK_GETTIME_VSYSCALL    "__vdso_clock_gettime"
 # define HAVE_GETTIMEOFDAY_VSYSCALL     "__vdso_gettimeofday"
+# define HAVE_TIME_VSYSCALL		"__vdso_time"
+# define USE_TIME_VSYSCALL_IFUNC	1
 # define HAVE_GETCPU_VSYSCALL		"__vdso_getcpu"
 
 # define SINGLE_THREAD_BY_GLOBAL		1