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