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