1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker
5*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
6*635a8641SAndroid Build Coastguard Worker #include "base/threading/simple_thread.h"
7*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_local.h"
8*635a8641SAndroid Build Coastguard Worker #include "base/synchronization/waitable_event.h"
9*635a8641SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
10*635a8641SAndroid Build Coastguard Worker
11*635a8641SAndroid Build Coastguard Worker namespace base {
12*635a8641SAndroid Build Coastguard Worker
13*635a8641SAndroid Build Coastguard Worker namespace {
14*635a8641SAndroid Build Coastguard Worker
15*635a8641SAndroid Build Coastguard Worker class ThreadLocalTesterBase : public base::DelegateSimpleThreadPool::Delegate {
16*635a8641SAndroid Build Coastguard Worker public:
17*635a8641SAndroid Build Coastguard Worker typedef base::ThreadLocalPointer<char> TLPType;
18*635a8641SAndroid Build Coastguard Worker
ThreadLocalTesterBase(TLPType * tlp,base::WaitableEvent * done)19*635a8641SAndroid Build Coastguard Worker ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done)
20*635a8641SAndroid Build Coastguard Worker : tlp_(tlp),
21*635a8641SAndroid Build Coastguard Worker done_(done) {
22*635a8641SAndroid Build Coastguard Worker }
23*635a8641SAndroid Build Coastguard Worker ~ThreadLocalTesterBase() override = default;
24*635a8641SAndroid Build Coastguard Worker
25*635a8641SAndroid Build Coastguard Worker protected:
26*635a8641SAndroid Build Coastguard Worker TLPType* tlp_;
27*635a8641SAndroid Build Coastguard Worker base::WaitableEvent* done_;
28*635a8641SAndroid Build Coastguard Worker };
29*635a8641SAndroid Build Coastguard Worker
30*635a8641SAndroid Build Coastguard Worker class SetThreadLocal : public ThreadLocalTesterBase {
31*635a8641SAndroid Build Coastguard Worker public:
SetThreadLocal(TLPType * tlp,base::WaitableEvent * done)32*635a8641SAndroid Build Coastguard Worker SetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
33*635a8641SAndroid Build Coastguard Worker : ThreadLocalTesterBase(tlp, done), val_(nullptr) {}
34*635a8641SAndroid Build Coastguard Worker ~SetThreadLocal() override = default;
35*635a8641SAndroid Build Coastguard Worker
set_value(char * val)36*635a8641SAndroid Build Coastguard Worker void set_value(char* val) { val_ = val; }
37*635a8641SAndroid Build Coastguard Worker
Run()38*635a8641SAndroid Build Coastguard Worker void Run() override {
39*635a8641SAndroid Build Coastguard Worker DCHECK(!done_->IsSignaled());
40*635a8641SAndroid Build Coastguard Worker tlp_->Set(val_);
41*635a8641SAndroid Build Coastguard Worker done_->Signal();
42*635a8641SAndroid Build Coastguard Worker }
43*635a8641SAndroid Build Coastguard Worker
44*635a8641SAndroid Build Coastguard Worker private:
45*635a8641SAndroid Build Coastguard Worker char* val_;
46*635a8641SAndroid Build Coastguard Worker };
47*635a8641SAndroid Build Coastguard Worker
48*635a8641SAndroid Build Coastguard Worker class GetThreadLocal : public ThreadLocalTesterBase {
49*635a8641SAndroid Build Coastguard Worker public:
GetThreadLocal(TLPType * tlp,base::WaitableEvent * done)50*635a8641SAndroid Build Coastguard Worker GetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
51*635a8641SAndroid Build Coastguard Worker : ThreadLocalTesterBase(tlp, done), ptr_(nullptr) {}
52*635a8641SAndroid Build Coastguard Worker ~GetThreadLocal() override = default;
53*635a8641SAndroid Build Coastguard Worker
set_ptr(char ** ptr)54*635a8641SAndroid Build Coastguard Worker void set_ptr(char** ptr) { ptr_ = ptr; }
55*635a8641SAndroid Build Coastguard Worker
Run()56*635a8641SAndroid Build Coastguard Worker void Run() override {
57*635a8641SAndroid Build Coastguard Worker DCHECK(!done_->IsSignaled());
58*635a8641SAndroid Build Coastguard Worker *ptr_ = tlp_->Get();
59*635a8641SAndroid Build Coastguard Worker done_->Signal();
60*635a8641SAndroid Build Coastguard Worker }
61*635a8641SAndroid Build Coastguard Worker
62*635a8641SAndroid Build Coastguard Worker private:
63*635a8641SAndroid Build Coastguard Worker char** ptr_;
64*635a8641SAndroid Build Coastguard Worker };
65*635a8641SAndroid Build Coastguard Worker
66*635a8641SAndroid Build Coastguard Worker } // namespace
67*635a8641SAndroid Build Coastguard Worker
68*635a8641SAndroid Build Coastguard Worker // In this test, we start 2 threads which will access a ThreadLocalPointer. We
69*635a8641SAndroid Build Coastguard Worker // make sure the default is NULL, and the pointers are unique to the threads.
TEST(ThreadLocalTest,Pointer)70*635a8641SAndroid Build Coastguard Worker TEST(ThreadLocalTest, Pointer) {
71*635a8641SAndroid Build Coastguard Worker base::DelegateSimpleThreadPool tp1("ThreadLocalTest tp1", 1);
72*635a8641SAndroid Build Coastguard Worker base::DelegateSimpleThreadPool tp2("ThreadLocalTest tp1", 1);
73*635a8641SAndroid Build Coastguard Worker tp1.Start();
74*635a8641SAndroid Build Coastguard Worker tp2.Start();
75*635a8641SAndroid Build Coastguard Worker
76*635a8641SAndroid Build Coastguard Worker base::ThreadLocalPointer<char> tlp;
77*635a8641SAndroid Build Coastguard Worker
78*635a8641SAndroid Build Coastguard Worker static char* const kBogusPointer = reinterpret_cast<char*>(0x1234);
79*635a8641SAndroid Build Coastguard Worker
80*635a8641SAndroid Build Coastguard Worker char* tls_val;
81*635a8641SAndroid Build Coastguard Worker base::WaitableEvent done(WaitableEvent::ResetPolicy::MANUAL,
82*635a8641SAndroid Build Coastguard Worker WaitableEvent::InitialState::NOT_SIGNALED);
83*635a8641SAndroid Build Coastguard Worker
84*635a8641SAndroid Build Coastguard Worker GetThreadLocal getter(&tlp, &done);
85*635a8641SAndroid Build Coastguard Worker getter.set_ptr(&tls_val);
86*635a8641SAndroid Build Coastguard Worker
87*635a8641SAndroid Build Coastguard Worker // Check that both threads defaulted to NULL.
88*635a8641SAndroid Build Coastguard Worker tls_val = kBogusPointer;
89*635a8641SAndroid Build Coastguard Worker done.Reset();
90*635a8641SAndroid Build Coastguard Worker tp1.AddWork(&getter);
91*635a8641SAndroid Build Coastguard Worker done.Wait();
92*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(static_cast<char*>(nullptr), tls_val);
93*635a8641SAndroid Build Coastguard Worker
94*635a8641SAndroid Build Coastguard Worker tls_val = kBogusPointer;
95*635a8641SAndroid Build Coastguard Worker done.Reset();
96*635a8641SAndroid Build Coastguard Worker tp2.AddWork(&getter);
97*635a8641SAndroid Build Coastguard Worker done.Wait();
98*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(static_cast<char*>(nullptr), tls_val);
99*635a8641SAndroid Build Coastguard Worker
100*635a8641SAndroid Build Coastguard Worker SetThreadLocal setter(&tlp, &done);
101*635a8641SAndroid Build Coastguard Worker setter.set_value(kBogusPointer);
102*635a8641SAndroid Build Coastguard Worker
103*635a8641SAndroid Build Coastguard Worker // Have thread 1 set their pointer value to kBogusPointer.
104*635a8641SAndroid Build Coastguard Worker done.Reset();
105*635a8641SAndroid Build Coastguard Worker tp1.AddWork(&setter);
106*635a8641SAndroid Build Coastguard Worker done.Wait();
107*635a8641SAndroid Build Coastguard Worker
108*635a8641SAndroid Build Coastguard Worker tls_val = nullptr;
109*635a8641SAndroid Build Coastguard Worker done.Reset();
110*635a8641SAndroid Build Coastguard Worker tp1.AddWork(&getter);
111*635a8641SAndroid Build Coastguard Worker done.Wait();
112*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(kBogusPointer, tls_val);
113*635a8641SAndroid Build Coastguard Worker
114*635a8641SAndroid Build Coastguard Worker // Make sure thread 2 is still NULL
115*635a8641SAndroid Build Coastguard Worker tls_val = kBogusPointer;
116*635a8641SAndroid Build Coastguard Worker done.Reset();
117*635a8641SAndroid Build Coastguard Worker tp2.AddWork(&getter);
118*635a8641SAndroid Build Coastguard Worker done.Wait();
119*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(static_cast<char*>(nullptr), tls_val);
120*635a8641SAndroid Build Coastguard Worker
121*635a8641SAndroid Build Coastguard Worker // Set thread 2 to kBogusPointer + 1.
122*635a8641SAndroid Build Coastguard Worker setter.set_value(kBogusPointer + 1);
123*635a8641SAndroid Build Coastguard Worker
124*635a8641SAndroid Build Coastguard Worker done.Reset();
125*635a8641SAndroid Build Coastguard Worker tp2.AddWork(&setter);
126*635a8641SAndroid Build Coastguard Worker done.Wait();
127*635a8641SAndroid Build Coastguard Worker
128*635a8641SAndroid Build Coastguard Worker tls_val = nullptr;
129*635a8641SAndroid Build Coastguard Worker done.Reset();
130*635a8641SAndroid Build Coastguard Worker tp2.AddWork(&getter);
131*635a8641SAndroid Build Coastguard Worker done.Wait();
132*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(kBogusPointer + 1, tls_val);
133*635a8641SAndroid Build Coastguard Worker
134*635a8641SAndroid Build Coastguard Worker // Make sure thread 1 is still kBogusPointer.
135*635a8641SAndroid Build Coastguard Worker tls_val = nullptr;
136*635a8641SAndroid Build Coastguard Worker done.Reset();
137*635a8641SAndroid Build Coastguard Worker tp1.AddWork(&getter);
138*635a8641SAndroid Build Coastguard Worker done.Wait();
139*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(kBogusPointer, tls_val);
140*635a8641SAndroid Build Coastguard Worker
141*635a8641SAndroid Build Coastguard Worker tp1.JoinAll();
142*635a8641SAndroid Build Coastguard Worker tp2.JoinAll();
143*635a8641SAndroid Build Coastguard Worker }
144*635a8641SAndroid Build Coastguard Worker
TEST(ThreadLocalTest,Boolean)145*635a8641SAndroid Build Coastguard Worker TEST(ThreadLocalTest, Boolean) {
146*635a8641SAndroid Build Coastguard Worker {
147*635a8641SAndroid Build Coastguard Worker base::ThreadLocalBoolean tlb;
148*635a8641SAndroid Build Coastguard Worker EXPECT_FALSE(tlb.Get());
149*635a8641SAndroid Build Coastguard Worker
150*635a8641SAndroid Build Coastguard Worker tlb.Set(false);
151*635a8641SAndroid Build Coastguard Worker EXPECT_FALSE(tlb.Get());
152*635a8641SAndroid Build Coastguard Worker
153*635a8641SAndroid Build Coastguard Worker tlb.Set(true);
154*635a8641SAndroid Build Coastguard Worker EXPECT_TRUE(tlb.Get());
155*635a8641SAndroid Build Coastguard Worker }
156*635a8641SAndroid Build Coastguard Worker
157*635a8641SAndroid Build Coastguard Worker // Our slot should have been freed, we're all reset.
158*635a8641SAndroid Build Coastguard Worker {
159*635a8641SAndroid Build Coastguard Worker base::ThreadLocalBoolean tlb;
160*635a8641SAndroid Build Coastguard Worker EXPECT_FALSE(tlb.Get());
161*635a8641SAndroid Build Coastguard Worker }
162*635a8641SAndroid Build Coastguard Worker }
163*635a8641SAndroid Build Coastguard Worker
164*635a8641SAndroid Build Coastguard Worker } // namespace base
165