/* * Copyright (c) 2024, Andrew Kaster * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include namespace WebView { static sig_atomic_t s_received_sigchld = 0; ProcessType process_type_from_name(StringView name) { if (name == "Chrome"sv) return ProcessType::Chrome; if (name == "WebContent"sv) return ProcessType::WebContent; if (name == "WebWorker"sv) return ProcessType::WebWorker; if (name == "SQLServer"sv) return ProcessType::SQLServer; if (name == "RequestServer"sv) return ProcessType::RequestServer; if (name == "ImageDecoder"sv) return ProcessType::ImageDecoder; dbgln("Unknown process type: '{}'", name); VERIFY_NOT_REACHED(); } StringView process_name_from_type(ProcessType type) { switch (type) { case ProcessType::Chrome: return "Chrome"sv; case ProcessType::WebContent: return "WebContent"sv; case ProcessType::WebWorker: return "WebWorker"sv; case ProcessType::SQLServer: return "SQLServer"sv; case ProcessType::RequestServer: return "RequestServer"sv; case ProcessType::ImageDecoder: return "ImageDecoder"sv; } VERIFY_NOT_REACHED(); } ProcessManager::ProcessManager() { } ProcessManager::~ProcessManager() { } ProcessManager& ProcessManager::the() { static ProcessManager s_the; return s_the; } void ProcessManager::initialize() { // FIXME: Should we change this to call EventLoop::register_signal? // Note that only EventLoopImplementationUnix has a working register_signal struct sigaction action { }; action.sa_flags = SA_RESTART; action.sa_sigaction = [](int, auto*, auto) { s_received_sigchld = 1; }; MUST(Core::System::sigaction(SIGCHLD, &action, nullptr)); the().add_process(WebView::ProcessType::Chrome, getpid()); } void ProcessManager::add_process(ProcessType type, pid_t pid) { dbgln("ProcessManager::add_process({}, {})", process_name_from_type(type), pid); m_processes.append({ type, pid, 0, 0 }); } void ProcessManager::remove_process(pid_t pid) { m_processes.remove_first_matching([&](auto& info) { if (info.pid == pid) { dbgln("ProcessManager: Remove process {} ({})", process_name_from_type(info.type), pid); return true; } return false; }); } void ProcessManager::update_all_processes() { if (s_received_sigchld) { s_received_sigchld = 0; auto result = Core::System::waitpid(-1, WNOHANG); while (!result.is_error() && result.value().pid > 0) { auto& [pid, status] = result.value(); if (WIFEXITED(status) || WIFSIGNALED(status)) { remove_process(pid); } result = Core::System::waitpid(-1, WNOHANG); } } // FIXME: Actually gather stats in a platform-specific way } String ProcessManager::generate_html() { StringBuilder builder; auto processes = m_processes; builder.append(R"( )"sv); for (auto& process : processes) { builder.append(""sv); builder.append(""sv); builder.append(""sv); builder.append(""sv); builder.append(""sv); builder.append(""sv); } builder.append(R"(
Type PID Memory Usage CPU %
"sv); builder.append(WebView::process_name_from_type(process.type)); builder.append(""sv); builder.append(MUST(String::number(process.pid))); builder.append(""sv); builder.append(MUST(String::formatted("{} KB", process.memory_usage_kib))); builder.append(""sv); builder.append(MUST(String::formatted("{:.1f}", process.cpu_percent))); builder.append("
)"sv); return builder.to_string_without_validation(); } }