LibWebView: Force-exit unresponsive child processes

Let ProcessManager own hard process termination. Callers can now
schedule a forced exit after graceful shutdown is requested. The request
is canceled automatically when the process monitor observes exit.
This commit is contained in:
Andreas Kling 2026-05-26 18:02:04 +02:00 committed by Andreas Kling
parent 297a727970
commit a52ff3dfd8
2 changed files with 43 additions and 0 deletions

View file

@ -10,6 +10,7 @@
#include <LibCore/EventLoop.h>
#include <LibCore/System.h>
#include <LibWebView/ProcessManager.h>
#include <signal.h>
namespace WebView {
@ -109,12 +110,48 @@ void ProcessManager::set_process_mach_port(pid_t pid, Core::MachPort&& port)
Optional<Process> ProcessManager::remove_process(pid_t pid)
{
verify_event_loop();
cancel_forced_exit(pid);
m_statistics.processes.remove_first_matching([&](auto const& info) {
return (info->pid == pid);
});
return m_processes.take(pid);
}
void ProcessManager::cancel_forced_exit(pid_t pid)
{
verify_event_loop();
if (auto timer = m_forced_exit_timers.take(pid); timer.has_value())
(*timer)->stop();
}
void ProcessManager::force_exit_after_timeout(pid_t pid, int timeout_ms)
{
verify_event_loop();
if (!m_processes.contains(pid))
return;
if (m_forced_exit_timers.contains(pid))
return;
auto timer = Core::Timer::create_single_shot(timeout_ms, [this, pid] {
m_forced_exit_timers.remove(pid);
auto process = m_processes.get(pid);
if (!process.has_value())
return;
#if defined(AK_OS_WINDOWS)
constexpr auto signal = SIGTERM;
#else
constexpr auto signal = SIGKILL;
#endif
dbgln("Force-killing unresponsive {} process {}", process_name_from_type(process->type()), pid);
auto result = Core::System::kill(pid, signal);
if (result.is_error())
dbgln("Failed to force-kill process {}: {}", pid, result.error());
});
timer->start();
m_forced_exit_timers.set(pid, move(timer));
}
void ProcessManager::update_all_process_statistics()
{
verify_event_loop();

View file

@ -7,10 +7,13 @@
#pragma once
#include <AK/Function.h>
#include <AK/HashMap.h>
#include <AK/JsonValue.h>
#include <AK/RefPtr.h>
#include <AK/Types.h>
#include <LibCore/EventLoop.h>
#include <LibCore/Platform/ProcessStatistics.h>
#include <LibCore/Timer.h>
#include <LibWebView/Forward.h>
#include <LibWebView/Process.h>
#include <LibWebView/ProcessMonitor.h>
@ -31,6 +34,8 @@ public:
void for_each_process(Function<void(Process&)>);
Optional<Process> remove_process(pid_t);
Optional<Process&> find_process(pid_t);
void cancel_forced_exit(pid_t);
void force_exit_after_timeout(pid_t, int timeout_ms);
#if defined(AK_OS_MACH)
void set_process_mach_port(pid_t, Core::MachPort&&);
@ -47,6 +52,7 @@ private:
Core::Platform::ProcessStatistics m_statistics;
HashMap<pid_t, Process> m_processes;
HashMap<pid_t, RefPtr<Core::Timer>> m_forced_exit_timers;
ProcessMonitor m_process_monitor;
Core::EventLoop* m_creation_event_loop { &Core::EventLoop::current() };
};