diff --git a/src/cdp/CDP.zig b/src/cdp/CDP.zig index d1a0fb91..9d8bbc8d 100644 --- a/src/cdp/CDP.zig +++ b/src/cdp/CDP.zig @@ -168,6 +168,12 @@ pub fn onLinkDisconnect(self: *CDP, err: ?anyerror) void { self.browser.http_client.inbox.push(arena, .{ .disconnect = err }); } +// Called by Network to try to force the Worker to shutdown. Protects against a +// stuck worker. +pub fn terminateFromNetwork(self: *CDP) void { + self.browser.env.terminate(); +} + // Called in the Worker to dispatch a single CDP message bubbled up by // HttpClient.drainInbox. The Network thread already parsed the JSON // when it pushed the message to the inbox, so we skip straight to diff --git a/src/network/Network.zig b/src/network/Network.zig index 1e51f042..3459256e 100644 --- a/src/network/Network.zig +++ b/src/network/Network.zig @@ -536,6 +536,8 @@ fn dropCdp(self: *Network, link: *CdpLink, err: ?anyerror, notify: bool) void { link.state = .removed; self.cdp_dirty = true; if (notify) { + link.cdp.terminateFromNetwork(); + // notify=true means the worker hasn't been told yet — push the // disconnect into the inbox and break it out of curl_multi_poll. // notify=false paths have already woken the worker (close frame