fpu_signal.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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. #include <stdio.h>
  15. #include <unistd.h>
  16. #include <sys/syscall.h>
  17. #include <sys/time.h>
  18. #include <sys/types.h>
  19. #include <sys/wait.h>
  20. #include <stdlib.h>
  21. #include <pthread.h>
  22. #include "utils.h"
  23. /* Number of times each thread should receive the signal */
  24. #define ITERATIONS 10
  25. /*
  26. * Factor by which to multiply number of online CPUs for total number of
  27. * worker threads
  28. */
  29. #define THREAD_FACTOR 8
  30. __thread double darray[] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
  31. 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0,
  32. 2.1};
  33. bool bad_context;
  34. int threads_starting;
  35. int running;
  36. extern long preempt_fpu(double *darray, int *threads_starting, int *running);
  37. void signal_fpu_sig(int sig, siginfo_t *info, void *context)
  38. {
  39. int i;
  40. ucontext_t *uc = context;
  41. mcontext_t *mc = &uc->uc_mcontext;
  42. /* Only the non volatiles were loaded up */
  43. for (i = 14; i < 32; i++) {
  44. if (mc->fp_regs[i] != darray[i - 14]) {
  45. bad_context = true;
  46. break;
  47. }
  48. }
  49. }
  50. void *signal_fpu_c(void *p)
  51. {
  52. int i;
  53. long rc;
  54. struct sigaction act;
  55. act.sa_sigaction = signal_fpu_sig;
  56. act.sa_flags = SA_SIGINFO;
  57. rc = sigaction(SIGUSR1, &act, NULL);
  58. if (rc)
  59. return p;
  60. srand(pthread_self());
  61. for (i = 0; i < 21; i++)
  62. darray[i] = rand();
  63. rc = preempt_fpu(darray, &threads_starting, &running);
  64. return (void *) rc;
  65. }
  66. int test_signal_fpu(void)
  67. {
  68. int i, j, rc, threads;
  69. void *rc_p;
  70. pthread_t *tids;
  71. threads = sysconf(_SC_NPROCESSORS_ONLN) * THREAD_FACTOR;
  72. tids = malloc(threads * sizeof(pthread_t));
  73. FAIL_IF(!tids);
  74. running = true;
  75. threads_starting = threads;
  76. for (i = 0; i < threads; i++) {
  77. rc = pthread_create(&tids[i], NULL, signal_fpu_c, NULL);
  78. FAIL_IF(rc);
  79. }
  80. setbuf(stdout, NULL);
  81. printf("\tWaiting for all workers to start...");
  82. while (threads_starting)
  83. asm volatile("": : :"memory");
  84. printf("done\n");
  85. printf("\tSending signals to all threads %d times...", ITERATIONS);
  86. for (i = 0; i < ITERATIONS; i++) {
  87. for (j = 0; j < threads; j++) {
  88. pthread_kill(tids[j], SIGUSR1);
  89. }
  90. sleep(1);
  91. }
  92. printf("done\n");
  93. printf("\tStopping workers...");
  94. running = 0;
  95. for (i = 0; i < threads; i++) {
  96. pthread_join(tids[i], &rc_p);
  97. /*
  98. * Harness will say the fail was here, look at why signal_fpu
  99. * returned
  100. */
  101. if ((long) rc_p || bad_context)
  102. printf("oops\n");
  103. if (bad_context)
  104. fprintf(stderr, "\t!! bad_context is true\n");
  105. FAIL_IF((long) rc_p || bad_context);
  106. }
  107. printf("done\n");
  108. free(tids);
  109. return 0;
  110. }
  111. int main(int argc, char *argv[])
  112. {
  113. return test_harness(test_signal_fpu, "fpu_signal");
  114. }