PageRenderTime 56ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/test/t40f.c

http://www.minix3.org/
C | 184 lines | 121 code | 37 blank | 26 comment | 27 complexity | fded411b16cedf5fe001f8cbdaeccaa4 MD5 | raw file
Possible License(s): MIT, WTFPL, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.0, JSON, 0BSD
  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. #define DO_HANDLEDATA 1
  21. #define DO_PAUSE 3
  22. #define DO_TIMEOUT 7
  23. #define DO_DELTA 0.5
  24. #define MAX_ERROR 5
  25. #define DELTA(x,y) (x.tv_sec - y.tv_sec) * CLOCKS_PER_SEC \
  26. + (x.tv_usec - y.tv_usec) * CLOCKS_PER_SEC / 1000000
  27. int errct = 0, subtest = -1, got_signal = 0;
  28. int fd_ap[2];
  29. void catch_signal(int sig_no) {
  30. got_signal = 1;
  31. }
  32. void e(int n, char *s) {
  33. printf("Subtest %d, error %d, %s\n", subtest, n, s);
  34. if (errct++ > MAX_ERROR) {
  35. printf("Too many errors; test aborted\n");
  36. exit(errct);
  37. }
  38. }
  39. float compute_diff(struct timeval start, struct timeval end, float compare) {
  40. /* Compute time difference. It is assumed that the value of start <= end. */
  41. clock_t delta;
  42. int seconds, hundreths;
  43. float diff;
  44. delta = DELTA(end, start); /* delta is in ticks */
  45. seconds = (int) (delta / CLOCKS_PER_SEC);
  46. hundreths = (int) (delta * 100 / CLOCKS_PER_SEC) - (seconds * 100);
  47. diff = seconds + (hundreths / 100.0);
  48. diff -= compare;
  49. if(diff < 0) diff *= -1; /* Make diff a positive value */
  50. return diff;
  51. }
  52. void do_child(void) {
  53. struct timeval tv;
  54. /* Let the parent do initial read and write tests from and to the pipe. */
  55. tv.tv_sec = DO_PAUSE + DO_PAUSE + DO_PAUSE + 1;
  56. tv.tv_usec = 0;
  57. (void) select(0, NULL, NULL, NULL, &tv);
  58. /* At this point the parent has a pending select with a DO_TIMEOUT timeout.
  59. We're going to interrupt by sending a signal */
  60. if(kill(getppid(), SIGUSR1) < 0) perror("Failed to send signal");
  61. exit(0);
  62. }
  63. void do_parent(int child) {
  64. fd_set fds_read;
  65. struct timeval tv, start_time, end_time;
  66. int retval;
  67. /* Install signal handler for SIGUSR1 */
  68. signal(SIGUSR1, catch_signal);
  69. /* Parent and child share an anonymous pipe. Select for read and wait for the
  70. timeout to occur. We wait for DO_PAUSE seconds. Let's see if that's
  71. approximately right.*/
  72. FD_ZERO(&fds_read);
  73. FD_SET(fd_ap[0], &fds_read);
  74. tv.tv_sec = DO_PAUSE;
  75. tv.tv_usec = 0;
  76. (void) gettimeofday(&start_time, NULL); /* Record starting time */
  77. retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
  78. (void) gettimeofday(&end_time, NULL); /* Record ending time */
  79. /* Did we time out? */
  80. if(retval != 0) e(1, "Should have timed out");
  81. /* Approximately right? The standard does not specify how precise the timeout
  82. should be. Instead, the granularity is implementation-defined. In this
  83. test we assume that the difference should be no more than half a second.*/
  84. if(compute_diff(start_time, end_time, DO_PAUSE) > DO_DELTA)
  85. e(2, "Time difference too large");
  86. /* Let's wait for another DO_PAUSE seconds, expressed as microseconds */
  87. FD_ZERO(&fds_read);
  88. FD_SET(fd_ap[0], &fds_read);
  89. tv.tv_sec = 0;
  90. tv.tv_usec = DO_PAUSE * 1000000L;
  91. (void) gettimeofday(&start_time, NULL); /* Record starting time */
  92. retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
  93. (void) gettimeofday(&end_time, NULL); /* Record ending time */
  94. if(retval != 0) e(3, "Should have timed out");
  95. if(compute_diff(start_time, end_time, DO_PAUSE) > DO_DELTA)
  96. e(4, "Time difference too large");
  97. /* Let's wait for another DO_PAUSE seconds, expressed in seconds and micro
  98. seconds. */
  99. FD_ZERO(&fds_read);
  100. FD_SET(fd_ap[0], &fds_read);
  101. tv.tv_sec = DO_PAUSE - 1;
  102. tv.tv_usec = (DO_PAUSE - tv.tv_sec) * 1000000L;
  103. (void) gettimeofday(&start_time, NULL); /* Record starting time */
  104. retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
  105. (void) gettimeofday(&end_time, NULL); /* Record ending time */
  106. if(retval != 0) e(5, "Should have timed out");
  107. if(compute_diff(start_time, end_time, DO_PAUSE) > DO_DELTA)
  108. e(6, "Time difference too large");
  109. /* Finally, we test if our timeout is interrupted by a signal */
  110. FD_ZERO(&fds_read);
  111. FD_SET(fd_ap[0], &fds_read);
  112. tv.tv_sec = DO_TIMEOUT;
  113. tv.tv_usec = 0;
  114. (void) gettimeofday(&start_time, NULL); /* Record starting time */
  115. retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
  116. (void) gettimeofday(&end_time, NULL); /* Record ending time */
  117. if(retval != -1) e(7, "Should have been interrupted");
  118. if(compute_diff(start_time, end_time, DO_TIMEOUT) < DO_DELTA)
  119. e(8, "Failed to get interrupted by a signal");
  120. if(!got_signal) e(9, "Failed to get interrupted by a signal");
  121. waitpid(child, &retval, 0);
  122. exit(errct);
  123. }
  124. int main(int argc, char **argv) {
  125. int forkres;
  126. /* Get subtest number */
  127. if(argc != 2) {
  128. printf("Usage: %s subtest_no\n", argv[0]);
  129. exit(-2);
  130. } else if(sscanf(argv[1], "%d", &subtest) != 1) {
  131. printf("Usage: %s subtest_no\n", argv[0]);
  132. exit(-2);
  133. }
  134. /* Set up anonymous pipe */
  135. if(pipe(fd_ap) < 0) {
  136. perror("Could not create anonymous pipe");
  137. exit(-1);
  138. }
  139. forkres = fork();
  140. if(forkres == 0) do_child();
  141. else if(forkres > 0) do_parent(forkres);
  142. else { /* Fork failed */
  143. perror("Unable to fork");
  144. exit(-1);
  145. }
  146. exit(-2); /* We're not supposed to get here. Both do_* routines should exit*/
  147. }