Home | History | Annotate | Download | only in common
      1 // Copyright (c) 2011 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 "content/common/gamepad_seqlock.h"
      6 
      7 #include <stdlib.h>
      8 
      9 #include "base/atomic_ref_count.h"
     10 #include "base/threading/platform_thread.h"
     11 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 namespace base {
     15 
     16 // Basic test to make sure that basic operation works correctly.
     17 
     18 struct TestData {
     19   unsigned a, b, c;
     20 };
     21 
     22 class BasicSeqLockTestThread : public PlatformThread::Delegate {
     23  public:
     24   BasicSeqLockTestThread() {}
     25 
     26   void Init(
     27       content::GamepadSeqLock* seqlock,
     28       TestData* data,
     29       base::subtle::Atomic32* ready) {
     30     seqlock_ = seqlock;
     31     data_ = data;
     32     ready_ = ready;
     33   }
     34   virtual void ThreadMain() {
     35     while (AtomicRefCountIsZero(ready_)) {
     36       PlatformThread::YieldCurrentThread();
     37     }
     38 
     39     for (unsigned i = 0; i < 1000; ++i) {
     40       TestData copy;
     41       base::subtle::Atomic32 version;
     42       do {
     43         version = seqlock_->ReadBegin();
     44         copy = *data_;
     45       } while (seqlock_->ReadRetry(version));
     46 
     47       EXPECT_EQ(copy.a + 100, copy.b);
     48       EXPECT_EQ(copy.c, copy.b + copy.a);
     49     }
     50 
     51     AtomicRefCountDec(ready_);
     52   }
     53 
     54  private:
     55   content::GamepadSeqLock* seqlock_;
     56   TestData* data_;
     57   base::AtomicRefCount* ready_;
     58 
     59   DISALLOW_COPY_AND_ASSIGN(BasicSeqLockTestThread);
     60 };
     61 
     62 TEST(GamepadSeqLockTest, ManyThreads) {
     63   content::GamepadSeqLock seqlock;
     64   TestData data = { 0, 0, 0 };
     65   base::AtomicRefCount ready = 0;
     66 
     67   ANNOTATE_BENIGN_RACE_SIZED(&data, sizeof(data), "Racey reads are discarded");
     68 
     69   static const unsigned kNumReaderThreads = 10;
     70   BasicSeqLockTestThread threads[kNumReaderThreads];
     71   PlatformThreadHandle handles[kNumReaderThreads];
     72 
     73   for (unsigned i = 0; i < kNumReaderThreads; ++i)
     74     threads[i].Init(&seqlock, &data, &ready);
     75   for (unsigned i = 0; i < kNumReaderThreads; ++i)
     76     ASSERT_TRUE(PlatformThread::Create(0, &threads[i], &handles[i]));
     77 
     78   // The main thread is the writer, and the spawned are readers.
     79   unsigned counter = 0;
     80   for (;;) {
     81     seqlock.WriteBegin();
     82     data.a = counter++;
     83     data.b = data.a + 100;
     84     data.c = data.b + data.a;
     85     seqlock.WriteEnd();
     86 
     87     if (counter == 1)
     88       base::AtomicRefCountIncN(&ready, kNumReaderThreads);
     89 
     90     if (AtomicRefCountIsZero(&ready))
     91       break;
     92   }
     93 
     94   for (unsigned i = 0; i < kNumReaderThreads; ++i)
     95     PlatformThread::Join(handles[i]);
     96 }
     97 
     98 }  // namespace base
     99