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