[email protected] | 444b8a3c | 2012-01-30 16:52:09 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
license.bot | bf09a50 | 2008-08-24 00:55:55 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 4 | |
[email protected] | fe236c9 | 2008-09-11 23:37:54 | [diff] [blame] | 5 | #if defined(OS_WIN) |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 6 | #include <windows.h> |
| 7 | #include <process.h> |
[email protected] | fe236c9 | 2008-09-11 23:37:54 | [diff] [blame] | 8 | #endif |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 9 | |
avi | 9ceb8b8 | 2015-12-24 21:53:59 | [diff] [blame] | 10 | #include "base/macros.h" |
[email protected] | ac9ba8fe | 2010-12-30 18:08:36 | [diff] [blame] | 11 | #include "base/threading/simple_thread.h" |
[email protected] | 1357c32 | 2010-12-30 22:18:56 | [diff] [blame] | 12 | #include "base/threading/thread_local_storage.h" |
avi | 9ceb8b8 | 2015-12-24 21:53:59 | [diff] [blame] | 13 | #include "build/build_config.h" |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 14 | #include "testing/gtest/include/gtest/gtest.h" |
| 15 | |
[email protected] | fe236c9 | 2008-09-11 23:37:54 | [diff] [blame] | 16 | #if defined(OS_WIN) |
| 17 | // Ignore warnings about ptr->int conversions that we use when |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 18 | // storing ints into ThreadLocalStorage. |
| 19 | #pragma warning(disable : 4311 4312) |
[email protected] | fe236c9 | 2008-09-11 23:37:54 | [diff] [blame] | 20 | #endif |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 21 | |
[email protected] | 1357c32 | 2010-12-30 22:18:56 | [diff] [blame] | 22 | namespace base { |
| 23 | |
| 24 | namespace { |
| 25 | |
[email protected] | fe236c9 | 2008-09-11 23:37:54 | [diff] [blame] | 26 | const int kInitialTlsValue = 0x5555; |
[email protected] | e517d20 | 2011-11-29 21:38:26 | [diff] [blame] | 27 | const int kFinalTlsValue = 0x7777; |
| 28 | // How many times must a destructor be called before we really are done. |
| 29 | const int kNumberDestructorCallRepetitions = 3; |
| 30 | |
[email protected] | 444b8a3c | 2012-01-30 16:52:09 | [diff] [blame] | 31 | static ThreadLocalStorage::StaticSlot tls_slot = TLS_INITIALIZER; |
[email protected] | fe236c9 | 2008-09-11 23:37:54 | [diff] [blame] | 32 | |
[email protected] | 1357c32 | 2010-12-30 22:18:56 | [diff] [blame] | 33 | class ThreadLocalStorageRunner : public DelegateSimpleThread::Delegate { |
[email protected] | fe236c9 | 2008-09-11 23:37:54 | [diff] [blame] | 34 | public: |
| 35 | explicit ThreadLocalStorageRunner(int* tls_value_ptr) |
| 36 | : tls_value_ptr_(tls_value_ptr) {} |
| 37 | |
dcheng | 5648818 | 2014-10-21 10:54:51 | [diff] [blame] | 38 | ~ThreadLocalStorageRunner() override {} |
[email protected] | fe236c9 | 2008-09-11 23:37:54 | [diff] [blame] | 39 | |
dcheng | 5648818 | 2014-10-21 10:54:51 | [diff] [blame] | 40 | void Run() override { |
[email protected] | fe236c9 | 2008-09-11 23:37:54 | [diff] [blame] | 41 | *tls_value_ptr_ = kInitialTlsValue; |
| 42 | tls_slot.Set(tls_value_ptr_); |
| 43 | |
| 44 | int *ptr = static_cast<int*>(tls_slot.Get()); |
| 45 | EXPECT_EQ(ptr, tls_value_ptr_); |
| 46 | EXPECT_EQ(*ptr, kInitialTlsValue); |
| 47 | *tls_value_ptr_ = 0; |
| 48 | |
| 49 | ptr = static_cast<int*>(tls_slot.Get()); |
| 50 | EXPECT_EQ(ptr, tls_value_ptr_); |
| 51 | EXPECT_EQ(*ptr, 0); |
[email protected] | e517d20 | 2011-11-29 21:38:26 | [diff] [blame] | 52 | |
| 53 | *ptr = kFinalTlsValue + kNumberDestructorCallRepetitions; |
[email protected] | fe236c9 | 2008-09-11 23:37:54 | [diff] [blame] | 54 | } |
| 55 | |
| 56 | private: |
| 57 | int* tls_value_ptr_; |
| 58 | DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorageRunner); |
| 59 | }; |
| 60 | |
| 61 | |
| 62 | void ThreadLocalStorageCleanup(void *value) { |
| 63 | int *ptr = reinterpret_cast<int*>(value); |
[email protected] | e517d20 | 2011-11-29 21:38:26 | [diff] [blame] | 64 | // Destructors should never be called with a NULL. |
| 65 | ASSERT_NE(reinterpret_cast<int*>(NULL), ptr); |
| 66 | if (*ptr == kFinalTlsValue) |
| 67 | return; // We've been called enough times. |
| 68 | ASSERT_LT(kFinalTlsValue, *ptr); |
| 69 | ASSERT_GE(kFinalTlsValue + kNumberDestructorCallRepetitions, *ptr); |
| 70 | --*ptr; // Move closer to our target. |
| 71 | // Tell tls that we're not done with this thread, and still need destruction. |
| 72 | tls_slot.Set(value); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 73 | } |
| 74 | |
[email protected] | 1357c32 | 2010-12-30 22:18:56 | [diff] [blame] | 75 | } // namespace |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 76 | |
| 77 | TEST(ThreadLocalStorageTest, Basics) { |
[email protected] | 6a6e657 | 2008-08-20 22:54:52 | [diff] [blame] | 78 | ThreadLocalStorage::Slot slot; |
| 79 | slot.Set(reinterpret_cast<void*>(123)); |
[email protected] | cf76214 | 2009-08-03 15:59:22 | [diff] [blame] | 80 | int value = reinterpret_cast<intptr_t>(slot.Get()); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 81 | EXPECT_EQ(value, 123); |
| 82 | } |
| 83 | |
brettw | 9a19ddb | 2015-04-24 19:30:50 | [diff] [blame] | 84 | #if defined(THREAD_SANITIZER) || \ |
| 85 | (defined(OS_WIN) && defined(ARCH_CPU_X86_64) && !defined(NDEBUG)) |
[email protected] | 18280ae4 | 2012-12-10 15:40:58 | [diff] [blame] | 86 | // Do not run the test under ThreadSanitizer. Because this test iterates its |
| 87 | // own TSD destructor for the maximum possible number of times, TSan can't jump |
| 88 | // in after the last destructor invocation, therefore the destructor remains |
| 89 | // unsynchronized with the following users of the same TSD slot. This results |
| 90 | // in race reports between the destructor and functions in other tests. |
scottmg | a3f851d | 2014-09-19 20:28:37 | [diff] [blame] | 91 | // |
brettw | 9a19ddb | 2015-04-24 19:30:50 | [diff] [blame] | 92 | // It is disabled on Win x64 with incremental linking (i.e. "Debug") pending |
| 93 | // resolution of http://crbug.com/251251. |
[email protected] | 18280ae4 | 2012-12-10 15:40:58 | [diff] [blame] | 94 | #define MAYBE_TLSDestructors DISABLED_TLSDestructors |
| 95 | #else |
| 96 | #define MAYBE_TLSDestructors TLSDestructors |
| 97 | #endif |
| 98 | TEST(ThreadLocalStorageTest, MAYBE_TLSDestructors) { |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 99 | // Create a TLS index with a destructor. Create a set of |
| 100 | // threads that set the TLS, while the destructor cleans it up. |
| 101 | // After the threads finish, verify that the value is cleaned up. |
| 102 | const int kNumThreads = 5; |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 103 | int values[kNumThreads]; |
[email protected] | fe236c9 | 2008-09-11 23:37:54 | [diff] [blame] | 104 | ThreadLocalStorageRunner* thread_delegates[kNumThreads]; |
[email protected] | 1357c32 | 2010-12-30 22:18:56 | [diff] [blame] | 105 | DelegateSimpleThread* threads[kNumThreads]; |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 106 | |
[email protected] | 6a6e657 | 2008-08-20 22:54:52 | [diff] [blame] | 107 | tls_slot.Initialize(ThreadLocalStorageCleanup); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 108 | |
| 109 | // Spawn the threads. |
[email protected] | fe236c9 | 2008-09-11 23:37:54 | [diff] [blame] | 110 | for (int index = 0; index < kNumThreads; index++) { |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 111 | values[index] = kInitialTlsValue; |
[email protected] | fe236c9 | 2008-09-11 23:37:54 | [diff] [blame] | 112 | thread_delegates[index] = new ThreadLocalStorageRunner(&values[index]); |
[email protected] | 1357c32 | 2010-12-30 22:18:56 | [diff] [blame] | 113 | threads[index] = new DelegateSimpleThread(thread_delegates[index], |
| 114 | "tls thread"); |
[email protected] | fe236c9 | 2008-09-11 23:37:54 | [diff] [blame] | 115 | threads[index]->Start(); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 116 | } |
| 117 | |
| 118 | // Wait for the threads to finish. |
| 119 | for (int index = 0; index < kNumThreads; index++) { |
[email protected] | fe236c9 | 2008-09-11 23:37:54 | [diff] [blame] | 120 | threads[index]->Join(); |
| 121 | delete threads[index]; |
| 122 | delete thread_delegates[index]; |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 123 | |
[email protected] | fe236c9 | 2008-09-11 23:37:54 | [diff] [blame] | 124 | // Verify that the destructor was called and that we reset. |
[email protected] | e517d20 | 2011-11-29 21:38:26 | [diff] [blame] | 125 | EXPECT_EQ(values[index], kFinalTlsValue); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 126 | } |
[email protected] | 8a79a21 | 2011-11-10 17:14:05 | [diff] [blame] | 127 | tls_slot.Free(); // Stop doing callbacks to cleanup threads. |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 128 | } |
[email protected] | 1357c32 | 2010-12-30 22:18:56 | [diff] [blame] | 129 | |
| 130 | } // namespace base |