15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 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 "base/atomic_sequence_num.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/waitable_event.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/simple_thread.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SetIntRunner : public DelegateSimpleThread::Delegate {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetIntRunner(int* ptr, int val) : ptr_(ptr), val_(val) { }
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~SetIntRunner() { }
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Run() OVERRIDE {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *ptr_ = val_;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int* ptr_;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int val_;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class WaitEventRunner : public DelegateSimpleThread::Delegate {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit WaitEventRunner(WaitableEvent* event) : event_(event) { }
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~WaitEventRunner() { }
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Run() OVERRIDE {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_FALSE(event_->IsSignaled());
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    event_->Signal();
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(event_->IsSignaled());
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WaitableEvent* event_;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SeqRunner : public DelegateSimpleThread::Delegate {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit SeqRunner(AtomicSequenceNumber* seq) : seq_(seq) { }
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Run() OVERRIDE {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    seq_->GetNext();
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AtomicSequenceNumber* seq_;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We count up on a sequence number, firing on the event when we've hit our
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// expected amount, otherwise we wait on the event.  This will ensure that we
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// have all threads outstanding until we hit our expected thread pool size.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class VerifyPoolRunner : public DelegateSimpleThread::Delegate {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyPoolRunner(AtomicSequenceNumber* seq,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   int total, WaitableEvent* event)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : seq_(seq), total_(total), event_(event) { }
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Run() OVERRIDE {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (seq_->GetNext() == total_) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event_->Signal();
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event_->Wait();
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AtomicSequenceNumber* seq_;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int total_;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WaitableEvent* event_;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(SimpleThreadTest, CreateAndJoin) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int stack_int = 0;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetIntRunner runner(&stack_int, 7);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, stack_int);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DelegateSimpleThread thread(&runner, "int_setter");
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(thread.HasBeenStarted());
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(thread.HasBeenJoined());
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, stack_int);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread.Start();
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(thread.HasBeenStarted());
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(thread.HasBeenJoined());
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread.Join();
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(thread.HasBeenStarted());
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(thread.HasBeenJoined());
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(7, stack_int);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(SimpleThreadTest, WaitForEvent) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a thread, and wait for it to signal us.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WaitableEvent event(true, false);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WaitEventRunner runner(&event);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DelegateSimpleThread thread(&runner, "event_waiter");
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(event.IsSignaled());
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread.Start();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.Wait();
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(event.IsSignaled());
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread.Join();
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(SimpleThreadTest, NamedWithOptions) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WaitableEvent event(true, false);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WaitEventRunner runner(&event);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SimpleThread::Options options;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DelegateSimpleThread thread(&runner, "event_waiter", options);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(thread.name_prefix(), "event_waiter");
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(event.IsSignaled());
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread.Start();
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(thread.name_prefix(), "event_waiter");
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(thread.name(),
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            std::string("event_waiter/") + IntToString(thread.tid()));
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.Wait();
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(event.IsSignaled());
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread.Join();
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We keep the name and tid, even after the thread is gone.
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(thread.name_prefix(), "event_waiter");
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(thread.name(),
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            std::string("event_waiter/") + IntToString(thread.tid()));
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(SimpleThreadTest, ThreadPool) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AtomicSequenceNumber seq;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SeqRunner runner(&seq);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DelegateSimpleThreadPool pool("seq_runner", 10);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add work before we're running.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pool.AddWork(&runner, 300);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(seq.GetNext(), 0);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pool.Start();
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add work while we're running.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pool.AddWork(&runner, 300);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pool.JoinAll();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(seq.GetNext(), 601);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We can reuse our pool.  Verify that all 10 threads can actually run in
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // parallel, so this test will only pass if there are actually 10 threads.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AtomicSequenceNumber seq2;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WaitableEvent event(true, false);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Changing 9 to 10, for example, would cause us JoinAll() to never return.
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyPoolRunner verifier(&seq2, 9, &event);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pool.Start();
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pool.AddWork(&verifier, 10);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pool.JoinAll();
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(seq2.GetNext(), 10);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
171