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
15static 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
26static 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
142static 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
154static 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
164BEGIN_TEST_CASE(fifo_tests)
165RUN_TEST(basic_test)
166RUN_TEST(peer_closed_test)
167RUN_TEST(options_test)
168END_TEST_CASE(fifo_tests)
169
170#ifndef BUILD_COMBINED_TESTS
171int main(int argc, char** argv) {
172    return unittest_run_all_tests(argc, argv) ? 0 : -1;
173}
174#endif
175