Skip to content

Commit 8867ffb

Browse files
committed
Web Inspector: Closing JSContext inspector while execution is paused hangs owner app
rdar://142537911 https://bugs.webkit.org/show_bug.cgi?id=291711 Reviewed by Devin Rousso. When closing Web Inspector and disconnecting the frontend from the debuggable, we have the logic to resume code execution if it was paused. Resuming execution by default notifies the frontend via RemoteConnectionToTarget::sendMessageToFrontend, which tries to grab the m_targetMutex, but that was already grabbed in RemoteConnectionToTarget::close (in the callback with dispatchAsyncOnTarget). This resulted in a deadlock. - The reason why this deadlocking only happens for JSContexts is because the other kinds of debuggables call into a different thread at some point to complete the disconnecting process. PageDebuggable and WebPageDebuggable call callOnMainThreadAndWait in the debuggables' disconnect method; for service workers, postDebuggerTask is used in ServiceWorkerInspectorProxy::disconnectFromWorker. JSContext does everything on the same thread that calls disconnect. If the frontend were going to be closed anyway, RemoteConnectionToTarget should be able to avoid sending the frontend any messages, and that's the logic behind this patch. * Source/JavaScriptCore/inspector/remote/RemoteConnectionToTarget.cpp: (Inspector::RemoteConnectionToTarget::setup): (Inspector::RemoteConnectionToTarget::sendMessageToTarget): (Inspector::RemoteConnectionToTarget::close): (Inspector::RemoteConnectionToTarget::targetClosed): (Inspector::RemoteConnectionToTarget::sendMessageToFrontend): * Source/JavaScriptCore/inspector/remote/RemoteConnectionToTarget.h: * Source/JavaScriptCore/inspector/remote/cocoa/RemoteConnectionToTargetCocoa.mm: (Inspector::RemoteConnectionToTarget::setup): (Inspector::RemoteConnectionToTarget::targetClosed): (Inspector::RemoteConnectionToTarget::close): (Inspector::RemoteConnectionToTarget::sendMessageToTarget): (Inspector::RemoteConnectionToTarget::sendMessageToFrontend): Canonical link: https://commits.webkit.org/293950@main
1 parent cfa4aa1 commit 8867ffb

File tree

3 files changed

+25
-6
lines changed

3 files changed

+25
-6
lines changed

Source/JavaScriptCore/inspector/remote/RemoteConnectionToTarget.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,17 @@ bool RemoteConnectionToTarget::setup(bool isAutomaticInspection, bool automatica
6767
else if (auto* automationTarget = dynamicDowncast<RemoteAutomationTarget>(*target))
6868
automationTarget->connect(*this);
6969

70-
m_connected = true;
70+
m_connectionState = ConnectionState::Connected;
7171
RemoteInspector::singleton().updateTargetListing(targetIdentifier);
7272
RemoteInspector::singleton().setupCompleted(targetIdentifier);
7373
return true;
7474
}
7575

7676
void RemoteConnectionToTarget::sendMessageToTarget(String&& message)
7777
{
78+
if (m_connectionState == ConnectionState::Closed)
79+
return;
80+
7881
RefPtr<RemoteControllableTarget> target;
7982
{
8083
Locker locker { m_targetMutex };
@@ -93,7 +96,7 @@ void RemoteConnectionToTarget::close()
9396
if (RefPtr target = m_target.get()) {
9497
targetIdentifier = target->targetIdentifier();
9598

96-
if (m_connected)
99+
if (m_connectionState.exchange(ConnectionState::Closed) == ConnectionState::Connected)
97100
target->disconnect(*this);
98101

99102
m_target = nullptr;
@@ -107,6 +110,7 @@ void RemoteConnectionToTarget::close()
107110
void RemoteConnectionToTarget::targetClosed()
108111
{
109112
Locker locker { m_targetMutex };
113+
m_connectionState = ConnectionState::Closed;
110114
m_target = nullptr;
111115
}
112116

@@ -118,6 +122,9 @@ std::optional<TargetID> RemoteConnectionToTarget::targetIdentifier() const
118122

119123
void RemoteConnectionToTarget::sendMessageToFrontend(const String& message)
120124
{
125+
if (m_connectionState == ConnectionState::Closed)
126+
return;
127+
121128
std::optional<TargetID> targetIdentifier;
122129
{
123130
Locker locker { m_targetMutex };

Source/JavaScriptCore/inspector/remote/RemoteConnectionToTarget.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,13 @@ class RemoteConnectionToTarget final : public ThreadSafeRefCounted<RemoteConnect
105105
#endif
106106

107107
ThreadSafeWeakPtr<RemoteControllableTarget> m_target WTF_GUARDED_BY_LOCK(m_targetMutex);
108-
bool m_connected { false };
108+
109+
enum class ConnectionState {
110+
Pending,
111+
Connected,
112+
Closed,
113+
};
114+
std::atomic<ConnectionState> m_connectionState { ConnectionState::Pending };
109115

110116
#if PLATFORM(COCOA)
111117
RetainPtr<NSString> m_connectionIdentifier;

Source/JavaScriptCore/inspector/remote/cocoa/RemoteConnectionToTargetCocoa.mm

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ static void RemoteTargetHandleRunSourceWithInfo(void* info)
185185
else if (auto* automationTarget = dynamicDowncast<RemoteAutomationTarget>(target.get()))
186186
automationTarget->connect(*this);
187187

188-
m_connected = true;
188+
m_connectionState = ConnectionState::Connected;
189189
RemoteInspector::singleton().updateTargetListing(targetIdentifier);
190190
RemoteInspector::singleton().setupCompleted(targetIdentifier);
191191
});
@@ -196,7 +196,7 @@ static void RemoteTargetHandleRunSourceWithInfo(void* info)
196196
void RemoteConnectionToTarget::targetClosed()
197197
{
198198
Locker locker { m_targetMutex };
199-
199+
m_connectionState = ConnectionState::Closed;
200200
m_target = nullptr;
201201
}
202202

@@ -212,7 +212,7 @@ static void RemoteTargetHandleRunSourceWithInfo(void* info)
212212
dispatchAsyncOnTarget([this, targetIdentifier, protectedThis = Ref { *this }]() {
213213
Locker locker { m_targetMutex };
214214
if (RefPtr target = m_target.get()) {
215-
if (m_connected)
215+
if (m_connectionState.exchange(ConnectionState::Closed) == ConnectionState::Connected)
216216
target->disconnect(*this);
217217

218218
m_target = nullptr;
@@ -225,6 +225,9 @@ static void RemoteTargetHandleRunSourceWithInfo(void* info)
225225

226226
void RemoteConnectionToTarget::sendMessageToTarget(NSString *message)
227227
{
228+
if (m_connectionState == ConnectionState::Closed)
229+
return;
230+
228231
dispatchAsyncOnTarget([this, strongMessage = retainPtr(message), protectedThis = Ref { *this }]() {
229232
RefPtr<RemoteControllableTarget> target;
230233
{
@@ -238,6 +241,9 @@ static void RemoteTargetHandleRunSourceWithInfo(void* info)
238241

239242
void RemoteConnectionToTarget::sendMessageToFrontend(const String& message)
240243
{
244+
if (m_connectionState == ConnectionState::Closed)
245+
return;
246+
241247
std::optional<TargetID> targetIdentifier;
242248
{
243249
Locker locker { m_targetMutex };

0 commit comments

Comments
 (0)