Merge ThreadHolder to WTF::Thread itself
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Aug 2017 18:29:16 +0000 (18:29 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Aug 2017 18:29:16 +0000 (18:29 +0000)
https://bugs.webkit.org/show_bug.cgi?id=175013

Reviewed by Mark Lam.

Currently, we store ThreadHolder* to the TLS, and ThreadHolder* holds Ref<Thread>.
When we get Thread& from the current thread TLS, we need to dereference the ThreadHolder*.
However, ideally, we can store Thread* directly to the current thread TLS.
While the ThreadHolder design is beautiful, it's worth optimizing by storing Thread* directly
since Thread::current() is so frequently executed.

This patch merges ThreadHolder to Thread. And we now store Thread* directly in the TLS.
When storing it to TLS, we call leakRef() to keep Thread ref count incremented by the TLS.
And when destroying the TLS, we call `deref()` to ensure that Thread* is dereferenced from
the TLS.

* WTF.xcodeproj/project.pbxproj:
* wtf/CMakeLists.txt:
* wtf/ThreadHolder.cpp: Removed.
* wtf/ThreadHolder.h: Removed.
* wtf/ThreadHolderPthreads.cpp: Removed.
* wtf/ThreadHolderWin.cpp: Removed.
* wtf/Threading.cpp:
(WTF::Thread::entryPoint):
(WTF::initializeThreading):
* wtf/Threading.h:
(WTF::Thread::currentMayBeNull):
(WTF::Thread::current):
* wtf/ThreadingPthreads.cpp:
(WTF::Thread::waitForCompletion):
(WTF::Thread::initializeCurrentTLS):
(WTF::Thread::initializeTLSKey):
(WTF::Thread::initializeTLS):
(WTF::Thread::destructTLS):
(WTF::Thread::createCurrentThread): Deleted.
* wtf/ThreadingWin.cpp:
(WTF::Thread::initializeCurrentTLS):
(WTF::threadMapMutex):
(WTF::Thread::initializeTLSKey):
(WTF::Thread::currentDying):
(WTF::Thread::get):
(WTF::Thread::initializeTLS):
(WTF::Thread::destructTLS):
(WTF::waitForThreadCompletion):
(WTF::Thread::createCurrentThread): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@220214 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WTF/ChangeLog
Source/WTF/WTF.xcodeproj/project.pbxproj
Source/WTF/wtf/CMakeLists.txt
Source/WTF/wtf/ThreadHolder.cpp [deleted file]
Source/WTF/wtf/ThreadHolder.h [deleted file]
Source/WTF/wtf/ThreadHolderPthreads.cpp [deleted file]
Source/WTF/wtf/ThreadHolderWin.cpp [deleted file]
Source/WTF/wtf/Threading.cpp
Source/WTF/wtf/Threading.h
Source/WTF/wtf/ThreadingPthreads.cpp
Source/WTF/wtf/ThreadingWin.cpp

index 01a1775..6146577 100644 (file)
@@ -1,5 +1,53 @@
 2017-08-03  Yusuke Suzuki  <utatane.tea@gmail.com>
 
+        Merge ThreadHolder to WTF::Thread itself
+        https://bugs.webkit.org/show_bug.cgi?id=175013
+
+        Reviewed by Mark Lam.
+
+        Currently, we store ThreadHolder* to the TLS, and ThreadHolder* holds Ref<Thread>.
+        When we get Thread& from the current thread TLS, we need to dereference the ThreadHolder*.
+        However, ideally, we can store Thread* directly to the current thread TLS.
+        While the ThreadHolder design is beautiful, it's worth optimizing by storing Thread* directly
+        since Thread::current() is so frequently executed.
+
+        This patch merges ThreadHolder to Thread. And we now store Thread* directly in the TLS.
+        When storing it to TLS, we call leakRef() to keep Thread ref count incremented by the TLS.
+        And when destroying the TLS, we call `deref()` to ensure that Thread* is dereferenced from
+        the TLS.
+
+        * WTF.xcodeproj/project.pbxproj:
+        * wtf/CMakeLists.txt:
+        * wtf/ThreadHolder.cpp: Removed.
+        * wtf/ThreadHolder.h: Removed.
+        * wtf/ThreadHolderPthreads.cpp: Removed.
+        * wtf/ThreadHolderWin.cpp: Removed.
+        * wtf/Threading.cpp:
+        (WTF::Thread::entryPoint):
+        (WTF::initializeThreading):
+        * wtf/Threading.h:
+        (WTF::Thread::currentMayBeNull):
+        (WTF::Thread::current):
+        * wtf/ThreadingPthreads.cpp:
+        (WTF::Thread::waitForCompletion):
+        (WTF::Thread::initializeCurrentTLS):
+        (WTF::Thread::initializeTLSKey):
+        (WTF::Thread::initializeTLS):
+        (WTF::Thread::destructTLS):
+        (WTF::Thread::createCurrentThread): Deleted.
+        * wtf/ThreadingWin.cpp:
+        (WTF::Thread::initializeCurrentTLS):
+        (WTF::threadMapMutex):
+        (WTF::Thread::initializeTLSKey):
+        (WTF::Thread::currentDying):
+        (WTF::Thread::get):
+        (WTF::Thread::initializeTLS):
+        (WTF::Thread::destructTLS):
+        (WTF::waitForThreadCompletion):
+        (WTF::Thread::createCurrentThread): Deleted.
+
+2017-08-03  Yusuke Suzuki  <utatane.tea@gmail.com>
+
         [Linux][WTF] Use one global semaphore to notify thread suspend and resume completion
         https://bugs.webkit.org/show_bug.cgi?id=175124
 
index 4bc2377..ca9e375 100644 (file)
                A8A4743C151A825B004123FF /* StringBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A8A47324151A825B004123FF /* StringBuilder.cpp */; };
                A8A47440151A825B004123FF /* StringImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A8A47328151A825B004123FF /* StringImpl.cpp */; };
                A8A47445151A825B004123FF /* WTFString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A8A4732D151A825B004123FF /* WTFString.cpp */; };
