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