include: reduce default stack size
[minix.git] / test / t40d.c
blob4a5285484695173c6f30e65991a2093713a4d660
1 /* t40d.c
3 * Test FIFOs and pipes
5 * Select works on regular files, (pseudo) terminal devices, streams-based
6 * files, FIFOs, pipes, and sockets. This test verifies selecting for FIFOs
7 * (named pipes) and pipes (anonymous pipes). This test will not verify most
8 * error file descriptors, as the setting of this fdset in the face of an error
9 * condition is implementation-specific (except for regular files (alway set)
10 * and sockets (protocol-specific or OOB data received), but those file types
11 * are not being tested in this specific test).
13 * This test is part of a bigger select test. It expects as argument which sub-
14 * test it is.
16 * [1] If a socket has a pending error, it shall be considered to have an
17 * exceptional condition pending. Otherwise, what constitutes an exceptional
18 * condition is file type-specific. For a file descriptor for use with a
19 * socket, it is protocol-specific except as noted below. For other file types
20 * it is implementation-defined. If the operation is meaningless for a
21 * particular file type, pselect() or select() shall indicate that the
22 * descriptor is ready for read or write operations, and shall indicate that
23 * the descriptor has no exceptional condition pending.
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <sys/select.h>
33 #include <errno.h>
34 #include <sys/wait.h>
35 #include <string.h>
36 #include <time.h>
37 #include <assert.h>
39 #define NAMEDPIPE1 "selecttestd-1"
40 #define NAMEDPIPE2 "selecttestd-2"
41 #define SENDSTRING "minixrocks"
42 #define DO_HANDLEDATA 1
43 #define DO_PAUSE 3
44 #define DO_TIMEOUT 7
45 #define MAX_ERROR 5
47 int errct = 0, subtest = -1;
48 char errbuf[1000];
49 int fd_ap[2]; /* Anonymous pipe; read from fd_ap[0], write to fd_ap[1] */
50 int fd_np1; /* Named pipe */
51 int fd_np2; /* Named pipe */
53 void e(int n, char *s) {
54 printf("Subtest %d, error %d, %s\n", subtest, n, s);
56 if (errct++ > MAX_ERROR) {
57 printf("Too many errors; test aborted\n");
58 exit(errct);
62 void do_child(void) {
63 struct timeval tv;
64 int retval;
66 /* Open named pipe for writing. This will block until a reader arrives. */
67 if((fd_np1 = open(NAMEDPIPE1, O_WRONLY)) == -1) {
68 printf("Error opening %s for writing, signalling parent to quit\n",
69 NAMEDPIPE1);
70 perror(NULL);
71 printf("Please make sure that %s is not in use while running this test\n",
72 NAMEDPIPE1);
73 exit(-1);
76 /* Going to sleep for three seconds to allow the parent proc to get ready */
77 tv.tv_sec = DO_HANDLEDATA;
78 tv.tv_usec = 0;
79 select(0, NULL, NULL, NULL, &tv);
81 /* Try to write. Doesn't matter how many bytes we actually send. */
82 retval = write(fd_np1, SENDSTRING, strlen(SENDSTRING));
84 /* Wait for another second to allow the parent to process incoming data */
85 tv.tv_sec = DO_HANDLEDATA;
86 tv.tv_usec = 0;
87 retval = select(0,NULL, NULL, NULL, &tv);
89 close(fd_np1);
91 /* Wait for another second to allow the parent to process incoming data */
92 tv.tv_sec = DO_HANDLEDATA;
93 tv.tv_usec = 0;
94 retval = select(0,NULL, NULL, NULL, &tv);
96 /* Open named pipe for reading. This will block until a writer arrives. */
97 if((fd_np2 = open(NAMEDPIPE2, O_RDONLY)) == -1) {
98 printf("Error opening %s for reading, signalling parent to quit\n",
99 NAMEDPIPE2);
100 perror(NULL);
101 printf("Please make sure that %s is not in use while running this test\n",
102 NAMEDPIPE2);
103 exit(-1);
106 /* Wait for another second to allow the parent to run some tests. */
107 tv.tv_sec = DO_HANDLEDATA;
108 tv.tv_usec = 0;
109 retval = select(0, NULL, NULL, NULL, &tv);
111 close(fd_np2);
113 /* Anonymous pipe */
115 /* Let the parent do initial read and write tests from and to the pipe. */
116 tv.tv_sec = DO_PAUSE;
117 tv.tv_usec = 0;
118 retval = select(0, NULL, NULL, NULL, &tv);
120 /* Unblock blocking read select by writing data */
121 if(write(fd_ap[1], SENDSTRING, strlen(SENDSTRING)) < 0) {
122 perror("Could not write to anonymous pipe");
123 exit(-1);
126 exit(0);
129 int count_fds(int nfds, fd_set *fds) {
130 /* Return number of bits set in fds */
131 int i, result = 0;
132 assert(fds != NULL && nfds > 0);
133 for(i = 0; i < nfds; i++) {
134 if(FD_ISSET(i, fds)) result++;
136 return result;
139 int empty_fds(int nfds, fd_set *fds) {
140 /* Returns nonzero if the first bits up to nfds in fds are not set */
141 int i;
142 assert(fds != NULL && nfds > 0);
143 for(i = 0; i < nfds; i++) if(FD_ISSET(i, fds)) return 0;
144 return 1;
147 int compare_fds(int nfds, fd_set *lh, fd_set *rh) {
148 /* Returns nonzero if lh equals rh up to nfds bits */
149 int i;
150 assert(lh != NULL && rh != NULL && nfds > 0);
151 for(i = 0; i < nfds; i++) {
152 if((FD_ISSET(i, lh) && !FD_ISSET(i, rh)) ||
153 (!FD_ISSET(i, lh) && FD_ISSET(i, rh))) {
154 return 0;
157 return 1;
160 void dump_fds(int nfds, fd_set *fds) {
161 /* Print a graphical representation of bits in fds */
162 int i;
163 if(fds != NULL && nfds > 0) {
164 for(i = 0; i < nfds; i++) printf("%d ", (FD_ISSET(i, fds) ? 1 : 0));
165 printf("\n");
169 void do_parent(int child) {
170 fd_set fds_read, fds_write, fds_error;
171 fd_set fds_compare_read, fds_compare_write;
172 struct timeval tv;
173 time_t start, end;
174 int retval;
175 char buf[20];
177 /* Open named pipe for reading. This will block until a writer arrives. */
178 if((fd_np1 = open(NAMEDPIPE1, O_RDONLY)) == -1) {
179 printf("Error opening %s for reading\n", NAMEDPIPE1);
180 perror(NULL);
181 printf("Please make sure that %s is not in use while running this test.\n",
182 NAMEDPIPE1);
183 waitpid(child, &retval, 0);
184 exit(-1);
187 /* Clear bit masks */
188 FD_ZERO(&fds_read); FD_ZERO(&fds_write);
189 /* Set read and write bits */
190 FD_SET(fd_np1, &fds_read);
191 FD_SET(fd_np1, &fds_write);
192 tv.tv_sec = DO_TIMEOUT;
193 tv.tv_usec = 0;
195 /* Test if we can read or write from/to fd_np1. As fd_np1 is opened read only
196 * we cannot actually write, so the select should return immediately [1] and
197 * the offending bit set in the fd set. We read from a pipe that is opened
198 * with O_NONBLOCKING cleared, so it is guaranteed we can read.
199 * However, at this moment the writer is sleeping, so the pipe is empty and
200 * read is supposed to block. Therefore, only 1 file descriptor should be
201 * ready. A timeout value is still set in case an error occurs in a faulty
202 * implementation. */
203 retval = select(fd_np1+1, &fds_read, &fds_write, NULL, &tv);
205 /* Did we receive an error? */
206 if(retval <= 0) {
207 snprintf(errbuf, sizeof(errbuf),
208 "one fd should be set%s", (retval == 0 ? " (TIMEOUT)" : ""));
209 e(1, errbuf);
212 if(!empty_fds(fd_np1+1,&fds_read)) e(2, "no read bits should be set");
215 /* Make sure the write bit is set (and just 1 bit) */
216 FD_ZERO(&fds_compare_write); FD_SET(fd_np1, &fds_compare_write);
217 if(!compare_fds(fd_np1+1, &fds_compare_write, &fds_write))
218 e(3, "write should be set");
220 /* Clear sets and set up new bit masks */
221 FD_ZERO(&fds_read); FD_ZERO(&fds_write);
222 FD_SET(fd_np1, &fds_read);
223 tv.tv_sec = DO_TIMEOUT; /* To make sure we get to see some error messages
224 instead of blocking forever when the
225 implementation is faulty. A timeout causes retval
226 to be 0. */
227 tv.tv_usec = 0;
228 /* The sleeping writer is about to wake up and write data to the pipe. */
229 retval = select(fd_np1+1, &fds_read, &fds_write, NULL, &tv);
231 /* Correct amount of ready file descriptors? Just 1 read */
232 if(retval != 1) {
233 snprintf(errbuf, sizeof(errbuf),
234 "one fd should be set%s", (retval == 0 ? " (TIMEOUT)" : ""));
235 e(4, errbuf);
238 if(!FD_ISSET(fd_np1, &fds_read)) e(5, "read should be set");
240 /* Note that we left the write set empty. This should be equivalent to
241 * setting this parameter to NULL. */
242 if(!empty_fds(fd_np1+1, &fds_write)) e(6, "write should NOT be set");
244 /* In case something went wrong above, we might end up with a child process
245 * blocking on a write call we close the file descriptor now. Synchronize on
246 * a read. */
247 if(read(fd_np1, buf, sizeof(SENDSTRING)) < 0) perror("Read error");
249 /* Close file descriptor. We're going to reverse the test */
250 close(fd_np1);
252 /* Wait for a second to allow the child to close the pipe as well */
253 tv.tv_sec = DO_HANDLEDATA;
254 tv.tv_usec = 0;
255 retval = select(0,NULL, NULL, NULL, &tv);
257 /* Open named pipe for writing. This call blocks until a reader arrives. */
258 if((fd_np2 = open(NAMEDPIPE2, O_WRONLY)) == -1) {
259 printf("Error opening %s for writing\n",
260 NAMEDPIPE2);
261 perror(NULL);
262 printf("Please make sure that %s is not in use while running this test\n",
263 NAMEDPIPE2);
264 exit(-1);
267 /* At this moment the child process has opened the named pipe for reading and
268 * we have opened it for writing. We're now going to reverse some of the
269 * tests we've done earlier. */
271 /* Clear sets and set up bit masks */
272 FD_ZERO(&fds_read); FD_ZERO(&fds_write); FD_ZERO(&fds_error);
273 FD_SET(fd_np2, &fds_read);
274 FD_SET(fd_np2, &fds_write);
275 tv.tv_sec = DO_TIMEOUT;
276 tv.tv_usec = 0;
277 /* Select for reading from an fd opened O_WRONLY. This should return
278 * immediately as it is not a meaningful operation [1] and is therefore not
279 * blocking. The select should return two file descriptors are ready (the
280 * failing read and valid write). */
282 retval = select(fd_np2+1, &fds_read, &fds_write, &fds_error, &tv);
284 /* Did we receive an error? */
285 if(retval <= 0) {
286 snprintf(errbuf, sizeof(errbuf),
287 "two fds should be set%s", (retval == 0 ? " (TIMEOUT)" : ""));
288 e(7, errbuf);
291 /* Make sure read bit is set (and just 1 bit) */
292 FD_ZERO(&fds_compare_read); FD_SET(fd_np2, &fds_compare_read);
293 if(!compare_fds(fd_np2+1, &fds_compare_read, &fds_read))
294 e(8, "read should be set");
296 /* Write bit should be set (and just 1 bit) */
297 FD_ZERO(&fds_compare_write); FD_SET(fd_np2, &fds_compare_write);
298 if(!compare_fds(fd_np2+1, &fds_compare_write, &fds_write))
299 e(9, "write should be set");
301 if(!empty_fds(fd_np2+1, &fds_error))
302 e(10, "Error should NOT be set");
304 FD_ZERO(&fds_read); FD_ZERO(&fds_write);
305 FD_SET(fd_np2, &fds_write);
306 tv.tv_sec = DO_TIMEOUT;
307 tv.tv_usec = 0;
308 retval = select(fd_np2+1, &fds_read, &fds_write, NULL, &tv);
310 /* Correct amount of ready file descriptors? Just 1 write */
311 if(retval != 1) {
312 snprintf(errbuf, sizeof(errbuf),
313 "one fd should be set%s", (retval == 0 ? " (TIMEOUT)" : ""));
314 e(11, errbuf);
317 if(!empty_fds(fd_np2+1, &fds_read)) e(12, "read should NOT be set");
319 /* Anonymous pipe */
321 /* Check if we can write to the pipe */
322 FD_ZERO(&fds_read); FD_ZERO(&fds_write);
323 FD_SET(fd_ap[1], &fds_write);
324 tv.tv_sec = DO_TIMEOUT;
325 tv.tv_usec = 0;
326 retval = select(fd_ap[1]+1, NULL, &fds_write, NULL, &tv);
328 /* Correct amount of ready file descriptors? Just 1 write */
329 if(retval != 1) {
330 snprintf(errbuf, sizeof(errbuf),
331 "one fd should be set%s", (retval == 0 ? " (TIMEOUT)" : ""));
332 e(13, errbuf);
335 /* Make sure write bit is set (and just 1 bit) */
336 FD_ZERO(&fds_compare_write); FD_SET(fd_ap[1], &fds_compare_write);
337 if(!compare_fds(fd_ap[1]+1, &fds_compare_write, &fds_write))
338 e(14, "write should be set");
340 /* Intentionally test reading from pipe and letting it time out. */
341 FD_SET(fd_ap[0], &fds_read);
342 tv.tv_sec = 1;
343 tv.tv_usec = 0;
344 start = time(NULL);
345 retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
346 end = time(NULL);
348 /* Did we time out? */
349 if(retval != 0) e(15, "we should have timed out");
351 /* Did it take us approximately 1 second? */
352 if((int) (end - start) != 1) {
353 snprintf(errbuf, sizeof(errbuf),
354 "time out is not 1 second (instead, it is %ld)",
355 (long int) (end - start));
356 e(16, errbuf);
359 /* Do another read, but this time we expect incoming data from child. */
360 FD_ZERO(&fds_read);
361 FD_SET(fd_ap[0], &fds_read);
362 tv.tv_sec = DO_TIMEOUT;
363 tv.tv_usec = 0;
364 retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
366 /* Correct amount of ready file descriptors? Just 1 read. */
367 if(retval != 1) e(17, "one fd should be set");
369 /* Is the read bit set? And just 1 bit. */
370 FD_ZERO(&fds_compare_read); FD_SET(fd_ap[0], &fds_compare_read);
371 if(!compare_fds(fd_ap[0]+1, &fds_compare_read, &fds_read))
372 e(18, "read should be set.");
374 /* By convention fd_ap[0] is meant to be used for reading from the pipe and
375 * fd_ap[1] is meant for writing, where fd_ap is a an anonymous pipe.
376 * However, it is unspecified what happens when fd_ap[0] is used for writing
377 * and fd_ap[1] for reading. (It is unsupported on Minix.) As such, it is not
378 * necessary to make test cases for wrong pipe file descriptors using select.
381 waitpid(child, &retval, 0);
382 unlink(NAMEDPIPE2);
383 unlink(NAMEDPIPE1);
384 exit(errct);
387 int main(int argc, char **argv) {
388 int forkres;
390 /* Get subtest number */
391 if(argc != 2) {
392 printf("Usage: %s subtest_no\n", argv[0]);
393 exit(-2);
394 } else if(sscanf(argv[1], "%d", &subtest) != 1) {
395 printf("Usage: %s subtest_no\n", argv[0]);
396 exit(-2);
399 /* Set up anonymous pipe */
400 if(pipe(fd_ap) < 0) {
401 perror("Could not create anonymous pipe");
402 exit(-1);
405 /* Create named pipe2. It is unlinked by do_parent. */
406 if(mkfifo(NAMEDPIPE1, 0600) < 0) {
407 printf("Could not create named pipe %s", NAMEDPIPE1);
408 perror(NULL);
409 exit(-1);
412 if(mkfifo(NAMEDPIPE2, 0600) < 0) {
413 printf("Could not create named pipe %s", NAMEDPIPE2);
414 perror(NULL);
415 exit(-1);
418 forkres = fork();
419 if(forkres == 0) do_child();
420 else if(forkres > 0) do_parent(forkres);
421 else { /* Fork failed */
422 perror("Unable to fork");
423 exit(-1);
426 exit(-2); /* We're not supposed to get here. Both do_* routines should exit*/