5 * Select works on regular files, (pseudo) terminal devices, streams-based
6 * files, FIFOs, pipes, and sockets. This test verifies selecting with a time
13 #include <sys/types.h>
14 #include <sys/select.h>
22 #define DO_HANDLEDATA 1
27 #define DELTA(x,y) (x.tv_sec - y.tv_sec) * CLOCKS_PER_SEC \
28 + (x.tv_usec - y.tv_usec) * CLOCKS_PER_SEC / 1000000
30 int errct
= 0, subtest
= -1, got_signal
= 0;
33 void catch_signal(int sig_no
) {
37 void e(int n
, char *s
) {
38 printf("Subtest %d, error %d, %s\n", subtest
, n
, s
);
40 if (errct
++ > MAX_ERROR
) {
41 printf("Too many errors; test aborted\n");
46 float compute_diff(struct timeval start
, struct timeval end
, float compare
) {
47 /* Compute time difference. It is assumed that the value of start <= end. */
49 int seconds
, hundreths
;
52 delta
= DELTA(end
, start
); /* delta is in ticks */
53 seconds
= (int) (delta
/ CLOCKS_PER_SEC
);
54 hundreths
= (int) (delta
* 100 / CLOCKS_PER_SEC
) - (seconds
* 100);
56 diff
= seconds
+ (hundreths
/ 100.0);
58 if(diff
< 0) diff
*= -1; /* Make diff a positive value */
67 /* Let the parent do initial read and write tests from and to the pipe. */
68 tv
.tv_sec
= DO_PAUSE
+ DO_PAUSE
+ DO_PAUSE
+ 1;
70 retval
= select(0, NULL
, NULL
, NULL
, &tv
);
72 /* At this point the parent has a pending select with a DO_TIMEOUT timeout.
73 We're going to interrupt by sending a signal */
74 if(kill(getppid(), SIGUSR1
) < 0) perror("Failed to send signal");
79 void do_parent(int child
) {
81 struct timeval tv
, start_time
, end_time
;
84 /* Install signal handler for SIGUSR1 */
85 signal(SIGUSR1
, catch_signal
);
87 /* Parent and child share an anonymous pipe. Select for read and wait for the
88 timeout to occur. We wait for DO_PAUSE seconds. Let's see if that's
89 approximately right.*/
91 FD_SET(fd_ap
[0], &fds_read
);
95 (void) gettimeofday(&start_time
, NULL
); /* Record starting time */
96 retval
= select(fd_ap
[0]+1, &fds_read
, NULL
, NULL
, &tv
);
97 (void) gettimeofday(&end_time
, NULL
); /* Record ending time */
99 /* Did we time out? */
100 if(retval
!= 0) e(1, "Should have timed out");
102 /* Approximately right? The standard does not specify how precise the timeout
103 should be. Instead, the granularity is implementation-defined. In this
104 test we assume that the difference should be no more than half a second.*/
105 if(compute_diff(start_time
, end_time
, DO_PAUSE
) > DO_DELTA
)
106 e(2, "Time difference too large");
108 /* Let's wait for another DO_PAUSE seconds, expressed as microseconds */
110 FD_SET(fd_ap
[0], &fds_read
);
112 tv
.tv_usec
= DO_PAUSE
* 1000000L;
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 */
118 if(retval
!= 0) e(3, "Should have timed out");
119 if(compute_diff(start_time
, end_time
, DO_PAUSE
) > DO_DELTA
)
120 e(4, "Time difference too large");
122 /* Let's wait for another DO_PAUSE seconds, expressed in seconds and micro
125 FD_SET(fd_ap
[0], &fds_read
);
126 tv
.tv_sec
= DO_PAUSE
- 1;
127 tv
.tv_usec
= (DO_PAUSE
- tv
.tv_sec
) * 1000000L;
129 (void) gettimeofday(&start_time
, NULL
); /* Record starting time */
130 retval
= select(fd_ap
[0]+1, &fds_read
, NULL
, NULL
, &tv
);
131 (void) gettimeofday(&end_time
, NULL
); /* Record ending time */
133 if(retval
!= 0) e(5, "Should have timed out");
134 if(compute_diff(start_time
, end_time
, DO_PAUSE
) > DO_DELTA
)
135 e(6, "Time difference too large");
137 /* Finally, we test if our timeout is interrupted by a signal */
139 FD_SET(fd_ap
[0], &fds_read
);
140 tv
.tv_sec
= DO_TIMEOUT
;
143 (void) gettimeofday(&start_time
, NULL
); /* Record starting time */
144 retval
= select(fd_ap
[0]+1, &fds_read
, NULL
, NULL
, &tv
);
145 (void) gettimeofday(&end_time
, NULL
); /* Record ending time */
147 if(retval
!= -1) e(7, "Should have been interrupted");
148 if(compute_diff(start_time
, end_time
, DO_TIMEOUT
) < DO_DELTA
)
149 e(8, "Failed to get interrupted by a signal");
151 if(!got_signal
) e(9, "Failed to get interrupted by a signal");
153 waitpid(child
, &retval
, 0);
157 int main(int argc
, char **argv
) {
160 /* Get subtest number */
162 printf("Usage: %s subtest_no\n", argv
[0]);
164 } else if(sscanf(argv
[1], "%d", &subtest
) != 1) {
165 printf("Usage: %s subtest_no\n", argv
[0]);
169 /* Set up anonymous pipe */
170 if(pipe(fd_ap
) < 0) {
171 perror("Could not create anonymous pipe");
176 if(forkres
== 0) do_child();
177 else if(forkres
> 0) do_parent(forkres
);
178 else { /* Fork failed */
179 perror("Unable to fork");
183 exit(-2); /* We're not supposed to get here. Both do_* routines should exit*/