mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 17:52:45 +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>()); | ||||
|                 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; | ||||
|             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); | ||||
|                 state.tid = thread.tid; | ||||
|                 state.tid = process.pid; | ||||
|                 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.name = process.name; | ||||
|                 state.command = read_command_line(process.pid); | ||||
|                 state.uid = process.uid; | ||||
|                 state.state = thread.state; | ||||
|                 state.state = "Zombie"; | ||||
|                 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; | ||||
| 
 | ||||
|                 auto thread_data = m_threads.ensure(thread.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(thread.tid); | ||||
|                 add_thread_data(process.pid, **process_state, move(state)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Liav A
						Liav A