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