Handle threading after a fork() (XCC)
[akaros.git] / user / utest / qio.c
1 /* Copyright (c) 2017 Google, Inc.
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details. */
4
5 #define _GNU_SOURCE
6 #include <utest/utest.h>
7 #include <stdio.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <errno.h>
13
14
15 TEST_SUITE("QIO");
16
17 /* <--- Begin definition of test cases ---> */
18
19 static bool fd_is_writable(int fd)
20 {
21         struct stat stat_buf;
22         int ret;
23
24         ret = fstat(fd, &stat_buf);
25         UT_ASSERT_FMT("fstat failed", !ret);
26         return S_WRITABLE(stat_buf.st_mode);
27 }
28
29 /* This is a little fragile, in that it relies on the kernel's value of
30  * Maxatomic in qio.c. */
31 bool test_partial_write_to_full_queue(void)
32 {
33         int pipefd[2];
34         ssize_t ret;
35         char *buf;
36         size_t buf_sz = 1ULL << 20;
37
38         buf = malloc(buf_sz);
39         UT_ASSERT_FMT("buf alloc failed", buf);
40         ret = pipe2(pipefd, O_NONBLOCK);
41         UT_ASSERT_FMT("pipe2 failed", ret == 0);
42
43         /* Fill the pipe.  The limit is usually O(10K) */
44         do {
45                 ret = write(pipefd[1], buf, 1024);
46         } while (ret > 0);
47         UT_ASSERT_FMT("Didn't get EAGAIN, got %d", errno == EAGAIN, errno);
48
49         /* The way qio works is we accept the last block, and won't accept future
50          * blocks until we drop below the limit.  Let's drain until we get there.
51          * Should be only one or two. */
52         while (!fd_is_writable(pipefd[1])) {
53                 ret = read(pipefd[0], buf, 1024);
54                 UT_ASSERT_FMT("Failed to read from pipe with data", ret > 0);
55         }
56
57         /* Now we have a little room.  If we send in a very large write, greater
58          * than Maxatomic, we should get a partial write.  If we get -1 back, then
59          * the kernel said it was writable, but we couldn't write.  This happened
60          * once when the kernel would write some, then get EAGAIN and throw -
61          * ignoring the successful initial write. */
62         ret = write(pipefd[1], buf, buf_sz);
63         UT_ASSERT_FMT("write error %d, errno %d", ret > 0, ret, errno);
64         UT_ASSERT_FMT("wrote %d >= %d buf_sz", ret < buf_sz, ret, buf_sz);
65
66         free(buf);
67         close(pipefd[0]);
68         close(pipefd[1]);
69         return TRUE;
70 }
71
72
73 /* <--- End definition of test cases ---> */
74
75 struct utest utests[] = {
76         UTEST_REG(partial_write_to_full_queue),
77 };
78 int num_utests = sizeof(utests) / sizeof(struct utest);
79
80 int main(int argc, char *argv[])
81 {
82         // Run test suite passing it all the args as whitelist of what tests to run.
83         char **whitelist = &argv[1];
84         int whitelist_len = argc - 1;
85
86         RUN_TEST_SUITE(utests, num_utests, whitelist, whitelist_len);
87 }