/minix/tests/t40f.c

https://gitlab.com/storedmirrors/minix · C · 193 lines · 126 code · 39 blank · 28 comment · 35 complexity · 6520ffa9c00505f3df86fc06610f63fa MD5 · raw file

  1. /* t40f.c
  2. *
  3. * Test timing
  4. *
  5. * Select works on regular files, (pseudo) terminal devices, streams-based
  6. * files, FIFOs, pipes, and sockets. This test verifies selecting with a time
  7. * out set.
  8. */
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <unistd.h>
  12. #include <sys/types.h>
  13. #include <sys/select.h>
  14. #include <sys/wait.h>
  15. #include <sys/time.h>
  16. #include <time.h>
  17. #include <errno.h>
  18. #include <string.h>
  19. #include <signal.h>
  20. #include "common.h"
  21. #define DO_HANDLEDATA 1
  22. #define DO_PAUSE 3
  23. #define DO_TIMEOUT 7
  24. #define DO_DELTA 0.5
  25. #define MAX_ERROR 5
  26. #define DELTA(x,y) (x.tv_sec - y.tv_sec) * system_hz \
  27. + (x.tv_usec - y.tv_usec) * system_hz / 1000000
  28. int got_signal = 0;
  29. int fd_ap[2];
  30. int system_hz;
  31. static void catch_signal(int sig_no) {
  32. got_signal = 1;
  33. }
  34. static float compute_diff(struct timeval start, struct timeval end, float compare) {
  35. /* Compute time difference. It is assumed that the value of start <= end. */
  36. clock_t delta;
  37. int seconds, hundreths;
  38. float diff;
  39. delta = DELTA(end, start); /* delta is in ticks */
  40. seconds = (int) (delta / system_hz);
  41. hundreths = (int) (delta * 100 / system_hz) - (seconds * 100);
  42. diff = seconds + (hundreths / 100.0);
  43. diff -= compare;
  44. if(diff < 0) diff *= -1; /* Make diff a positive value */
  45. return diff;
  46. }
  47. static void do_child(void) {
  48. struct timeval tv;
  49. /* Let the parent do initial read and write tests from and to the pipe. */
  50. tv.tv_sec = DO_PAUSE + DO_PAUSE + 1;
  51. tv.tv_usec = 0;
  52. (void) select(0, NULL, NULL, NULL, &tv);
  53. /* At this point the parent has a pending select with a DO_TIMEOUT timeout.
  54. We're going to interrupt by sending a signal */
  55. if(kill(getppid(), SIGUSR1) < 0) perror("Failed to send signal");
  56. exit(0);
  57. }
  58. static void do_parent(int child) {
  59. fd_set fds_read;
  60. struct timeval tv, start_time, end_time;
  61. int retval;
  62. /* Install signal handler for SIGUSR1 */
  63. signal(SIGUSR1, catch_signal);
  64. /* Parent and child share an anonymous pipe. Select for read and wait for the
  65. timeout to occur. We wait for DO_PAUSE seconds. Let's see if that's
  66. approximately right.*/
  67. FD_ZERO(&fds_read);
  68. FD_SET(fd_ap[0], &fds_read);
  69. tv.tv_sec = DO_PAUSE;
  70. tv.tv_usec = 0;
  71. (void) gettimeofday(&start_time, NULL); /* Record starting time */
  72. retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
  73. (void) gettimeofday(&end_time, NULL); /* Record ending time */
  74. /* Did we time out? */
  75. if(retval != 0) em(1, "Should have timed out");
  76. /* Approximately right? The standard does not specify how precise the timeout
  77. should be. Instead, the granularity is implementation-defined. In this
  78. test we assume that the difference should be no more than half a second.*/
  79. if(compute_diff(start_time, end_time, DO_PAUSE) > DO_DELTA)
  80. em(2, "Time difference too large");
  81. /* Let's wait for another DO_PAUSE seconds, expressed as microseconds */
  82. FD_ZERO(&fds_read);
  83. FD_SET(fd_ap[0], &fds_read);
  84. tv.tv_sec = 0;
  85. tv.tv_usec = DO_PAUSE * 1000000L;
  86. (void) gettimeofday(&start_time, NULL); /* Record starting time */
  87. retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
  88. (void) gettimeofday(&end_time, NULL); /* Record ending time */
  89. if(retval != -1) em(3, "Should have failed");
  90. if(errno != EINVAL) em(4, "Incorrect error thrown");
  91. /* Do a few more tests for invalid timeout values. */
  92. tv.tv_sec = 0;
  93. tv.tv_usec = 1000000;
  94. retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
  95. if (retval != -1) em(0, "Should have failed");
  96. if (errno != EINVAL) em(0, "Incorrect error thrown");
  97. tv.tv_sec = 0;
  98. tv.tv_usec = ~0;
  99. retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
  100. if (retval != -1) em(0, "Should have failed");
  101. if (errno != EINVAL) em(0, "Incorrect error thrown");
  102. /* Let's wait for another DO_PAUSE seconds, expressed in seconds and micro
  103. seconds. */
  104. FD_ZERO(&fds_read);
  105. FD_SET(fd_ap[0], &fds_read);
  106. tv.tv_sec = DO_PAUSE - 1;
  107. tv.tv_usec = 999999L; /* close enough */
  108. (void) gettimeofday(&start_time, NULL); /* Record starting time */
  109. retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
  110. (void) gettimeofday(&end_time, NULL); /* Record ending time */
  111. if(retval != 0) em(5, "Should have timed out");
  112. if(compute_diff(start_time, end_time, DO_PAUSE) > DO_DELTA)
  113. em(6, "Time difference too large");
  114. /* Finally, we test if our timeout is interrupted by a signal */
  115. FD_ZERO(&fds_read);
  116. FD_SET(fd_ap[0], &fds_read);
  117. tv.tv_sec = DO_TIMEOUT;
  118. tv.tv_usec = 0;
  119. (void) gettimeofday(&start_time, NULL); /* Record starting time */
  120. retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
  121. (void) gettimeofday(&end_time, NULL); /* Record ending time */
  122. if(retval != -1) em(7, "Should have been interrupted");
  123. if(compute_diff(start_time, end_time, DO_TIMEOUT) < DO_DELTA)
  124. em(8, "Failed to get interrupted by a signal");
  125. if(!got_signal) em(9, "Failed to get interrupted by a signal");
  126. waitpid(child, &retval, 0);
  127. exit(errct);
  128. }
  129. int main(int argc, char **argv) {
  130. int forkres;
  131. /* Retrieve actual system frequency. */
  132. system_hz = sysconf(_SC_CLK_TCK);
  133. /* Get subtest number */
  134. if(argc != 2) {
  135. printf("Usage: %s subtest_no\n", argv[0]);
  136. exit(-2);
  137. } else if(sscanf(argv[1], "%d", &subtest) != 1) {
  138. printf("Usage: %s subtest_no\n", argv[0]);
  139. exit(-2);
  140. }
  141. /* Set up anonymous pipe */
  142. if(pipe(fd_ap) < 0) {
  143. perror("Could not create anonymous pipe");
  144. exit(-1);
  145. }
  146. forkres = fork();
  147. if(forkres == 0) do_child();
  148. else if(forkres > 0) do_parent(forkres);
  149. else { /* Fork failed */
  150. perror("Unable to fork");
  151. exit(-1);
  152. }
  153. exit(-2); /* We're not supposed to get here. Both do_* routines should exit*/
  154. }