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