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
11namespace base {
12
13namespace {
14
15class 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
30class 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
50class 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.
74TEST(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
150TEST(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