← All issues

REGRESSION(313609@main): visionOS debug uid 1 == main thread invariant

d1483c0

WTF's Thread and WorkQueue classes share one monotonically-increasing UID namespace. The main work queue is hard-coded with mainThreadID == 1; sequence-safety assertions across IDB, DOMCacheEngine, and NativePromise resolution depend on the invariant that the main thread's Thread::uid() is also 1. Before this fix, UID assignment was purely positional — whichever thread constructed its Thread object first won uid 1.

Source/WTF/wtf/Threading.h

- explicit Thread(SchedulingPolicy schedulingPolicy)
+ enum class IsMain : uint8_t { No, Yes, Unknown };
+
+ explicit Thread(SchedulingPolicy schedulingPolicy, IsMain isMain = IsMain::Unknown)
: m_isRealtime(schedulingPolicy == SchedulingPolicy::Realtime)
+ , m_uid(isMain == IsMain::Yes ? 1 : ++s_uid)
{
}

Source/WTF/wtf/posix/ThreadingPOSIX.cpp

+#if PLATFORM(COCOA)
+ Ref thread = adoptRef(*new Thread(SchedulingPolicy::Other, pthread_main_np() ? IsMain::Yes : IsMain::No));
+#else
Ref thread = adoptRef(*new Thread(SchedulingPolicy::Other));
+#endif

Source/WTF/wtf/MainThread.cpp

+ RELEASE_ASSERT(Thread::currentSingleton().uid() == 1);

On visionOS debug, the RefCountDebugger path inside CStringBuffer's constructor called Thread::currentSingleton() from the libxpc bootstrap queue before initializeMainThread() ran — stealing uid 1 and pushing the real main thread to uid 2. The fix introduces an IsMain enum, uses pthread_main_np() on Cocoa to detect the main thread reliably, and adds a RELEASE_ASSERT enforcing the invariant.

The uid 1 == main thread invariant is load-bearing across WebKit's entire concurrency model; a stolen uid silently misfires RELEASE_ASSERTs in unrelated code paths, making crashes appear in the wrong place and masking real threading bugs.

🔒

The non-Cocoa fallback path and WebThread identity edge cases in the new dispatcher logic are worth investigating.

Subscribe to read more