| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/common/gamepad_seqlock.h" |
| |
| #include <stdlib.h> |
| |
| #include "base/atomic_ref_count.h" |
| #include "base/threading/platform_thread.h" |
| #include "base/third_party/dynamic_annotations/dynamic_annotations.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace base { |
| |
| // Basic test to make sure that basic operation works correctly. |
| |
| struct TestData { |
| unsigned a, b, c; |
| }; |
| |
| class BasicSeqLockTestThread : public PlatformThread::Delegate { |
| public: |
| BasicSeqLockTestThread() {} |
| |
| void Init( |
| content::GamepadSeqLock* seqlock, |
| TestData* data, |
| base::subtle::Atomic32* ready) { |
| seqlock_ = seqlock; |
| data_ = data; |
| ready_ = ready; |
| } |
| virtual void ThreadMain() { |
| while (AtomicRefCountIsZero(ready_)) { |
| PlatformThread::YieldCurrentThread(); |
| } |
| |
| for (unsigned i = 0; i < 1000; ++i) { |
| TestData copy; |
| base::subtle::Atomic32 version; |
| do { |
| version = seqlock_->ReadBegin(); |
| copy = *data_; |
| } while (seqlock_->ReadRetry(version)); |
| |
| EXPECT_EQ(copy.a + 100, copy.b); |
| EXPECT_EQ(copy.c, copy.b + copy.a); |
| } |
| |
| AtomicRefCountDec(ready_); |
| } |
| |
| private: |
| content::GamepadSeqLock* seqlock_; |
| TestData* data_; |
| base::AtomicRefCount* ready_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BasicSeqLockTestThread); |
| }; |
| |
| TEST(GamepadSeqLockTest, ManyThreads) { |
| content::GamepadSeqLock seqlock; |
| TestData data = { 0, 0, 0 }; |
| base::AtomicRefCount ready = 0; |
| |
| ANNOTATE_BENIGN_RACE_SIZED(&data, sizeof(data), "Racey reads are discarded"); |
| |
| static const unsigned kNumReaderThreads = 10; |
| BasicSeqLockTestThread threads[kNumReaderThreads]; |
| PlatformThreadHandle handles[kNumReaderThreads]; |
| |
| for (unsigned i = 0; i < kNumReaderThreads; ++i) |
| threads[i].Init(&seqlock, &data, &ready); |
| for (unsigned i = 0; i < kNumReaderThreads; ++i) |
| ASSERT_TRUE(PlatformThread::Create(0, &threads[i], &handles[i])); |
| |
| // The main thread is the writer, and the spawned are readers. |
| unsigned counter = 0; |
| for (;;) { |
| seqlock.WriteBegin(); |
| data.a = counter++; |
| data.b = data.a + 100; |
| data.c = data.b + data.a; |
| seqlock.WriteEnd(); |
| |
| if (counter == 1) |
| base::AtomicRefCountIncN(&ready, kNumReaderThreads); |
| |
| if (AtomicRefCountIsZero(&ready)) |
| break; |
| } |
| |
| for (unsigned i = 0; i < kNumReaderThreads; ++i) |
| PlatformThread::Join(handles[i]); |
| } |
| |
| } // namespace base |