• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
TrivialDispatcher()23   TrivialDispatcher() {}
24 
GetType() const25   virtual Type GetType() const OVERRIDE {
26     return kTypeUnknown;
27   }
28 
29  private:
30   friend class base::RefCountedThreadSafe<TrivialDispatcher>;
~TrivialDispatcher()31   virtual ~TrivialDispatcher() {}
32 
33   virtual scoped_refptr<Dispatcher>
CreateEquivalentDispatcherAndCloseImplNoLock()34       CreateEquivalentDispatcherAndCloseImplNoLock() OVERRIDE {
35     lock().AssertAcquired();
36     return scoped_refptr<Dispatcher>(new TrivialDispatcher());
37   }
38 
39   DISALLOW_COPY_AND_ASSIGN(TrivialDispatcher);
40 };
41 
TEST(DispatcherTest,Basic)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 
ThreadSafetyStressThread(base::WaitableEvent * event,scoped_refptr<Dispatcher> dispatcher,DispatcherOp op)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 
~ThreadSafetyStressThread()127   virtual ~ThreadSafetyStressThread() {
128     Join();
129   }
130 
131  private:
Run()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 
TEST(DispatcherTest,ThreadSafetyStress)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 
TEST(DispatcherTest,ThreadSafetyStressNoClose)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