| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "mojo/edk/system/wait_set_dispatcher.h" | 5 #include "mojo/edk/system/wait_set_dispatcher.h" |
| 6 | 6 |
| 7 #include "mojo/edk/system/mock_simple_dispatcher.h" | 7 #include "mojo/edk/system/mock_simple_dispatcher.h" |
| 8 #include "testing/gtest/include/gtest/gtest.h" | 8 #include "testing/gtest/include/gtest/gtest.h" |
| 9 | 9 |
| 10 using mojo::util::MakeRefCounted; | 10 using mojo::util::MakeRefCounted; |
| 11 | 11 |
| 12 namespace mojo { | 12 namespace mojo { |
| 13 namespace system { | 13 namespace system { |
| 14 namespace { | 14 namespace { |
| 15 | 15 |
| 16 // Helper to check if an array of |MojoWaitSetResult|s has a result |r| for the |
| 17 // given cookie, in which case: |
| 18 // - |r.wait_result| must equal |wait_result|. |
| 19 // - If |wait_result| is |MOJO_RESULT_OK| or |
| 20 // |MOJO_RESULT_FAILED_PRECONDITION|, then |
| 21 // - |r.signals_state.satisfied_signals & signals| must equal |
| 22 // |signals_state.satisfied_signals & signals|, and |
| 23 // - |r.signals_state.satisfiable & signals| must equal |
| 24 // |signals_state.satisfiable_signals & signals|. |
| 25 // - Otherwise, |r.signals_state| must equals |signals_state|. |
| 26 // (This doesn't check that the result is unique; you should check |num_results| |
| 27 // versus the expect number and exhaustively check every expected result.) |
| 28 bool CheckHasResult(uint32_t num_results, |
| 29 const MojoWaitSetResult* results, |
| 30 uint64_t cookie, |
| 31 MojoHandleSignals signals, |
| 32 MojoResult wait_result, |
| 33 const MojoHandleSignalsState& signals_state) { |
| 34 for (uint32_t i = 0; i < num_results; i++) { |
| 35 if (results[i].cookie == cookie) { |
| 36 EXPECT_EQ(wait_result, results[i].wait_result) << cookie; |
| 37 EXPECT_EQ(0u, results[i].reserved) << cookie; |
| 38 if (wait_result == MOJO_RESULT_OK || |
| 39 wait_result == MOJO_RESULT_FAILED_PRECONDITION) { |
| 40 EXPECT_EQ(signals_state.satisfied_signals & signals, |
| 41 results[i].signals_state.satisfied_signals & signals) |
| 42 << cookie; |
| 43 EXPECT_EQ(signals_state.satisfiable_signals & signals, |
| 44 results[i].signals_state.satisfiable_signals & signals) |
| 45 << cookie; |
| 46 } else { |
| 47 EXPECT_EQ(signals_state.satisfied_signals, |
| 48 results[i].signals_state.satisfied_signals) |
| 49 << cookie; |
| 50 EXPECT_EQ(signals_state.satisfiable_signals, |
| 51 results[i].signals_state.satisfiable_signals) |
| 52 << cookie; |
| 53 } |
| 54 return true; |
| 55 } |
| 56 } |
| 57 return false; |
| 58 } |
| 59 |
| 16 TEST(WaitSetDispatcherTest, Basic) { | 60 TEST(WaitSetDispatcherTest, Basic) { |
| 61 static constexpr auto kR = MOJO_HANDLE_SIGNAL_READABLE; |
| 62 static constexpr auto kW = MOJO_HANDLE_SIGNAL_WRITABLE; |
| 63 |
| 64 static constexpr auto kIndefinite = MOJO_DEADLINE_INDEFINITE; |
| 65 static constexpr auto k10ms = static_cast<MojoDeadline>(10 * 1000u); |
| 66 |
| 17 auto d = WaitSetDispatcher::Create(WaitSetDispatcher::kDefaultCreateOptions); | 67 auto d = WaitSetDispatcher::Create(WaitSetDispatcher::kDefaultCreateOptions); |
| 18 | 68 |
| 19 // These will be members of our wait set. | 69 // These will be members of our wait set. |
| 20 auto d_member0 = MakeRefCounted<test::MockSimpleDispatcher>( | 70 auto d_member0 = MakeRefCounted<test::MockSimpleDispatcher>(kW, kR | kW); |
| 21 MOJO_HANDLE_SIGNAL_NONE, | 71 auto d_member1 = MakeRefCounted<test::MockSimpleDispatcher>(kR, kR); |
| 22 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE); | |
| 23 auto d_member1 = MakeRefCounted<test::MockSimpleDispatcher>( | |
| 24 MOJO_HANDLE_SIGNAL_READABLE, MOJO_HANDLE_SIGNAL_READABLE); | |
| 25 | 72 |
| 26 // Add |d_member0|, for something not satisfied, but satisfiable. | 73 // Add |d_member0|, for something not satisfied, but satisfiable. |
| 27 const uint64_t kCookie0 = 0x123456789abcdef0ULL; | 74 static constexpr uint64_t kCookie0 = 0x123456789abcdef0ULL; |
| 28 EXPECT_EQ(MOJO_RESULT_OK, | 75 static constexpr auto kSignals0 = kR; |
| 29 d->WaitSetAdd(NullUserPointer(), d_member0.Clone(), | 76 EXPECT_EQ(MOJO_RESULT_OK, d->WaitSetAdd(NullUserPointer(), d_member0.Clone(), |
| 30 MOJO_HANDLE_SIGNAL_READABLE, kCookie0)); | 77 kSignals0, kCookie0)); |
| 31 | 78 |
| 32 // Add |d_member1|, for something satisfied. | 79 // Add |d_member1|, for something satisfied. |
| 33 const uint64_t kCookie1 = 0x23456789abcdef01ULL; | 80 static constexpr uint64_t kCookie1 = 0x23456789abcdef01ULL; |
| 34 EXPECT_EQ(MOJO_RESULT_OK, | 81 static constexpr auto kSignals1 = kR; |
| 35 d->WaitSetAdd(NullUserPointer(), d_member1.Clone(), | 82 EXPECT_EQ(MOJO_RESULT_OK, d->WaitSetAdd(NullUserPointer(), d_member1.Clone(), |
| 36 MOJO_HANDLE_SIGNAL_READABLE, kCookie1)); | 83 kSignals1, kCookie1)); |
| 37 | 84 |
| 38 // Can add |d_member0| again, with a different cookie. | 85 // Can add |d_member0| again (satisfied), with a different cookie. |
| 39 const uint64_t kCookie2 = 0x3456789abcdef012ULL; | 86 static constexpr uint64_t kCookie2 = 0x3456789abcdef012ULL; |
| 40 EXPECT_EQ(MOJO_RESULT_OK, | 87 static constexpr auto kSignals2 = kW; |
| 41 d->WaitSetAdd(NullUserPointer(), d_member0.Clone(), | 88 EXPECT_EQ(MOJO_RESULT_OK, d->WaitSetAdd(NullUserPointer(), d_member0.Clone(), |
| 42 MOJO_HANDLE_SIGNAL_WRITABLE, kCookie2)); | 89 kSignals2, kCookie2)); |
| 43 | 90 |
| 44 // Adding something with the same cookie yields "already exists". | 91 // Adding something with the same cookie yields "already exists". |
| 45 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, | 92 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, |
| 46 d->WaitSetAdd(NullUserPointer(), d_member1.Clone(), | 93 d->WaitSetAdd(NullUserPointer(), d_member1.Clone(), kR, kCookie2)); |
| 47 MOJO_HANDLE_SIGNAL_READABLE, kCookie2)); | |
| 48 | 94 |
| 49 // Can remove something based on a cookie. | 95 // Can remove something based on a cookie. |
| 50 EXPECT_EQ(MOJO_RESULT_OK, d->WaitSetRemove(kCookie0)); | 96 EXPECT_EQ(MOJO_RESULT_OK, d->WaitSetRemove(kCookie0)); |
| 51 | 97 |
| 52 // Trying to remove the same cookie again should fail. | 98 // Trying to remove the same cookie again should fail. |
| 53 EXPECT_EQ(MOJO_RESULT_NOT_FOUND, d->WaitSetRemove(kCookie0)); | 99 EXPECT_EQ(MOJO_RESULT_NOT_FOUND, d->WaitSetRemove(kCookie0)); |
| 54 | 100 |
| 55 // Can re-add it. | 101 // Can re-add it (still not satisfied, but satisfiable). |
| 56 EXPECT_EQ(MOJO_RESULT_OK, | 102 EXPECT_EQ(MOJO_RESULT_OK, |
| 57 d->WaitSetAdd(NullUserPointer(), d_member0.Clone(), | 103 d->WaitSetAdd(NullUserPointer(), d_member0.Clone(), kR, kCookie0)); |
| 58 MOJO_HANDLE_SIGNAL_READABLE, kCookie0)); | |
| 59 | 104 |
| 60 // TODO(vtl): Test waiting here. | 105 // Wait. Recall: |
| 106 // - |kCookie0| is for |d_member0| and is not satisfied (but satisfiable). |
| 107 // - |kCookie1| is for |d_member1| and is satisfied. |
| 108 // - |kCookie2| is for |d_member0| and is satisfied. |
| 109 { |
| 110 uint32_t num_results = 10u; |
| 111 MojoWaitSetResult results[10] = {}; |
| 112 uint32_t max_results = static_cast<uint32_t>(-1); |
| 113 EXPECT_EQ(MOJO_RESULT_OK, |
| 114 d->WaitSetWait(k10ms, MakeUserPointer(&num_results), |
| 115 MakeUserPointer(results), |
| 116 MakeUserPointer(&max_results))); |
| 117 EXPECT_EQ(2u, num_results); |
| 118 EXPECT_EQ(2u, max_results); |
| 61 | 119 |
| 62 // Can close a dispatcher that's "in" the wait set. | 120 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie1, kSignals1, |
| 121 MOJO_RESULT_OK, |
| 122 d_member1->GetHandleSignalsState())); |
| 123 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie2, kSignals2, |
| 124 MOJO_RESULT_OK, |
| 125 d_member0->GetHandleSignalsState())); |
| 126 } |
| 127 |
| 128 // Do the same, but test the "indefinite" (forever) wait code path and only |
| 129 // allow one result. |
| 130 { |
| 131 uint32_t num_results = 1u; |
| 132 MojoWaitSetResult results[1] = {}; |
| 133 uint32_t max_results = static_cast<uint32_t>(-1); |
| 134 EXPECT_EQ(MOJO_RESULT_OK, |
| 135 d->WaitSetWait(kIndefinite, MakeUserPointer(&num_results), |
| 136 MakeUserPointer(results), |
| 137 MakeUserPointer(&max_results))); |
| 138 EXPECT_EQ(1u, num_results); |
| 139 EXPECT_EQ(2u, max_results); |
| 140 |
| 141 // We should have *one* of the results. |
| 142 EXPECT_TRUE( |
| 143 CheckHasResult(num_results, results, kCookie1, kSignals1, |
| 144 MOJO_RESULT_OK, d_member1->GetHandleSignalsState()) || |
| 145 CheckHasResult(num_results, results, kCookie2, kSignals2, |
| 146 MOJO_RESULT_OK, d_member0->GetHandleSignalsState())); |
| 147 } |
| 148 |
| 149 // Change the state of |d_member0|. This makes |kCookie0| satisfied. |
| 150 d_member0->SetSatisfiedSignals(kR | kW); |
| 151 |
| 152 // Wait. |
| 153 { |
| 154 uint32_t num_results = 3u; |
| 155 MojoWaitSetResult results[3] = {}; |
| 156 uint32_t max_results = static_cast<uint32_t>(-1); |
| 157 EXPECT_EQ(MOJO_RESULT_OK, |
| 158 d->WaitSetWait(k10ms, MakeUserPointer(&num_results), |
| 159 MakeUserPointer(results), |
| 160 MakeUserPointer(&max_results))); |
| 161 EXPECT_EQ(3u, num_results); |
| 162 EXPECT_EQ(3u, max_results); |
| 163 |
| 164 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie0, kSignals0, |
| 165 MOJO_RESULT_OK, |
| 166 d_member0->GetHandleSignalsState())); |
| 167 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie1, kSignals1, |
| 168 MOJO_RESULT_OK, |
| 169 d_member1->GetHandleSignalsState())); |
| 170 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie2, kSignals2, |
| 171 MOJO_RESULT_OK, |
| 172 d_member0->GetHandleSignalsState())); |
| 173 } |
| 174 |
| 175 // Change the state of |d_member0| in two steps. |kCookie0| remains satisfied, |
| 176 // but |kCookie2| becomes unsatisfiable. |
| 177 d_member0->SetSatisfiedSignals(kR); |
| 178 d_member0->SetSatisfiableSignals(kR); |
| 179 |
| 180 // Wait. |
| 181 { |
| 182 uint32_t num_results = 10u; |
| 183 MojoWaitSetResult results[10] = {}; |
| 184 uint32_t max_results = static_cast<uint32_t>(-1); |
| 185 EXPECT_EQ(MOJO_RESULT_OK, |
| 186 d->WaitSetWait(k10ms, MakeUserPointer(&num_results), |
| 187 MakeUserPointer(results), |
| 188 MakeUserPointer(&max_results))); |
| 189 EXPECT_EQ(3u, num_results); |
| 190 EXPECT_EQ(3u, max_results); |
| 191 |
| 192 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie0, kSignals0, |
| 193 MOJO_RESULT_OK, |
| 194 d_member0->GetHandleSignalsState())); |
| 195 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie1, kSignals1, |
| 196 MOJO_RESULT_OK, |
| 197 d_member1->GetHandleSignalsState())); |
| 198 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie2, kSignals2, |
| 199 MOJO_RESULT_FAILED_PRECONDITION, |
| 200 d_member0->GetHandleSignalsState())); |
| 201 } |
| 202 |
| 203 // Can close a dispatcher that's "in" the wait set. This should make |
| 204 // |kCookie1| "cancelled". |
| 63 EXPECT_EQ(MOJO_RESULT_OK, d_member1->Close()); | 205 EXPECT_EQ(MOJO_RESULT_OK, d_member1->Close()); |
| 64 | 206 |
| 65 // TODO(vtl): Test waiting here. | 207 // Wait. |
| 208 { |
| 209 uint32_t num_results = 10u; |
| 210 MojoWaitSetResult results[10] = {}; |
| 211 uint32_t max_results = static_cast<uint32_t>(-1); |
| 212 EXPECT_EQ(MOJO_RESULT_OK, |
| 213 d->WaitSetWait(k10ms, MakeUserPointer(&num_results), |
| 214 MakeUserPointer(results), |
| 215 MakeUserPointer(&max_results))); |
| 216 EXPECT_EQ(3u, num_results); |
| 217 EXPECT_EQ(3u, max_results); |
| 218 |
| 219 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie0, kSignals0, |
| 220 MOJO_RESULT_OK, |
| 221 d_member0->GetHandleSignalsState())); |
| 222 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie1, kSignals1, |
| 223 MOJO_RESULT_CANCELLED, |
| 224 MojoHandleSignalsState())); |
| 225 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie2, kSignals2, |
| 226 MOJO_RESULT_FAILED_PRECONDITION, |
| 227 d_member0->GetHandleSignalsState())); |
| 228 } |
| 66 | 229 |
| 67 // Can remove something whose dispatcher has been closed. | 230 // Can remove something whose dispatcher has been closed. |
| 68 EXPECT_EQ(MOJO_RESULT_OK, d->WaitSetRemove(kCookie1)); | 231 EXPECT_EQ(MOJO_RESULT_OK, d->WaitSetRemove(kCookie1)); |
| 69 | 232 |
| 70 // Can close the wait set when it's not empty. | 233 // Can close the wait set when it's not empty. |
| 71 EXPECT_EQ(MOJO_RESULT_OK, d->Close()); | 234 EXPECT_EQ(MOJO_RESULT_OK, d->Close()); |
| 72 | 235 |
| 73 EXPECT_EQ(MOJO_RESULT_OK, d_member0->Close()); | 236 EXPECT_EQ(MOJO_RESULT_OK, d_member0->Close()); |
| 74 } | 237 } |
| 75 | 238 |
| 76 // TODO(vtl): Test options validation for "create" and "add" (not that there's | 239 // TODO(vtl): Test options validation for "create" and "add" (not that there's |
| 77 // much to test). | 240 // much to test). |
| 78 | 241 |
| 79 } // namespace | 242 } // namespace |
| 80 } // namespace system | 243 } // namespace system |
| 81 } // namespace mojo | 244 } // namespace mojo |
| OLD | NEW |