Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright 2015, Cyril Bur, IBM Corp.
0004  *
0005  * This test attempts to see if the FPU registers are correctly reported in a
0006  * signal context. Each worker just spins checking its FPU registers, at some
0007  * point a signal will interrupt it and C code will check the signal context
0008  * ensuring it is also the same.
0009  */
0010 
0011 #include <stdio.h>
0012 #include <unistd.h>
0013 #include <sys/syscall.h>
0014 #include <sys/time.h>
0015 #include <sys/types.h>
0016 #include <sys/wait.h>
0017 #include <stdlib.h>
0018 #include <pthread.h>
0019 
0020 #include "utils.h"
0021 
0022 /* Number of times each thread should receive the signal */
0023 #define ITERATIONS 10
0024 /*
0025  * Factor by which to multiply number of online CPUs for total number of
0026  * worker threads
0027  */
0028 #define THREAD_FACTOR 8
0029 
0030 __thread double darray[] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
0031              1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0,
0032              2.1};
0033 
0034 bool bad_context;
0035 int threads_starting;
0036 int running;
0037 
0038 extern long preempt_fpu(double *darray, int *threads_starting, int *running);
0039 
0040 void signal_fpu_sig(int sig, siginfo_t *info, void *context)
0041 {
0042     int i;
0043     ucontext_t *uc = context;
0044     mcontext_t *mc = &uc->uc_mcontext;
0045 
0046     /* Only the non volatiles were loaded up */
0047     for (i = 14; i < 32; i++) {
0048         if (mc->fp_regs[i] != darray[i - 14]) {
0049             bad_context = true;
0050             break;
0051         }
0052     }
0053 }
0054 
0055 void *signal_fpu_c(void *p)
0056 {
0057     int i;
0058     long rc;
0059     struct sigaction act;
0060     act.sa_sigaction = signal_fpu_sig;
0061     act.sa_flags = SA_SIGINFO;
0062     rc = sigaction(SIGUSR1, &act, NULL);
0063     if (rc)
0064         return p;
0065 
0066     srand(pthread_self());
0067     for (i = 0; i < 21; i++)
0068         darray[i] = rand();
0069 
0070     rc = preempt_fpu(darray, &threads_starting, &running);
0071 
0072     return (void *) rc;
0073 }
0074 
0075 int test_signal_fpu(void)
0076 {
0077     int i, j, rc, threads;
0078     void *rc_p;
0079     pthread_t *tids;
0080 
0081     threads = sysconf(_SC_NPROCESSORS_ONLN) * THREAD_FACTOR;
0082     tids = malloc(threads * sizeof(pthread_t));
0083     FAIL_IF(!tids);
0084 
0085     running = true;
0086     threads_starting = threads;
0087     for (i = 0; i < threads; i++) {
0088         rc = pthread_create(&tids[i], NULL, signal_fpu_c, NULL);
0089         FAIL_IF(rc);
0090     }
0091 
0092     setbuf(stdout, NULL);
0093     printf("\tWaiting for all workers to start...");
0094     while (threads_starting)
0095         asm volatile("": : :"memory");
0096     printf("done\n");
0097 
0098     printf("\tSending signals to all threads %d times...", ITERATIONS);
0099     for (i = 0; i < ITERATIONS; i++) {
0100         for (j = 0; j < threads; j++) {
0101             pthread_kill(tids[j], SIGUSR1);
0102         }
0103         sleep(1);
0104     }
0105     printf("done\n");
0106 
0107     printf("\tStopping workers...");
0108     running = 0;
0109     for (i = 0; i < threads; i++) {
0110         pthread_join(tids[i], &rc_p);
0111 
0112         /*
0113          * Harness will say the fail was here, look at why signal_fpu
0114          * returned
0115          */
0116         if ((long) rc_p || bad_context)
0117             printf("oops\n");
0118         if (bad_context)
0119             fprintf(stderr, "\t!! bad_context is true\n");
0120         FAIL_IF((long) rc_p || bad_context);
0121     }
0122     printf("done\n");
0123 
0124     free(tids);
0125     return 0;
0126 }
0127 
0128 int main(int argc, char *argv[])
0129 {
0130     return test_harness(test_signal_fpu, "fpu_signal");
0131 }