1 // Copyright 2018 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 <stdio.h>
7 #include <unistd.h>
8
9 #include <lib/fzl/time.h>
10 #include <lib/fzl/fifo.h>
11 #include <fbl/algorithm.h>
12 #include <unittest/unittest.h>
13 #include <zircon/syscalls.h>
14
15 #include <utility>
16
17 namespace {
18
19 template <typename T>
AlmostEqual(T t0,T t1,T e)20 bool AlmostEqual(T t0, T t1, T e) {
21 BEGIN_HELPER;
22
23 char buf[128];
24 snprintf(buf, sizeof(buf), "%zu != %zu (within error of %zu)", t0, t1, e);
25 ASSERT_TRUE(fbl::min(t0, t1) + e >= fbl::max(t0, t1), buf);
26
27 END_HELPER;
28 }
29
TickConverter(zx::ticks ticks,zx::ticks err)30 bool TickConverter(zx::ticks ticks, zx::ticks err) {
31 BEGIN_HELPER;
32 ASSERT_TRUE(AlmostEqual(ticks.get(), fzl::NsToTicks(fzl::TicksToNs(ticks)).get(), err.get()));
33 ASSERT_TRUE(AlmostEqual(ticks.get(), ns_to_ticks(ticks_to_ns(ticks.get())), err.get()));
34 END_HELPER;
35 }
36
NsConverter(zx::duration ns,zx::duration err)37 bool NsConverter(zx::duration ns, zx::duration err) {
38 BEGIN_HELPER;
39 ASSERT_TRUE(AlmostEqual(ns.get(), fzl::TicksToNs(fzl::NsToTicks(ns)).get(), err.get()));
40 ASSERT_TRUE(AlmostEqual(ns.get(), ticks_to_ns(ns_to_ticks(ns.get())), err.get()));
41 END_HELPER;
42 }
43
TimeTest()44 bool TimeTest() {
45 BEGIN_TEST;
46
47 zx::ticks tps = zx::ticks::per_second();
48 zx::duration nps = zx::sec(1);
49
50 // The following tests check converting from:
51 // - ticks --> nanoseconds --> ticks
52 // - nanoseconds --> ticks --> nanoseconds
53 //
54 // This conversion is inherently lossy if the number of ticks/ns (or
55 // ns/tick) is not an exact integer -- which is almost always the case.
56 //
57 // To convert N nanoseconds to ticks, we'd logically multiply by
58 // "ticks/sec" / "ns/second". However, by converting N into the ticks
59 // equivalent T, we may be losing the fractional component of this number: N
60 // may actually be represented by T +/- a partial tick.
61 //
62 // In most situations, where ticks are higher precision than nanoseconds,
63 // there will actually be even more loss in the other direction: when
64 // converting from ticks to nanoseconds, we may potentially lose as many as
65 // "ticks/second / ns/second" ticks.
66 //
67 // To ensure our error margins account for this loss, where we lose
68 // minimally a "partial unit" and maximally an integer ratio of the units,
69 // we calculate acceptable loss as:
70 //
71 // loss = max(1 + ratio, 1)
72 //
73 // Where we add one to the ratio to "round up to the nearest integer ratio" while
74 // doing the conversion.
75 zx::ticks tick_loss = fbl::max(zx::ticks(1 + (tps.get() / nps.get())),
76 zx::ticks(1));
77 zx::duration duration_loss = fbl::max(zx::duration(1 + (nps.get() / tps.get())),
78 zx::duration(1));
79
80 ASSERT_TRUE(TickConverter(zx::ticks(0), zx::ticks(0)));
81 ASSERT_TRUE(TickConverter(zx::ticks(50), tick_loss));
82 ASSERT_TRUE(TickConverter(zx::ticks(100), tick_loss));
83 ASSERT_TRUE(TickConverter(zx::ticks(100000), tick_loss));
84 ASSERT_TRUE(TickConverter(zx::ticks(1000000000), tick_loss));
85 ASSERT_TRUE(TickConverter(zx::ticks(10000000000000), tick_loss));
86
87 ASSERT_TRUE(NsConverter(zx::duration(0), zx::duration(0)));
88 ASSERT_TRUE(NsConverter(zx::duration(50), duration_loss));
89 ASSERT_TRUE(NsConverter(zx::duration(100), duration_loss));
90 ASSERT_TRUE(NsConverter(zx::duration(100000), duration_loss));
91 ASSERT_TRUE(NsConverter(zx::duration(1000000000), duration_loss));
92 ASSERT_TRUE(NsConverter(zx::duration(10000000000000), duration_loss));
93
94 END_TEST;
95 }
96
FifoTest()97 bool FifoTest() {
98 BEGIN_TEST;
99
100 // Default constructor
101 {
102 fzl::fifo<int> invalid;
103 ASSERT_EQ(invalid.get_handle(), ZX_HANDLE_INVALID);
104 }
105
106 // Move constructors, reset() and release()
107 {
108 zx::fifo zx_fifo_0, zx_fifo_1;
109 zx_status_t status = zx::fifo::create(4, 4, 0, &zx_fifo_0, &zx_fifo_1);
110 ASSERT_EQ(status, ZX_OK);
111 zx_handle_t handle_0 = zx_fifo_0.get();
112 ASSERT_NE(handle_0, ZX_HANDLE_INVALID);
113
114 fzl::fifo<int> moved_fifo(std::move(zx_fifo_0));
115 ASSERT_EQ(moved_fifo.get_handle(), handle_0);
116 ASSERT_EQ(zx_fifo_0.get(), ZX_HANDLE_INVALID);
117
118 fzl::fifo<int> moved_again(std::move(moved_fifo));
119 ASSERT_EQ(moved_again.get_handle(), handle_0);
120 ASSERT_EQ(moved_fifo.get_handle(), ZX_HANDLE_INVALID);
121
122 zx::handle opaque_handle(moved_again.release());
123 fzl::fifo<int> from_opaque(std::move(opaque_handle));
124 ASSERT_EQ(from_opaque.get_handle(), handle_0);
125 ASSERT_EQ(opaque_handle.get(), ZX_HANDLE_INVALID);
126
127 from_opaque.reset();
128 ASSERT_EQ(from_opaque.get_handle(), ZX_HANDLE_INVALID);
129 }
130
131 // Create, read, write
132
133 fzl::fifo<int64_t, char[8]> fifo_0;
134 fzl::fifo<char[8], int64_t> fifo_1;
135
136 {
137 zx_status_t status = fzl::create_fifo(4, 0, &fifo_0, &fifo_1);
138 ASSERT_EQ(status, ZX_OK);
139 }
140
141 {
142 const int64_t numbers[2] = {10, -20};
143 size_t actual = 0;
144 zx_status_t status = fifo_0.write(numbers, 2, &actual);
145 ASSERT_EQ(status, ZX_OK);
146 ASSERT_EQ(actual, 2);
147 }
148
149 {
150 int64_t numbers[3] = { 0, 0, 0 };
151 size_t actual = 0;
152 zx_status_t status = fifo_1.read(numbers, 3, &actual);
153 ASSERT_EQ(status, ZX_OK);
154 ASSERT_EQ(actual, 2);
155 ASSERT_EQ(numbers[0], 10);
156 ASSERT_EQ(numbers[1], -20);
157 }
158
159 {
160 char str[8] = "hi fifo";
161 zx_status_t status = fifo_1.write_one(str);
162 ASSERT_EQ(status, ZX_OK);
163 }
164
165 {
166 char str[8] = ".......";
167 zx_status_t status = fifo_0.read_one(&str);
168 ASSERT_EQ(status, ZX_OK);
169 ASSERT_STR_EQ("hi fifo", str);
170 }
171
172 // Signal & wait_one
173 {
174 fifo_0.signal(0, ZX_USER_SIGNAL_0);
175 zx_signals_t pending = 0;
176 fifo_0.wait_one(ZX_USER_SIGNAL_0, zx::deadline_after(zx::sec(1)), &pending);
177 ASSERT_TRUE(pending & ZX_USER_SIGNAL_0);
178 }
179
180 // Replace
181 {
182 fzl::fifo<int64_t, char[8]> replaced;
183 fifo_0.replace(0, &replaced);
184 ASSERT_EQ(fifo_0.get_handle(), ZX_HANDLE_INVALID);
185 ASSERT_NE(replaced.get_handle(), ZX_HANDLE_INVALID);
186 }
187
188 END_TEST;
189 }
190
191 } // namespace
192
193 BEGIN_TEST_CASE(libfzl_tests)
194 RUN_TEST(TimeTest)
195 RUN_TEST(FifoTest)
196 END_TEST_CASE(libfzl_tests)
197