Add a callback to cleanup TLS data on Windows.
authorscroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 25 Oct 2012 19:12:40 +0000 (19:12 +0000)
committerscroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 25 Oct 2012 19:12:40 +0000 (19:12 +0000)
Add a test to ensure that it works.

BUG: http://code.google.com/p/skia/issues/detail?id=939

Review URL: https://codereview.appspot.com/6785045

git-svn-id: http://skia.googlecode.com/svn/trunk@6126 2bbb7eff-a529-9590-31e7-b0007b416f81

src/ports/SkThread_win.cpp
tests/TLSTest.cpp

index 91a5ceb..07a67ef 100644 (file)
@@ -93,3 +93,44 @@ void SkTLS::PlatformSetSpecific(void* ptr) {
     (void)TlsSetValue(gTlsIndex, ptr);
 }
 
+// Call TLS destructors on thread exit. Code based on Chromium's
+// base/threading/thread_local_storage_win.cc
+#ifdef _WIN64
+
+#pragma comment(linker, "/INCLUDE:_tls_used")
+#pragma comment(linker, "/INCLUDE:skia_tls_callback")
+
+#else
+
+#pragma comment(linker, "/INCLUDE:__tls_used")
+#pragma comment(linker, "/INCLUDE:_skia_tls_callback")
+
+#endif
+
+void NTAPI onTLSCallback(PVOID unused, DWORD reason, PVOID unused2) {
+    if ((DLL_THREAD_DETACH == reason || DLL_PROCESS_DETACH == reason) && gOnce) {
+        void* ptr = TlsGetValue(gTlsIndex);
+        if (ptr != NULL) {
+            SkTLS::Destructor(ptr);
+            TlsSetValue(gTlsIndex, NULL);
+        }
+    }
+}
+
+extern "C" {
+
+#ifdef _WIN64
+
+#pragma const_seg(".CRT$XLB")
+extern const PIMAGE_TLS_CALLBACK skia_tls_callback;
+PIMAGE_TLS_CALLBACK skia_tls_callback = onTLSCallback;
+#pragma const_seg()
+
+#else
+
+#pragma data_seg(".CRT$XLB")
+PIMAGE_TLS_CALLBACK skia_tls_callback = onTLSCallback;
+#pragma data_seg()
+
+#endif
+}
index 5fa0903..17f7dcb 100644 (file)
@@ -30,13 +30,13 @@ static void thread_main(void*) {
     }
 }
 
-static void test_measuretext(skiatest::Reporter* reporter) {
+static void test_threads(SkThread::entryPointProc proc) {
     SkThread* threads[8];
     int N = SK_ARRAY_COUNT(threads);
     int i;
 
     for (i = 0; i < N; ++i) {
-        threads[i] = new SkThread(thread_main);
+        threads[i] = new SkThread(proc);
     }
 
     for (i = 0; i < N; ++i) {
@@ -52,12 +52,32 @@ static void test_measuretext(skiatest::Reporter* reporter) {
     }
 }
 
+static int32_t gCounter;
+
+static void* FakeCreateTLS() {
+    sk_atomic_inc(&gCounter);
+    return NULL;
+}
+
+static void FakeDeleteTLS(void* unused) {
+    sk_atomic_dec(&gCounter);
+}
+
+static void testTLSDestructor(void* unused) {
+    SkTLS::Get(FakeCreateTLS, FakeDeleteTLS);
+}
+
 static void TestTLS(skiatest::Reporter* reporter) {
-    test_measuretext(reporter);
+    // TODO: Disabled for now to work around
+    // http://code.google.com/p/skia/issues/detail?id=619
+    // ('flaky segfault in TLS test on Shuttle_Ubuntu12 buildbots')
+    //test_threads(&thread_main);
+
+    // Test to ensure that at thread destruction, TLS destructors
+    // have been called.
+    test_threads(&testTLSDestructor);
+    REPORTER_ASSERT(reporter, 0 == gCounter);
 }
 
 #include "TestClassDef.h"
-// TODO: Disabled for now to work around
-// http://code.google.com/p/skia/issues/detail?id=619
-// ('flaky segfault in TLS test on Shuttle_Ubuntu12 buildbots')
-// DEFINE_TESTCLASS("TLS", TLSClass, TestTLS)
+DEFINE_TESTCLASS("TLS", TLSClass, TestTLS)