| /* | |
| * Copyright 2015, Michael Neuling, IBM Corp. | |
| * Licensed under GPLv2. | |
| * | |
| * Test the kernel's signal delievery code to ensure that we don't | |
| * trelaim twice in the kernel signal delivery code. This can happen | |
| * if we trigger a signal when in a transaction and the stack pointer | |
| * is bogus. | |
| * | |
| * This test case registers a SEGV handler, sets the stack pointer | |
| * (r1) to NULL, starts a transaction and then generates a SEGV. The | |
| * SEGV should be handled but we exit here as the stack pointer is | |
| * invalid and hance we can't sigreturn. We only need to check that | |
| * this flow doesn't crash the kernel. | |
| */ | |
| #include <unistd.h> | |
| #include <sys/types.h> | |
| #include <sys/wait.h> | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <signal.h> | |
| #include "utils.h" | |
| #include "tm.h" | |
| void signal_segv(int signum) | |
| { | |
| /* This should never actually run since stack is foobar */ | |
| exit(1); | |
| } | |
| int tm_signal_stack() | |
| { | |
| int pid; | |
| SKIP_IF(!have_htm()); | |
| pid = fork(); | |
| if (pid < 0) | |
| exit(1); | |
| if (pid) { /* Parent */ | |
| /* | |
| * It's likely the whole machine will crash here so if | |
| * the child ever exits, we are good. | |
| */ | |
| wait(NULL); | |
| return 0; | |
| } | |
| /* | |
| * The flow here is: | |
| * 1) register a signal handler (so signal delievery occurs) | |
| * 2) make stack pointer (r1) = NULL | |
| * 3) start transaction | |
| * 4) cause segv | |
| */ | |
| if (signal(SIGSEGV, signal_segv) == SIG_ERR) | |
| exit(1); | |
| asm volatile("li 1, 0 ;" /* stack ptr == NULL */ | |
| "1:" | |
| "tbegin.;" | |
| "beq 1b ;" /* retry forever */ | |
| "tsuspend.;" | |
| "ld 2, 0(1) ;" /* trigger segv" */ | |
| : : : "memory"); | |
| /* This should never get here due to above segv */ | |
| return 1; | |
| } | |
| int main(void) | |
| { | |
| return test_harness(tm_signal_stack, "tm_signal_stack"); | |
| } |