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"
21 // Trivial subclass that makes the constructor public.
22 class TrivialDispatcher
: public Dispatcher
{
24 TrivialDispatcher() {}
26 Type
GetType() const override
{ return kTypeUnknown
; }
29 friend class base::RefCountedThreadSafe
<TrivialDispatcher
>;
30 ~TrivialDispatcher() override
{}
32 scoped_refptr
<Dispatcher
> CreateEquivalentDispatcherAndCloseImplNoLock()
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));
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
{
128 DUPLICATE_BUFFER_HANDLE
,
135 ThreadSafetyStressThread(base::WaitableEvent
* event
,
136 scoped_refptr
<Dispatcher
> dispatcher
,
138 : base::SimpleThread("thread_safety_stress_thread"),
140 dispatcher_(dispatcher
),
143 CHECK_LT(op_
, DISPATCHER_OP_COUNT
);
146 ~ThreadSafetyStressThread() override
{ Join(); }
149 void Run() override
{
155 MojoResult r
= dispatcher_
->Close();
156 EXPECT_TRUE(r
== MOJO_RESULT_OK
|| r
== MOJO_RESULT_INVALID_ARGUMENT
)
161 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT
,
162 dispatcher_
->WriteMessage(NullUserPointer(), 0, nullptr,
163 MOJO_WRITE_MESSAGE_FLAG_NONE
));
166 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT
,
167 dispatcher_
->ReadMessage(NullUserPointer(), NullUserPointer(),
169 MOJO_WRITE_MESSAGE_FLAG_NONE
));
172 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT
,
173 dispatcher_
->WriteData(NullUserPointer(), NullUserPointer(),
174 MOJO_WRITE_DATA_FLAG_NONE
));
176 case BEGIN_WRITE_DATA
:
178 MOJO_RESULT_INVALID_ARGUMENT
,
179 dispatcher_
->BeginWriteData(NullUserPointer(), NullUserPointer(),
180 MOJO_WRITE_DATA_FLAG_NONE
));
183 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT
, dispatcher_
->EndWriteData(0));
186 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT
,
187 dispatcher_
->ReadData(NullUserPointer(), NullUserPointer(),
188 MOJO_READ_DATA_FLAG_NONE
));
190 case BEGIN_READ_DATA
:
192 MOJO_RESULT_INVALID_ARGUMENT
,
193 dispatcher_
->BeginReadData(NullUserPointer(), NullUserPointer(),
194 MOJO_READ_DATA_FLAG_NONE
));
197 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT
, dispatcher_
->EndReadData(0));
199 case DUPLICATE_BUFFER_HANDLE
: {
200 scoped_refptr
<Dispatcher
> unused
;
202 MOJO_RESULT_INVALID_ARGUMENT
,
203 dispatcher_
->DuplicateBufferHandle(NullUserPointer(), &unused
));
207 scoped_ptr
<embedder::PlatformSharedBufferMapping
> unused
;
209 MOJO_RESULT_INVALID_ARGUMENT
,
210 dispatcher_
->MapBuffer(0u, 0u, MOJO_MAP_BUFFER_FLAG_NONE
, &unused
));
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
);
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
);
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_
;
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:
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:
299 } // Joins all the threads.
301 EXPECT_EQ(MOJO_RESULT_OK
, d
->Close());
306 } // namespace system