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 
ThreadLocalTesterBase(TLPType * tlp,base::WaitableEvent * done)19   ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done)
20       : tlp_(tlp),
21         done_(done) {
22   }
~ThreadLocalTesterBase()23   ~ThreadLocalTesterBase() override {}
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   ~SetThreadLocal() override {}
37 
set_value(char * val)38   void set_value(char* val) { val_ = val; }
39 
Run()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:
GetThreadLocal(TLPType * tlp,base::WaitableEvent * done)52   GetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
53       : ThreadLocalTesterBase(tlp, done),
54         ptr_(NULL) {
55   }
~GetThreadLocal()56   ~GetThreadLocal() override {}
57 
set_ptr(char ** ptr)58   void set_ptr(char** ptr) { ptr_ = ptr; }
59 
Run()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.
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<char> tlp;
81 
82   static char* const kBogusPointer = reinterpret_cast<char*>(0x1234);
83 
84   char* tls_val;
85   base::WaitableEvent done(true, false);
86 
87   GetThreadLocal getter(&tlp, &done);
88   getter.set_ptr(&tls_val);
89 
90   // Check that both threads defaulted to NULL.
91   tls_val = kBogusPointer;
92   done.Reset();
93   tp1.AddWork(&getter);
94   done.Wait();
95   EXPECT_EQ(static_cast<char*>(NULL), tls_val);
96 
97   tls_val = kBogusPointer;
98   done.Reset();
99   tp2.AddWork(&getter);
100   done.Wait();
101   EXPECT_EQ(static_cast<char*>(NULL), tls_val);
102 
103 
104   SetThreadLocal setter(&tlp, &done);
105   setter.set_value(kBogusPointer);
106 
107   // Have thread 1 set their pointer value to kBogusPointer.
108   done.Reset();
109   tp1.AddWork(&setter);
110   done.Wait();
111 
112   tls_val = NULL;
113   done.Reset();
114   tp1.AddWork(&getter);
115   done.Wait();
116   EXPECT_EQ(kBogusPointer, tls_val);
117 
118   // Make sure thread 2 is still NULL
119   tls_val = kBogusPointer;
120   done.Reset();
121   tp2.AddWork(&getter);
122   done.Wait();
123   EXPECT_EQ(static_cast<char*>(NULL), tls_val);
124 
125   // Set thread 2 to kBogusPointer + 1.
126   setter.set_value(kBogusPointer + 1);
127 
128   done.Reset();
129   tp2.AddWork(&setter);
130   done.Wait();
131 
132   tls_val = NULL;
133   done.Reset();
134   tp2.AddWork(&getter);
135   done.Wait();
136   EXPECT_EQ(kBogusPointer + 1, tls_val);
137 
138   // Make sure thread 1 is still kBogusPointer.
139   tls_val = NULL;
140   done.Reset();
141   tp1.AddWork(&getter);
142   done.Wait();
143   EXPECT_EQ(kBogusPointer, tls_val);
144 
145   tp1.JoinAll();
146   tp2.JoinAll();
147 }
148 
TEST(ThreadLocalTest,Boolean)149 TEST(ThreadLocalTest, Boolean) {
150   {
151     base::ThreadLocalBoolean tlb;
152     EXPECT_FALSE(tlb.Get());
153 
154     tlb.Set(false);
155     EXPECT_FALSE(tlb.Get());
156 
157     tlb.Set(true);
158     EXPECT_TRUE(tlb.Get());
159   }
160 
161   // Our slot should have been freed, we're all reset.
162   {
163     base::ThreadLocalBoolean tlb;
164     EXPECT_FALSE(tlb.Get());
165   }
166 }
167 
168 }  // namespace base
169