mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 19:47:44 +00:00
SystemMonitor: Handle zombie processes properly
SystemMonitor had a bug in which it would crash in case there are zombie processes left in the system. The fix for this is to check if a process has no threads (which will indicate that the process is a zombie and is waiting to be reaped), and if that's the case, artificially create a thread row that is just enough to represent the zombie process.
This commit is contained in:
parent
dca56ce1cb
commit
e931b2ecd9
1 changed files with 64 additions and 29 deletions
|
@ -468,55 +468,90 @@ void ProcessModel::update()
|
||||||
m_processes.append(make<Process>());
|
m_processes.append(make<Process>());
|
||||||
process_state = &m_processes.last();
|
process_state = &m_processes.last();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto add_thread_data = [&live_tids, this](int tid, Process& process_state, ThreadState state) {
|
||||||
|
auto thread_data = m_threads.ensure(tid, [&] { return make_ref_counted<Thread>(process_state); });
|
||||||
|
thread_data->previous_state = move(thread_data->current_state);
|
||||||
|
thread_data->current_state = move(state);
|
||||||
|
if (auto maybe_thread_index = process_state.threads.find_first_index(thread_data); maybe_thread_index.has_value()) {
|
||||||
|
process_state.threads[maybe_thread_index.value()] = thread_data;
|
||||||
|
} else {
|
||||||
|
process_state.threads.append(thread_data);
|
||||||
|
}
|
||||||
|
live_tids.set(tid);
|
||||||
|
};
|
||||||
|
|
||||||
(*process_state)->pid = process.pid;
|
(*process_state)->pid = process.pid;
|
||||||
for (auto& thread : process.threads) {
|
if (!process.threads.is_empty()) {
|
||||||
|
for (auto& thread : process.threads) {
|
||||||
|
ThreadState state(**process_state);
|
||||||
|
state.tid = thread.tid;
|
||||||
|
state.pid = process.pid;
|
||||||
|
state.ppid = process.ppid;
|
||||||
|
state.pgid = process.pgid;
|
||||||
|
state.sid = process.sid;
|
||||||
|
state.time_user = thread.time_user;
|
||||||
|
state.time_kernel = thread.time_kernel;
|
||||||
|
state.kernel = process.kernel;
|
||||||
|
state.executable = process.executable;
|
||||||
|
state.name = thread.name;
|
||||||
|
state.command = read_command_line(process.pid);
|
||||||
|
state.uid = process.uid;
|
||||||
|
state.state = thread.state;
|
||||||
|
state.user = process.username;
|
||||||
|
state.pledge = process.pledge;
|
||||||
|
state.veil = process.veil;
|
||||||
|
state.cpu = thread.cpu;
|
||||||
|
state.priority = thread.priority;
|
||||||
|
state.amount_virtual = process.amount_virtual;
|
||||||
|
state.amount_resident = process.amount_resident;
|
||||||
|
state.amount_dirty_private = process.amount_dirty_private;
|
||||||
|
state.amount_clean_inode = process.amount_clean_inode;
|
||||||
|
state.amount_purgeable_volatile = process.amount_purgeable_volatile;
|
||||||
|
state.amount_purgeable_nonvolatile = process.amount_purgeable_nonvolatile;
|
||||||
|
state.syscall_count = thread.syscall_count;
|
||||||
|
state.inode_faults = thread.inode_faults;
|
||||||
|
state.zero_faults = thread.zero_faults;
|
||||||
|
state.cow_faults = thread.cow_faults;
|
||||||
|
state.unix_socket_read_bytes = thread.unix_socket_read_bytes;
|
||||||
|
state.unix_socket_write_bytes = thread.unix_socket_write_bytes;
|
||||||
|
state.ipv4_socket_read_bytes = thread.ipv4_socket_read_bytes;
|
||||||
|
state.ipv4_socket_write_bytes = thread.ipv4_socket_write_bytes;
|
||||||
|
state.file_read_bytes = thread.file_read_bytes;
|
||||||
|
state.file_write_bytes = thread.file_write_bytes;
|
||||||
|
state.cpu_percent = 0;
|
||||||
|
|
||||||
|
add_thread_data(thread.tid, **process_state, move(state));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// FIXME: If there are no threads left in a process this is an indication
|
||||||
|
// for a zombie process, so it should be handled differently - we add a mock thread
|
||||||
|
// just to simulate a process with a single thread.
|
||||||
|
// Find a way to untie the process representation from a main thread so we can
|
||||||
|
// just represent a zombie process without creating a mock thread.
|
||||||
ThreadState state(**process_state);
|
ThreadState state(**process_state);
|
||||||
state.tid = thread.tid;
|
state.tid = process.pid;
|
||||||
state.pid = process.pid;
|
state.pid = process.pid;
|
||||||
state.ppid = process.ppid;
|
state.ppid = process.ppid;
|
||||||
state.pgid = process.pgid;
|
state.pgid = process.pgid;
|
||||||
state.sid = process.sid;
|
state.sid = process.sid;
|
||||||
state.time_user = thread.time_user;
|
|
||||||
state.time_kernel = thread.time_kernel;
|
|
||||||
state.kernel = process.kernel;
|
state.kernel = process.kernel;
|
||||||
state.executable = process.executable;
|
state.executable = process.executable;
|
||||||
state.name = thread.name;
|
state.name = process.name;
|
||||||
state.command = read_command_line(process.pid);
|
state.command = read_command_line(process.pid);
|
||||||
state.uid = process.uid;
|
state.uid = process.uid;
|
||||||
state.state = thread.state;
|
state.state = "Zombie";
|
||||||
state.user = process.username;
|
state.user = process.username;
|
||||||
state.pledge = process.pledge;
|
state.pledge = process.pledge;
|
||||||
state.veil = process.veil;
|
state.veil = process.veil;
|
||||||
state.cpu = thread.cpu;
|
|
||||||
state.priority = thread.priority;
|
|
||||||
state.amount_virtual = process.amount_virtual;
|
state.amount_virtual = process.amount_virtual;
|
||||||
state.amount_resident = process.amount_resident;
|
state.amount_resident = process.amount_resident;
|
||||||
state.amount_dirty_private = process.amount_dirty_private;
|
state.amount_dirty_private = process.amount_dirty_private;
|
||||||
state.amount_clean_inode = process.amount_clean_inode;
|
state.amount_clean_inode = process.amount_clean_inode;
|
||||||
state.amount_purgeable_volatile = process.amount_purgeable_volatile;
|
state.amount_purgeable_volatile = process.amount_purgeable_volatile;
|
||||||
state.amount_purgeable_nonvolatile = process.amount_purgeable_nonvolatile;
|
state.amount_purgeable_nonvolatile = process.amount_purgeable_nonvolatile;
|
||||||
state.syscall_count = thread.syscall_count;
|
|
||||||
state.inode_faults = thread.inode_faults;
|
|
||||||
state.zero_faults = thread.zero_faults;
|
|
||||||
state.cow_faults = thread.cow_faults;
|
|
||||||
state.unix_socket_read_bytes = thread.unix_socket_read_bytes;
|
|
||||||
state.unix_socket_write_bytes = thread.unix_socket_write_bytes;
|
|
||||||
state.ipv4_socket_read_bytes = thread.ipv4_socket_read_bytes;
|
|
||||||
state.ipv4_socket_write_bytes = thread.ipv4_socket_write_bytes;
|
|
||||||
state.file_read_bytes = thread.file_read_bytes;
|
|
||||||
state.file_write_bytes = thread.file_write_bytes;
|
|
||||||
state.cpu_percent = 0;
|
|
||||||
|
|
||||||
auto thread_data = m_threads.ensure(thread.tid, [&] { return make_ref_counted<Thread>(**process_state); });
|
add_thread_data(process.pid, **process_state, move(state));
|
||||||
thread_data->previous_state = move(thread_data->current_state);
|
|
||||||
thread_data->current_state = move(state);
|
|
||||||
if (auto maybe_thread_index = (*process_state)->threads.find_first_index(thread_data); maybe_thread_index.has_value()) {
|
|
||||||
(*process_state)->threads[maybe_thread_index.value()] = thread_data;
|
|
||||||
} else {
|
|
||||||
(*process_state)->threads.append(thread_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
live_tids.set(thread.tid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue