• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ThreadLocalTesterBase(TLPType * tlp,base::WaitableEvent * done)19   ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done)
20       : tlp_(tlp), done_(done) { }
~ThreadLocalTesterBase()21   ~ThreadLocalTesterBase() { }
22 
23  protected:
24   TLPType* tlp_;
25   base::WaitableEvent* done_;
26 };
27 
28 class SetThreadLocal : public ThreadLocalTesterBase {
29  public:
SetThreadLocal(TLPType * tlp,base::WaitableEvent * done)30   SetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
31       : ThreadLocalTesterBase(tlp, done), val_(NULL) { }
~SetThreadLocal()32   ~SetThreadLocal() { }
33 
set_value(ThreadLocalTesterBase * val)34   void set_value(ThreadLocalTesterBase* val) { val_ = val; }
35 
Run()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:
GetThreadLocal(TLPType * tlp,base::WaitableEvent * done)48   GetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
49       : ThreadLocalTesterBase(tlp, done), ptr_(NULL) { }
~GetThreadLocal()50   ~GetThreadLocal() { }
51 
set_ptr(ThreadLocalTesterBase ** ptr)52   void set_ptr(ThreadLocalTesterBase** ptr) { ptr_ = ptr; }
53 
Run()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.
TEST(ThreadLocalTest,Pointer)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 
TEST(ThreadLocalTest,Boolean)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