13f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h"
63f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/simple_thread.h"
73f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread_local.h"
83f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/synchronization/waitable_event.h"
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "testing/gtest/include/gtest/gtest.h"
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
113f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsennamespace base {
123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace {
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass ThreadLocalTesterBase : public base::DelegateSimpleThreadPool::Delegate {
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  typedef base::ThreadLocalPointer<ThreadLocalTesterBase> TLPType;
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done)
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      : tlp_(tlp), done_(done) { }
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ~ThreadLocalTesterBase() { }
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott protected:
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  TLPType* tlp_;
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  base::WaitableEvent* done_;
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass SetThreadLocal : public ThreadLocalTesterBase {
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      : ThreadLocalTesterBase(tlp, done), val_(NULL) { }
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ~SetThreadLocal() { }
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void set_value(ThreadLocalTesterBase* val) { val_ = val; }
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  virtual void Run() {
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DCHECK(!done_->IsSignaled());
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tlp_->Set(val_);
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    done_->Signal();
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private:
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ThreadLocalTesterBase* val_;
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass GetThreadLocal : public ThreadLocalTesterBase {
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  GetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      : ThreadLocalTesterBase(tlp, done), ptr_(NULL) { }
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ~GetThreadLocal() { }
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void set_ptr(ThreadLocalTesterBase** ptr) { ptr_ = ptr; }
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  virtual void Run() {
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DCHECK(!done_->IsSignaled());
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    *ptr_ = tlp_->Get();
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    done_->Signal();
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private:
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ThreadLocalTesterBase** ptr_;
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// In this test, we start 2 threads which will access a ThreadLocalPointer.  We
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// make sure the default is NULL, and the pointers are unique to the threads.
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST(ThreadLocalTest, Pointer) {
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  base::DelegateSimpleThreadPool tp1("ThreadLocalTest tp1", 1);
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  base::DelegateSimpleThreadPool tp2("ThreadLocalTest tp1", 1);
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tp1.Start();
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tp2.Start();
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  base::ThreadLocalPointer<ThreadLocalTesterBase> tlp;
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  static ThreadLocalTesterBase* const kBogusPointer =
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      reinterpret_cast<ThreadLocalTesterBase*>(0x1234);
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ThreadLocalTesterBase* tls_val;
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  base::WaitableEvent done(true, false);
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  GetThreadLocal getter(&tlp, &done);
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  getter.set_ptr(&tls_val);
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Check that both threads defaulted to NULL.
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tls_val = kBogusPointer;
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  done.Reset();
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tp1.AddWork(&getter);
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  done.Wait();
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(NULL), tls_val);
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tls_val = kBogusPointer;
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  done.Reset();
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tp2.AddWork(&getter);
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  done.Wait();
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(NULL), tls_val);
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SetThreadLocal setter(&tlp, &done);
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  setter.set_value(kBogusPointer);
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Have thread 1 set their pointer value to kBogusPointer.
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  done.Reset();
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tp1.AddWork(&setter);
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  done.Wait();
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tls_val = NULL;
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  done.Reset();
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tp1.AddWork(&getter);
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  done.Wait();
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(kBogusPointer, tls_val);
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Make sure thread 2 is still NULL
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tls_val = kBogusPointer;
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  done.Reset();
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tp2.AddWork(&getter);
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  done.Wait();
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(NULL), tls_val);
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Set thread 2 to kBogusPointer + 1.
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  setter.set_value(kBogusPointer + 1);
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  done.Reset();
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tp2.AddWork(&setter);
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  done.Wait();
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tls_val = NULL;
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  done.Reset();
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tp2.AddWork(&getter);
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  done.Wait();
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(kBogusPointer + 1, tls_val);
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Make sure thread 1 is still kBogusPointer.
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tls_val = NULL;
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  done.Reset();
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tp1.AddWork(&getter);
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  done.Wait();
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(kBogusPointer, tls_val);
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tp1.JoinAll();
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tp2.JoinAll();
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST(ThreadLocalTest, Boolean) {
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    base::ThreadLocalBoolean tlb;
147731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    EXPECT_FALSE(tlb.Get());
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tlb.Set(false);
150731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    EXPECT_FALSE(tlb.Get());
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tlb.Set(true);
153731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    EXPECT_TRUE(tlb.Get());
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Our slot should have been freed, we're all reset.
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    base::ThreadLocalBoolean tlb;
159731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    EXPECT_FALSE(tlb.Get());
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
1623f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
1633f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}  // namespace base
164