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::EpsilonTimeout()| 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/system/waiter_list.h" 11 12#include "base/threading/platform_thread.h" // For |Sleep()|. 13#include "base/time/time.h" 14#include "mojo/system/handle_signals_state.h" 15#include "mojo/system/test_utils.h" 16#include "mojo/system/waiter.h" 17#include "mojo/system/waiter_test_utils.h" 18#include "testing/gtest/include/gtest/gtest.h" 19 20namespace mojo { 21namespace system { 22namespace { 23 24TEST(WaiterListTest, BasicCancel) { 25 MojoResult result; 26 uint32_t context; 27 28 // Cancel immediately after thread start. 29 { 30 WaiterList waiter_list; 31 test::SimpleWaiterThread thread(&result, &context); 32 waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1); 33 thread.Start(); 34 waiter_list.CancelAllWaiters(); 35 // Double-remove okay: 36 waiter_list.RemoveWaiter(thread.waiter()); 37 } // Join |thread|. 38 EXPECT_EQ(MOJO_RESULT_CANCELLED, result); 39 EXPECT_EQ(1u, context); 40 41 // Cancel before after thread start. 42 { 43 WaiterList waiter_list; 44 test::SimpleWaiterThread thread(&result, &context); 45 waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2); 46 waiter_list.CancelAllWaiters(); 47 thread.Start(); 48 } // Join |thread|. 49 EXPECT_EQ(MOJO_RESULT_CANCELLED, result); 50 EXPECT_EQ(2u, context); 51 52 // Cancel some time after thread start. 53 { 54 WaiterList waiter_list; 55 test::SimpleWaiterThread thread(&result, &context); 56 waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3); 57 thread.Start(); 58 base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); 59 waiter_list.CancelAllWaiters(); 60 } // Join |thread|. 61 EXPECT_EQ(MOJO_RESULT_CANCELLED, result); 62 EXPECT_EQ(3u, context); 63} 64 65TEST(WaiterListTest, BasicAwakeSatisfied) { 66 MojoResult result; 67 uint32_t context; 68 69 // Awake immediately after thread start. 70 { 71 WaiterList waiter_list; 72 test::SimpleWaiterThread thread(&result, &context); 73 waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1); 74 thread.Start(); 75 waiter_list.AwakeWaitersForStateChange(HandleSignalsState( 76 MOJO_HANDLE_SIGNAL_READABLE, 77 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE)); 78 waiter_list.RemoveWaiter(thread.waiter()); 79 } // Join |thread|. 80 EXPECT_EQ(MOJO_RESULT_OK, result); 81 EXPECT_EQ(1u, context); 82 83 // Awake before after thread start. 84 { 85 WaiterList waiter_list; 86 test::SimpleWaiterThread thread(&result, &context); 87 waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2); 88 waiter_list.AwakeWaitersForStateChange(HandleSignalsState( 89 MOJO_HANDLE_SIGNAL_WRITABLE, 90 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE)); 91 waiter_list.RemoveWaiter(thread.waiter()); 92 // Double-remove okay: 93 waiter_list.RemoveWaiter(thread.waiter()); 94 thread.Start(); 95 } // Join |thread|. 96 EXPECT_EQ(MOJO_RESULT_OK, result); 97 EXPECT_EQ(2u, context); 98 99 // Awake some time after thread start. 100 { 101 WaiterList waiter_list; 102 test::SimpleWaiterThread thread(&result, &context); 103 waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3); 104 thread.Start(); 105 base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); 106 waiter_list.AwakeWaitersForStateChange(HandleSignalsState( 107 MOJO_HANDLE_SIGNAL_READABLE, 108 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE)); 109 waiter_list.RemoveWaiter(thread.waiter()); 110 } // Join |thread|. 111 EXPECT_EQ(MOJO_RESULT_OK, result); 112 EXPECT_EQ(3u, context); 113} 114 115TEST(WaiterListTest, BasicAwakeUnsatisfiable) { 116 MojoResult result; 117 uint32_t context; 118 119 // Awake (for unsatisfiability) immediately after thread start. 120 { 121 WaiterList waiter_list; 122 test::SimpleWaiterThread thread(&result, &context); 123 waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1); 124 thread.Start(); 125 waiter_list.AwakeWaitersForStateChange(HandleSignalsState( 126 MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_WRITABLE)); 127 waiter_list.RemoveWaiter(thread.waiter()); 128 } // Join |thread|. 129 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); 130 EXPECT_EQ(1u, context); 131 132 // Awake (for unsatisfiability) before after thread start. 133 { 134 WaiterList waiter_list; 135 test::SimpleWaiterThread thread(&result, &context); 136 waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2); 137 waiter_list.AwakeWaitersForStateChange(HandleSignalsState( 138 MOJO_HANDLE_SIGNAL_READABLE, MOJO_HANDLE_SIGNAL_READABLE)); 139 waiter_list.RemoveWaiter(thread.waiter()); 140 thread.Start(); 141 } // Join |thread|. 142 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); 143 EXPECT_EQ(2u, context); 144 145 // Awake (for unsatisfiability) some time after thread start. 146 { 147 WaiterList waiter_list; 148 test::SimpleWaiterThread thread(&result, &context); 149 waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3); 150 thread.Start(); 151 base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); 152 waiter_list.AwakeWaitersForStateChange(HandleSignalsState( 153 MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_WRITABLE)); 154 waiter_list.RemoveWaiter(thread.waiter()); 155 // Double-remove okay: 156 waiter_list.RemoveWaiter(thread.waiter()); 157 } // Join |thread|. 158 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); 159 EXPECT_EQ(3u, context); 160} 161 162TEST(WaiterListTest, MultipleWaiters) { 163 MojoResult result1; 164 MojoResult result2; 165 MojoResult result3; 166 MojoResult result4; 167 uint32_t context1; 168 uint32_t context2; 169 uint32_t context3; 170 uint32_t context4; 171 172 // Cancel two waiters. 173 { 174 WaiterList waiter_list; 175 test::SimpleWaiterThread thread1(&result1, &context1); 176 waiter_list.AddWaiter(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1); 177 thread1.Start(); 178 test::SimpleWaiterThread thread2(&result2, &context2); 179 waiter_list.AddWaiter(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2); 180 thread2.Start(); 181 base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); 182 waiter_list.CancelAllWaiters(); 183 } // Join threads. 184 EXPECT_EQ(MOJO_RESULT_CANCELLED, result1); 185 EXPECT_EQ(1u, context1); 186 EXPECT_EQ(MOJO_RESULT_CANCELLED, result2); 187 EXPECT_EQ(2u, context2); 188 189 // Awake one waiter, cancel other. 190 { 191 WaiterList waiter_list; 192 test::SimpleWaiterThread thread1(&result1, &context1); 193 waiter_list.AddWaiter(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3); 194 thread1.Start(); 195 test::SimpleWaiterThread thread2(&result2, &context2); 196 waiter_list.AddWaiter(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 4); 197 thread2.Start(); 198 base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); 199 waiter_list.AwakeWaitersForStateChange(HandleSignalsState( 200 MOJO_HANDLE_SIGNAL_READABLE, 201 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE)); 202 waiter_list.RemoveWaiter(thread1.waiter()); 203 waiter_list.CancelAllWaiters(); 204 } // Join threads. 205 EXPECT_EQ(MOJO_RESULT_OK, result1); 206 EXPECT_EQ(3u, context1); 207 EXPECT_EQ(MOJO_RESULT_CANCELLED, result2); 208 EXPECT_EQ(4u, context2); 209 210 // Cancel one waiter, awake other for unsatisfiability. 211 { 212 WaiterList waiter_list; 213 test::SimpleWaiterThread thread1(&result1, &context1); 214 waiter_list.AddWaiter(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 5); 215 thread1.Start(); 216 test::SimpleWaiterThread thread2(&result2, &context2); 217 waiter_list.AddWaiter(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 6); 218 thread2.Start(); 219 base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); 220 waiter_list.AwakeWaitersForStateChange(HandleSignalsState( 221 MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_READABLE)); 222 waiter_list.RemoveWaiter(thread2.waiter()); 223 waiter_list.CancelAllWaiters(); 224 } // Join threads. 225 EXPECT_EQ(MOJO_RESULT_CANCELLED, result1); 226 EXPECT_EQ(5u, context1); 227 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result2); 228 EXPECT_EQ(6u, context2); 229 230 // Cancel one waiter, awake other for unsatisfiability. 231 { 232 WaiterList waiter_list; 233 test::SimpleWaiterThread thread1(&result1, &context1); 234 waiter_list.AddWaiter(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 7); 235 thread1.Start(); 236 237 base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); 238 239 // Should do nothing. 240 waiter_list.AwakeWaitersForStateChange(HandleSignalsState( 241 MOJO_HANDLE_SIGNAL_NONE, 242 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE)); 243 244 test::SimpleWaiterThread thread2(&result2, &context2); 245 waiter_list.AddWaiter(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 8); 246 thread2.Start(); 247 248 base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); 249 250 // Awake #1. 251 waiter_list.AwakeWaitersForStateChange(HandleSignalsState( 252 MOJO_HANDLE_SIGNAL_READABLE, 253 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE)); 254 waiter_list.RemoveWaiter(thread1.waiter()); 255 256 base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); 257 258 test::SimpleWaiterThread thread3(&result3, &context3); 259 waiter_list.AddWaiter(thread3.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 9); 260 thread3.Start(); 261 262 test::SimpleWaiterThread thread4(&result4, &context4); 263 waiter_list.AddWaiter(thread4.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 10); 264 thread4.Start(); 265 266 base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); 267 268 // Awake #2 and #3 for unsatisfiability. 269 waiter_list.AwakeWaitersForStateChange(HandleSignalsState( 270 MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_READABLE)); 271 waiter_list.RemoveWaiter(thread2.waiter()); 272 waiter_list.RemoveWaiter(thread3.waiter()); 273 274 // Cancel #4. 275 waiter_list.CancelAllWaiters(); 276 } // Join threads. 277 EXPECT_EQ(MOJO_RESULT_OK, result1); 278 EXPECT_EQ(7u, context1); 279 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result2); 280 EXPECT_EQ(8u, context2); 281 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result3); 282 EXPECT_EQ(9u, context3); 283 EXPECT_EQ(MOJO_RESULT_CANCELLED, result4); 284 EXPECT_EQ(10u, context4); 285} 286 287} // namespace 288} // namespace system 289} // namespace mojo 290