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<ThreadLocalTesterBase> TLPType; 18 19 ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done) 20 : tlp_(tlp), 21 done_(done) { 22 } 23 virtual ~ThreadLocalTesterBase() {} 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 virtual ~SetThreadLocal() {} 37 38 void set_value(ThreadLocalTesterBase* val) { val_ = val; } 39 40 virtual void Run() OVERRIDE { 41 DCHECK(!done_->IsSignaled()); 42 tlp_->Set(val_); 43 done_->Signal(); 44 } 45 46 private: 47 ThreadLocalTesterBase* 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 virtual ~GetThreadLocal() {} 57 58 void set_ptr(ThreadLocalTesterBase** ptr) { ptr_ = ptr; } 59 60 virtual void Run() OVERRIDE { 61 DCHECK(!done_->IsSignaled()); 62 *ptr_ = tlp_->Get(); 63 done_->Signal(); 64 } 65 66 private: 67 ThreadLocalTesterBase** 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<ThreadLocalTesterBase> tlp; 81 82 static ThreadLocalTesterBase* const kBogusPointer = 83 reinterpret_cast<ThreadLocalTesterBase*>(0x1234); 84 85 ThreadLocalTesterBase* tls_val; 86 base::WaitableEvent done(true, false); 87 88 GetThreadLocal getter(&tlp, &done); 89 getter.set_ptr(&tls_val); 90 91 // Check that both threads defaulted to NULL. 92 tls_val = kBogusPointer; 93 done.Reset(); 94 tp1.AddWork(&getter); 95 done.Wait(); 96 EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(NULL), tls_val); 97 98 tls_val = kBogusPointer; 99 done.Reset(); 100 tp2.AddWork(&getter); 101 done.Wait(); 102 EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(NULL), tls_val); 103 104 105 SetThreadLocal setter(&tlp, &done); 106 setter.set_value(kBogusPointer); 107 108 // Have thread 1 set their pointer value to kBogusPointer. 109 done.Reset(); 110 tp1.AddWork(&setter); 111 done.Wait(); 112 113 tls_val = NULL; 114 done.Reset(); 115 tp1.AddWork(&getter); 116 done.Wait(); 117 EXPECT_EQ(kBogusPointer, tls_val); 118 119 // Make sure thread 2 is still NULL 120 tls_val = kBogusPointer; 121 done.Reset(); 122 tp2.AddWork(&getter); 123 done.Wait(); 124 EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(NULL), tls_val); 125 126 // Set thread 2 to kBogusPointer + 1. 127 setter.set_value(kBogusPointer + 1); 128 129 done.Reset(); 130 tp2.AddWork(&setter); 131 done.Wait(); 132 133 tls_val = NULL; 134 done.Reset(); 135 tp2.AddWork(&getter); 136 done.Wait(); 137 EXPECT_EQ(kBogusPointer + 1, tls_val); 138 139 // Make sure thread 1 is still kBogusPointer. 140 tls_val = NULL; 141 done.Reset(); 142 tp1.AddWork(&getter); 143 done.Wait(); 144 EXPECT_EQ(kBogusPointer, tls_val); 145 146 tp1.JoinAll(); 147 tp2.JoinAll(); 148 } 149 150 TEST(ThreadLocalTest, Boolean) { 151 { 152 base::ThreadLocalBoolean tlb; 153 EXPECT_FALSE(tlb.Get()); 154 155 tlb.Set(false); 156 EXPECT_FALSE(tlb.Get()); 157 158 tlb.Set(true); 159 EXPECT_TRUE(tlb.Get()); 160 } 161 162 // Our slot should have been freed, we're all reset. 163 { 164 base::ThreadLocalBoolean tlb; 165 EXPECT_FALSE(tlb.Get()); 166 } 167 } 168 169 } // namespace base 170