[email protected] | 4410618 | 2012-04-06 03:53:02 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 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" |
[email protected] | ac9ba8fe | 2010-12-30 18:08:36 | [diff] [blame] | 6 | #include "base/threading/simple_thread.h" |
[email protected] | 1357c32 | 2010-12-30 22:18:56 | [diff] [blame] | 7 | #include "base/threading/thread_local.h" |
[email protected] | 44f9c95 | 2011-01-02 06:05:39 | [diff] [blame] | 8 | #include "base/synchronization/waitable_event.h" |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 9 | #include "testing/gtest/include/gtest/gtest.h" |
| 10 | |
[email protected] | 1357c32 | 2010-12-30 22:18:56 | [diff] [blame] | 11 | namespace base { |
| 12 | |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 13 | namespace { |
| 14 | |
| 15 | class ThreadLocalTesterBase : public base::DelegateSimpleThreadPool::Delegate { |
| 16 | public: |
pcc | 5b3c85ae | 2015-03-31 19:08:15 | [diff] [blame] | 17 | typedef base::ThreadLocalPointer<char> TLPType; |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 18 | |
| 19 | ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done) |
[email protected] | 4410618 | 2012-04-06 03:53:02 | [diff] [blame] | 20 | : tlp_(tlp), |
| 21 | done_(done) { |
| 22 | } |
Chris Watkins | bb7211c | 2017-11-29 07:16:38 | [diff] [blame] | 23 | ~ThreadLocalTesterBase() override = default; |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 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) |
Ivan Kotenkov | a16212a5 | 2017-11-08 12:37:33 | [diff] [blame] | 33 | : ThreadLocalTesterBase(tlp, done), val_(nullptr) {} |
Chris Watkins | bb7211c | 2017-11-29 07:16:38 | [diff] [blame] | 34 | ~SetThreadLocal() override = default; |
[email protected] | 52a261f | 2009-03-03 15:01:12 | [diff] [blame] | 35 | |
pcc | 5b3c85ae | 2015-03-31 19:08:15 | [diff] [blame] | 36 | void set_value(char* val) { val_ = val; } |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 37 | |
dcheng | 5648818 | 2014-10-21 10:54:51 | [diff] [blame] | 38 | void Run() override { |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 39 | DCHECK(!done_->IsSignaled()); |
| 40 | tlp_->Set(val_); |
| 41 | done_->Signal(); |
| 42 | } |
| 43 | |
| 44 | private: |
pcc | 5b3c85ae | 2015-03-31 19:08:15 | [diff] [blame] | 45 | char* val_; |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 46 | }; |
| 47 | |
| 48 | class GetThreadLocal : public ThreadLocalTesterBase { |
| 49 | public: |
| 50 | GetThreadLocal(TLPType* tlp, base::WaitableEvent* done) |
Ivan Kotenkov | a16212a5 | 2017-11-08 12:37:33 | [diff] [blame] | 51 | : ThreadLocalTesterBase(tlp, done), ptr_(nullptr) {} |
Chris Watkins | bb7211c | 2017-11-29 07:16:38 | [diff] [blame] | 52 | ~GetThreadLocal() override = default; |
[email protected] | 52a261f | 2009-03-03 15:01:12 | [diff] [blame] | 53 | |
pcc | 5b3c85ae | 2015-03-31 19:08:15 | [diff] [blame] | 54 | void set_ptr(char** ptr) { ptr_ = ptr; } |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 55 | |
dcheng | 5648818 | 2014-10-21 10:54:51 | [diff] [blame] | 56 | void Run() override { |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 57 | DCHECK(!done_->IsSignaled()); |
| 58 | *ptr_ = tlp_->Get(); |
| 59 | done_->Signal(); |
| 60 | } |
| 61 | |
| 62 | private: |
pcc | 5b3c85ae | 2015-03-31 19:08:15 | [diff] [blame] | 63 | char** ptr_; |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 64 | }; |
| 65 | |
| 66 | } // namespace |
| 67 | |
| 68 | // In this test, we start 2 threads which will access a ThreadLocalPointer. We |
| 69 | // make sure the default is NULL, and the pointers are unique to the threads. |
| 70 | TEST(ThreadLocalTest, Pointer) { |
| 71 | base::DelegateSimpleThreadPool tp1("ThreadLocalTest tp1", 1); |
| 72 | base::DelegateSimpleThreadPool tp2("ThreadLocalTest tp1", 1); |
| 73 | tp1.Start(); |
| 74 | tp2.Start(); |
| 75 | |
pcc | 5b3c85ae | 2015-03-31 19:08:15 | [diff] [blame] | 76 | base::ThreadLocalPointer<char> tlp; |
[email protected] | 52a261f | 2009-03-03 15:01:12 | [diff] [blame] | 77 | |
pcc | 5b3c85ae | 2015-03-31 19:08:15 | [diff] [blame] | 78 | static char* const kBogusPointer = reinterpret_cast<char*>(0x1234); |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 79 | |
pcc | 5b3c85ae | 2015-03-31 19:08:15 | [diff] [blame] | 80 | char* tls_val; |
gab | 75d7233 | 2016-06-01 21:15:33 | [diff] [blame] | 81 | base::WaitableEvent done(WaitableEvent::ResetPolicy::MANUAL, |
| 82 | WaitableEvent::InitialState::NOT_SIGNALED); |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 83 | |
| 84 | GetThreadLocal getter(&tlp, &done); |
| 85 | getter.set_ptr(&tls_val); |
| 86 | |
| 87 | // Check that both threads defaulted to NULL. |
| 88 | tls_val = kBogusPointer; |
| 89 | done.Reset(); |
| 90 | tp1.AddWork(&getter); |
| 91 | done.Wait(); |
Ivan Kotenkov | a16212a5 | 2017-11-08 12:37:33 | [diff] [blame] | 92 | EXPECT_EQ(static_cast<char*>(nullptr), tls_val); |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 93 | |
| 94 | tls_val = kBogusPointer; |
| 95 | done.Reset(); |
| 96 | tp2.AddWork(&getter); |
| 97 | done.Wait(); |
Ivan Kotenkov | a16212a5 | 2017-11-08 12:37:33 | [diff] [blame] | 98 | EXPECT_EQ(static_cast<char*>(nullptr), tls_val); |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 99 | |
| 100 | SetThreadLocal setter(&tlp, &done); |
| 101 | setter.set_value(kBogusPointer); |
| 102 | |
| 103 | // Have thread 1 set their pointer value to kBogusPointer. |
| 104 | done.Reset(); |
| 105 | tp1.AddWork(&setter); |
| 106 | done.Wait(); |
| 107 | |
Ivan Kotenkov | a16212a5 | 2017-11-08 12:37:33 | [diff] [blame] | 108 | tls_val = nullptr; |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 109 | done.Reset(); |
| 110 | tp1.AddWork(&getter); |
| 111 | done.Wait(); |
| 112 | EXPECT_EQ(kBogusPointer, tls_val); |
| 113 | |
| 114 | // Make sure thread 2 is still NULL |
| 115 | tls_val = kBogusPointer; |
| 116 | done.Reset(); |
| 117 | tp2.AddWork(&getter); |
| 118 | done.Wait(); |
Ivan Kotenkov | a16212a5 | 2017-11-08 12:37:33 | [diff] [blame] | 119 | EXPECT_EQ(static_cast<char*>(nullptr), tls_val); |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 120 | |
| 121 | // Set thread 2 to kBogusPointer + 1. |
| 122 | setter.set_value(kBogusPointer + 1); |
| 123 | |
| 124 | done.Reset(); |
| 125 | tp2.AddWork(&setter); |
| 126 | done.Wait(); |
| 127 | |
Ivan Kotenkov | a16212a5 | 2017-11-08 12:37:33 | [diff] [blame] | 128 | tls_val = nullptr; |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 129 | done.Reset(); |
| 130 | tp2.AddWork(&getter); |
| 131 | done.Wait(); |
| 132 | EXPECT_EQ(kBogusPointer + 1, tls_val); |
| 133 | |
| 134 | // Make sure thread 1 is still kBogusPointer. |
Ivan Kotenkov | a16212a5 | 2017-11-08 12:37:33 | [diff] [blame] | 135 | tls_val = nullptr; |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 136 | done.Reset(); |
| 137 | tp1.AddWork(&getter); |
| 138 | done.Wait(); |
| 139 | EXPECT_EQ(kBogusPointer, tls_val); |
| 140 | |
| 141 | tp1.JoinAll(); |
| 142 | tp2.JoinAll(); |
| 143 | } |
| 144 | |
| 145 | TEST(ThreadLocalTest, Boolean) { |
| 146 | { |
| 147 | base::ThreadLocalBoolean tlb; |
[email protected] | 34f4094 | 2010-10-04 00:34:04 | [diff] [blame] | 148 | EXPECT_FALSE(tlb.Get()); |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 149 | |
| 150 | tlb.Set(false); |
[email protected] | 34f4094 | 2010-10-04 00:34:04 | [diff] [blame] | 151 | EXPECT_FALSE(tlb.Get()); |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 152 | |
| 153 | tlb.Set(true); |
[email protected] | 34f4094 | 2010-10-04 00:34:04 | [diff] [blame] | 154 | EXPECT_TRUE(tlb.Get()); |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 155 | } |
| 156 | |
| 157 | // Our slot should have been freed, we're all reset. |
| 158 | { |
| 159 | base::ThreadLocalBoolean tlb; |
[email protected] | 34f4094 | 2010-10-04 00:34:04 | [diff] [blame] | 160 | EXPECT_FALSE(tlb.Get()); |
[email protected] | 83a05dd | 2008-09-03 16:47:37 | [diff] [blame] | 161 | } |
| 162 | } |
[email protected] | 1357c32 | 2010-12-30 22:18:56 | [diff] [blame] | 163 | |
| 164 | } // namespace base |