Signed-off-by: Cyril Bur <cyril...@gmail.com> --- .../selftests/powerpc/tm/tm-signal-context-chk.c | 102 +++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 tools/testing/selftests/powerpc/tm/tm-signal-context-chk.c
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk.c new file mode 100644 index 0000000..4c906cf --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk.c @@ -0,0 +1,102 @@ +/* + * Copyright 2016, Cyril Bur, IBM Corp. + * Licensed under GPLv2. + * + * Test the kernel's signal frame code. + * + * The kernel sets up two sets of ucontexts if the signal was to be delivered + * while the thread was in a transaction. Expected behaviour is that the + * currently executing code is in the first and the checkpointed state (the + * state that will be rolled back to) is in the uc_link ucontext. + * + * The reason for this is that code which is not TM aware and installs a signal + * handler will expect to see/modify its currently running state in the uc, + * this code may have dynamicially linked against code which is TM aware and is + * doing HTM under the hood. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> +#include <unistd.h> + +#include "utils.h" +#include "tm.h" + +#define TBEGIN ".long 0x7C00051D ;" +#define TSUSPEND ".long 0x7C0005DD ;" +#define TRESUME ".long 0x7C2005DD ;" +#define MAX_ATTEMPT 100 + +static double fps[] = { 1, 2, 3, 4, 5, 6, 7, 8, + -1, -2, -3, -4, -5, -6, -7, -8 }; + +extern long tm_signal_self(pid_t pid, double *fps); + +static int signaled; +static int fail; + +static void signal_usr1(int signum, siginfo_t *info, void *uc) +{ + int i; + ucontext_t *ucp = uc; + ucontext_t *tm_ucp = ucp->uc_link; + + signaled = 1; + + /* Always be 64bit, don't really care about 32bit */ + for (i = 0; i < 8 && !fail; i++) { + fail = (ucp->uc_mcontext.gp_regs[i + 14] != i); + fail |= (tm_ucp->uc_mcontext.gp_regs[i + 14] != 0xFF - i); + } + if (fail) { + printf("Failed on %d gpr %lu or %lu\n", i - 1, ucp->uc_mcontext.gp_regs[i + 13], tm_ucp->uc_mcontext.gp_regs[i + 13]); + return; + } + for (i = 0; i < 8 && !fail; i++) { + fail = (ucp->uc_mcontext.fp_regs[i + 14] != fps[i]); + fail |= (tm_ucp->uc_mcontext.fp_regs[i + 14] != fps[i + 8]); + } + if (fail) { + printf("Failed on %d FP %g or %g\n", i - 1, ucp->uc_mcontext.fp_regs[i + 13], tm_ucp->uc_mcontext.fp_regs[i + 13]); + } +} + +static int tm_signal_context_chk() +{ + struct sigaction act; + int i; + long rc; + pid_t pid = getpid(); + + SKIP_IF(!have_htm()); + + act.sa_sigaction = signal_usr1; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + if (sigaction(SIGUSR1, &act, NULL) < 0) { + perror("sigaction sigusr1"); + exit(1); + } + + i = 0; + while (!signaled && i < MAX_ATTEMPT) { + rc = tm_signal_self(pid, fps); + if (!rc) { + fprintf(stderr, "Transaction was not doomed...\n"); + FAIL_IF(!rc); + } + i++; + } + + if (i == MAX_ATTEMPT) { + fprintf(stderr, "Tried to signal %d times and didn't work, failing!\n", MAX_ATTEMPT); + fail = 1; + } + return fail; +} + +int main(void) +{ + return test_harness(tm_signal_context_chk, "tm_signal_context_chk"); +} -- 2.9.0 _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev