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) && \
84 defined(INCREMENTAL_LINKING))
85 // Do not run the test under ThreadSanitizer. Because this test iterates its
86 // own TSD destructor for the maximum possible number of times, TSan can't jump
87 // in after the last destructor invocation, therefore the destructor remains
88 // unsynchronized with the following users of the same TSD slot. This results
89 // in race reports between the destructor and functions in other tests.
91 // It is disabled on Win x64 with incremental linking pending resolution of
92 // http://crbug.com/251251.
93 #define MAYBE_TLSDestructors DISABLED_TLSDestructors
95 #define MAYBE_TLSDestructors TLSDestructors
97 TEST(ThreadLocalStorageTest
, MAYBE_TLSDestructors
) {
98 // Create a TLS index with a destructor. Create a set of
99 // threads that set the TLS, while the destructor cleans it up.
100 // After the threads finish, verify that the value is cleaned up.
101 const int kNumThreads
= 5;
102 int values
[kNumThreads
];
103 ThreadLocalStorageRunner
* thread_delegates
[kNumThreads
];
104 DelegateSimpleThread
* threads
[kNumThreads
];
106 tls_slot
.Initialize(ThreadLocalStorageCleanup
);
108 // Spawn the threads.
109 for (int index
= 0; index
< kNumThreads
; index
++) {
110 values
[index
] = kInitialTlsValue
;
111 thread_delegates
[index
] = new ThreadLocalStorageRunner(&values
[index
]);
112 threads
[index
] = new DelegateSimpleThread(thread_delegates
[index
],
114 threads
[index
]->Start();
117 // Wait for the threads to finish.
118 for (int index
= 0; index
< kNumThreads
; index
++) {
119 threads
[index
]->Join();
120 delete threads
[index
];
121 delete thread_delegates
[index
];
123 // Verify that the destructor was called and that we reset.
124 EXPECT_EQ(values
[index
], kFinalTlsValue
);
126 tls_slot
.Free(); // Stop doing callbacks to cleanup threads.