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 } 157