-               A8A47448151A825B004123FF /* ThreadHolderPthreads.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A8A47330151A825B004123FF /* ThreadHolderPthreads.cpp */; };
                A8A4744A151A825B004123FF /* Threading.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A8A47332151A825B004123FF /* Threading.cpp */; };
                A8A4744E151A825B004123FF /* ThreadingPthreads.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A8A47336151A825B004123FF /* ThreadingPthreads.cpp */; };
                A8A47451151A825B004123FF /* BinarySemaphore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A8A4733A151A825B004123FF /* BinarySemaphore.cpp */; };
                DCEE22031CEA7551000C2396 /* PlatformUserPreferredLanguagesMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = DCEE21FF1CEA7551000C2396 /* PlatformUserPreferredLanguagesMac.mm */; };
                E15556F518A0CC18006F48FB /* CryptographicUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E15556F318A0CC18006F48FB /* CryptographicUtilities.cpp */; };
                E311FB171F0A568B003C08DE /* ThreadGroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E311FB151F0A568B003C08DE /* ThreadGroup.cpp */; };
-               E3200AB81E9A536D003B59D2 /* ThreadHolder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3200AB51E9A536D003B59D2 /* ThreadHolder.cpp */; };
                E38C41251EB4E04C0042957D /* CPUTimeCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = E38C41241EB4E04C0042957D /* CPUTimeCocoa.mm */; };
                E38C41281EB4E0680042957D /* CPUTime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38C41261EB4E0680042957D /* CPUTime.cpp */; };
                E43A46971E228B9100276B05 /* Decoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E43A46921E228B9100276B05 /* Decoder.cpp */; };
                A8A4732C151A825B004123FF /* TextPosition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextPosition.h; sourceTree = "<group>"; };
                A8A4732D151A825B004123FF /* WTFString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WTFString.cpp; sourceTree = "<group>"; };
                A8A4732E151A825B004123FF /* WTFString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WTFString.h; sourceTree = "<group>"; };
-               A8A47330151A825B004123FF /* ThreadHolderPthreads.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadHolderPthreads.cpp; sourceTree = "<group>"; };
                A8A47332151A825B004123FF /* Threading.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Threading.cpp; sourceTree = "<group>"; };
                A8A47333151A825B004123FF /* Threading.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Threading.h; sourceTree = "<group>"; };
                A8A47335151A825B004123FF /* ThreadingPrimitives.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadingPrimitives.h; sourceTree = "<group>"; };
                E311FB151F0A568B003C08DE /* ThreadGroup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadGroup.cpp; sourceTree = "<group>"; };
                E311FB161F0A568B003C08DE /* ThreadGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadGroup.h; sourceTree = "<group>"; };
                E3200AB41E9A536D003B59D2 /* PlatformRegisters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformRegisters.h; sourceTree = "<group>"; };
-               E3200AB51E9A536D003B59D2 /* ThreadHolder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadHolder.cpp; sourceTree = "<group>"; };
-               E3200AB61E9A536D003B59D2 /* ThreadHolder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadHolder.h; sourceTree = "<group>"; };
                E38C41241EB4E04C0042957D /* CPUTimeCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CPUTimeCocoa.mm; sourceTree = "<group>"; };
                E38C41261EB4E0680042957D /* CPUTime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CPUTime.cpp; sourceTree = "<group>"; };
                E38C41271EB4E0680042957D /* CPUTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CPUTime.h; sourceTree = "<group>"; };
                                0FB317C31C488001007E395A /* SystemTracing.h */,
                                E311FB151F0A568B003C08DE /* ThreadGroup.cpp */,
                                E311FB161F0A568B003C08DE /* ThreadGroup.h */,
-                               E3200AB51E9A536D003B59D2 /* ThreadHolder.cpp */,
-                               E3200AB61E9A536D003B59D2 /* ThreadHolder.h */,
-                               A8A47330151A825B004123FF /* ThreadHolderPthreads.cpp */,
                                A8A47332151A825B004123FF /* Threading.cpp */,
                                A8A47333151A825B004123FF /* Threading.h */,
                                A8A47335151A825B004123FF /* ThreadingPrimitives.h */,
                                70A993FE1AD7151300FA615B /* SymbolRegistry.cpp in Sources */,
                                1C181C7F1D3078DA00F5FA16 /* TextBreakIterator.cpp in Sources */,
                                1C181C961D30800A00F5FA16 /* TextBreakIteratorInternalICUMac.mm in Sources */,
