Skip to content

Commit 48e8c57

Browse files
cyrilbur-ibmmpe
authored andcommitted
selftests/powerpc: Test FPU and VMX regs in signal ucontext
Load up the non volatile FPU and VMX regs and ensure that they are the expected value in a signal handler Signed-off-by: Cyril Bur <cyrilbur@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
1 parent e5ab8be commit 48e8c57

File tree

4 files changed

+296
-1
lines changed

4 files changed

+296
-1
lines changed

tools/testing/selftests/powerpc/math/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ fpu_syscall
22
vmx_syscall
33
fpu_preempt
44
vmx_preempt
5+
fpu_signal
6+
vmx_signal

tools/testing/selftests/powerpc/math/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
TEST_PROGS := fpu_syscall fpu_preempt vmx_syscall vmx_preempt
1+
TEST_PROGS := fpu_syscall fpu_preempt fpu_signal vmx_syscall vmx_preempt vmx_signal
22

33
all: $(TEST_PROGS)
44

@@ -7,9 +7,11 @@ $(TEST_PROGS): CFLAGS += -O2 -g -pthread -m64 -maltivec
77

88
fpu_syscall: fpu_asm.S
99
fpu_preempt: fpu_asm.S
10+
fpu_signal: fpu_asm.S
1011

1112
vmx_syscall: vmx_asm.S
1213
vmx_preempt: vmx_asm.S
14+
vmx_signal: vmx_asm.S
1315

