1 // Copyright 2013 The Chromium 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 // NOTE(vtl): Some of these tests are inherently flaky (e.g., if run on a 6 // heavily-loaded system). Sorry. |test::EpsilonDeadline()| may be increased to 7 // increase tolerance and reduce observed flakiness (though doing so reduces the 8 // meaningfulness of the test). 9 10 #include "mojo/edk/system/awakable_list.h" 11 12 #include "mojo/edk/system/handle_signals_state.h" 13 #include "mojo/edk/system/test_utils.h" 14 #include "mojo/edk/system/waiter.h" 15 #include "mojo/edk/system/waiter_test_utils.h" 16 #include "testing/gtest/include/gtest/gtest.h" 17 18 namespace mojo { 19 namespace edk { 20 namespace { 21 22 TEST(AwakableListTest, BasicCancel) { 23 MojoResult result; 24 uintptr_t context; 25 26 // Cancel immediately after thread start. 27 { 28 AwakableList awakable_list; 29 test::SimpleWaiterThread thread(&result, &context); 30 awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1); 31 thread.Start(); 32 awakable_list.CancelAll(); 33 // Double-remove okay: 34 awakable_list.Remove(thread.waiter()); 35 } // Join |thread|. 36 EXPECT_EQ(MOJO_RESULT_CANCELLED, result); 37 EXPECT_EQ(1u, context); 38 39 // Cancel before after thread start. 40 { 41 AwakableList awakable_list; 42 test::SimpleWaiterThread thread(&result, &context); 43 awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2); 44 awakable_list.CancelAll(); 45 thread.Start(); 46 } // Join |thread|. 47 EXPECT_EQ(MOJO_RESULT_CANCELLED, result); 48 EXPECT_EQ(2u, context); 49 50 // Cancel some time after thread start. 51 { 52 AwakableList awakable_list; 53 test::SimpleWaiterThread thread(&result, &context); 54 awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3); 55 thread.Start(); 56 test::Sleep(2 * test::EpsilonDeadline()); 57 awakable_list.CancelAll(); 58 } // Join |thread|. 59 EXPECT_EQ(MOJO_RESULT_CANCELLED, result); 60 EXPECT_EQ(3u, context); 61 } 62 63 TEST(AwakableListTest, BasicAwakeSatisfied) { 64 MojoResult result; 65 uintptr_t context; 66 67 // Awake immediately after thread start. 68 { 69 AwakableList awakable_list; 70 test::SimpleWaiterThread thread(&result, &context); 71 awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1); 72 thread.Start(); 73 awakable_list.AwakeForStateChange(HandleSignalsState( 74 MOJO_HANDLE_SIGNAL_READABLE, 75 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE)); 76 awakable_list.Remove(thread.waiter()); 77 } // Join |thread|. 78 EXPECT_EQ(MOJO_RESULT_OK, result); 79 EXPECT_EQ(1u, context); 80 81 // Awake before after thread start. 82 { 83 AwakableList awakable_list; 84 test::SimpleWaiterThread thread(&result, &context); 85 awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2); 86 awakable_list.AwakeForStateChange(HandleSignalsState( 87 MOJO_HANDLE_SIGNAL_WRITABLE, 88 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE)); 89 awakable_list.Remove(thread.waiter()); 90 // Double-remove okay: 91 awakable_list.Remove(thread.waiter()); 92 thread.Start(); 93 } // Join |thread|. 94 EXPECT_EQ(MOJO_RESULT_OK, result); 95 EXPECT_EQ(2u, context); 96 97 // Awake some time after thread start. 98 { 99 AwakableList awakable_list; 100 test::SimpleWaiterThread thread(&result, &context); 101 awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3); 102 thread.Start(); 103 test::Sleep(2 * test::EpsilonDeadline()); 104 awakable_list.AwakeForStateChange(HandleSignalsState( 105 MOJO_HANDLE_SIGNAL_READABLE, 106 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE)); 107 awakable_list.Remove(thread.waiter()); 108 } // Join |thread|. 109 EXPECT_EQ(MOJO_RESULT_OK, result); 110 EXPECT_EQ(3u, context); 111 } 112 113 TEST(AwakableListTest, BasicAwakeUnsatisfiable) { 114 MojoResult result; 115 uintptr_t context; 116 117 // Awake (for unsatisfiability) immediately after thread start. 118 { 119 AwakableList awakable_list; 120 test::SimpleWaiterThread thread(&result, &context); 121 awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1); 122 thread.Start(); 123 awakable_list.AwakeForStateChange(HandleSignalsState( 124 MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_WRITABLE)); 125 awakable_list.Remove(thread.waiter()); 126 } // Join |thread|. 127 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); 128 EXPECT_EQ(1u, context); 129 130 // Awake (for unsatisfiability) before after thread start. 131 { 132 AwakableList awakable_list; 133 test::SimpleWaiterThread thread(&result, &context); 134 awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2); 135 awakable_list.AwakeForStateChange(HandleSignalsState( 136 MOJO_HANDLE_SIGNAL_READABLE, MOJO_HANDLE_SIGNAL_READABLE)); 137 awakable_list.Remove(thread.waiter()); 138 thread.Start(); 139 } // Join |thread|. 140 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); 141 EXPECT_EQ(2u, context); 142 143 // Awake (for unsatisfiability) some time after thread start. 144 { 145 AwakableList awakable_list; 146 test::SimpleWaiterThread thread(&result, &context); 147 awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3); 148 thread.Start(); 149 test::Sleep(2 * test::EpsilonDeadline()); 150 awakable_list.AwakeForStateChange(HandleSignalsState( 151 MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_WRITABLE)); 152 awakable_list.Remove(thread.waiter()); 153 // Double-remove okay: 154 awakable_list.Remove(thread.waiter()); 155 } // Join |thread|. 156 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); 157 EXPECT_EQ(3u, context); 158 } 159 160 TEST(AwakableListTest, MultipleAwakables) { 161 MojoResult result1; 162 MojoResult result2; 163 MojoResult result3; 164 MojoResult result4; 165 uintptr_t context1; 166 uintptr_t context2; 167 uintptr_t context3; 168 uintptr_t context4; 169 170 // Cancel two awakables. 171 { 172 AwakableList awakable_list; 173 test::SimpleWaiterThread thread1(&result1, &context1); 174 awakable_list.Add(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1); 175 thread1.Start(); 176 test::SimpleWaiterThread thread2(&result2, &context2); 177 awakable_list.Add(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2); 178 thread2.Start(); 179 test::Sleep(2 * test::EpsilonDeadline()); 180 awakable_list.CancelAll(); 181 } // Join threads. 182 EXPECT_EQ(MOJO_RESULT_CANCELLED, result1); 183 EXPECT_EQ(1u, context1); 184 EXPECT_EQ(MOJO_RESULT_CANCELLED, result2); 185 EXPECT_EQ(2u, context2); 186 187 // Awake one awakable, cancel other. 188 { 189 AwakableList awakable_list; 190 test::SimpleWaiterThread thread1(&result1, &context1); 191 awakable_list.Add(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3); 192 thread1.Start(); 193 test::SimpleWaiterThread thread2(&result2, &context2); 194 awakable_list.Add(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 4); 195 thread2.Start(); 196 test::Sleep(2 * test::EpsilonDeadline()); 197 awakable_list.AwakeForStateChange(HandleSignalsState( 198 MOJO_HANDLE_SIGNAL_READABLE, 199 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE)); 200 awakable_list.Remove(thread1.waiter()); 201 awakable_list.CancelAll(); 202 } // Join threads. 203 EXPECT_EQ(MOJO_RESULT_OK, result1); 204 EXPECT_EQ(3u, context1); 205 EXPECT_EQ(MOJO_RESULT_CANCELLED, result2); 206 EXPECT_EQ(4u, context2); 207 208 // Cancel one awakable, awake other for unsatisfiability. 209 { 210 AwakableList awakable_list; 211 test::SimpleWaiterThread thread1(&result1, &context1); 212 awakable_list.Add(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 5); 213 thread1.Start(); 214 test::SimpleWaiterThread thread2(&result2, &context2); 215 awakable_list.Add(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 6); 216 thread2.Start(); 217 test::Sleep(2 * test::EpsilonDeadline()); 218 awakable_list.AwakeForStateChange(HandleSignalsState( 219 MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_READABLE)); 220 awakable_list.Remove(thread2.waiter()); 221 awakable_list.CancelAll(); 222 } // Join threads. 223 EXPECT_EQ(MOJO_RESULT_CANCELLED, result1); 224 EXPECT_EQ(5u, context1); 225 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result2); 226 EXPECT_EQ(6u, context2); 227 228 // Cancel one awakable, awake other for unsatisfiability. 229 { 230 AwakableList awakable_list; 231 test::SimpleWaiterThread thread1(&result1, &context1); 232 awakable_list.Add(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 7); 233 thread1.Start(); 234 235 test::Sleep(1 * test::EpsilonDeadline()); 236 237 // Should do nothing. 238 awakable_list.AwakeForStateChange(HandleSignalsState( 239 MOJO_HANDLE_SIGNAL_NONE, 240 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE)); 241 242 test::SimpleWaiterThread thread2(&result2, &context2); 243 awakable_list.Add(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 8); 244 thread2.Start(); 245 246 test::Sleep(1 * test::EpsilonDeadline()); 247 248 // Awake #1. 249 awakable_list.AwakeForStateChange(HandleSignalsState( 250 MOJO_HANDLE_SIGNAL_READABLE, 251 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE)); 252 awakable_list.Remove(thread1.waiter()); 253 254 test::Sleep(1 * test::EpsilonDeadline()); 255 256 test::SimpleWaiterThread thread3(&result3, &context3); 257 awakable_list.Add(thread3.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 9); 258 thread3.Start(); 259 260 test::SimpleWaiterThread thread4(&result4, &context4); 261 awakable_list.Add(thread4.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 10); 262 thread4.Start(); 263 264 test::Sleep(1 * test::EpsilonDeadline()); 265 266 // Awake #2 and #3 for unsatisfiability. 267 awakable_list.AwakeForStateChange(HandleSignalsState( 268 MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_READABLE)); 269 awakable_list.Remove(thread2.waiter()); 270 awakable_list.Remove(thread3.waiter()); 271 272 // Cancel #4. 273 awakable_list.CancelAll(); 274 } // Join threads. 275 EXPECT_EQ(MOJO_RESULT_OK, result1); 276 EXPECT_EQ(7u, context1); 277 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result2); 278 EXPECT_EQ(8u, context2); 279 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result3); 280 EXPECT_EQ(9u, context3); 281 EXPECT_EQ(MOJO_RESULT_CANCELLED, result4); 282 EXPECT_EQ(10u, context4); 283 } 284 285 class KeepAwakable : public Awakable { 286 public: 287 KeepAwakable() : awake_count(0) {} 288 289 bool Awake(MojoResult result, uintptr_t context) override { 290 awake_count++; 291 return true; 292 } 293 294 int awake_count; 295 296 DISALLOW_COPY_AND_ASSIGN(KeepAwakable); 297 }; 298 299 class RemoveAwakable : public Awakable { 300 public: 301 RemoveAwakable() : awake_count(0) {} 302 303 bool Awake(MojoResult result, uintptr_t context) override { 304 awake_count++; 305 return false; 306 } 307 308 int awake_count; 309 310 DISALLOW_COPY_AND_ASSIGN(RemoveAwakable); 311 }; 312 313 TEST(AwakableListTest, KeepAwakablesReturningTrue) { 314 KeepAwakable keep0; 315 KeepAwakable keep1; 316 RemoveAwakable remove0; 317 RemoveAwakable remove1; 318 RemoveAwakable remove2; 319 320 HandleSignalsState hss(MOJO_HANDLE_SIGNAL_WRITABLE, 321 MOJO_HANDLE_SIGNAL_WRITABLE); 322 323 AwakableList remove_all; 324 remove_all.Add(&remove0, MOJO_HANDLE_SIGNAL_WRITABLE, 0); 325 remove_all.Add(&remove1, MOJO_HANDLE_SIGNAL_WRITABLE, 0); 326 327 remove_all.AwakeForStateChange(hss); 328 EXPECT_EQ(remove0.awake_count, 1); 329 EXPECT_EQ(remove1.awake_count, 1); 330 331 remove_all.AwakeForStateChange(hss); 332 EXPECT_EQ(remove0.awake_count, 1); 333 EXPECT_EQ(remove1.awake_count, 1); 334 335 AwakableList remove_first; 336 remove_first.Add(&remove2, MOJO_HANDLE_SIGNAL_WRITABLE, 0); 337 remove_first.Add(&keep0, MOJO_HANDLE_SIGNAL_WRITABLE, 0); 338 remove_first.Add(&keep1, MOJO_HANDLE_SIGNAL_WRITABLE, 0); 339 340 remove_first.AwakeForStateChange(hss); 341 EXPECT_EQ(keep0.awake_count, 1); 342 EXPECT_EQ(keep1.awake_count, 1); 343 EXPECT_EQ(remove2.awake_count, 1); 344 345 remove_first.AwakeForStateChange(hss); 346 EXPECT_EQ(keep0.awake_count, 2); 347 EXPECT_EQ(keep1.awake_count, 2); 348 EXPECT_EQ(remove2.awake_count, 1); 349 350 remove_first.Remove(&keep0); 351 remove_first.Remove(&keep1); 352 } 353 354 } // namespace 355 } // namespace edk 356 } // namespace mojo 357