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