1416
include ../../lib.mk
1517

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
* Copyright 2015, Cyril Bur, IBM Corp.
3+
*
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation; either version
7+
* 2 of the License, or (at your option) any later version.
8+
*
9+
* This test attempts to see if the FPU registers are correctly reported in a
10+
* signal context. Each worker just spins checking its FPU registers, at some
11+
* point a signal will interrupt it and C code will check the signal context
12+
* ensuring it is also the same.
13+
*/
14+
15+
#include <stdio.h>
16+
#include <unistd.h>
17+
#include <sys/syscall.h>
18+
#include <sys/time.h>
19+
#include <sys/types.h>
20+
#include <sys/wait.h>
21+
#include <stdlib.h>
22+
#include <pthread.h>
23+
24+
#include "utils.h"
25+
26+
/* Number of times each thread should receive the signal */
27+
#define ITERATIONS 10
28+
/*
29+
* Factor by which to multiply number of online CPUs for total number of
30+
* worker threads
31+
*/
32+
#define THREAD_FACTOR 8
33+
34+
__thread double darray[] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
35+
1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0,
36+
2.1};
37+
38+
bool bad_context;
39+
int threads_starting;
40+
int running;
41+
42+
extern long preempt_fpu(double *darray, int *threads_starting, int *running);
43+
44+
void signal_fpu_sig(int sig, siginfo_t *info, void *context)
45+
{
46+
int i;
47+
ucontext_t *uc = context;
48+
mcontext_t *mc = &uc->uc_mcontext;
49+
50+
/* Only the non volatiles were loaded up */
51+
for (i = 14; i < 32; i++) {
52+
if (mc->fp_regs[i] != darray[i - 14]) {
53+
bad_context = true;
54+
break;
55+
}
56+
}
57+
}
58+
59+
void *signal_fpu_c(void *p)
60+
{
61+
int i;
62+
long rc;
63+
struct sigaction act;
64+
act.sa_sigaction = signal_fpu_sig;
65+
act.sa_flags = SA_SIGINFO;
66+
rc = sigaction(SIGUSR1, &act, NULL);
67+
if (rc)
68+
return p;
69+
70+
srand(pthread_self());
71+
for (i = 0; i < 21; i++)
72+
darray[i] = rand();
73+
74+
rc = preempt_fpu(darray, &threads_starting, &running);
75+
76+
return (void *) rc;
77+
}
78+
79+
int test_signal_fpu(void)
80+
{
81+
int i, j, rc, threads;
82+
void *rc_p;
83+
pthread_t *tids;
84+
85+
threads = sysconf(_SC_NPROCESSORS_ONLN) * THREAD_FACTOR;
86+
tids = malloc(threads * sizeof(pthread_t));
87+
FAIL_IF(!tids);
88+
89+
running = true;
90+
threads_starting = threads;
91+
for (i = 0; i < threads; i++) {
92+
rc = pthread_create(&tids[i], NULL, signal_fpu_c, NULL);
93+
FAIL_IF(rc);
94+
}
95+
96+
setbuf(stdout, NULL);
97+
printf("\tWaiting for all workers to start...");
98+
while (threads_starting)
99+
asm volatile("": : :"memory");
100+
printf("done\n");
101+
102+
printf("\tSending signals to all threads %d times...", ITERATIONS);
103+
for (i = 0; i < ITERATIONS; i++) {
104+
for (j = 0; j < threads; j++) {
105+
pthread_kill(tids[j], SIGUSR1);
106+
}
107+
sleep(1);
108+
}
109+
printf("done\n");
110+
111+
printf("\tStopping workers...");
112+
running = 0;
113+
for (i = 0; i < threads; i++) {
114+
pthread_join(tids[i], &rc_p);
115+
116+
/*
117+
* Harness will say the fail was here, look at why signal_fpu
118+
* returned
119+
*/
120+
if ((long) rc_p || bad_context)
121+
printf("oops\n");
122+
if (bad_context)
123+
fprintf(stderr, "\t!! bad_context is true\n");
124+
FAIL_IF((long) rc_p || bad_context);
125+
}
126+
printf("done\n");
127+
128+
free(tids);
129+
return 0;
130+
}
131+
132+
int main(int argc, char *argv[])
133+
{
134+
return test_harness(test_signal_fpu, "fpu_signal");
135+
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/*
2+
* Copyright 2015, Cyril Bur, IBM Corp.
3+
*
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation; either version
7+
* 2 of the License, or (at your option) any later version.
8+
*
9+
* This test attempts to see if the VMX registers are correctly reported in a
10+
* signal context. Each worker just spins checking its VMX registers, at some
11+
* point a signal will interrupt it and C code will check the signal context
12+
* ensuring it is also the same.
13+
*/
14+
15+
#include <stdio.h>
16+
#include <unistd.h>
17+
#include <sys/syscall.h>
18+
#include <sys/time.h>
19+
#include <sys/types.h>
20+
#include <sys/wait.h>
21+
#include <stdlib.h>
22+
#include <string.h>
23+
#include <pthread.h>
24+
#include <altivec.h>
25+
26+
#include "utils.h"
27+
28+
/* Number of times each thread should receive the signal */
29+
#define ITERATIONS 10
30+
/*
31+
* Factor by which to multiply number of online CPUs for total number of
32+
* worker threads
33+
*/
34+
#define THREAD_FACTOR 8
35+
36+
__thread vector int varray[] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10,11,12},
37+
{13,14,15,16},{17,18,19,20},{21,22,23,24},
38+
{25,26,27,28},{29,30,31,32},{33,34,35,36},
39+
{37,38,39,40},{41,42,43,44},{45,46,47,48}};
40+
41+
bool bad_context;
42+
int running;
43+
int threads_starting;
44+
45+
extern int preempt_vmx(vector int *varray, int *threads_starting, int *sentinal);
46+
47+
void signal_vmx_sig(int sig, siginfo_t *info, void *context)
48+
{
49+
int i;
50+
ucontext_t *uc = context;
51+
mcontext_t *mc = &uc->uc_mcontext;
52+
53+
/* Only the non volatiles were loaded up */
54+
for (i = 20; i < 32; i++) {
55+
if (memcmp(mc->v_regs->vrregs[i], &varray[i - 20], 16)) {
56+
int j;
57+
/*
58+
* Shouldn't printf() in a signal handler, however, this is a
59+
* test and we've detected failure. Understanding what failed
60+
* is paramount. All that happens after this is tests exit with
61+
* failure.
62+
*/
63+
printf("VMX mismatch at reg %d!\n", i);
64+
printf("Reg | Actual | Expected\n");
65+
for (j = 20; j < 32; j++) {
66+
printf("%d | 0x%04x%04x%04x%04x | 0x%04x%04x%04x%04x\n", j, mc->v_regs->vrregs[j][0],
67+
mc->v_regs->vrregs[j][1], mc->v_regs->vrregs[j][2], mc->v_regs->vrregs[j][3],
68+
varray[j - 20][0], varray[j - 20][1], varray[j - 20][2], varray[j - 20][3]);
69+
}
70+
bad_context = true;
71+
break;
72+
}
73+
}
74+
}
75+
76+
void *signal_vmx_c(void *p)
77+
{
78+
int i, j;
79+
long rc;
80+
struct sigaction act;
81+
act.sa_sigaction = signal_vmx_sig;
82+
act.sa_flags = SA_SIGINFO;
83+
rc = sigaction(SIGUSR1, &act, NULL);
84+
if (rc)
85+
return p;
86+
87+
srand(pthread_self());
88+
for (i = 0; i < 12; i++)
89+
for (j = 0; j < 4; j++)
90+
varray[i][j] = rand();
91+
92+
rc = preempt_vmx(varray, &threads_starting, &running);
93+
94+
return (void *) rc;
95+
}
96+
97+
int test_signal_vmx(void)
98+
{
99+
int i, j, rc, threads;
100+
void *rc_p;
101+
pthread_t *tids;
102+
103+
threads = sysconf(_SC_NPROCESSORS_ONLN) * THREAD_FACTOR;
104+
tids = malloc(threads * sizeof(pthread_t));
105+
FAIL_IF(!tids);
106+
107+
running = true;
108+
threads_starting = threads;
109+
for (i = 0; i < threads; i++) {
110+
rc = pthread_create(&tids[i], NULL, signal_vmx_c, NULL);
111+
FAIL_IF(rc);
112+
}
113+
114+
setbuf(stdout, NULL);
115+
printf("\tWaiting for %d workers to start... %d", threads, threads_starting);
116+
while (threads_starting) {
117+
asm volatile("": : :"memory");
118+
usleep(1000);
119+
printf(", %d", threads_starting);
120+
}
121+
printf(" ...done\n");
122+
123+
printf("\tSending signals to all threads %d times...", ITERATIONS);
124+
for (i = 0; i < ITERATIONS; i++) {
125+
for (j = 0; j < threads; j++) {
126+
pthread_kill(tids[j], SIGUSR1);
127+
}
128+
sleep(1);
129+
}
130+
printf("done\n");
131+
132+
printf("\tKilling workers...");
133+
running = 0;
134+
for (i = 0; i < threads; i++) {
135+
pthread_join(tids[i], &rc_p);
136+
137+
/*
138+
* Harness will say the fail was here, look at why signal_vmx
139+
* returned
140+
*/
141+
if ((long) rc_p || bad_context)
142+
printf("oops\n");
143+
if (bad_context)
144+
fprintf(stderr, "\t!! bad_context is true\n");
145+
FAIL_IF((long) rc_p || bad_context);
146+
}
147+
printf("done\n");
148+
149+
free(tids);
150+
return 0;
151+
}
152+
153+
int main(int argc, char *argv[])
154+
{
155+
return test_harness(test_signal_vmx, "vmx_signal");
156+
}

0 commit comments

Comments
 (0)