selftests/powerpc: Add transactional syscall test
Check that a syscall made during an active transaction will fail with the correct failure code and that one made during a suspended transaction will succeed. Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
parent
2b03fc1db5
commit
7fe924d9d7
|
@ -1 +1,2 @@
|
|||
tm-resched-dscr
|
||||
tm-syscall
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
PROGS := tm-resched-dscr
|
||||
PROGS := tm-resched-dscr tm-syscall
|
||||
|
||||
all: $(PROGS)
|
||||
|
||||
$(PROGS): ../harness.c
|
||||
|
||||
tm-syscall: tm-syscall-asm.S
|
||||
tm-syscall: CFLAGS += -mhtm
|
||||
|
||||
run_tests: all
|
||||
@-for PROG in $(PROGS); do \
|
||||
./$$PROG; \
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#include <ppc-asm.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
.text
|
||||
FUNC_START(getppid_tm_active)
|
||||
tbegin.
|
||||
beq 1f
|
||||
li r0, __NR_getppid
|
||||
sc
|
||||
tend.
|
||||
blr
|
||||
1:
|
||||
li r3, -1
|
||||
blr
|
||||
|
||||
FUNC_START(getppid_tm_suspended)
|
||||
tbegin.
|
||||
beq 1f
|
||||
li r0, __NR_getppid
|
||||
tsuspend.
|
||||
sc
|
||||
tresume.
|
||||
tend.
|
||||
blr
|
||||
1:
|
||||
li r3, -1
|
||||
blr
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright 2015, Sam Bobroff, IBM Corp.
|
||||
* Licensed under GPLv2.
|
||||
*
|
||||
* Test the kernel's system call code to ensure that a system call
|
||||
* made from within an active HTM transaction is aborted with the
|
||||
* correct failure code.
|
||||
* Conversely, ensure that a system call made from within a
|
||||
* suspended transaction can succeed.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <asm/tm.h>
|
||||
#include <asm/cputable.h>
|
||||
#include <linux/auxvec.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
extern int getppid_tm_active(void);
|
||||
extern int getppid_tm_suspended(void);
|
||||
|
||||
unsigned retries = 0;
|
||||
|
||||
#define TEST_DURATION 10 /* seconds */
|
||||
#define TM_RETRIES 100
|
||||
|
||||
long failure_code(void)
|
||||
{
|
||||
return __builtin_get_texasru() >> 24;
|
||||
}
|
||||
|
||||
bool failure_is_persistent(void)
|
||||
{
|
||||
return (failure_code() & TM_CAUSE_PERSISTENT) == TM_CAUSE_PERSISTENT;
|
||||
}
|
||||
|
||||
bool failure_is_syscall(void)
|
||||
{
|
||||
return (failure_code() & TM_CAUSE_SYSCALL) == TM_CAUSE_SYSCALL;
|
||||
}
|
||||
|
||||
pid_t getppid_tm(bool suspend)
|
||||
{
|
||||
int i;
|
||||
pid_t pid;
|
||||
|
||||
for (i = 0; i < TM_RETRIES; i++) {
|
||||
if (suspend)
|
||||
pid = getppid_tm_suspended();
|
||||
else
|
||||
pid = getppid_tm_active();
|
||||
|
||||
if (pid >= 0)
|
||||
return pid;
|
||||
|
||||
if (failure_is_persistent()) {
|
||||
if (failure_is_syscall())
|
||||
return -1;
|
||||
|
||||
printf("Unexpected persistent transaction failure.\n");
|
||||
printf("TEXASR 0x%016lx, TFIAR 0x%016lx.\n",
|
||||
__builtin_get_texasr(), __builtin_get_tfiar());
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
retries++;
|
||||
}
|
||||
|
||||
printf("Exceeded limit of %d temporary transaction failures.\n", TM_RETRIES);
|
||||
printf("TEXASR 0x%016lx, TFIAR 0x%016lx.\n",
|
||||
__builtin_get_texasr(), __builtin_get_tfiar());
|
||||
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int tm_syscall(void)
|
||||
{
|
||||
unsigned count = 0;
|
||||
struct timeval end, now;
|
||||
|
||||
SKIP_IF(!((long)get_auxv_entry(AT_HWCAP2) & PPC_FEATURE2_HTM));
|
||||
setbuf(stdout, NULL);
|
||||
|
||||
printf("Testing transactional syscalls for %d seconds...\n", TEST_DURATION);
|
||||
|
||||
gettimeofday(&end, NULL);
|
||||
now.tv_sec = TEST_DURATION;
|
||||
now.tv_usec = 0;
|
||||
timeradd(&end, &now, &end);
|
||||
|
||||
for (count = 0; timercmp(&now, &end, <); count++) {
|
||||
/*
|
||||
* Test a syscall within a suspended transaction and verify
|
||||
* that it succeeds.
|
||||
*/
|
||||
FAIL_IF(getppid_tm(true) == -1); /* Should succeed. */
|
||||
|
||||
/*
|
||||
* Test a syscall within an active transaction and verify that
|
||||
* it fails with the correct failure code.
|
||||
*/
|
||||
FAIL_IF(getppid_tm(false) != -1); /* Should fail... */
|
||||
FAIL_IF(!failure_is_persistent()); /* ...persistently... */
|
||||
FAIL_IF(!failure_is_syscall()); /* ...with code syscall. */
|
||||
gettimeofday(&now, 0);
|
||||
}
|
||||
|
||||
printf("%d active and suspended transactions behaved correctly.\n", count);
|
||||
printf("(There were %d transaction retries.)\n", retries);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return test_harness(tm_syscall, "tm_syscall");
|
||||
}
|
Loading…
Reference in New Issue