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.
10 #include "base/threading/simple_thread.h"
11 #include "base/threading/thread_local_storage.h"
12 #include "testing/gtest/include/gtest/gtest.h"
15 // Ignore warnings about ptr->int conversions that we use when
16 // storing ints into ThreadLocalStorage.
17 #pragma warning(disable : 4311 4312)
24 const int kInitialTlsValue
= 0x5555;
25 const int kFinalTlsValue
= 0x7777;
26 // How many times must a destructor be called before we really are done.
27 const int kNumberDestructorCallRepetitions
= 3;
29 static ThreadLocalStorage::StaticSlot tls_slot
= TLS_INITIALIZER
;
31 class ThreadLocalStorageRunner
: public DelegateSimpleThread::Delegate
{
33 explicit ThreadLocalStorageRunner(int* tls_value_ptr
)
34 : tls_value_ptr_(tls_value_ptr
) {}
36 ~ThreadLocalStorageRunner() override
{}
39 *tls_value_ptr_
= kInitialTlsValue
;
40 tls_slot
.Set(tls_value_ptr_
);
42 int *ptr
= static_cast<int*>(tls_slot
.Get());
43 EXPECT_EQ(ptr
, tls_value_ptr_
);
44 EXPECT_EQ(*ptr
, kInitialTlsValue
);
47 ptr
= static_cast<int*>(tls_slot
.Get());
48 EXPECT_EQ(ptr
, tls_value_ptr_
);
51 *ptr
= kFinalTlsValue
+ kNumberDestructorCallRepetitions
;
56 DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorageRunner
);
60 void ThreadLocalStorageCleanup(void *value
) {
61 int *ptr
= reinterpret_cast<int*>(value
);
62 // Destructors should never be called with a NULL.
63 ASSERT_NE(reinterpret_cast<int*>(NULL
), ptr
);
64 if (*ptr
== kFinalTlsValue
)
65 return; // We've been called enough times.
66 ASSERT_LT(kFinalTlsValue
, *ptr
);
67 ASSERT_GE(kFinalTlsValue
+ kNumberDestructorCallRepetitions
, *ptr
);
68 --*ptr
; // Move closer to our target.
69 // Tell tls that we're not done with this thread, and still need destruction.
75 TEST(ThreadLocalStorageTest
, Basics
) {
76 ThreadLocalStorage::Slot slot
;
77 slot
.Set(reinterpret_cast<void*>(123));
78 int value
= reinterpret_cast<intptr_t>(slot
.Get());
79 EXPECT_EQ(value
, 123);
82 #if defined(THREAD_SANITIZER) || \
83 (defined(OS_WIN) && defined(ARCH_CPU_X86_64) && !defined(NDEBUG))
84 // Do not run the test under ThreadSanitizer. Because this test iterates its
85 // own TSD destructor for the maximum possible number of times, TSan can't jump
86 // in after the last destructor invocation, therefore the destructor remains
87 // unsynchronized with the following users of the same TSD slot. This results
88 // in race reports between the destructor and functions in other tests.
90 // It is disabled on Win x64 with incremental linking (i.e. "Debug") pending
91 // resolution of http://crbug.com/251251.
92 #define MAYBE_TLSDestructors DISABLED_TLSDestructors
94 #define MAYBE_TLSDestructors TLSDestructors
96 TEST(ThreadLocalStorageTest
, MAYBE_TLSDestructors
) {
97 // Create a TLS index with a destructor. Create a set of
98 // threads that set the TLS, while the destructor cleans it up.
99 // After the threads finish, verify that the value is cleaned up.
100 const int kNumThreads
= 5;
101 int values
[kNumThreads
];
102 ThreadLocalStorageRunner
* thread_delegates
[kNumThreads
];
103 DelegateSimpleThread
* threads
[kNumThreads
];
105 tls_slot
.Initialize(ThreadLocalStorageCleanup
);
107 // Spawn the threads.
108 for (int index
= 0; index
< kNumThreads
; index
++) {
109 values
[index
] = kInitialTlsValue
;
110 thread_delegates
[index
] = new ThreadLocalStorageRunner(&values
[index
]);
111 threads
[index
] = new DelegateSimpleThread(thread_delegates
[index
],
113 threads
[index
]->Start();
116 // Wait for the threads to finish.
117 for (int index
= 0; index
< kNumThreads
; index
++) {
118 threads
[index
]->Join();
119 delete threads
[index
];
120 delete thread_delegates
[index
];
122 // Verify that the destructor was called and that we reset.
123 EXPECT_EQ(values
[index
], kFinalTlsValue
);
125 tls_slot
.Free(); // Stop doing callbacks to cleanup threads.