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 17namespace mojo { 18namespace system { 19namespace { 20 21// Trivial subclass that makes the constructor public. 22class 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 41TEST(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 130class 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 270TEST(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 297TEST(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 327