-                               E3200AB81E9A536D003B59D2 /* ThreadHolder.cpp in Sources */,
-                               A8A47448151A825B004123FF /* ThreadHolderPthreads.cpp in Sources */,
                                A8A4744A151A825B004123FF /* Threading.cpp in Sources */,
                                A8A4744E151A825B004123FF /* ThreadingPthreads.cpp in Sources */,
                                E311FB171F0A568B003C08DE /* ThreadGroup.cpp in Sources */,
index ee769b5..7f8fb7c 100644 (file)
@@ -137,7 +137,6 @@ set(WTF_HEADERS
     SystemFree.h
     SystemTracing.h
     ThreadGroup.h
-    ThreadHolder.cpp
     ThreadMessage.h
     ThreadSafeRefCounted.h
     ThreadSpecific.h
@@ -347,7 +346,6 @@ list(APPEND WTF_LIBRARIES
 if (WIN32)
     list(APPEND WTF_SOURCES
         OSAllocatorWin.cpp
-        ThreadHolderWin.cpp
         ThreadSpecificWin.cpp
         ThreadingWin.cpp
     )
@@ -357,7 +355,6 @@ if (WIN32)
 else ()
     list(APPEND WTF_SOURCES
         OSAllocatorPosix.cpp
-        ThreadHolderPthreads.cpp
         ThreadingPthreads.cpp
     )
 endif ()
diff --git a/Source/WTF/wtf/ThreadHolder.cpp b/Source/WTF/wtf/ThreadHolder.cpp
deleted file mode 100644 (file)
index 6acbb1b..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2009, 2011 Google Inc. All rights reserved.
- * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com>.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "ThreadHolder.h"
-
-#include "Threading.h"
-
-namespace WTF {
-
-#if !HAVE(FAST_TLS)
-ThreadSpecificKey ThreadHolder::m_key = InvalidThreadSpecificKey;
-#endif
-
-ThreadHolder::~ThreadHolder()
-{
-    m_thread->didExit();
-}
-
-ThreadHolder& ThreadHolder::initializeCurrent()
-{
-    return initialize(Thread::createCurrentThread());
-}
-
-} // namespace WTF
diff --git a/Source/WTF/wtf/ThreadHolder.h b/Source/WTF/wtf/ThreadHolder.h
deleted file mode 100644 (file)
index c8f8004..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com>.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-// FIXME: We intentionally use ifndef guards instead of `#pragma once` here to avoid build failures.
-// WTF headers are copied to build directory. Based on how we include headers, WTF headers may be
-// included from either source directory or build directory. Compilers are confused with their
-// two different paths and include the same file twice.
-// https://bugs.webkit.org/show_bug.cgi?id=174986
-#ifndef ThreadHolder_h
-#define ThreadHolder_h
-
-#include <wtf/FastTLS.h>
-#include <wtf/Ref.h>
-#include <wtf/RefPtr.h>
-#include <wtf/ThreadSpecific.h>
-
-namespace WTF {
-
-class Thread;
-
-// This function can be called from any threads.
-WTF_EXPORT_PRIVATE void initializeThreading();
-
-// Holds Thread in the thread-specific storage. The destructor of this holder reliably destroy Thread.
-// For pthread, it employs pthreads-specific 2-pass destruction to reliably remove Thread.
-// For Windows, we use thread_local to defer thread holder destruction. It assumes regular ThreadSpecific
-// types don't use multiple-pass destruction.
-class ThreadHolder {
-    WTF_MAKE_NONCOPYABLE(ThreadHolder);
-public:
-    friend class Thread;
-    friend void WTF::initializeThreading();
-    ~ThreadHolder();
-
-    static ThreadHolder& current();
-
-    Thread& thread() { return m_thread.get(); }
-
-#if OS(WINDOWS)
-    static RefPtr<Thread> get(ThreadIdentifier);
-#endif
-
-private:
-    ThreadHolder(Ref<Thread>&& thread)
-        : m_thread(WTFMove(thread))
-        , m_isDestroyedOnce(false)
-    {
-    }
-
-    // Creates and puts an instance of ThreadHolder into thread-specific storage.
-    static ThreadHolder& initialize(Ref<Thread>&&);
-    WTF_EXPORT_PRIVATE static ThreadHolder& initializeCurrent();
-
-#if !HAVE(FAST_TLS)
-    // One time initialization for this class as a whole.
-    // This method must be called before initialize() and it is not thread-safe.
-    WTF_EXPORT_PRIVATE static void initializeKey();
-#endif
-
-    // Returns 0 if thread-specific storage was not initialized.
-    static ThreadHolder* currentMayBeNull();
-
-#if OS(WINDOWS)
-    WTF_EXPORT_PRIVATE static ThreadHolder* currentDying();
-#endif
-
-    // This thread-specific destructor is called 2 times when thread terminates:
-    // - first, when all the other thread-specific destructors are called, it simply remembers it was 'destroyed once'
-    // and (1) re-sets itself into the thread-specific slot or (2) constructs thread local value to call it again later.
-    // - second, after all thread-specific destructors were invoked, it gets called again - this time, we remove the
-    // Thread from the threadMap, completing the cleanup.
-    static void THREAD_SPECIFIC_CALL destruct(void* data);
-
-    Ref<Thread> m_thread;
-    bool m_isDestroyedOnce;
-#if !HAVE(FAST_TLS)
-    static WTF_EXPORTDATA ThreadSpecificKey m_key;
-#endif
-};
-
-inline ThreadHolder* ThreadHolder::currentMayBeNull()
-{
-#if !HAVE(FAST_TLS)
-    ASSERT(m_key != InvalidThreadSpecificKey);
-    return static_cast<ThreadHolder*>(threadSpecificGet(m_key));
-#else
-    return static_cast<ThreadHolder*>(_pthread_getspecific_direct(WTF_THREAD_DATA_KEY));
-#endif
-}
-
-inline ThreadHolder& ThreadHolder::current()
-{
-    // WRT WebCore:
-    //    ThreadHolder is used on main thread before it could possibly be used
-    //    on secondary ones, so there is no need for synchronization here.
-    // WRT JavaScriptCore:
-    //    ThreadHolder::initializeKey() is initially called from initializeThreading(), ensuring
-    //    this is initially called in a pthread_once locked context.
-#if !HAVE(FAST_TLS)
-    if (UNLIKELY(ThreadHolder::m_key == InvalidThreadSpecificKey))
-        WTF::initializeThreading();
-#endif
-    if (auto* holder = currentMayBeNull())
-        return *holder;
-#if OS(WINDOWS)
-    if (auto* holder = currentDying())
-        return *holder;
-#endif
-    return initializeCurrent();
-}
-
-} // namespace WTF
-#endif // ThreadHolder_h
diff --git a/Source/WTF/wtf/ThreadHolderPthreads.cpp b/Source/WTF/wtf/ThreadHolderPthreads.cpp
deleted file mode 100644 (file)
index 688f9e5..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2009, 2011 Google Inc. All rights reserved.
- * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com>.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "ThreadHolder.h"
-
-#include <wtf/Threading.h>
-
-namespace WTF {
-
-#if !HAVE(FAST_TLS)
-void ThreadHolder::initializeKey()
-{
-    threadSpecificKeyCreate(&m_key, destruct);
-}
-#endif
-
-ThreadHolder& ThreadHolder::initialize(Ref<Thread>&& thread)
-{
-    auto* holder = new ThreadHolder(WTFMove(thread));
-#if !HAVE(FAST_TLS)
-    ASSERT(m_key != InvalidThreadSpecificKey);
-    threadSpecificSet(m_key, holder);
-#else
-    _pthread_setspecific_direct(WTF_THREAD_DATA_KEY, holder);
-    pthread_key_init_np(WTF_THREAD_DATA_KEY, &destruct);
-#endif
-    return *holder;
-}
-
-void ThreadHolder::destruct(void* data)
-{
-    ThreadHolder* holder = static_cast<ThreadHolder*>(data);
-    ASSERT(holder);
-
-    if (holder->m_isDestroyedOnce) {
-        delete holder;
-        return;
-    }
-
-    holder->m_isDestroyedOnce = true;
-    // Re-setting the value for key causes another destruct() call after all other thread-specific destructors were called.
-#if !HAVE(FAST_TLS)
-    ASSERT(m_key != InvalidThreadSpecificKey);
-    threadSpecificSet(m_key, holder);
-#else
-    _pthread_setspecific_direct(WTF_THREAD_DATA_KEY, holder);
-    pthread_key_init_np(WTF_THREAD_DATA_KEY, &destruct);
-#endif
-}
-
-} // namespace WTF
diff --git a/Source/WTF/wtf/ThreadHolderWin.cpp b/Source/WTF/wtf/ThreadHolderWin.cpp
deleted file mode 100644 (file)
index 0341313..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com>.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "ThreadHolder.h"
-
-#include <mutex>
-#include <wtf/HashMap.h>
-#include <wtf/NeverDestroyed.h>
-#include <wtf/Threading.h>
-
-namespace WTF {
-
-#define InvalidThreadHolder ((ThreadHolder*)(0xbbadbeef))
-
-static std::mutex& threadMapMutex()
-{
-    static NeverDestroyed<std::mutex> mutex;
-    return mutex.get();
-}
-
-static HashMap<ThreadIdentifier, ThreadHolder*>& threadMap()
-{
-    static NeverDestroyed<HashMap<ThreadIdentifier, ThreadHolder*>> map;
-    return map.get();
-}
-
-void ThreadHolder::initializeKey()
-{
-    threadMapMutex();
-    threadMap();
-    threadSpecificKeyCreate(&m_key, destruct);
-}
-
-ThreadHolder* ThreadHolder::currentDying()
-{
-    ASSERT(m_key != InvalidThreadSpecificKey);
-    // After FLS is destroyed, this map offers the value until the second thread exit callback is called.
-    std::lock_guard<std::mutex> locker(threadMapMutex());
-    return threadMap().get(currentThread());
-}
-
-// FIXME: Remove this workaround code once <rdar://problem/31793213> is fixed.
-RefPtr<Thread> ThreadHolder::get(ThreadIdentifier id)
-{
-    std::lock_guard<std::mutex> locker(threadMapMutex());
-    ThreadHolder* holder = threadMap().get(id);
-    if (holder)
-        return &holder->thread();
-    return nullptr;
-}
-
-ThreadHolder& ThreadHolder::initialize(Ref<Thread>&& thread)
-{
-    ASSERT(m_key != InvalidThreadSpecificKey);
-    // FIXME: Remove this workaround code once <rdar://problem/31793213> is fixed.
-    auto id = thread->id();
-    auto* holder = new ThreadHolder(WTFMove(thread));
-    threadSpecificSet(m_key, holder);
-    {
-        std::lock_guard<std::mutex> locker(threadMapMutex());
-        threadMap().add(id, holder);
-    }
-    return *holder;
-}
-
-void ThreadHolder::destruct(void* data)
-{
-    if (data == InvalidThreadHolder)
-        return;
-
-    ThreadHolder* holder = static_cast<ThreadHolder*>(data);
-    ASSERT(holder);
-
-    // Delay the deallocation of ThreadHolder more.
-    // It defers ThreadHolder deallocation after the other ThreadSpecific values are deallocated.
-    static thread_local class ThreadExitCallback {
-    public:
-        ThreadExitCallback(ThreadHolder* holder)
-            : m_holder(holder)
-        {
-        }
-
-        ~ThreadExitCallback()
-        {
-            ThreadHolder::destruct(m_holder);
-        }
-
-    private:
-        ThreadHolder* m_holder;
-    } callback(holder);
-
-    if (holder->m_isDestroyedOnce) {
-        {
-            std::lock_guard<std::mutex> locker(threadMapMutex());
-            ASSERT(threadMap().contains(holder->m_thread->id()));
-            threadMap().remove(holder->m_thread->id());
-        }
-        delete holder;
-
-        // Fill the FLS with the non-nullptr value. While FLS destructor won't be called for that,
-        // non-nullptr value tells us that we already destructed ThreadHolder. This allows us to
-        // detect incorrect use of Thread::current() after this point because it will crash.
-        threadSpecificSet(m_key, InvalidThreadHolder);
-        return;
-    }
-    threadSpecificSet(m_key, InvalidThreadHolder);
-    holder->m_isDestroyedOnce = true;
-}
-
-} // namespace WTF
index dc80386..0be5a10 100644 (file)
@@ -34,7 +34,6 @@
 #include <wtf/PrintStream.h>
 #include <wtf/RandomNumberSeed.h>
 #include <wtf/ThreadGroup.h>
-#include <wtf/ThreadHolder.h>
 #include <wtf/ThreadMessage.h>
 #include <wtf/ThreadingPrimitives.h>
 #include <wtf/text/AtomicStringTable.h>
@@ -113,13 +112,12 @@ void Thread::entryPoint(NewThreadContext* newThreadContext)
         MutexLocker locker(context->mutex);
         ASSERT(context->stage == NewThreadContext::Stage::EstablishedHandle);
 
-        // Initialize thread holder with established ID.
-        ThreadHolder::initialize(context->thread.copyRef());
-
         Thread::initializeCurrentThreadInternal(context->name);
         function = WTFMove(context->entryPoint);
         context->thread->initializeInThread();
 
+        Thread::initializeTLS(WTFMove(context->thread));
+
 #if !HAVE(STACK_BOUNDS_FOR_NEW_THREAD)
         // Ack completion of initialization to the creating thread.
         context->stage = NewThreadContext::Stage::Initialized;
@@ -278,13 +276,17 @@ void Thread::dump(PrintStream& out) const
     out.print(m_id);
 }
 
+#if !HAVE(FAST_TLS)
+ThreadSpecificKey Thread::s_key = InvalidThreadSpecificKey;
+#endif
+
 void initializeThreading()
 {
-    static std::once_flag initializeKey;
-    std::call_once(initializeKey, [] {
+    static std::once_flag onceKey;
+    std::call_once(onceKey, [] {
         initializeRandomNumberGenerator();
 #if !HAVE(FAST_TLS)
-        ThreadHolder::initializeKey();
+        Thread::initializeTLSKey();
 #endif
         initializeDates();
         Thread::initializePlatformThreading();
index 325e6ab..4cdd50e 100644 (file)
 #include <stdint.h>
 #include <wtf/Atomics.h>
 #include <wtf/Expected.h>
+#include <wtf/FastTLS.h>
 #include <wtf/Function.h>
 #include <wtf/PlatformRegisters.h>
+#include <wtf/Ref.h>
 #include <wtf/RefPtr.h>
 #include <wtf/StackBounds.h>
 #include <wtf/StackStats.h>
-#include <wtf/ThreadHolder.h>
 #include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/ThreadSpecific.h>
 #include <wtf/Vector.h>
 
 #if USE(PTHREADS) && !OS(DARWIN)
@@ -59,14 +61,26 @@ using AtomicStringTableDestructor = void (*)(AtomicStringTable*);
 enum class ThreadGroupAddResult;
 
 class ThreadGroup;
-class ThreadHolder;
 class PrintStream;
 
+// This function can be called from any threads.
+WTF_EXPORT_PRIVATE void initializeThreading();
+
+// FIXME: The following functions remain because they are used from WebKit Windows support library,
+// WebKitQuartzCoreAdditions.dll. When updating the support library, we should use new API instead
+// and the following workaound should be removed. And new code should not use the following APIs.
+// Remove this workaround code when <rdar://problem/31793213> is fixed.
+#if OS(WINDOWS)
+WTF_EXPORT_PRIVATE ThreadIdentifier createThread(ThreadFunction, void*, const char* threadName);
+WTF_EXPORT_PRIVATE int waitForThreadCompletion(ThreadIdentifier);
+#endif
+
 class Thread : public ThreadSafeRefCounted<Thread> {
 public:
     friend class ThreadGroup;
-    friend class ThreadHolder;
     friend class AtomicStringTable;
+    friend void initializeThreading();
+    friend int waitForThreadCompletion(ThreadIdentifier);
 
     WTF_EXPORT_PRIVATE ~Thread();
 
@@ -75,7 +89,7 @@ public:
     WTF_EXPORT_PRIVATE static RefPtr<Thread> create(const char* threadName, Function<void()>&&);
 
     // Returns Thread object.
-    static Thread& current() { return ThreadHolder::current().thread(); }
+    static Thread& current();
 
     // Returns ThreadIdentifier directly. It is useful if the user only cares about identity
     // of threads. At that time, users should know that holding this ThreadIdentifier does not ensure
@@ -192,7 +206,6 @@ public:
 protected:
     Thread() = default;
 
-    static Ref<Thread> createCurrentThread();
     void initializeInThread();
 
     // Internal platform-specific Thread establishment implementation.
@@ -234,12 +247,44 @@ protected:
     ThreadGroupAddResult addToThreadGroup(const AbstractLocker& threadGroupLocker, ThreadGroup&);
     void removeFromThreadGroup(const AbstractLocker& threadGroupLocker, ThreadGroup&);
 
+    // The Thread instance is ref'ed and held in thread-specific storage. It will be deref'ed by destructTLS at thread destruction time.
+    // For pthread, it employs pthreads-specific 2-pass destruction to reliably remove Thread.
+    // For Windows, we use thread_local to defer thread TLS destruction. It assumes regular ThreadSpecific
+    // types don't use multiple-pass destruction.
+
+#if !HAVE(FAST_TLS)
+    static WTF_EXPORTDATA ThreadSpecificKey s_key;
+    // One time initialization for this class as a whole.
+    // This method must be called before initializeTLS() and it is not thread-safe.
+    static void initializeTLSKey();
+#endif
+
+    // Creates and puts an instance of Thread into thread-specific storage.
+    static Thread& initializeTLS(Ref<Thread>&&);
+    WTF_EXPORT_PRIVATE static Thread& initializeCurrentTLS();
+
+    // Returns nullptr if thread-specific storage was not initialized.
+    static Thread* currentMayBeNull();
+
+#if OS(WINDOWS)
+    WTF_EXPORT_PRIVATE static Thread* currentDying();
+    static RefPtr<Thread> get(ThreadIdentifier);
+#endif
+
+    // This thread-specific destructor is called 2 times when thread terminates:
+    // - first, when all the other thread-specific destructors are called, it simply remembers it was 'destroyed once'
+    // and (1) re-sets itself into the thread-specific slot or (2) constructs thread local value to call it again later.
+    // - second, after all thread-specific destructors were invoked, it gets called again - this time, we remove the
+    // Thread from the threadMap, completing the cleanup.
+    static void THREAD_SPECIFIC_CALL destructTLS(void* data);
+
     // WordLock & Lock rely on ThreadSpecific. But Thread object can be destroyed even after ThreadSpecific things are destroyed.
     std::mutex m_mutex;
     ThreadIdentifier m_id { 0 };
     JoinableState m_joinableState { Joinable };
     bool m_isShuttingDown { false };
     bool m_didExit { false };
+    bool m_isDestroyedOnce { false };
     StackBounds m_stack { StackBounds::emptyBounds() };
     Vector<std::weak_ptr<ThreadGroup>> m_threadGroups;
     PlatformThreadHandle m_handle;
@@ -267,14 +312,36 @@ inline ThreadIdentifier currentThread()
     return Thread::currentID();
 }
 
-// FIXME: The following functions remain because they are used from WebKit Windows support library,
-// WebKitQuartzCoreAdditions.dll. When updating the support library, we should use new API instead
-// and the following workaound should be removed. And new code should not use the following APIs.
-// Remove this workaround code when <rdar://problem/31793213> is fixed.
+inline Thread* Thread::currentMayBeNull()
+{
+#if !HAVE(FAST_TLS)
+    ASSERT(s_key != InvalidThreadSpecificKey);
+    return static_cast<Thread*>(threadSpecificGet(s_key));
+#else
+    return static_cast<Thread*>(_pthread_getspecific_direct(WTF_THREAD_DATA_KEY));
+#endif
+}
+
+inline Thread& Thread::current()
+{
+    // WRT WebCore:
+    //    Thread::current() is used on main thread before it could possibly be used
+    //    on secondary ones, so there is no need for synchronization here.
+    // WRT JavaScriptCore:
+    //    Thread::initializeTLSKey() is initially called from initializeThreading(), ensuring
+    //    this is initially called in a pthread_once locked context.
+#if !HAVE(FAST_TLS)
+    if (UNLIKELY(Thread::s_key == InvalidThreadSpecificKey))
+        WTF::initializeThreading();
+#endif
+    if (auto* thread = currentMayBeNull())
+        return *thread;
 #if OS(WINDOWS)
-WTF_EXPORT_PRIVATE ThreadIdentifier createThread(ThreadFunction, void*, const char* threadName);
-WTF_EXPORT_PRIVATE int waitForThreadCompletion(ThreadIdentifier);
+    if (auto* thread = currentDying())
+        return *thread;
 #endif
+    return initializeCurrentTLS();
+}
 
 } // namespace WTF
 
index 7f798cf..3437505 100644 (file)
@@ -41,7 +41,6 @@
 #include <wtf/RawPointer.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/ThreadGroup.h>
-#include <wtf/ThreadHolder.h>
 #include <wtf/ThreadingPrimitives.h>
 #include <wtf/WordLock.h>
 
@@ -294,7 +293,7 @@ int Thread::waitForCompletion()
     ASSERT(joinableState() == Joinable);
 
     // If the thread has already exited, then do nothing. If the thread hasn't exited yet, then just signal that we've already joined on it.
-    // In both cases, ThreadHolder::destruct() will take care of destroying Thread.
+    // In both cases, Thread::destructTLS() will take care of destroying Thread.
     if (!hasExited())
         didJoin();
 
@@ -312,15 +311,15 @@ void Thread::detach()
         didBecomeDetached();
 }
 
-
-Ref<Thread> Thread::createCurrentThread()
+Thread& Thread::initializeCurrentTLS()
 {
     // Not a WTF-created thread, ThreadIdentifier is not established yet.
     Ref<Thread> thread = adoptRef(*new Thread());
     thread->establishPlatformSpecificHandle(pthread_self());
     thread->initializeInThread();
     initializeCurrentThreadEvenIfNonWTFCreated();
-    return thread;
+
+    return initializeTLS(WTFMove(thread));
 }
 
 ThreadIdentifier Thread::currentID()
@@ -466,6 +465,49 @@ void Thread::establishPlatformSpecificHandle(pthread_t handle)
     }
 }
 
+#if !HAVE(FAST_TLS)
+void Thread::initializeTLSKey()
+{
+    threadSpecificKeyCreate(&s_key, destructTLS);
+}
+#endif
+
+Thread& Thread::initializeTLS(Ref<Thread>&& thread)
+{
+    // We leak the ref to keep the Thread alive while it is held in TLS. destructTLS will deref it later at thread destruction time.
+    auto& threadInTLS = thread.leakRef();
+#if !HAVE(FAST_TLS)
+    ASSERT(s_key != InvalidThreadSpecificKey);
+    threadSpecificSet(s_key, &threadInTLS);
+#else
+    _pthread_setspecific_direct(WTF_THREAD_DATA_KEY, &threadInTLS);
+    pthread_key_init_np(WTF_THREAD_DATA_KEY, &destructTLS);
+#endif
+    return threadInTLS;
+}
+
+void Thread::destructTLS(void* data)
+{
+    Thread* thread = static_cast<Thread*>(data);
+    ASSERT(thread);
+
+    if (thread->m_isDestroyedOnce) {
+        thread->didExit();
+        thread->deref();
+        return;
+    }
+
+    thread->m_isDestroyedOnce = true;
+    // Re-setting the value for key causes another destructTLS() call after all other thread-specific destructors were called.
+#if !HAVE(FAST_TLS)
+    ASSERT(s_key != InvalidThreadSpecificKey);
+    threadSpecificSet(s_key, thread);
+#else
+    _pthread_setspecific_direct(WTF_THREAD_DATA_KEY, thread);
+    pthread_key_init_np(WTF_THREAD_DATA_KEY, &destructTLS);
+#endif
+}
+
 Mutex::Mutex()
 {
     pthread_mutexattr_t attr;
index cdfec30..bec0d34 100644 (file)
 #include <process.h>
 #include <windows.h>
 #include <wtf/CurrentTime.h>
+#include <wtf/HashMap.h>
 #include <wtf/Lock.h>
 #include <wtf/MainThread.h>
 #include <wtf/MathExtras.h>
 #include <wtf/NeverDestroyed.h>
-#include <wtf/ThreadHolder.h>
 #include <wtf/ThreadingPrimitives.h>
 
 namespace WTF {
@@ -239,7 +239,7 @@ size_t Thread::getRegisters(PlatformRegisters& registers)
     return sizeof(CONTEXT);
 }
 
-Ref<Thread> Thread::createCurrentThread()
+Thread& Thread::initializeCurrentTLS()
 {
     // Not a WTF-created thread, ThreadIdentifier is not established yet.
     Ref<Thread> thread = adoptRef(*new Thread());
@@ -251,7 +251,8 @@ Ref<Thread> Thread::createCurrentThread()
     thread->establishPlatformSpecificHandle(handle, currentID());
     thread->initializeInThread();
     initializeCurrentThreadEvenIfNonWTFCreated();
-    return thread;
+
+    return initializeTLS(WTFMove(thread));
 }
 
 ThreadIdentifier Thread::currentID()
@@ -266,6 +267,105 @@ void Thread::establishPlatformSpecificHandle(HANDLE handle, ThreadIdentifier thr
     m_id = threadID;
 }
 
+#define InvalidThread ((Thread*)(0xbbadbeef))
+
+static std::mutex& threadMapMutex()
+{
+    static NeverDestroyed<std::mutex> mutex;
+    return mutex.get();
+}
+
+static HashMap<ThreadIdentifier, Thread*>& threadMap()
+{
+    static NeverDestroyed<HashMap<ThreadIdentifier, Thread*>> map;
+    return map.get();
+}
+
+void Thread::initializeTLSKey()
+{
+    threadMapMutex();
+    threadMap();
+    threadSpecificKeyCreate(&s_key, destructTLS);
+}
+
+Thread* Thread::currentDying()
+{
+    ASSERT(s_key != InvalidThreadSpecificKey);
+    // After FLS is destroyed, this map offers the value until the second thread exit callback is called.
+    std::lock_guard<std::mutex> locker(threadMapMutex());
+    return threadMap().get(currentThread());
+}
+
+// FIXME: Remove this workaround code once <rdar://problem/31793213> is fixed.
+RefPtr<Thread> Thread::get(ThreadIdentifier id)
+{
+    std::lock_guard<std::mutex> locker(threadMapMutex());
+    Thread* thread = threadMap().get(id);
+    if (thread)
+        return thread;
+    return nullptr;
+}
+
+Thread& Thread::initializeTLS(Ref<Thread>&& thread)
+{
+    ASSERT(s_key != InvalidThreadSpecificKey);
+    // FIXME: Remove this workaround code once <rdar://problem/31793213> is fixed.
+    auto id = thread->id();
+    // We leak the ref to keep the Thread alive while it is held in TLS. destructTLS will deref it later at thread destruction time.
+    auto& threadInTLS = thread.leakRef();
+    threadSpecificSet(s_key, &threadInTLS);
+    {
+        std::lock_guard<std::mutex> locker(threadMapMutex());
+        threadMap().add(id, &threadInTLS);
+    }
+    return threadInTLS;
+}
+
+void Thread::destructTLS(void* data)
+{
+    if (data == InvalidThread)
+        return;
+
+    Thread* thread = static_cast<Thread*>(data);
+    ASSERT(thread);
+
+    // Delay the deallocation of Thread more.
+    // It defers Thread deallocation after the other ThreadSpecific values are deallocated.
+    static thread_local class ThreadExitCallback {
+    public:
+        ThreadExitCallback(Thread* thread)
+            : m_thread(thread)
+        {
+        }
+
+        ~ThreadExitCallback()
+        {
+            Thread::destructTLS(m_thread);
+        }
+
+    private:
+        Thread* m_thread;
+    } callback(thread);
+
+    if (thread->m_isDestroyedOnce) {
+        {
+            std::lock_guard<std::mutex> locker(threadMapMutex());
+            ASSERT(threadMap().contains(thread->id()));
+            threadMap().remove(thread->id());
+        }
+        thread->didExit();
+        thread->deref();
+
+        // Fill the FLS with the non-nullptr value. While FLS destructor won't be called for that,
+        // non-nullptr value tells us that we already destructed Thread. This allows us to
+        // detect incorrect use of Thread::current() after this point because it will crash.
+        threadSpecificSet(s_key, InvalidThread);
+        return;
+    }
+    threadSpecificSet(s_key, InvalidThread);
+    thread->m_isDestroyedOnce = true;
+}
+
 Mutex::Mutex()
 {
     m_mutex.m_recursionCount = 0;
@@ -505,7 +605,7 @@ int waitForThreadCompletion(ThreadIdentifier threadID)
     // it should not be used in new code.
     ASSERT(threadID);
 
-    RefPtr<Thread> thread = ThreadHolder::get(threadID);
+    RefPtr<Thread> thread = Thread::get(threadID);
     if (!thread) {
         LOG_ERROR("ThreadIdentifier %u did not correspond to an active thread when trying to quit", threadID);
         return WAIT_FAILED;