Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: a98eac5157ce2230198592b9c97155b1b2cf707d
https://github.com/WebKit/WebKit/commit/a98eac5157ce2230198592b9c97155b1b2cf707d
Author: Jean-Yves Avenard <[email protected]>
Date: 2026-05-31 (Sun, 31 May 2026)
Changed paths:
M LayoutTests/platform/visionos/TestExpectations
M Source/WTF/wtf/MainThread.cpp
M Source/WTF/wtf/Threading.cpp
M Source/WTF/wtf/Threading.h
M Source/WTF/wtf/posix/ThreadingPOSIX.cpp
M Source/WTF/wtf/win/ThreadingWin.cpp
M Source/WebCore/dom/ScriptExecutionContext.cpp
Log Message:
-----------
REGRESSION(313609@main): [visionOS debug]
pdf/pdf-plugin-hang-during-destruction.html is a constant crash.
https://bugs.webkit.org/show_bug.cgi?id=315675
rdar://178065646
Reviewed by Chris Dumez and Youenn Fablet
313609@main added work on the libxpc bootstrap dispatch queue in
XPCServiceMain.mm that runs before WTF::initializeMainThread() —
specifically String::utf8() inside setUserDirSuffix(suffix.utf8().data()).
String::utf8() allocates a CStringBuffer, which derives from non-thread-safe
RefCounted. On debug builds (ASSERT_ENABLED || ENABLE(SECURITY_ASSERTIONS))
the RefCounted constructor records the owning thread via
RefCountDebugger::initialOwnerThread(), which calls Thread::currentSingleton()
and lazily constructs the dispatch-queue Thread. That Thread got uid 1 from
m_uid { ++s_uid } (s_uid was default-zero-initialised). The main thread's
later Thread then got uid 2. On release builds the RefCountDebugger path
is compiled out, so the dispatch queue did not construct its Thread first
and the main thread kept uid 1 — which is why this only manifested on debug.
The main thread's uid being 1 is not local to ScriptExecutionContextDispatcher.
WorkQueue and Thread deliberately share one id namespace (WorkQueueCocoa.cpp):
non-main work queues take their id from ++s_uid, while the main work queue is
constructed with the constant mainThreadID (== 1, ThreadAssertions.h).
ThreadLike::currentSequence() returns that id when running inside a tracked
queue, and Thread::currentSingleton().uid() when running on a bare thread. For
an "is current" assertion tagged with the main sequence (1) to hold when checked
on the main thread, the main Thread's uid must also be 1. When 313609@main
pushed main's uid to 2 this shared-namespace assumption broke;
ScriptExecutionContextDispatcher's queue.isCurrent() RELEASE_ASSERT in
NativePromise<T>::ThenCallback::processResult (on main-thread native-promise
resolution — DOMCacheEngine, IDB, etc.) is simply the path that fired in the
affected test.
uid 1 == main was a consequence of startup ordering, not a guaranteed
invariant. We make it explicit on platforms where main can be detected
without prior initialisation, and assert the invariant unconditionally:
- Thread's constructor takes an IsMain { No, Yes, Unknown } argument and
sets m_uid to 1 for IsMain::Yes, otherwise ++s_uid. Thread::create()
passes IsMain::No (a created thread is never main).
- On Cocoa (PLATFORM(COCOA)), ThreadLike::s_uid is initialised to 1 so
++s_uid yields uids >= 2 for every non-main thread, and
Thread::initializeCurrentTLS() passes IsMain::Yes when pthread_main_np()
returns true. pthread_main_np() works without any setup, closing the
window for the libxpc dispatch-queue race.
- initializeCurrentTLS() uses pthread_main_np() directly rather than
isMainThread(): under USE(WEB_THREAD) isMainThread() is also true on the
WebThread, which would stamp uid 1 onto two threads. pthread_main_np()
identifies only the genuine UI thread, keeping uid 1 unique.
- On other platforms (Windows, generic POSIX) main cannot be detected
before initializeMainThreadPlatform() captures s_mainThread, so
initializeCurrentTLS() constructs with IsMain::Unknown. ThreadLike::s_uid
is initialised to 0 there, so ++s_uid assigns uid 1 to whichever Thread
constructs first — the main thread, matching pre-regression
startup-ordering behaviour. These ports do not have the libxpc bootstrap
path that triggers this regression.
- WTF::initializeMainThread() asserts the invariant unconditionally
(RELEASE_ASSERT). On Cocoa it is guaranteed by construction (above). On
Windows/generic POSIX it rests on main being the first thread to construct
its Thread; the RELEASE_ASSERT enforces it by aborting at startup if that
ever fails, rather than letting a sequence assertion mis-fire later.
ScriptExecutionContextDispatcher is refactored to use
std::optional<uint32_t> m_workerThreadId and isMainThread() for the
non-worker branch, removing the dependency on the magic number.
Covered by existing tests.
* LayoutTests/platform/visionos/TestExpectations:
* Source/WTF/wtf/MainThread.cpp:
(WTF::initializeMainThread):
* Source/WTF/wtf/Threading.cpp:
(WTF::Thread::create):
* Source/WTF/wtf/Threading.h:
(WTF::Thread::Thread):
* Source/WTF/wtf/posix/ThreadingPOSIX.cpp:
(WTF::Thread::initializeCurrentTLS):
* Source/WTF/wtf/win/ThreadingWin.cpp:
* Source/WebCore/dom/ScriptExecutionContext.cpp:
(WebCore::ScriptExecutionContextDispatcher::ScriptExecutionContextDispatcher):
(WebCore::ScriptExecutionContextDispatcher::dispatch):
(WebCore::ScriptExecutionContextDispatcher::isCurrent):
Canonical link: https://commits.webkit.org/314233@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications