• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ThreadLocalTesterBase(TLPType * tlp,base::WaitableEvent * done)20   ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done)
21       : tlp_(tlp),
22         done_(done) {
23   }
~ThreadLocalTesterBase()24   virtual ~ThreadLocalTesterBase() {}
25 
26  protected:
27   TLPType* tlp_;
28   base::WaitableEvent* done_;
29 };
30 
31 class SetThreadLocal : public ThreadLocalTesterBase {
32  public:
SetThreadLocal(TLPType * tlp,base::WaitableEvent * done)33   SetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
34       : ThreadLocalTesterBase(tlp, done),
35         val_(NULL) {
36   }
~SetThreadLocal()37   virtual ~SetThreadLocal() {}
38 
set_value(ThreadLocalTesterBase * val)39   void set_value(ThreadLocalTesterBase* val) { val_ = val; }
40 
Run()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:
GetThreadLocal(TLPType * tlp,base::WaitableEvent * done)53   GetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
54       : ThreadLocalTesterBase(tlp, done),
55         ptr_(NULL) {
56   }
~GetThreadLocal()57   virtual ~GetThreadLocal() {}
58 
set_ptr(ThreadLocalTesterBase ** ptr)59   void set_ptr(ThreadLocalTesterBase** ptr) { ptr_ = ptr; }
60 
Run()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.
TEST(ThreadLocalTest,Pointer)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 
TEST(ThreadLocalTest,Boolean)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