xref: /aosp_15_r20/external/libchrome/base/threading/thread_local_unittest.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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