Message ID | 20210910043102.3616198-2-alistair.francis@opensource.wdc.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v2,1/2] perf benchmark: Call the futex syscall from a function | expand |
On Fri, Sep 10, 2021 at 6:31 AM Alistair Francis <alistair.francis@opensource.wdc.com> wrote: > > From: Alistair Francis <alistair.francis@wdc.com> > > Some 32-bit architectures (such are 32-bit RISC-V) only have a 64-bit > time_t and as such don't have the SYS_futex syscall. This patch will > allow us to use the SYS_futex_time64 syscall on those platforms. > > Signed-off-by: Alistair Francis <alistair.francis@wdc.com> > --- > tools/perf/bench/futex.h | 43 +++++++++++++++++++++++++++++++++++++++- > 1 file changed, 42 insertions(+), 1 deletion(-) > > diff --git a/tools/perf/bench/futex.h b/tools/perf/bench/futex.h > index f80a4759ee79b..09c5596726c60 100644 > --- a/tools/perf/bench/futex.h > +++ b/tools/perf/bench/futex.h > @@ -27,6 +27,12 @@ struct bench_futex_parameters { > unsigned int nrequeue; > }; > > +/* A version of 'struct timespec' with 32-bit time_t and nanoseconds. */ > +struct __timespec32 { > + __kernel_long_t tv_sec; > + __kernel_long_t tv_nsec; > +}; Why not use the existing __kernel_old_timespec structure definition from the header? > +#if defined(SYS_futex) > + if (sizeof(*timeout) == sizeof(struct __timespec32)) > + return syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3); > + > + if (timeout && timeout->tv_sec == (long)timeout->tv_sec) { > + struct __timespec32 ts32; > + > + ts32.tv_sec = (__kernel_long_t) timeout->tv_sec; > + ts32.tv_nsec = (__kernel_long_t) timeout->tv_nsec; > + > + return syscall(SYS_futex, uaddr, op | opflags, val, ts32, uaddr2, val3); > + } else if (!timeout) { > + return syscall(SYS_futex, uaddr, op | opflags, val, NULL, uaddr2, val3); > + } > +#endif > + > + errno = ENOSYS; > + return -1; Similarly, I think just using the kernel's constants like __NR_futex instead of SYS_futex would be more appropriate here, this way you know if futex_time64 is available and don't have to do the emulation for running the binary on pre-5.1 kernels. Perf already uses __NR_perf_event_open, __NR_getcpu, and __NR_setns instead of the SYS_* versions. Arnd
diff --git a/tools/perf/bench/futex.h b/tools/perf/bench/futex.h index f80a4759ee79b..09c5596726c60 100644 --- a/tools/perf/bench/futex.h +++ b/tools/perf/bench/futex.h @@ -27,6 +27,12 @@ struct bench_futex_parameters { unsigned int nrequeue; }; +/* A version of 'struct timespec' with 32-bit time_t and nanoseconds. */ +struct __timespec32 { + __kernel_long_t tv_sec; + __kernel_long_t tv_nsec; +}; + /** * futex_syscall() - SYS_futex syscall wrapper * @uaddr: address of first futex @@ -49,14 +55,49 @@ static inline int futex_syscall(u_int32_t *uaddr, int op, u_int32_t val, struct timespec *timeout, u_int32_t *uaddr2, int val3, int opflags) { - return syscall(SYS_futex, uaddr, op | opflags, val, ts32, uaddr2, val3); +#if defined(SYS_futex_time64) + if (sizeof(*timeout) != sizeof(struct __timespec32)) { + int ret = syscall(SYS_futex_time64, uaddr, op | opflags, val, timeout, + uaddr2, val3); + if (ret == 0 || errno != ENOSYS) + return ret; + } +#endif + +#if defined(SYS_futex) + if (sizeof(*timeout) == sizeof(struct __timespec32)) + return syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3); + + if (timeout && timeout->tv_sec == (long)timeout->tv_sec) { + struct __timespec32 ts32; + + ts32.tv_sec = (__kernel_long_t) timeout->tv_sec; + ts32.tv_nsec = (__kernel_long_t) timeout->tv_nsec; + + return syscall(SYS_futex, uaddr, op | opflags, val, ts32, uaddr2, val3); + } else if (!timeout) { + return syscall(SYS_futex, uaddr, op | opflags, val, NULL, uaddr2, val3); + } +#endif + + errno = ENOSYS; + return -1; } static inline int futex_syscall_nr_requeue(u_int32_t *uaddr, int op, u_int32_t val, int nr_requeue, u_int32_t *uaddr2, int val3, int opflags) { +#if defined(SYS_futex_time64) + int ret = syscall(SYS_futex_time64, uaddr, op | opflags, val, nr_requeue, + uaddr2, val3); + if (ret == 0 || errno != ENOSYS) + return ret; +#endif + +#if defined(SYS_futex) return syscall(SYS_futex, uaddr, op | opflags, val, nr_requeue, uaddr2, val3); +#endif } /**