]> Zhao Yanbai Git Server - minix.git/commitdiff
test68: test pipe2 functionality 73/373/2
authorThomas Veerman <thomas@minix3.org>
Wed, 27 Feb 2013 15:40:54 +0000 (15:40 +0000)
committerThomas Veerman <thomas@minix3.org>
Thu, 28 Feb 2013 10:08:54 +0000 (10:08 +0000)
Change-Id: Idb15ec83983d0b052232c9533f89d637229d19df

test/Makefile
test/run
test/t68a.c [new file with mode: 0644]
test/t68b.c [new file with mode: 0644]
test/test68.c [new file with mode: 0644]

index bdb06e0888c37a050db1a432f443658a90665d14..623ee8675c6286d550dcb1706adabaa6d946a346 100644 (file)
@@ -23,11 +23,12 @@ OBJS.test57=test57loop.o
  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 \
 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
-61 62    64 65 66 67
+61 62    64 65 66 67 68
 PROG+= test$(t)
 .endfor
   
-PROG+= t10a t11a t11b t40a t40b t40c t40d t40e t40f t60a t60b t67a t67b
+PROG+= t10a t11a t11b t40a t40b t40c t40d t40e t40f t60a t60b \
+       t67a t67b t68a t68b
 
 .include <bsd.own.mk>
 
@@ -53,5 +54,5 @@ clean: .PHONY .MAKE
        $(MAKE) -C select clean
        rm -rf *.o *.s *.bak test? test?? t10a t11a t11b \
                t40a t40b t40c t40d t40e t40f \
-               t60a t60b t67a t67b \
+               t60a t60b t67a t67b t68a t68b \
                DIR*
index df2ca9912ddeba62524942af5e2d307e057224a6..4c81951a451f2d5a2eb61bca2b97b1ff91cbb5f9 100755 (executable)
--- a/test/run
+++ b/test/run
@@ -14,7 +14,7 @@ badones=                      # list of tests that failed
 tests="   1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 \
          21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
          41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
-         61 62 63 64 65 66 67\
+         61 62 63 64 65 66 67 68\
         sh1.sh sh2.sh interp.sh"
 tests_no=`expr 0`
 
