• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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<ThreadLocalTesterBase> TLPType;
18 
ThreadLocalTesterBase(TLPType * tlp,base::WaitableEvent * done)19   ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done)
20       : tlp_(tlp),
21         done_(done) {
22   }
~ThreadLocalTesterBase()23   virtual ~ThreadLocalTesterBase() {}
24 
25  protected:
26   TLPType* tlp_;
27   base::WaitableEvent* done_;
28 };
29 
30 class SetThreadLocal : public ThreadLocalTesterBase {
31  public:
SetThreadLocal(TLPType * tlp,base::WaitableEvent * done)32   SetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
33       : ThreadLocalTesterBase(tlp, done),
34         val_(NULL) {
35   }
~SetThreadLocal()36   virtual ~SetThreadLocal() {}
37 
set_value(ThreadLocalTesterBase * val)38   void set_value(ThreadLocalTesterBase* val) { val_ = val; }
39 
Run()40   virtual void Run() OVERRIDE {
41     DCHECK(!done_->IsSignaled());
42     tlp_->Set(val_);
43     done_->Signal();
44   }
45 
46  private:
47   ThreadLocalTesterBase* val_;
48 };
49 
50 class GetThreadLocal : public ThreadLocalTesterBase {
51  public:
GetThreadLocal(TLPType * tlp,base::WaitableEvent * done)52   GetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
53       : ThreadLocalTesterBase(tlp, done),
54         ptr_(NULL) {
55   }
~GetThreadLocal()56   virtual ~GetThreadLocal() {}
57 
set_ptr(ThreadLocalTesterBase ** ptr)58   void set_ptr(ThreadLocalTesterBase** ptr) { ptr_ = ptr; }
59 
Run()60   virtual void Run() OVERRIDE {
61     DCHECK(!done_->IsSignaled());
62     *ptr_ = tlp_->Get();
63     done_->Signal();
64   }
65 
66  private:
67   ThreadLocalTesterBase** 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.
TEST(ThreadLocalTest,Pointer)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<ThreadLocalTesterBase> tlp;
81 
82   static ThreadLocalTesterBase* const kBogusPointer =
83       reinterpret_cast<ThreadLocalTesterBase*>(0x1234);
84 
85   ThreadLocalTesterBase* tls_val;
86   base::WaitableEvent done(true, false);
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<ThreadLocalTesterBase*>(NULL), tls_val);
97 
98   tls_val = kBogusPointer;
99   done.Reset();
100   tp2.AddWork(&getter);
101   done.Wait();
102   EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(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<ThreadLocalTesterBase*>(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 
TEST(ThreadLocalTest,Boolean)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