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/logging.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/simple_thread.h"
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_local.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/waitable_event.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 ThreadLocalTesterBase : public base::DelegateSimpleThreadPool::Delegate {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef base::ThreadLocalPointer<ThreadLocalTesterBase> TLPType;
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : tlp_(tlp),
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        done_(done) {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~ThreadLocalTesterBase() {}
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TLPType* tlp_;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::WaitableEvent* done_;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SetThreadLocal : public ThreadLocalTesterBase {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : ThreadLocalTesterBase(tlp, done),
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        val_(NULL) {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~SetThreadLocal() {}
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void set_value(ThreadLocalTesterBase* val) { val_ = val; }
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Run() OVERRIDE {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!done_->IsSignaled());
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tlp_->Set(val_);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    done_->Signal();
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ThreadLocalTesterBase* val_;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class GetThreadLocal : public ThreadLocalTesterBase {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : ThreadLocalTesterBase(tlp, done),
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ptr_(NULL) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~GetThreadLocal() {}
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void set_ptr(ThreadLocalTesterBase** ptr) { ptr_ = ptr; }
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Run() OVERRIDE {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!done_->IsSignaled());
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *ptr_ = tlp_->Get();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    done_->Signal();
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ThreadLocalTesterBase** ptr_;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In this test, we start 2 threads which will access a ThreadLocalPointer.  We
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// make sure the default is NULL, and the pointers are unique to the threads.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(ThreadLocalTest, Pointer) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::DelegateSimpleThreadPool tp1("ThreadLocalTest tp1", 1);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::DelegateSimpleThreadPool tp2("ThreadLocalTest tp1", 1);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tp1.Start();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tp2.Start();
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadLocalPointer<ThreadLocalTesterBase> tlp;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static ThreadLocalTesterBase* const kBogusPointer =
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<ThreadLocalTesterBase*>(0x1234);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ThreadLocalTesterBase* tls_val;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::WaitableEvent done(true, false);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetThreadLocal getter(&tlp, &done);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  getter.set_ptr(&tls_val);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check that both threads defaulted to NULL.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tls_val = kBogusPointer;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  done.Reset();
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tp1.AddWork(&getter);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  done.Wait();
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(NULL), tls_val);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tls_val = kBogusPointer;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  done.Reset();
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tp2.AddWork(&getter);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  done.Wait();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(NULL), tls_val);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetThreadLocal setter(&tlp, &done);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setter.set_value(kBogusPointer);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Have thread 1 set their pointer value to kBogusPointer.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  done.Reset();
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tp1.AddWork(&setter);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  done.Wait();
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tls_val = NULL;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  done.Reset();
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tp1.AddWork(&getter);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  done.Wait();
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(kBogusPointer, tls_val);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure thread 2 is still NULL
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tls_val = kBogusPointer;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  done.Reset();
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tp2.AddWork(&getter);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  done.Wait();
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(NULL), tls_val);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set thread 2 to kBogusPointer + 1.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setter.set_value(kBogusPointer + 1);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  done.Reset();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tp2.AddWork(&setter);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  done.Wait();
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tls_val = NULL;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  done.Reset();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tp2.AddWork(&getter);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  done.Wait();
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(kBogusPointer + 1, tls_val);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure thread 1 is still kBogusPointer.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tls_val = NULL;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  done.Reset();
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tp1.AddWork(&getter);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  done.Wait();
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(kBogusPointer, tls_val);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tp1.JoinAll();
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tp2.JoinAll();
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(ThreadLocalTest, Boolean) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ThreadLocalBoolean tlb;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_FALSE(tlb.Get());
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tlb.Set(false);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_FALSE(tlb.Get());
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tlb.Set(true);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(tlb.Get());
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Our slot should have been freed, we're all reset.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ThreadLocalBoolean tlb;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_FALSE(tlb.Get());
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
170