Home | History | Annotate | Download | only in utility
      1 // Copyright 2013 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 "base/threading/thread_local.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/synchronization/waitable_event.h"
      9 #include "base/threading/simple_thread.h"
     10 #include "testing/gtest/include/gtest/gtest.h"
     11 
     12 namespace base {
     13 
     14 namespace {
     15 
     16 class ThreadLocalTesterBase : public base::DelegateSimpleThreadPool::Delegate {
     17  public:
     18   typedef base::ThreadLocalPointer<ThreadLocalTesterBase> TLPType;
     19 
     20   ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done)
     21       : tlp_(tlp),
     22         done_(done) {
     23   }
     24   virtual ~ThreadLocalTesterBase() {}
     25 
     26  protected:
     27   TLPType* tlp_;
     28   base::WaitableEvent* done_;
     29 };
     30 
     31 class SetThreadLocal : public ThreadLocalTesterBase {
     32  public:
     33   SetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
     34       : ThreadLocalTesterBase(tlp, done),
     35         val_(NULL) {
     36   }
     37   virtual ~SetThreadLocal() {}
     38 
     39   void set_value(ThreadLocalTesterBase* val) { val_ = val; }
     40 
     41   virtual void Run() OVERRIDE {
     42     DCHECK(!done_->IsSignaled());
     43     tlp_->Set(val_);
     44     done_->Signal();
     45   }
     46 
     47  private:
     48   ThreadLocalTesterBase* val_;
     49 };
     50 
     51 class GetThreadLocal : public ThreadLocalTesterBase {
     52  public:
     53   GetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
     54       : ThreadLocalTesterBase(tlp, done),
     55         ptr_(NULL) {
     56   }
     57   virtual ~GetThreadLocal() {}
     58 
     59   void set_ptr(ThreadLocalTesterBase** ptr) { ptr_ = ptr; }
     60 
     61   virtual void Run() OVERRIDE {
     62     DCHECK(!done_->IsSignaled());
     63     *ptr_ = tlp_->Get();
     64     done_->Signal();
     65   }
     66 
     67  private:
     68   ThreadLocalTesterBase** ptr_;
     69 };
     70 
     71 }  // namespace
     72 
     73 // In this test, we start 2 threads which will access a ThreadLocalPointer.  We
     74 // make sure the default is NULL, and the pointers are unique to the threads.
     75 TEST(ThreadLocalTest, Pointer) {
     76   base::DelegateSimpleThreadPool tp1("ThreadLocalTest tp1", 1);
     77   base::DelegateSimpleThreadPool tp2("ThreadLocalTest tp1", 1);
     78   tp1.Start();
     79   tp2.Start();
     80 
     81   base::ThreadLocalPointer<ThreadLocalTesterBase> tlp;
     82 
     83   static ThreadLocalTesterBase* const kBogusPointer =
     84       reinterpret_cast<ThreadLocalTesterBase*>(0x1234);
     85 
     86   ThreadLocalTesterBase* tls_val;
     87   base::WaitableEvent done(true, false);
     88 
     89   GetThreadLocal getter(&tlp, &done);
     90   getter.set_ptr(&tls_val);
     91 
     92   // Check that both threads defaulted to NULL.
     93   tls_val = kBogusPointer;
     94   done.Reset();
     95   tp1.AddWork(&getter);
     96   done.Wait();
     97   EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(NULL), tls_val);
     98 
     99   tls_val = kBogusPointer;
    100   done.Reset();
    101   tp2.AddWork(&getter);
    102   done.Wait();
    103   EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(NULL), tls_val);
    104 
    105 
    106   SetThreadLocal setter(&tlp, &done);
    107   setter.set_value(kBogusPointer);
    108 
    109   // Have thread 1 set their pointer value to kBogusPointer.
    110   done.Reset();
    111   tp1.AddWork(&setter);
    112   done.Wait();
    113 
    114   tls_val = NULL;
    115   done.Reset();
    116   tp1.AddWork(&getter);
    117   done.Wait();
    118   EXPECT_EQ(kBogusPointer, tls_val);
    119 
    120   // Make sure thread 2 is still NULL
    121   tls_val = kBogusPointer;
    122   done.Reset();
    123   tp2.AddWork(&getter);
    124   done.Wait();
    125   EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(NULL), tls_val);
    126 
    127   // Set thread 2 to kBogusPointer + 1.
    128   setter.set_value(kBogusPointer + 1);
    129 
    130   done.Reset();
    131   tp2.AddWork(&setter);
    132   done.Wait();
    133 
    134   tls_val = NULL;
    135   done.Reset();
    136   tp2.AddWork(&getter);
    137   done.Wait();
    138   EXPECT_EQ(kBogusPointer + 1, tls_val);
    139 
    140   // Make sure thread 1 is still kBogusPointer.
    141   tls_val = NULL;
    142   done.Reset();
    143   tp1.AddWork(&getter);
    144   done.Wait();
    145   EXPECT_EQ(kBogusPointer, tls_val);
    146 
    147   tp1.JoinAll();
    148   tp2.JoinAll();
    149 }
    150 
    151 TEST(ThreadLocalTest, Boolean) {
    152   {
    153     base::ThreadLocalBoolean tlb;
    154     EXPECT_FALSE(tlb.Get());
    155 
    156     tlb.Set(false);
    157     EXPECT_FALSE(tlb.Get());
    158 
    159     tlb.Set(true);
    160     EXPECT_TRUE(tlb.Get());
    161   }
    162 
    163   // Our slot should have been freed, we're all reset.
    164   {
    165     base::ThreadLocalBoolean tlb;
    166     EXPECT_FALSE(tlb.Get());
    167   }
    168 }
    169 
    170 }  // namespace base
    171