selftests/powerpc: Check that signals always get delivered
Signed-off-by: Cyril Bur <cyrilbur@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
Родитель
8e03bd4e70
Коммит
ef186331b4
|
@ -19,6 +19,7 @@ SUB_DIRS = alignment \
|
|||
dscr \
|
||||
mm \
|
||||
pmu \
|
||||
signal \
|
||||
primitives \
|
||||
stringloops \
|
||||
switch_endian \
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
TEST_PROGS := signal signal_tm
|
||||
|
||||
all: $(TEST_PROGS)
|
||||
|
||||
$(TEST_PROGS): ../harness.c ../utils.c signal.S
|
||||
|
||||
CFLAGS += -maltivec
|
||||
signal_tm: CFLAGS += -mhtm
|
||||
|
||||
include ../../lib.mk
|
||||
|
||||
clean:
|
||||
rm -f $(TEST_PROGS) *.o
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2015, Cyril Bur, IBM Corp.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "../basic_asm.h"
|
||||
|
||||
/* long signal_self(pid_t pid, int sig); */
|
||||
FUNC_START(signal_self)
|
||||
li r0,37 /* sys_kill */
|
||||
/* r3 already has our pid in it */
|
||||
/* r4 already has signal type in it */
|
||||
sc
|
||||
bc 4,3,1f
|
||||
subfze r3,r3
|
||||
1: blr
|
||||
FUNC_END(signal_self)
|
||||
|
||||
/* long tm_signal_self(pid_t pid, int sig, int *ret); */
|
||||
FUNC_START(tm_signal_self)
|
||||
PUSH_BASIC_STACK(8)
|
||||
std r5,STACK_FRAME_PARAM(0)(sp) /* ret */
|
||||
tbegin.
|
||||
beq 1f
|
||||
tsuspend.
|
||||
li r0,37 /* sys_kill */
|
||||
/* r3 already has our pid in it */
|
||||
/* r4 already has signal type in it */
|
||||
sc
|
||||
ld r5,STACK_FRAME_PARAM(0)(sp) /* ret */
|
||||
bc 4,3,2f
|
||||
subfze r3,r3
|
||||
2: std r3,0(r5)
|
||||
tabort. 0
|
||||
tresume. /* Be nice to some cleanup, jumps back to tbegin then to 1: */
|
||||
/*
|
||||
* Transaction should be proper doomed and we should never get
|
||||
* here
|
||||
*/
|
||||
li r3,1
|
||||
POP_BASIC_STACK(8)
|
||||
blr
|
||||
1: li r3,0
|
||||
POP_BASIC_STACK(8)
|
||||
blr
|
||||
FUNC_END(tm_signal_self)
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright 2016, Cyril Bur, IBM Corp.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Sending one self a signal should always get delivered.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <altivec.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define MAX_ATTEMPT 500000
|
||||
#define TIMEOUT 5
|
||||
|
||||
extern long signal_self(pid_t pid, int sig);
|
||||
|
||||
static sig_atomic_t signaled;
|
||||
static sig_atomic_t fail;
|
||||
|
||||
static void signal_handler(int sig)
|
||||
{
|
||||
if (sig == SIGUSR1)
|
||||
signaled = 1;
|
||||
else
|
||||
fail = 1;
|
||||
}
|
||||
|
||||
static int test_signal()
|
||||
{
|
||||
int i;
|
||||
struct sigaction act;
|
||||
pid_t ppid = getpid();
|
||||
pid_t pid;
|
||||
|
||||
act.sa_handler = signal_handler;
|
||||
act.sa_flags = 0;
|
||||
sigemptyset(&act.sa_mask);
|
||||
if (sigaction(SIGUSR1, &act, NULL) < 0) {
|
||||
perror("sigaction SIGUSR1");
|
||||
exit(1);
|
||||
}
|
||||
if (sigaction(SIGALRM, &act, NULL) < 0) {
|
||||
perror("sigaction SIGALRM");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Don't do this for MAX_ATTEMPT, its simply too long */
|
||||
for(i = 0; i < 1000; i++) {
|
||||
pid = fork();
|
||||
if (pid == -1) {
|
||||
perror("fork");
|
||||
exit(1);
|
||||
}
|
||||
if (pid == 0) {
|
||||
signal_self(ppid, SIGUSR1);
|
||||
exit(1);
|
||||
} else {
|
||||
alarm(0); /* Disable any pending */
|
||||
alarm(2);
|
||||
while (!signaled && !fail)
|
||||
asm volatile("": : :"memory");
|
||||
if (!signaled) {
|
||||
fprintf(stderr, "Didn't get signal from child\n");
|
||||
FAIL_IF(1); /* For the line number */
|
||||
}
|
||||
/* Otherwise we'll loop too fast and fork() will eventually fail */
|
||||
waitpid(pid, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_ATTEMPT; i++) {
|
||||
long rc;
|
||||
|
||||
alarm(0); /* Disable any pending */
|
||||
signaled = 0;
|
||||
alarm(TIMEOUT);
|
||||
rc = signal_self(ppid, SIGUSR1);
|
||||
if (rc) {
|
||||
fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx",
|
||||
i, fail, rc);
|
||||
FAIL_IF(1); /* For the line number */
|
||||
}
|
||||
while (!signaled && !fail)
|
||||
asm volatile("": : :"memory");
|
||||
if (!signaled) {
|
||||
fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx",
|
||||
i, fail, rc);
|
||||
FAIL_IF(1); /* For the line number */
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_harness_set_timeout(300);
|
||||
return test_harness(test_signal, "signal");
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright 2016, Cyril Bur, IBM Corp.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Sending one self a signal should always get delivered.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <altivec.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "../tm/tm.h"
|
||||
|
||||
#define MAX_ATTEMPT 500000
|
||||
#define TIMEOUT 10
|
||||
|
||||
extern long tm_signal_self(pid_t pid, int sig, long *ret);
|
||||
|
||||
static sig_atomic_t signaled;
|
||||
static sig_atomic_t fail;
|
||||
|
||||
static void signal_handler(int sig)
|
||||
{
|
||||
if (tcheck_active()) {
|
||||
fail = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sig == SIGUSR1)
|
||||
signaled = 1;
|
||||
else
|
||||
fail = 1;
|
||||
}
|
||||
|
||||
static int test_signal_tm()
|
||||
{
|
||||
int i;
|
||||
struct sigaction act;
|
||||
|
||||
act.sa_handler = signal_handler;
|
||||
act.sa_flags = 0;
|
||||
sigemptyset(&act.sa_mask);
|
||||
if (sigaction(SIGUSR1, &act, NULL) < 0) {
|
||||
perror("sigaction SIGUSR1");
|
||||
exit(1);
|
||||
}
|
||||
if (sigaction(SIGALRM, &act, NULL) < 0) {
|
||||
perror("sigaction SIGALRM");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SKIP_IF(!have_htm());
|
||||
|
||||
for (i = 0; i < MAX_ATTEMPT; i++) {
|
||||
/*
|
||||
* If anything bad happens in ASM and we fail to set ret
|
||||
* because *handwave* TM this will cause failure
|
||||
*/
|
||||
long ret = 0xdead;
|
||||
long rc = 0xbeef;
|
||||
|
||||
alarm(0); /* Disable any pending */
|
||||
signaled = 0;
|
||||
alarm(TIMEOUT);
|
||||
FAIL_IF(tcheck_transactional());
|
||||
rc = tm_signal_self(getpid(), SIGUSR1, &ret);
|
||||
if (ret == 0xdead)
|
||||
/*
|
||||
* This basically means the transaction aborted before we
|
||||
* even got to the suspend... this is crazy but it
|
||||
* happens.
|
||||
* Yes this also means we might never make forward
|
||||
* progress... the alarm() will trip eventually...
|
||||
*/
|
||||
continue;
|
||||
|
||||
if (rc || ret) {
|
||||
/* Ret is actually an errno */
|
||||
printf("TEXASR 0x%016lx, TFIAR 0x%016lx\n",
|
||||
__builtin_get_texasr(), __builtin_get_tfiar());
|
||||
fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx ret=0x%lx\n",
|
||||
i, fail, rc, ret);
|
||||
FAIL_IF(ret);
|
||||
}
|
||||
while(!signaled && !fail)
|
||||
asm volatile("": : :"memory");
|
||||
if (!signaled) {
|
||||
fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx ret=0x%lx\n",
|
||||
i, fail, rc, ret);
|
||||
FAIL_IF(fail); /* For the line number */
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return test_harness(test_signal_tm, "signal_tm");
|
||||
}
|
Загрузка…
Ссылка в новой задаче