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