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