| OLD | NEW |
| (Empty) |
| 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 #include "mojo/system/dispatcher.h" | |
| 6 | |
| 7 #include "base/macros.h" | |
| 8 #include "base/memory/ref_counted.h" | |
| 9 #include "base/memory/scoped_vector.h" | |
| 10 #include "base/synchronization/waitable_event.h" | |
| 11 #include "base/threading/simple_thread.h" | |
| 12 #include "mojo/embedder/platform_shared_buffer.h" | |
| 13 #include "mojo/system/memory.h" | |
| 14 #include "mojo/system/waiter.h" | |
| 15 #include "testing/gtest/include/gtest/gtest.h" | |
| 16 | |
| 17 namespace mojo { | |
| 18 namespace system { | |
| 19 namespace { | |
| 20 | |
| 21 // Trivial subclass that makes the constructor public. | |
| 22 class TrivialDispatcher : public Dispatcher { | |
| 23 public: | |
| 24 TrivialDispatcher() {} | |
| 25 | |
| 26 virtual Type GetType() const override { return kTypeUnknown; } | |
| 27 | |
| 28 private: | |
| 29 friend class base::RefCountedThreadSafe<TrivialDispatcher>; | |
| 30 virtual ~TrivialDispatcher() {} | |
| 31 | |
| 32 virtual scoped_refptr<Dispatcher> | |
| 33 CreateEquivalentDispatcherAndCloseImplNoLock() override { | |
| 34 lock().AssertAcquired(); | |
| 35 return scoped_refptr<Dispatcher>(new TrivialDispatcher()); | |
| 36 } | |
| 37 | |
| 38 DISALLOW_COPY_AND_ASSIGN(TrivialDispatcher); | |
| 39 }; | |
| 40 | |
| 41 TEST(DispatcherTest, Basic) { | |
| 42 scoped_refptr<Dispatcher> d(new TrivialDispatcher()); | |
| 43 | |
| 44 EXPECT_EQ(Dispatcher::kTypeUnknown, d->GetType()); | |
| 45 | |
| 46 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, | |
| 47 d->WriteMessage( | |
| 48 NullUserPointer(), 0, nullptr, MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
| 49 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, | |
| 50 d->ReadMessage(NullUserPointer(), | |
| 51 NullUserPointer(), | |
| 52 nullptr, | |
| 53 nullptr, | |
| 54 MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
| 55 EXPECT_EQ( | |
| 56 MOJO_RESULT_INVALID_ARGUMENT, | |
| 57 d->WriteData( | |
| 58 NullUserPointer(), NullUserPointer(), MOJO_WRITE_DATA_FLAG_NONE)); | |
| 59 EXPECT_EQ( | |
| 60 MOJO_RESULT_INVALID_ARGUMENT, | |
| 61 d->BeginWriteData( | |
| 62 NullUserPointer(), NullUserPointer(), MOJO_WRITE_DATA_FLAG_NONE)); | |
| 63 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, d->EndWriteData(0)); | |
| 64 EXPECT_EQ( | |
| 65 MOJO_RESULT_INVALID_ARGUMENT, | |
| 66 d->ReadData( | |
| 67 NullUserPointer(), NullUserPointer(), MOJO_READ_DATA_FLAG_NONE)); | |
| 68 EXPECT_EQ( | |
| 69 MOJO_RESULT_INVALID_ARGUMENT, | |
| 70 d->BeginReadData( | |
| 71 NullUserPointer(), NullUserPointer(), MOJO_READ_DATA_FLAG_NONE)); | |
| 72 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, d->EndReadData(0)); | |
| 73 Waiter w; | |
| 74 w.Init(); | |
| 75 HandleSignalsState hss; | |
| 76 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, | |
| 77 d->AddWaiter(&w, ~MOJO_HANDLE_SIGNAL_NONE, 0, &hss)); | |
| 78 EXPECT_EQ(0u, hss.satisfied_signals); | |
| 79 EXPECT_EQ(0u, hss.satisfiable_signals); | |
| 80 // Okay to remove even if it wasn't added (or was already removed). | |
| 81 hss = HandleSignalsState(); | |
| 82 d->RemoveWaiter(&w, &hss); | |
| 83 EXPECT_EQ(0u, hss.satisfied_signals); | |
| 84 EXPECT_EQ(0u, hss.satisfiable_signals); | |
| 85 hss = HandleSignalsState(); | |
| 86 d->RemoveWaiter(&w, &hss); | |
| 87 EXPECT_EQ(0u, hss.satisfied_signals); | |
| 88 EXPECT_EQ(0u, hss.satisfiable_signals); | |
| 89 | |
| 90 EXPECT_EQ(MOJO_RESULT_OK, d->Close()); | |
| 91 | |
| 92 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, | |
| 93 d->WriteMessage( | |
| 94 NullUserPointer(), 0, nullptr, MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
| 95 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, | |
| 96 d->ReadMessage(NullUserPointer(), | |
| 97 NullUserPointer(), | |
| 98 nullptr, | |
| 99 nullptr, | |
| 100 MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
| 101 EXPECT_EQ( | |
| 102 MOJO_RESULT_INVALID_ARGUMENT, | |
| 103 d->WriteData( | |
| 104 NullUserPointer(), NullUserPointer(), MOJO_WRITE_DATA_FLAG_NONE)); | |
| 105 EXPECT_EQ( | |
| 106 MOJO_RESULT_INVALID_ARGUMENT, | |
| 107 d->BeginWriteData( | |
| 108 NullUserPointer(), NullUserPointer(), MOJO_WRITE_DATA_FLAG_NONE)); | |
| 109 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, d->EndWriteData(0)); | |
| 110 EXPECT_EQ( | |
| 111 MOJO_RESULT_INVALID_ARGUMENT, | |
| 112 d->ReadData( | |
| 113 NullUserPointer(), NullUserPointer(), MOJO_READ_DATA_FLAG_NONE)); | |
| 114 EXPECT_EQ( | |
| 115 MOJO_RESULT_INVALID_ARGUMENT, | |
| 116 d->BeginReadData( | |
| 117 NullUserPointer(), NullUserPointer(), MOJO_READ_DATA_FLAG_NONE)); | |
| 118 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, d->EndReadData(0)); | |
| 119 hss = HandleSignalsState(); | |
| 120 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, | |
| 121 d->AddWaiter(&w, ~MOJO_HANDLE_SIGNAL_NONE, 0, &hss)); | |
| 122 EXPECT_EQ(0u, hss.satisfied_signals); | |
| 123 EXPECT_EQ(0u, hss.satisfiable_signals); | |
| 124 hss = HandleSignalsState(); | |
| 125 d->RemoveWaiter(&w, &hss); | |
| 126 EXPECT_EQ(0u, hss.satisfied_signals); | |
| 127 EXPECT_EQ(0u, hss.satisfiable_signals); | |
| 128 } | |
| 129 | |
| 130 class ThreadSafetyStressThread : public base::SimpleThread { | |
| 131 public: | |
| 132 enum DispatcherOp { | |
| 133 CLOSE = 0, | |
| 134 WRITE_MESSAGE, | |
| 135 READ_MESSAGE, | |
| 136 WRITE_DATA, | |
| 137 BEGIN_WRITE_DATA, | |
| 138 END_WRITE_DATA, | |
| 139 READ_DATA, | |
| 140 BEGIN_READ_DATA, | |
| 141 END_READ_DATA, | |
| 142 DUPLICATE_BUFFER_HANDLE, | |
| 143 MAP_BUFFER, | |
| 144 ADD_WAITER, | |
| 145 REMOVE_WAITER, | |
| 146 DISPATCHER_OP_COUNT | |
| 147 }; | |
| 148 | |
| 149 ThreadSafetyStressThread(base::WaitableEvent* event, | |
| 150 scoped_refptr<Dispatcher> dispatcher, | |
| 151 DispatcherOp op) | |
| 152 : base::SimpleThread("thread_safety_stress_thread"), | |
| 153 event_(event), | |
| 154 dispatcher_(dispatcher), | |
| 155 op_(op) { | |
| 156 CHECK_LE(0, op_); | |
| 157 CHECK_LT(op_, DISPATCHER_OP_COUNT); | |
| 158 } | |
| 159 | |
| 160 virtual ~ThreadSafetyStressThread() { Join(); } | |
| 161 | |
| 162 private: | |
| 163 virtual void Run() override { | |
| 164 event_->Wait(); | |
| 165 | |
| 166 waiter_.Init(); | |
| 167 switch (op_) { | |
| 168 case CLOSE: { | |
| 169 MojoResult r = dispatcher_->Close(); | |
| 170 EXPECT_TRUE(r == MOJO_RESULT_OK || r == MOJO_RESULT_INVALID_ARGUMENT) | |
| 171 << "Result: " << r; | |
| 172 break; | |
| 173 } | |
| 174 case WRITE_MESSAGE: | |
| 175 EXPECT_EQ( | |
| 176 MOJO_RESULT_INVALID_ARGUMENT, | |
| 177 dispatcher_->WriteMessage( | |
| 178 NullUserPointer(), 0, nullptr, MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
| 179 break; | |
| 180 case READ_MESSAGE: | |
| 181 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, | |
| 182 dispatcher_->ReadMessage(NullUserPointer(), | |
| 183 NullUserPointer(), | |
| 184 nullptr, | |
| 185 nullptr, | |
| 186 MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
| 187 break; | |
| 188 case WRITE_DATA: | |
| 189 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, | |
| 190 dispatcher_->WriteData(NullUserPointer(), | |
| 191 NullUserPointer(), | |
| 192 MOJO_WRITE_DATA_FLAG_NONE)); | |
| 193 break; | |
| 194 case BEGIN_WRITE_DATA: | |
| 195 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, | |
| 196 dispatcher_->BeginWriteData(NullUserPointer(), | |
| 197 NullUserPointer(), | |
| 198 MOJO_WRITE_DATA_FLAG_NONE)); | |
| 199 break; | |
| 200 case END_WRITE_DATA: | |
| 201 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, dispatcher_->EndWriteData(0)); | |
| 202 break; | |
| 203 case READ_DATA: | |
| 204 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, | |
| 205 dispatcher_->ReadData(NullUserPointer(), | |
| 206 NullUserPointer(), | |
| 207 MOJO_READ_DATA_FLAG_NONE)); | |
| 208 break; | |
| 209 case BEGIN_READ_DATA: | |
| 210 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, | |
| 211 dispatcher_->BeginReadData(NullUserPointer(), | |
| 212 NullUserPointer(), | |
| 213 MOJO_READ_DATA_FLAG_NONE)); | |
| 214 break; | |
| 215 case END_READ_DATA: | |
| 216 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, dispatcher_->EndReadData(0)); | |
| 217 break; | |
| 218 case DUPLICATE_BUFFER_HANDLE: { | |
| 219 scoped_refptr<Dispatcher> unused; | |
| 220 EXPECT_EQ( | |
| 221 MOJO_RESULT_INVALID_ARGUMENT, | |
| 222 dispatcher_->DuplicateBufferHandle(NullUserPointer(), &unused)); | |
| 223 break; | |
| 224 } | |
| 225 case MAP_BUFFER: { | |
| 226 scoped_ptr<embedder::PlatformSharedBufferMapping> unused; | |
| 227 EXPECT_EQ( | |
| 228 MOJO_RESULT_INVALID_ARGUMENT, | |
| 229 dispatcher_->MapBuffer(0u, 0u, MOJO_MAP_BUFFER_FLAG_NONE, &unused)); | |
| 230 break; | |
| 231 } | |
| 232 case ADD_WAITER: { | |
| 233 HandleSignalsState hss; | |
| 234 MojoResult r = | |
| 235 dispatcher_->AddWaiter(&waiter_, ~MOJO_HANDLE_SIGNAL_NONE, 0, &hss); | |
| 236 EXPECT_TRUE(r == MOJO_RESULT_FAILED_PRECONDITION || | |
| 237 r == MOJO_RESULT_INVALID_ARGUMENT); | |
| 238 EXPECT_EQ(0u, hss.satisfied_signals); | |
| 239 EXPECT_EQ(0u, hss.satisfiable_signals); | |
| 240 break; | |
| 241 } | |
| 242 case REMOVE_WAITER: { | |
| 243 HandleSignalsState hss; | |
| 244 dispatcher_->RemoveWaiter(&waiter_, &hss); | |
| 245 EXPECT_EQ(0u, hss.satisfied_signals); | |
| 246 EXPECT_EQ(0u, hss.satisfiable_signals); | |
| 247 break; | |
| 248 } | |
| 249 default: | |
| 250 NOTREACHED(); | |
| 251 break; | |
| 252 } | |
| 253 | |
| 254 // Always try to remove the waiter, in case we added it. | |
| 255 HandleSignalsState hss; | |
| 256 dispatcher_->RemoveWaiter(&waiter_, &hss); | |
| 257 EXPECT_EQ(0u, hss.satisfied_signals); | |
| 258 EXPECT_EQ(0u, hss.satisfiable_signals); | |
| 259 } | |
| 260 | |
| 261 base::WaitableEvent* const event_; | |
| 262 const scoped_refptr<Dispatcher> dispatcher_; | |
| 263 const DispatcherOp op_; | |
| 264 | |
| 265 Waiter waiter_; | |
| 266 | |
| 267 DISALLOW_COPY_AND_ASSIGN(ThreadSafetyStressThread); | |
| 268 }; | |
| 269 | |
| 270 TEST(DispatcherTest, ThreadSafetyStress) { | |
| 271 static const size_t kRepeatCount = 20; | |
| 272 static const size_t kNumThreads = 100; | |
| 273 | |
| 274 for (size_t i = 0; i < kRepeatCount; i++) { | |
| 275 // Manual reset, not initially signalled. | |
| 276 base::WaitableEvent event(true, false); | |
| 277 scoped_refptr<Dispatcher> d(new TrivialDispatcher()); | |
| 278 | |
| 279 { | |
| 280 ScopedVector<ThreadSafetyStressThread> threads; | |
| 281 for (size_t j = 0; j < kNumThreads; j++) { | |
| 282 ThreadSafetyStressThread::DispatcherOp op = | |
| 283 static_cast<ThreadSafetyStressThread::DispatcherOp>( | |
| 284 (i + j) % ThreadSafetyStressThread::DISPATCHER_OP_COUNT); | |
| 285 threads.push_back(new ThreadSafetyStressThread(&event, d, op)); | |
| 286 threads.back()->Start(); | |
| 287 } | |
| 288 // Kicks off real work on the threads: | |
| 289 event.Signal(); | |
| 290 } // Joins all the threads. | |
| 291 | |
| 292 // One of the threads should already have closed the dispatcher. | |
| 293 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, d->Close()); | |
| 294 } | |
| 295 } | |
| 296 | |
| 297 TEST(DispatcherTest, ThreadSafetyStressNoClose) { | |
| 298 static const size_t kRepeatCount = 20; | |
| 299 static const size_t kNumThreads = 100; | |
| 300 | |
| 301 for (size_t i = 0; i < kRepeatCount; i++) { | |
| 302 // Manual reset, not initially signalled. | |
| 303 base::WaitableEvent event(true, false); | |
| 304 scoped_refptr<Dispatcher> d(new TrivialDispatcher()); | |
| 305 | |
| 306 { | |
| 307 ScopedVector<ThreadSafetyStressThread> threads; | |
| 308 for (size_t j = 0; j < kNumThreads; j++) { | |
| 309 ThreadSafetyStressThread::DispatcherOp op = | |
| 310 static_cast<ThreadSafetyStressThread::DispatcherOp>( | |
| 311 (i + j) % (ThreadSafetyStressThread::DISPATCHER_OP_COUNT - 1) + | |
| 312 1); | |
| 313 threads.push_back(new ThreadSafetyStressThread(&event, d, op)); | |
| 314 threads.back()->Start(); | |
| 315 } | |
| 316 // Kicks off real work on the threads: | |
| 317 event.Signal(); | |
| 318 } // Joins all the threads. | |
| 319 | |
| 320 EXPECT_EQ(MOJO_RESULT_OK, d->Close()); | |
| 321 } | |
| 322 } | |
| 323 | |
| 324 } // namespace | |
| 325 } // namespace system | |
| 326 } // namespace mojo | |
| OLD | NEW |