Home | History | Annotate | Download | only in system
      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