diff --git a/test/t68a.c b/test/t68a.c
new file mode 100644 (file)
index 0000000..d398358
--- /dev/null
@@ -0,0 +1,33 @@
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main(int argc, char *argv[])
+{
+       int fd, fd_parent;
+       char buf[1];
+
+       if (argc != 2) {
+               return 1;
+       }
+
+       fd_parent = atoi(argv[1]);
+
+       /* If we open a new file, the fd we obtain should be fd_parent + 1 */
+       fd = open("open_plusplus_fd", O_CREAT|O_RDWR, 0660);
+       if (fd != fd_parent + 1) {
+               return 2;
+       }
+
+       /* Also, writing to fd_parent should succeed */
+       if (write(fd_parent, buf, sizeof(buf)) <= 0) {
+               return 3;
+       }
+
+       return 0;
+}
+
diff --git a/test/t68b.c b/test/t68b.c
new file mode 100644 (file)
index 0000000..ccdebd5
--- /dev/null
@@ -0,0 +1,39 @@
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main(int argc, char *argv[])
+{
+       int fd, fd_parent;
+       char buf[1];
+
+       if (argc != 2) {
+               return 1;
+       }
+
+       fd_parent = atoi(argv[1]);
+
+       /* Writing to fd_parent should fail as it has to be closed at this
+        * point */
+       if (write(fd_parent, buf, sizeof(buf)) != -1) {
+               return 2;
+       }
+       if (errno != EBADF) {
+               return 3;
+       }
+
+       /* If we open a new file, the fd we obtain should be identical to
+        * fd_parent */
+       fd = open("open_identical_fd", O_CREAT|O_RDWR, 0660);
+       if (fd != fd_parent) {
+               return 4;
+       }
+
+       return 0;
+}
+
diff --git a/test/test68.c b/test/test68.c
new file mode 100644 (file)
index 0000000..cdc5e6f
--- /dev/null
@@ -0,0 +1,298 @@
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define MAX_ERROR 5
+#include "common.c"
+
+void copy_subtests(void);
+void test_pipe_cloexec(void);
+void test_pipe_flag_setting(void);
+void test_pipe_nonblock(void);
+void test_pipe_normal(void);
+void test_pipe_nosigpipe(void);
+void alarm_handler(int sig);
+void pipe_handler(int sig);
+
+static int seen_pipe_signal = 0;
+static int seen_alarm_signal = 0;
+
+void
+alarm_handler(int sig)
+{
+       if (seen_pipe_signal == 0)
+               seen_pipe_signal = -1;
+       seen_alarm_signal = 1;
+}
+
+void
+pipe_handler(int sig)
+{
+       seen_pipe_signal = 1;
+}
+
+void
+copy_subtests()
+{
+       char *subtests[] = { "t68a", "t68b" };
+       char copy_cmd[8 + PATH_MAX + 1];
+       int i, no_tests;
+
+       no_tests = sizeof(subtests) / sizeof(char *);
+
+       for (i = 0; i < no_tests; i++) {
+               snprintf(copy_cmd, 8 + PATH_MAX, "cp ../%s .", subtests[i]);
+               system(copy_cmd);
+       }
+}
+
+void
+test_pipe_normal()
+{
+/* Verify pipe2 creates pipes that behave like a normal pipe */
+
+       int pipes[2];
+       char buf_in[1], buf_out[1];
+       pid_t pid;
+
+       subtest = 2;
+
+       if (pipe2(pipes, 0) != 0) e(1);
+
+       buf_out[0] = 'T';
+       if (write(pipes[1], buf_out, sizeof(buf_out)) != sizeof(buf_out)) e(2);
+       if (read(pipes[0], buf_in, sizeof(buf_in)) != sizeof(buf_in)) e(3);
+       if (buf_out[0] != buf_in[0]) e(4);
+
+       /* When we close the write end, reading should fail */
+       if (close(pipes[1]) != 0) e(5);
+       if (read(pipes[0], buf_in, sizeof(buf_in)) != 0) e(6);
+
+       /* Let's retry that experiment the other way around. Install a signal
+        * handler to catch SIGPIPE. Install an alarm handler to make sure
+        * this test finishes in finite time. */
+       if (pipe2(pipes, 0) != 0) e(7);
+       signal(SIGPIPE, pipe_handler);
+       signal(SIGALRM, alarm_handler);
+       seen_pipe_signal = 0;
+       seen_alarm_signal = 0;
+       alarm(1);
+       if (close(pipes[0]) != 0) e(8);
+       if (write(pipes[1], buf_out, sizeof(buf_out)) != -1) e(9);
+       while (seen_pipe_signal == 0)
+               ;
+       if (seen_pipe_signal != 1) e(10);
+       if (close(pipes[1]) != 0) e(11);
+
+       /* Collect alarm signal */
+       while (seen_alarm_signal == 0)
+               ;
+
+       if (pipe2(pipes, 0) != 0) e(12);
+
+       /* Now fork and verify we can write to the pipe */
+       pid = fork();
+       if (pid < 0) e(13);
+       if (pid == 0) {
+               /* We're the child */
+               char fd_buf[2];
+
+               /* Verify we can still write a byte into the pipe */
+               if (write(pipes[1], buf_out, sizeof(buf_out)) != 1) e(14);
+               
+               snprintf(fd_buf, sizeof(fd_buf), "%d", pipes[1]);
+               execl("./t68a", "t68a", fd_buf, NULL);
+
+               exit(1); /* Should not be reached */
+       } else {
+               /* We're the parent */
+               int result;
+
+               if (waitpid(pid, &result, 0) == -1) e(15);
+               if (WEXITSTATUS(result) != 0) e(16);
+       }
+
+       if (close(pipes[0]) != 0) e(17);
+       if (close(pipes[1]) != 0) e(18);
+}
+
+void
+test_pipe_cloexec()
+{
+/* Open a pipe with O_CLOEXEC */
+       int flags;
+       int pipes[2];
+       pid_t pid;
+       char buf_in[1], buf_out[1];
+
+       subtest = 3;
+
+       if (pipe2(pipes, O_CLOEXEC) != 0) e(1);
+
+       /* Verify O_CLOEXEC flag is set */
+       flags = fcntl(pipes[0], F_GETFD);
+       if (flags < 0) e(2);
+       if (!(flags & FD_CLOEXEC)) e(3);
+
+       pid = fork();
+       if (pid < 0) e(4);
+       if (pid == 0) {
+               /* We're the child */
+               char fd_buf[2];
+
+               /* Verify we can still write a byte into the pipe */
+               buf_in[0] = 0;
+               buf_out[0] = 'T';
+               if (write(pipes[1], buf_out, sizeof(buf_out)) != 1) e(5);
+               if (read(pipes[0], buf_in, sizeof(buf_in)) != 1) e(6);
+               if (buf_out[0] != buf_in[0]) e(7);
+               
+               /* Verify FD_CLOEXEC flag is still set */
+               flags = fcntl(pipes[0], F_GETFD);
+               if (flags < 0) e(8);
+               if (!(flags & FD_CLOEXEC)) e(9);
+               
+               snprintf(fd_buf, sizeof(fd_buf), "%d", pipes[0]);
+               execl("./t68b", "t68b", fd_buf, NULL);
+
+               exit(1); /* Should not be reached */
+       } else {
+               /* We're the parent */
+               int result;
+
+               if (waitpid(pid, &result, 0) == -1) e(10);
+               if (WEXITSTATUS(result) != 0) e(11);
+       }
+
+       /* Eventhough our child's pipe should've been closed upon exec, our
+        * pipe should still be functioning.
+        */
+       buf_in[0] = 0;
+       buf_out[0] = 't';
+       if (write(pipes[1], buf_out, sizeof(buf_out)) != sizeof(buf_out)) e(12);
+       if (read(pipes[0], buf_in, sizeof(buf_in)) != sizeof(buf_in)) e(13);
+       if (buf_out[0] != buf_in[0]) e(14);
+
+       if (close(pipes[0]) != 0) e(15);
+       if (close(pipes[1]) != 0) e(16);
+}
+
+void
+test_pipe_nonblock()
+{
+/* Open a pipe with O_NONBLOCK */
+       char *buf_in, *buf_out;
+       int pipes[2];
+       size_t pipe_size;
+
+       subtest = 4;
+
+       if (pipe2(pipes, O_NONBLOCK) != 0) e(1);
+       if ((pipe_size = fpathconf(pipes[0], _PC_PIPE_BUF)) == -1) e(2);
+       buf_in = calloc(2, pipe_size); /* Allocate twice the buffer size */
+       if (buf_in == NULL) e(3);
+       buf_out = calloc(2, pipe_size); /* Idem dito for output buffer */
+       if (buf_out == NULL) e(4);
+
+       /* According to POSIX, a pipe with O_NONBLOCK set shall never block.
+        * When we attempt to write PIPE_BUF or less bytes, and there is
+        * sufficient space available, write returns nbytes. Else write will
+        * return -1 and not transfer any data.
+        */
+       if (write(pipes[1], buf_out, 1) != 1) e(5);     /* Write 1 byte */
+       if (write(pipes[1], buf_out, pipe_size) != -1) e(6);    /* Can't fit */
+       if (errno != EAGAIN) e(7);
+
+       /* When writing more than PIPE_BUF bytes and when at least 1 byte can
+        * be tranferred, return the number of bytes written. We've written 1
+        * byte, so there are PIPE_BUF - 1 bytes left. */
+       if (write(pipes[1], buf_out, pipe_size + 1) != pipe_size - 1) e(8);
+
+       /* Read out all data and try again. This time we should be able to
+        * write PIPE_BUF bytes. */
+       if (read(pipes[0], buf_in, pipe_size) != pipe_size) e(9);
+       if (read(pipes[0], buf_in, 1) != -1) e(10);     /* Empty, can't read */
+       if (errno != EAGAIN) e(11);
+       if (write(pipes[1], buf_out, pipe_size + 1) != pipe_size) e(12);
+       if (close(pipes[0]) != 0) e(13);
+       if (close(pipes[1]) != 0) e(14);
+       free(buf_in);
+       free(buf_out);
+}
+
+void
+test_pipe_nosigpipe(void)
+{
+/* Let's retry the writing to pipe without readers experiment. This time we set
+ * the O_NOSIGPIPE flag to prevent getting a signal. */
+       int pipes[2];
+       char buf_out[1];
+
+       subtest = 5;
+
+       if (pipe2(pipes, O_NOSIGPIPE) != 0) e(7);
+       signal(SIGPIPE, pipe_handler);
+       signal(SIGALRM, alarm_handler);
+       seen_pipe_signal = 0;
+       seen_alarm_signal = 0;
+       alarm(1);
+       if (close(pipes[0]) != 0) e(8);
+       if (write(pipes[1], buf_out, sizeof(buf_out)) != -1) e(9);
+
+       /* Collect alarm signal */
+       while (seen_alarm_signal == 0)
+               ;
+       if (errno != EPIPE) e(10);
+       if (seen_pipe_signal != -1) e(11); /* Alarm sig handler set it to -1 */
+       if (close(pipes[1]) != 0) e(12);
+}
+
+void
+test_pipe_flag_setting()
+{
+       int pipes[2];
+
+       subtest = 1;
+
+       /* Create standard pipe with no flags and verify they're off */
+       if (pipe2(pipes, 0) != 0) e(1);
+       if (fcntl(pipes[0], F_GETFD) != 0) e(2);
+       if (fcntl(pipes[1], F_GETFD) != 0) e(3);
+       if (fcntl(pipes[0], F_GETFL) & O_NONBLOCK) e(4);
+       if (fcntl(pipes[1], F_GETFL) & O_NONBLOCK) e(5);
+       if (fcntl(pipes[0], F_GETNOSIGPIPE) != -1) e(6);
+       if (fcntl(pipes[1], F_GETNOSIGPIPE) != -1) e(7);
+       if (close(pipes[0]) != 0) e(8);
+       if (close(pipes[1]) != 0) e(9);
+
+       /* Create pipe with all flags and verify they're on */
+       if (pipe2(pipes, O_CLOEXEC|O_NONBLOCK|O_NOSIGPIPE) != 0) e(10);
+       if (fcntl(pipes[0], F_GETFD) != FD_CLOEXEC) e(11);
+       if (fcntl(pipes[1], F_GETFD) != FD_CLOEXEC) e(12);
+       if (!(fcntl(pipes[0], F_GETFL) & O_NONBLOCK)) e(13);
+       if (!(fcntl(pipes[1], F_GETFL) & O_NONBLOCK)) e(14);
+       if (fcntl(pipes[0], F_GETNOSIGPIPE) == -1) e(15);
+       if (fcntl(pipes[1], F_GETNOSIGPIPE) == -1) e(16);
+       if (close(pipes[0]) != 0) e(17);
+       if (close(pipes[1]) != 0) e(18);
+}
+
+int
+main(int argc, char *argv[])
+{
+       start(68);
+       copy_subtests();
+       test_pipe_flag_setting();
+       test_pipe_normal();
+       test_pipe_cloexec();
+       test_pipe_nonblock();
+       test_pipe_nosigpipe();
+       quit();
+       return(-1);     /* Unreachable */
+}
+