diff --git a/Source/JavaScriptCore/runtime/AtomicsObject.cpp b/Source/JavaScriptCore/runtime/AtomicsObject.cpp index 9f8833c13f674..e6125cc0b54e4 100644 --- a/Source/JavaScriptCore/runtime/AtomicsObject.cpp +++ b/Source/JavaScriptCore/runtime/AtomicsObject.cpp @@ -470,7 +470,12 @@ JSValue atomicsWaitImpl(JSGlobalObject* globalObject, JSArrayType* typedArray, u case WaiterListManager::WaitSyncResult::TimedOut: return vm.smallStrings.timedOutString(); case WaiterListManager::WaitSyncResult::Terminated: - vm.throwTerminationException(); + // The request may still be an unhandled NeedTermination trap fired from another thread + // while we were blocked; handling it records the request and throws the TerminationException. + if (vm.hasTerminationRequest()) + vm.throwTerminationException(); + else + vm.traps().handleTraps(VMTraps::NeedTermination); return { }; } RELEASE_ASSERT_NOT_REACHED(); diff --git a/Source/JavaScriptCore/runtime/WaiterListManager.cpp b/Source/JavaScriptCore/runtime/WaiterListManager.cpp index 5df3695bcf02a..4b738155f2d74 100644 --- a/Source/JavaScriptCore/runtime/WaiterListManager.cpp +++ b/Source/JavaScriptCore/runtime/WaiterListManager.cpp @@ -92,7 +92,14 @@ WaiterListManager::WaitSyncResult WaiterListManager::waitSyncImpl(VM& vm, ValueT list->addLast(listLocker, syncWaiter); dataLogLnIf(WaiterListsManagerInternal::verbose, " added a new SyncWaiter=", syncWaiter.get(), " to a waiterList for ptr ", RawPointer(ptr)); - while (syncWaiter->isOnList() && time.now() < time && !vm.hasTerminationRequest()) + // A termination requested from another thread (VM::notifyNeedTermination) is, until this + // thread handles its traps, only a fired NeedTermination trap bit: VMTraps notifies our + // condition for it, but hasTerminationRequest() is set by trap handling on this thread, + // which cannot happen while we block here. Wake for either. + auto terminationRequested = [&] { + return vm.hasTerminationRequest() || vm.traps().needHandling(VMTraps::NeedTermination); + }; + while (syncWaiter->isOnList() && time.now() < time && !terminationRequested()) syncWaiter->condition().waitUntil(list->lock, time.approximate()); // At this point, syncWaiter should be either notified (dequeued) or timeout (not dequeued). @@ -102,7 +109,7 @@ WaiterListManager::WaitSyncResult WaiterListManager::waitSyncImpl(VM& vm, ValueT didGetDequeued = list->findAndRemove(listLocker, syncWaiter); ASSERT(didGetDequeued); - return vm.hasTerminationRequest() ? WaitSyncResult::Terminated : WaitSyncResult::TimedOut; + return terminationRequested() ? WaitSyncResult::Terminated : WaitSyncResult::TimedOut; } }