[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[PATCH 1/2] m68k: Use vDSO for thread pointer access



Optimize __m68k_read_tp() to read the thread pointer directly from
the vDSO data page when available, avoiding the get_thread_area
syscall overhead.

The kernel maintains the thread pointer in a data page located at
a fixed offset (PAGE_SIZE) before the vDSO ELF header. This value
is updated on every context switch and set_thread_area() call.

The implementation uses lazy initialization: on first call, it
checks AT_SYSINFO_EHDR from auxv to locate the vDSO. If the vDSO
is not available (older kernels), it falls back to the syscall.

Reviewed-by:
Tested-by:

      * sysdeps/unix/sysv/linux/m68k/m68k-helpers.c: Include stdint.h
      and sys/auxv.h.
      (struct m68k_vdso_data): New struct matching kernel layout.
      (__m68k_vdso_data): New static variable for cached vDSO pointer.
      (__m68k_vdso_get): New helper to initialize and return vDSO
      data pointer.
      (__m68k_read_tp): Use vDSO fast path when available, fall back
      to syscall otherwise.
---
 sysdeps/unix/sysv/linux/m68k/m68k-helpers.c | 77 ++++++++++++++++++++-
 1 file changed, 76 insertions(+), 1 deletion(-)

diff --git a/sysdeps/unix/sysv/linux/m68k/m68k-helpers.c b/sysdeps/unix/sysv/linux/m68k/m68k-helpers.c
index 845aae51..1dee48e5 100644
--- a/sysdeps/unix/sysv/linux/m68k/m68k-helpers.c
+++ b/sysdeps/unix/sysv/linux/m68k/m68k-helpers.c
@@ -17,9 +17,84 @@
    <https://www.gnu.org/licenses/>.  */
 
 #include <sysdep.h>
+#include <stdint.h>
+#include <sys/auxv.h>
 
+/*
+ * vDSO data structure - must match the kernel's m68k_vdso_data struct.
+ * The TLS pointer is at offset 0 in the vDSO data page.
+ */
+struct m68k_vdso_data
+{
+  unsigned long tls_ptr;
+  unsigned long reserved[3];
+};
+
+/*
+ * Pointer to the vDSO data page.
+ * 0 = not yet initialized
+ * -1 = vDSO not available (fallback to syscall)
+ * other = valid vDSO data page address
+ */
+static volatile struct m68k_vdso_data *__m68k_vdso_data;
+
+/*
+ * Initialize the vDSO pointer on first use.
+ * Returns the pointer to the vDSO data, or NULL if not available.
+ */
+static inline struct m68k_vdso_data *
+__m68k_vdso_get (void)
+{
+  struct m68k_vdso_data *vdso = (struct m68k_vdso_data *) __m68k_vdso_data;
+
+  if (__glibc_unlikely (vdso == NULL))
+    {
+      /* Not yet initialized - try to get vDSO base from auxv */
+      unsigned long sysinfo_ehdr = __getauxval (AT_SYSINFO_EHDR);
+      if (sysinfo_ehdr != 0)
+	{
+	  /*
+	   * The kernel passes the address of the vDSO ELF header (code page).
+	   * The vDSO memory layout is:
+	   *   base + 0x0000: vvar (data page with TLS pointer, clock state)
+	   *   base + 0x1000: timer page (hardware timer registers)
+	   *   base + 0x2000: vDSO code (ELF, AT_SYSINFO_EHDR points here)
+	   * So the data page is 2 * PAGE_SIZE before the code page.
+	   */
+	  vdso = (struct m68k_vdso_data *) (sysinfo_ehdr - 2 * 4096);
+	}
+      else
+	{
+	  /* vDSO not available - mark as unavailable */
+	  vdso = (struct m68k_vdso_data *) (uintptr_t) -1;
+	}
+      __m68k_vdso_data = vdso;
+    }
+
+  /* Return NULL if vDSO is marked as unavailable */
+  if ((uintptr_t) vdso == (uintptr_t) -1)
+    return NULL;
+
+  return vdso;
+}
+
+/*
+ * Get the thread pointer.
+ *
+ * Fast path: Read directly from the vDSO data page if available.
+ * The kernel updates this on every context switch and set_thread_area() call.
+ *
+ * Slow path: Fall back to the get_thread_area syscall.
+ */
 void *
 __m68k_read_tp (void)
 {
-  return (void*) INTERNAL_SYSCALL_CALL (get_thread_area);
+  struct m68k_vdso_data *vdso = __m68k_vdso_get ();
+
+  /* Fast path: use vDSO if available */
+  if (__glibc_likely (vdso != NULL))
+    return (void *) vdso->tls_ptr;
+
+  /* Slow path: syscall fallback */
+  return (void *) INTERNAL_SYSCALL_CALL (get_thread_area);
 }
-- 
2.51.0


Reply to: