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