mirror of
https://github.com/RGBCube/serenity
synced 2025-07-03 05:32:13 +00:00
Kernel: Remove ProcessInspectionHandle and make Process RefCounted
By making the Process class RefCounted we don't really need ProcessInspectionHandle anymore. This also fixes some race conditions where a Process may be deleted while still being used by ProcFS. Also make sure to acquire the Process' lock when accessing regions. Last but not least, there's no reason why a thread can't be scheduled while being inspected, though in practice it won't happen anyway because the scheduler lock is held at the same time.
This commit is contained in:
parent
5bbf6ed46b
commit
538b985487
13 changed files with 191 additions and 273 deletions
|
@ -241,22 +241,21 @@ Optional<KBuffer> procfs$pid_fds(InodeIdentifier identifier)
|
|||
KBufferBuilder builder;
|
||||
JsonArraySerializer array { builder };
|
||||
|
||||
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
|
||||
if (!handle) {
|
||||
auto process = Process::from_pid(to_pid(identifier));
|
||||
if (!process) {
|
||||
array.finish();
|
||||
return builder.build();
|
||||
}
|
||||
auto& process = handle->process();
|
||||
if (process.number_of_open_file_descriptors() == 0) {
|
||||
if (process->number_of_open_file_descriptors() == 0) {
|
||||
array.finish();
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
for (int i = 0; i < process.max_open_file_descriptors(); ++i) {
|
||||
auto description = process.file_description(i);
|
||||
for (int i = 0; i < process->max_open_file_descriptors(); ++i) {
|
||||
auto description = process->file_description(i);
|
||||
if (!description)
|
||||
continue;
|
||||
bool cloexec = process.fd_flags(i) & FD_CLOEXEC;
|
||||
bool cloexec = process->fd_flags(i) & FD_CLOEXEC;
|
||||
|
||||
auto description_object = array.add_object();
|
||||
description_object.add("fd", i);
|
||||
|
@ -275,12 +274,11 @@ Optional<KBuffer> procfs$pid_fds(InodeIdentifier identifier)
|
|||
|
||||
Optional<KBuffer> procfs$pid_fd_entry(InodeIdentifier identifier)
|
||||
{
|
||||
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
|
||||
if (!handle)
|
||||
auto process = Process::from_pid(to_pid(identifier));
|
||||
if (!process)
|
||||
return {};
|
||||
auto& process = handle->process();
|
||||
int fd = to_fd(identifier);
|
||||
auto description = process.file_description(fd);
|
||||
auto description = process->file_description(fd);
|
||||
if (!description)
|
||||
return {};
|
||||
return description->absolute_path().to_byte_buffer();
|
||||
|
@ -288,46 +286,48 @@ Optional<KBuffer> procfs$pid_fd_entry(InodeIdentifier identifier)
|
|||
|
||||
Optional<KBuffer> procfs$pid_vm(InodeIdentifier identifier)
|
||||
{
|
||||
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
|
||||
if (!handle)
|
||||
auto process = Process::from_pid(to_pid(identifier));
|
||||
if (!process)
|
||||
return {};
|
||||
auto& process = handle->process();
|
||||
KBufferBuilder builder;
|
||||
JsonArraySerializer array { builder };
|
||||
for (auto& region : process.regions()) {
|
||||
if (!region.is_user_accessible() && !Process::current()->is_superuser())
|
||||
continue;
|
||||
auto region_object = array.add_object();
|
||||
region_object.add("readable", region.is_readable());
|
||||
region_object.add("writable", region.is_writable());
|
||||
region_object.add("executable", region.is_executable());
|
||||
region_object.add("stack", region.is_stack());
|
||||
region_object.add("shared", region.is_shared());
|
||||
region_object.add("user_accessible", region.is_user_accessible());
|
||||
region_object.add("purgeable", region.vmobject().is_purgeable());
|
||||
if (region.vmobject().is_purgeable()) {
|
||||
region_object.add("volatile", static_cast<const PurgeableVMObject&>(region.vmobject()).is_volatile());
|
||||
{
|
||||
ScopedSpinLock lock(process->get_lock());
|
||||
for (auto& region : process->regions()) {
|
||||
if (!region.is_user_accessible() && !Process::current()->is_superuser())
|
||||
continue;
|
||||
auto region_object = array.add_object();
|
||||
region_object.add("readable", region.is_readable());
|
||||
region_object.add("writable", region.is_writable());
|
||||
region_object.add("executable", region.is_executable());
|
||||
region_object.add("stack", region.is_stack());
|
||||
region_object.add("shared", region.is_shared());
|
||||
region_object.add("user_accessible", region.is_user_accessible());
|
||||
region_object.add("purgeable", region.vmobject().is_purgeable());
|
||||
if (region.vmobject().is_purgeable()) {
|
||||
region_object.add("volatile", static_cast<const PurgeableVMObject&>(region.vmobject()).is_volatile());
|
||||
}
|
||||
region_object.add("purgeable", region.vmobject().is_purgeable());
|
||||
region_object.add("address", region.vaddr().get());
|
||||
region_object.add("size", region.size());
|
||||
region_object.add("amount_resident", region.amount_resident());
|
||||
region_object.add("amount_dirty", region.amount_dirty());
|
||||
region_object.add("cow_pages", region.cow_pages());
|
||||
region_object.add("name", region.name());
|
||||
region_object.add("vmobject", region.vmobject().class_name());
|
||||
|
||||
StringBuilder pagemap_builder;
|
||||
for (size_t i = 0; i < region.page_count(); ++i) {
|
||||
auto* page = region.physical_page(i);
|
||||
if (!page)
|
||||
pagemap_builder.append('N');
|
||||
else if (page->is_shared_zero_page())
|
||||
pagemap_builder.append('Z');
|
||||
else
|
||||
pagemap_builder.append('P');
|
||||
}
|
||||
region_object.add("pagemap", pagemap_builder.to_string());
|
||||
}
|
||||
region_object.add("purgeable", region.vmobject().is_purgeable());
|
||||
region_object.add("address", region.vaddr().get());
|
||||
region_object.add("size", region.size());
|
||||
region_object.add("amount_resident", region.amount_resident());
|
||||
region_object.add("amount_dirty", region.amount_dirty());
|
||||
region_object.add("cow_pages", region.cow_pages());
|
||||
region_object.add("name", region.name());
|
||||
region_object.add("vmobject", region.vmobject().class_name());
|
||||
|
||||
StringBuilder pagemap_builder;
|
||||
for (size_t i = 0; i < region.page_count(); ++i) {
|
||||
auto* page = region.physical_page(i);
|
||||
if (!page)
|
||||
pagemap_builder.append('N');
|
||||
else if (page->is_shared_zero_page())
|
||||
pagemap_builder.append('Z');
|
||||
else
|
||||
pagemap_builder.append('P');
|
||||
}
|
||||
region_object.add("pagemap", pagemap_builder.to_string());
|
||||
}
|
||||
array.finish();
|
||||
return builder.build();
|
||||
|
@ -557,46 +557,47 @@ Optional<KBuffer> procfs$net_local(InodeIdentifier)
|
|||
|
||||
Optional<KBuffer> procfs$pid_vmobjects(InodeIdentifier identifier)
|
||||
{
|
||||
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
|
||||
if (!handle)
|
||||
auto process = Process::from_pid(to_pid(identifier));
|
||||
if (!process)
|
||||
return {};
|
||||
auto& process = handle->process();
|
||||
KBufferBuilder builder;
|
||||
builder.appendf("BEGIN END SIZE NAME\n");
|
||||
for (auto& region : process.regions()) {
|
||||
builder.appendf("%x -- %x %x %s\n",
|
||||
region.vaddr().get(),
|
||||
region.vaddr().offset(region.size() - 1).get(),
|
||||
region.size(),
|
||||
region.name().characters());
|
||||
builder.appendf("VMO: %s @ %x(%u)\n",
|
||||
region.vmobject().is_anonymous() ? "anonymous" : "file-backed",
|
||||
®ion.vmobject(),
|
||||
region.vmobject().ref_count());
|
||||
for (size_t i = 0; i < region.vmobject().page_count(); ++i) {
|
||||
auto& physical_page = region.vmobject().physical_pages()[i];
|
||||
bool should_cow = false;
|
||||
if (i >= region.first_page_index() && i <= region.last_page_index())
|
||||
should_cow = region.should_cow(i - region.first_page_index());
|
||||
builder.appendf("P%x%s(%u) ",
|
||||
physical_page ? physical_page->paddr().get() : 0,
|
||||
should_cow ? "!" : "",
|
||||
physical_page ? physical_page->ref_count() : 0);
|
||||
{
|
||||
ScopedSpinLock lock(process->get_lock());
|
||||
for (auto& region : process->regions()) {
|
||||
builder.appendf("%x -- %x %x %s\n",
|
||||
region.vaddr().get(),
|
||||
region.vaddr().offset(region.size() - 1).get(),
|
||||
region.size(),
|
||||
region.name().characters());
|
||||
builder.appendf("VMO: %s @ %x(%u)\n",
|
||||
region.vmobject().is_anonymous() ? "anonymous" : "file-backed",
|
||||
®ion.vmobject(),
|
||||
region.vmobject().ref_count());
|
||||
for (size_t i = 0; i < region.vmobject().page_count(); ++i) {
|
||||
auto& physical_page = region.vmobject().physical_pages()[i];
|
||||
bool should_cow = false;
|
||||
if (i >= region.first_page_index() && i <= region.last_page_index())
|
||||
should_cow = region.should_cow(i - region.first_page_index());
|
||||
builder.appendf("P%x%s(%u) ",
|
||||
physical_page ? physical_page->paddr().get() : 0,
|
||||
should_cow ? "!" : "",
|
||||
physical_page ? physical_page->ref_count() : 0);
|
||||
}
|
||||
builder.appendf("\n");
|
||||
}
|
||||
builder.appendf("\n");
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
Optional<KBuffer> procfs$pid_unveil(InodeIdentifier identifier)
|
||||
{
|
||||
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
|
||||
if (!handle)
|
||||
auto process = Process::from_pid(to_pid(identifier));
|
||||
if (!process)
|
||||
return {};
|
||||
auto& process = handle->process();
|
||||
KBufferBuilder builder;
|
||||
JsonArraySerializer array { builder };
|
||||
for (auto& unveiled_path : process.unveiled_paths()) {
|
||||
for (auto& unveiled_path : process->unveiled_paths()) {
|
||||
auto obj = array.add_object();
|
||||
obj.add("path", unveiled_path.path);
|
||||
StringBuilder permissions_builder;
|
||||
|
@ -616,38 +617,36 @@ Optional<KBuffer> procfs$pid_unveil(InodeIdentifier identifier)
|
|||
|
||||
Optional<KBuffer> procfs$pid_stack(InodeIdentifier identifier)
|
||||
{
|
||||
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
|
||||
if (!handle)
|
||||
auto process = Process::from_pid(to_pid(identifier));
|
||||
if (!process)
|
||||
return {};
|
||||
auto& process = handle->process();
|
||||
return process.backtrace(*handle);
|
||||
return process->backtrace();
|
||||
}
|
||||
|
||||
Optional<KBuffer> procfs$pid_exe(InodeIdentifier identifier)
|
||||
{
|
||||
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
|
||||
if (!handle)
|
||||
auto process = Process::from_pid(to_pid(identifier));
|
||||
if (!process)
|
||||
return {};
|
||||
auto& process = handle->process();
|
||||
auto* custody = process.executable();
|
||||
auto* custody = process->executable();
|
||||
ASSERT(custody);
|
||||
return custody->absolute_path().to_byte_buffer();
|
||||
}
|
||||
|
||||
Optional<KBuffer> procfs$pid_cwd(InodeIdentifier identifier)
|
||||
{
|
||||
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
|
||||
if (!handle)
|
||||
auto process = Process::from_pid(to_pid(identifier));
|
||||
if (!process)
|
||||
return {};
|
||||
return handle->process().current_directory().absolute_path().to_byte_buffer();
|
||||
return process->current_directory().absolute_path().to_byte_buffer();
|
||||
}
|
||||
|
||||
Optional<KBuffer> procfs$pid_root(InodeIdentifier identifier)
|
||||
{
|
||||
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier));
|
||||
if (!handle)
|
||||
auto process = Process::from_pid(to_pid(identifier));
|
||||
if (!process)
|
||||
return {};
|
||||
return handle->process().root_directory_relative_to_global_root().absolute_path().to_byte_buffer();
|
||||
return process->root_directory_relative_to_global_root().absolute_path().to_byte_buffer();
|
||||
}
|
||||
|
||||
Optional<KBuffer> procfs$self(InodeIdentifier)
|
||||
|
@ -783,8 +782,6 @@ Optional<KBuffer> procfs$memstat(InodeIdentifier)
|
|||
|
||||
Optional<KBuffer> procfs$all(InodeIdentifier)
|
||||
{
|
||||
ScopedSpinLock lock(g_scheduler_lock);
|
||||
auto processes = Process::all_processes();
|
||||
KBufferBuilder builder;
|
||||
JsonArraySerializer array { builder };
|
||||
|
||||
|
@ -856,9 +853,12 @@ Optional<KBuffer> procfs$all(InodeIdentifier)
|
|||
return IterationDecision::Continue;
|
||||
});
|
||||
};
|
||||
|
||||
ScopedSpinLock lock(g_scheduler_lock);
|
||||
auto processes = Process::all_processes();
|
||||
build_process(*Scheduler::colonel());
|
||||
for (auto* process : processes)
|
||||
build_process(*process);
|
||||
for (auto& process : processes)
|
||||
build_process(process);
|
||||
array.finish();
|
||||
return builder.build();
|
||||
}
|
||||
|
@ -1069,9 +1069,15 @@ InodeMetadata ProcFSInode::metadata() const
|
|||
#endif
|
||||
|
||||
if (is_process_related_file(identifier())) {
|
||||
auto handle = ProcessInspectionHandle::from_pid(pid);
|
||||
metadata.uid = handle->process().sys$getuid();
|
||||
metadata.gid = handle->process().sys$getgid();
|
||||
auto process = Process::from_pid(pid);
|
||||
if (process) {
|
||||
metadata.uid = process->sys$getuid();
|
||||
metadata.gid = process->sys$getgid();
|
||||
} else {
|
||||
// TODO: How to handle this?
|
||||
metadata.uid = 0;
|
||||
metadata.gid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (proc_parent_directory == PDI_PID_fd) {
|
||||
|
@ -1232,13 +1238,12 @@ KResult ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntr
|
|||
break;
|
||||
|
||||
case FI_PID: {
|
||||
auto handle = ProcessInspectionHandle::from_pid(pid);
|
||||
if (!handle)
|
||||
auto process = Process::from_pid(pid);
|
||||
if (!process)
|
||||
return KResult(-ENOENT);
|
||||
auto& process = handle->process();
|
||||
for (auto& entry : fs().m_entries) {
|
||||
if (entry.proc_file_type > __FI_PID_Start && entry.proc_file_type < __FI_PID_End) {
|
||||
if (entry.proc_file_type == FI_PID_exe && !process.executable())
|
||||
if (entry.proc_file_type == FI_PID_exe && !process->executable())
|
||||
continue;
|
||||
// FIXME: strlen() here is sad.
|
||||
callback({ entry.name, strlen(entry.name), to_identifier(fsid(), PDI_PID, pid, (ProcFileType)entry.proc_file_type), 0 });
|
||||
|
@ -1247,12 +1252,11 @@ KResult ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntr
|
|||
} break;
|
||||
|
||||
case FI_PID_fd: {
|
||||
auto handle = ProcessInspectionHandle::from_pid(pid);
|
||||
if (!handle)
|
||||
auto process = Process::from_pid(pid);
|
||||
if (!process)
|
||||
return KResult(-ENOENT);
|
||||
auto& process = handle->process();
|
||||
for (int i = 0; i < process.max_open_file_descriptors(); ++i) {
|
||||
auto description = process.file_description(i);
|
||||
for (int i = 0; i < process->max_open_file_descriptors(); ++i) {
|
||||
auto description = process->file_description(i);
|
||||
if (!description)
|
||||
continue;
|
||||
char name[16];
|
||||
|
@ -1324,13 +1328,12 @@ RefPtr<Inode> ProcFSInode::lookup(StringView name)
|
|||
}
|
||||
|
||||
if (proc_file_type == FI_PID) {
|
||||
auto handle = ProcessInspectionHandle::from_pid(to_pid(identifier()));
|
||||
if (!handle)
|
||||
auto process = Process::from_pid(to_pid(identifier()));
|
||||
if (!process)
|
||||
return {};
|
||||
auto& process = handle->process();
|
||||
for (auto& entry : fs().m_entries) {
|
||||
if (entry.proc_file_type > __FI_PID_Start && entry.proc_file_type < __FI_PID_End) {
|
||||
if (entry.proc_file_type == FI_PID_exe && !process.executable())
|
||||
if (entry.proc_file_type == FI_PID_exe && !process->executable())
|
||||
continue;
|
||||
if (entry.name == nullptr)
|
||||
continue;
|
||||
|
@ -1348,8 +1351,7 @@ RefPtr<Inode> ProcFSInode::lookup(StringView name)
|
|||
return {};
|
||||
bool fd_exists = false;
|
||||
{
|
||||
InterruptDisabler disabler;
|
||||
if (auto* process = Process::from_pid(to_pid(identifier())))
|
||||
if (auto process = Process::from_pid(to_pid(identifier())))
|
||||
fd_exists = process->file_description(name_as_number.value());
|
||||
}
|
||||
if (fd_exists)
|
||||
|
@ -1415,16 +1417,15 @@ KResultOr<NonnullRefPtr<Custody>> ProcFSInode::resolve_as_link(Custody& base, Re
|
|||
|
||||
auto pid = to_pid(identifier());
|
||||
auto proc_file_type = to_proc_file_type(identifier());
|
||||
auto handle = ProcessInspectionHandle::from_pid(pid);
|
||||
if (!handle)
|
||||
auto process = Process::from_pid(pid);
|
||||
if (!process)
|
||||
return KResult(-ENOENT);
|
||||
auto& process = handle->process();
|
||||
|
||||
if (to_proc_parent_directory(identifier()) == PDI_PID_fd) {
|
||||
if (out_parent)
|
||||
*out_parent = base;
|
||||
int fd = to_fd(identifier());
|
||||
auto description = process.file_description(fd);
|
||||
auto description = process->file_description(fd);
|
||||
if (!description)
|
||||
return KResult(-ENOENT);
|
||||
auto proxy_inode = ProcFSProxyInode::create(const_cast<ProcFS&>(fs()), *description);
|
||||
|
@ -1435,16 +1436,16 @@ KResultOr<NonnullRefPtr<Custody>> ProcFSInode::resolve_as_link(Custody& base, Re
|
|||
|
||||
switch (proc_file_type) {
|
||||
case FI_PID_cwd:
|
||||
res = &process.current_directory();
|
||||
res = &process->current_directory();
|
||||
break;
|
||||
case FI_PID_exe:
|
||||
res = process.executable();
|
||||
res = process->executable();
|
||||
break;
|
||||
case FI_PID_root:
|
||||
// Note: we open root_directory() here, not
|
||||
// root_directory_relative_to_global_root().
|
||||
// This seems more useful.
|
||||
res = &process.root_directory();
|
||||
res = &process->root_directory();
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue