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