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 20 ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done) 21 : tlp_(tlp), 22 done_(done) { 23 } 24 virtual ~ThreadLocalTesterBase() {} 25 26 protected: 27 TLPType* tlp_; 28 base::WaitableEvent* done_; 29 }; 30 31 class SetThreadLocal : public ThreadLocalTesterBase { 32 public: 33 SetThreadLocal(TLPType* tlp, base::WaitableEvent* done) 34 : ThreadLocalTesterBase(tlp, done), 35 val_(NULL) { 36 } 37 virtual ~SetThreadLocal() {} 38 39 void set_value(ThreadLocalTesterBase* val) { val_ = val; } 40 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: 53 GetThreadLocal(TLPType* tlp, base::WaitableEvent* done) 54 : ThreadLocalTesterBase(tlp, done), 55 ptr_(NULL) { 56 } 57 virtual ~GetThreadLocal() {} 58 59 void set_ptr(ThreadLocalTesterBase** ptr) { ptr_ = ptr; } 60 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. 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 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