1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <assert.h>
6 #include <stdbool.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <threads.h>
10 #include <unistd.h>
11 
12 #include <zircon/syscalls.h>
13 #include <unittest/unittest.h>
14 
get_signals(zx_handle_t h)15 static zx_signals_t get_signals(zx_handle_t h) {
16     zx_signals_t pending;
17     zx_status_t status = zx_object_wait_one(h, 0xFFFFFFFF, 0u, &pending);
18     if ((status != ZX_OK) && (status != ZX_ERR_TIMED_OUT)) {
19         return 0xFFFFFFFF;
20     }
21     return pending;
22 }
23 
24 #define EXPECT_SIGNALS(h, s) EXPECT_EQ(get_signals(h), s, "")
25 
basic_test(void)26 static bool basic_test(void) {
27     BEGIN_TEST;
28     zx_handle_t a, b;
29     uint64_t n[8] = { 1, 2, 3, 4, 5, 6, 7, 8};
30     enum { ELEM_SZ = sizeof(n[0]) };
31 
32     // ensure parameter validation works
33     EXPECT_EQ(zx_fifo_create(0, 0, 0, &a, &b), ZX_ERR_OUT_OF_RANGE, ""); // too small
34     EXPECT_EQ(zx_fifo_create(35, 32, 0, &a, &b), ZX_ERR_OUT_OF_RANGE, ""); // not power of two
35     EXPECT_EQ(zx_fifo_create(128, 33, 0, &a, &b), ZX_ERR_OUT_OF_RANGE, ""); // too large
36     EXPECT_EQ(zx_fifo_create(0, 0, 1, &a, &b), ZX_ERR_OUT_OF_RANGE, ""); // invalid options
37 
38     // simple 8 x 8 fifo
39     EXPECT_EQ(zx_fifo_create(8, ELEM_SZ, 0, &a, &b), ZX_OK, "");
40     EXPECT_SIGNALS(a, ZX_FIFO_WRITABLE);
41     EXPECT_SIGNALS(b, ZX_FIFO_WRITABLE);
42 
43     // Check that koids line up.
44     zx_info_handle_basic_t info[2] = {};
45     zx_status_t status = zx_object_get_info(a, ZX_INFO_HANDLE_BASIC, &info[0], sizeof(info[0]), NULL, NULL);
46     ASSERT_EQ(status, ZX_OK, "");
47     status = zx_object_get_info(b, ZX_INFO_HANDLE_BASIC, &info[1], sizeof(info[1]), NULL, NULL);
48     ASSERT_EQ(status, ZX_OK, "");
49     ASSERT_NE(info[0].koid, 0u, "zero koid!");
50     ASSERT_NE(info[0].related_koid, 0u, "zero peer koid!");
51     ASSERT_NE(info[1].koid, 0u, "zero koid!");
52     ASSERT_NE(info[1].related_koid, 0u, "zero peer koid!");
53     ASSERT_EQ(info[0].koid, info[1].related_koid, "mismatched koids!");
54     ASSERT_EQ(info[1].koid, info[0].related_koid, "mismatched koids!");
55 
56     // should not be able to read any entries from an empty fifo
57     size_t actual;
58     EXPECT_EQ(zx_fifo_read(a, ELEM_SZ, n, 8, &actual), ZX_ERR_SHOULD_WAIT, "");
59 
60     // not allowed to read or write zero elements
61     EXPECT_EQ(zx_fifo_read(a, ELEM_SZ, n, 0, &actual), ZX_ERR_OUT_OF_RANGE, "");
62     EXPECT_EQ(zx_fifo_write(a, ELEM_SZ, n, 0, &actual), ZX_ERR_OUT_OF_RANGE, "");
63 
64     // element size must match
65     EXPECT_EQ(zx_fifo_read(a, ELEM_SZ + 1, n, 8, &actual), ZX_ERR_OUT_OF_RANGE, "");
66     EXPECT_EQ(zx_fifo_write(a, ELEM_SZ + 1, n, 8, &actual), ZX_ERR_OUT_OF_RANGE, "");
67 
68     // should be able to write all entries into empty fifo
69     ASSERT_EQ(zx_fifo_write(a, ELEM_SZ, n, 8, &actual), ZX_OK, "");
70     ASSERT_EQ(actual, 8u, "");
71     EXPECT_SIGNALS(b, ZX_FIFO_READABLE | ZX_FIFO_WRITABLE);
72 
73     // should be able to write no entries into a full fifo
74     ASSERT_EQ(zx_fifo_write(a, ELEM_SZ, n, 8, &actual), ZX_ERR_SHOULD_WAIT, "");
75     EXPECT_SIGNALS(a, 0u);
76 
77     // read half the entries, make sure they're what we expect
78     memset(n, 0, sizeof(n));
79     EXPECT_EQ(zx_fifo_read(b, ELEM_SZ, n, 4, &actual), ZX_OK, "");
80     ASSERT_EQ(actual, 4u, "");
81     ASSERT_EQ(n[0], 1u, "");
82     ASSERT_EQ(n[1], 2u, "");
83     ASSERT_EQ(n[2], 3u, "");
84     ASSERT_EQ(n[3], 4u, "");
85 
86     // should be writable again now
87     EXPECT_SIGNALS(a, ZX_FIFO_WRITABLE);
88 
89     // write some more, wrapping to the front again
90     n[0] = 9u;
91     n[1] = 10u;
92     ASSERT_EQ(zx_fifo_write(a, ELEM_SZ, n, 2, &actual), ZX_OK, "");
93     ASSERT_EQ(actual, 2u, "");
94 
95     // read across the wrap, test partial read
96     ASSERT_EQ(zx_fifo_read(b, ELEM_SZ, n, 8, &actual), ZX_OK, "");
97     ASSERT_EQ(actual, 6u, "");
98     ASSERT_EQ(n[0], 5u, "");
99     ASSERT_EQ(n[1], 6u, "");
100     ASSERT_EQ(n[2], 7u, "");
101     ASSERT_EQ(n[3], 8u, "");
102     ASSERT_EQ(n[4], 9u, "");
103     ASSERT_EQ(n[5], 10u, "");
104 
105     // should no longer be readable
106     EXPECT_SIGNALS(b, ZX_FIFO_WRITABLE);
107 
108     // write across the wrap
109     n[0] = 11u; n[1] = 12u; n[2] = 13u; n[3] = 14u; n[4] = 15u;
110     ASSERT_EQ(zx_fifo_write(a, ELEM_SZ, n, 5, &actual), ZX_OK, "");
111     ASSERT_EQ(actual, 5u, "");
112 
113     // partial write test
114     n[0] = 16u; n[1] = 17u; n[2] = 18u;
115     ASSERT_EQ(zx_fifo_write(a, ELEM_SZ, n, 5, &actual), ZX_OK, "");
116     ASSERT_EQ(actual, 3u, "");
117 
118     // small reads
119     for (unsigned i = 0; i < 8; i++) {
120         ASSERT_EQ(zx_fifo_read(b, ELEM_SZ, n, 1, &actual), ZX_OK, "");
121         ASSERT_EQ(actual, 1u, "");
122         ASSERT_EQ(n[0], 11u + i, "");
123     }
124 
125     // write and then close, verify we can read written entries before
126     // receiving ZX_ERR_PEER_CLOSED.
127     n[0] = 19u;
128     ASSERT_EQ(zx_fifo_write(b, ELEM_SZ, n, 1, &actual), ZX_OK, "");
129     ASSERT_EQ(actual, 1u, "");
130     zx_handle_close(b);
131     EXPECT_SIGNALS(a, ZX_FIFO_READABLE | ZX_FIFO_PEER_CLOSED);
132     ASSERT_EQ(zx_fifo_read(a, ELEM_SZ, n, 8, &actual), ZX_OK, "");
133     ASSERT_EQ(actual, 1u, "");
134     EXPECT_SIGNALS(a, ZX_FIFO_PEER_CLOSED);
135     ASSERT_EQ(zx_fifo_read(a, ELEM_SZ, n, 8, &actual), ZX_ERR_PEER_CLOSED, "");
136 
137     zx_handle_close(a);
138 
139     END_TEST;
140 }
141 
peer_closed_test(void)142 static bool peer_closed_test(void) {
143     BEGIN_TEST;
144 
145     zx_handle_t fifo[2];
146     ASSERT_EQ(zx_fifo_create(16, 16, 0, &fifo[0], &fifo[1]), ZX_OK, "");
147     ASSERT_EQ(zx_handle_close(fifo[1]), ZX_OK, "");
148     ASSERT_EQ(zx_object_signal_peer(fifo[0], 0u, ZX_USER_SIGNAL_0), ZX_ERR_PEER_CLOSED, "");
149     ASSERT_EQ(zx_handle_close(fifo[0]), ZX_OK, "");
150 
151     END_TEST;
152 }
153 
options_test(void)154 static bool options_test(void) {
155     BEGIN_TEST;
156 
157     zx_handle_t fifos[2];
158     ASSERT_EQ(zx_fifo_create(23, 8, 8, &fifos[0], &fifos[1]),
159               ZX_ERR_OUT_OF_RANGE, "");
160 
161     END_TEST;
162 }
163 
164 BEGIN_TEST_CASE(fifo_tests)
RUN_TEST(basic_test)165 RUN_TEST(basic_test)
166 RUN_TEST(peer_closed_test)
167 RUN_TEST(options_test)
168 END_TEST_CASE(fifo_tests)
169 
170 #ifndef BUILD_COMBINED_TESTS
171 int main(int argc, char** argv) {
172     return unittest_run_all_tests(argc, argv) ? 0 : -1;
173 }
174 #endif
175