[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: