15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/common/gamepad_seqlock.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/atomic_ref_count.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/platform_thread.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Basic test to make sure that basic operation works correctly.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct TestData {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned a, b, c;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BasicSeqLockTestThread : public PlatformThread::Delegate {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BasicSeqLockTestThread() {}
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Init(
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::GamepadSeqLock* seqlock,
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TestData* data,
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::subtle::Atomic32* ready) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    seqlock_ = seqlock;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data_ = data;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ready_ = ready;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void ThreadMain() {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (AtomicRefCountIsZero(ready_)) {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PlatformThread::YieldCurrentThread();
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (unsigned i = 0; i < 1000; ++i) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TestData copy;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::subtle::Atomic32 version;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      do {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        version = seqlock_->ReadBegin();
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        copy = *data_;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } while (seqlock_->ReadRetry(version));
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_EQ(copy.a + 100, copy.b);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_EQ(copy.c, copy.b + copy.a);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AtomicRefCountDec(ready_);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::GamepadSeqLock* seqlock_;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TestData* data_;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AtomicRefCount* ready_;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(BasicSeqLockTestThread);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(GamepadSeqLockTest, ManyThreads) {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::GamepadSeqLock seqlock;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TestData data = { 0, 0, 0 };
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AtomicRefCount ready = 0;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ANNOTATE_BENIGN_RACE_SIZED(&data, sizeof(data), "Racey reads are discarded");
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const unsigned kNumReaderThreads = 10;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BasicSeqLockTestThread threads[kNumReaderThreads];
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PlatformThreadHandle handles[kNumReaderThreads];
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (unsigned i = 0; i < kNumReaderThreads; ++i)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    threads[i].Init(&seqlock, &data, &ready);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (unsigned i = 0; i < kNumReaderThreads; ++i)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(PlatformThread::Create(0, &threads[i], &handles[i]));
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The main thread is the writer, and the spawned are readers.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned counter = 0;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (;;) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    seqlock.WriteBegin();
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data.a = counter++;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data.b = data.a + 100;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data.c = data.b + data.a;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    seqlock.WriteEnd();
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (counter == 1)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::AtomicRefCountIncN(&ready, kNumReaderThreads);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (AtomicRefCountIsZero(&ready))
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (unsigned i = 0; i < kNumReaderThreads; ++i)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PlatformThread::Join(handles[i]);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
99