1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 21:07:34 +00:00

Kernel: Expose thread stacks as separate files

This breaks SystemMonitor, which the next commit fixes.
This commit is contained in:
Ben Wiederhake 2020-08-09 19:59:26 +02:00 committed by Andreas Kling
parent 9abac64333
commit c3df2fe83f

View file

@ -69,7 +69,9 @@ enum ProcParentDirectory {
PDI_Root_net, PDI_Root_net,
PDI_PID, PDI_PID,
PDI_PID_fd, PDI_PID_fd,
PDI_PID_stacks,
}; };
static_assert(PDI_PID_stacks < 16, "Too many directories for identifier scheme");
enum ProcFileType { enum ProcFileType {
FI_Invalid = 0, FI_Invalid = 0,
@ -111,7 +113,7 @@ enum ProcFileType {
__FI_PID_Start, __FI_PID_Start,
FI_PID_vm, FI_PID_vm,
FI_PID_vmobjects, FI_PID_vmobjects,
FI_PID_stack, FI_PID_stacks, // directory
FI_PID_fds, FI_PID_fds,
FI_PID_unveil, FI_PID_unveil,
FI_PID_exe, // symlink FI_PID_exe, // symlink
@ -131,6 +133,12 @@ static inline ProcessID to_pid(const InodeIdentifier& identifier)
return identifier.index() >> 16u; return identifier.index() >> 16u;
} }
static inline ThreadID to_tid(const InodeIdentifier& identifier)
{
// Sneakily, use the exact same mechanism.
return to_pid(identifier).value();
}
static inline ProcParentDirectory to_proc_parent_directory(const InodeIdentifier& identifier) static inline ProcParentDirectory to_proc_parent_directory(const InodeIdentifier& identifier)
{ {
return (ProcParentDirectory)((identifier.index() >> 12) & 0xf); return (ProcParentDirectory)((identifier.index() >> 12) & 0xf);
@ -164,6 +172,11 @@ static inline InodeIdentifier to_identifier_with_fd(unsigned fsid, ProcessID pid
return { fsid, (PDI_PID_fd << 12u) | ((unsigned)pid.value() << 16u) | (FI_MaxStaticFileIndex + fd) }; return { fsid, (PDI_PID_fd << 12u) | ((unsigned)pid.value() << 16u) | (FI_MaxStaticFileIndex + fd) };
} }
static inline InodeIdentifier to_identifier_with_stack(unsigned fsid, ThreadID tid)
{
return { fsid, (PDI_PID_stacks << 12u) | ((unsigned)tid.value() << 16u) | FI_MaxStaticFileIndex };
}
static inline InodeIdentifier sys_var_to_identifier(unsigned fsid, unsigned index) static inline InodeIdentifier sys_var_to_identifier(unsigned fsid, unsigned index)
{ {
ASSERT(index < 256); ASSERT(index < 256);
@ -184,6 +197,8 @@ static inline InodeIdentifier to_parent_id(const InodeIdentifier& identifier)
return to_identifier(identifier.fsid(), PDI_Root, to_pid(identifier), FI_PID); return to_identifier(identifier.fsid(), PDI_Root, to_pid(identifier), FI_PID);
case PDI_PID_fd: case PDI_PID_fd:
return to_identifier(identifier.fsid(), PDI_PID, to_pid(identifier), FI_PID_fd); return to_identifier(identifier.fsid(), PDI_PID, to_pid(identifier), FI_PID_fd);
case PDI_PID_stacks:
return to_identifier(identifier.fsid(), PDI_PID, to_pid(identifier), FI_PID_stacks);
} }
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
@ -209,6 +224,12 @@ static inline bool is_process_related_file(const InodeIdentifier& identifier)
} }
} }
static inline bool is_thread_related_file(const InodeIdentifier& identifier)
{
auto proc_parent_directory = to_proc_parent_directory(identifier);
return proc_parent_directory == PDI_PID_stacks;
}
static inline bool is_directory(const InodeIdentifier& identifier) static inline bool is_directory(const InodeIdentifier& identifier)
{ {
auto proc_file_type = to_proc_file_type(identifier); auto proc_file_type = to_proc_file_type(identifier);
@ -218,6 +239,7 @@ static inline bool is_directory(const InodeIdentifier& identifier)
case FI_Root_net: case FI_Root_net:
case FI_PID: case FI_PID:
case FI_PID_fd: case FI_PID_fd:
case FI_PID_stacks:
return true; return true;
default: default:
return false; return false;
@ -626,12 +648,15 @@ Optional<KBuffer> procfs$pid_unveil(InodeIdentifier identifier)
return builder.build(); return builder.build();
} }
Optional<KBuffer> procfs$pid_stack(InodeIdentifier identifier) Optional<KBuffer> procfs$tid_stack(InodeIdentifier identifier)
{ {
auto process = Process::from_pid(to_pid(identifier)); auto thread = Thread::from_tid(to_tid(identifier));
if (!process) if (!thread)
return {}; return {};
return process->backtrace(); KBufferBuilder builder;
builder.appendf("Thread %d (%s):\n", thread->tid().value(), thread->name().characters());
builder.append(thread->backtrace());
return builder.build();
} }
Optional<KBuffer> procfs$pid_exe(InodeIdentifier identifier) Optional<KBuffer> procfs$pid_exe(InodeIdentifier identifier)
@ -1071,7 +1096,6 @@ InodeMetadata ProcFSInode::metadata() const
metadata.atime = mepoch; metadata.atime = mepoch;
metadata.mtime = mepoch; metadata.mtime = mepoch;
auto proc_parent_directory = to_proc_parent_directory(identifier()); auto proc_parent_directory = to_proc_parent_directory(identifier());
auto pid = to_pid(identifier());
auto proc_file_type = to_proc_file_type(identifier()); auto proc_file_type = to_proc_file_type(identifier());
#ifdef PROCFS_DEBUG #ifdef PROCFS_DEBUG
@ -1079,6 +1103,7 @@ InodeMetadata ProcFSInode::metadata() const
#endif #endif
if (is_process_related_file(identifier())) { if (is_process_related_file(identifier())) {
ProcessID pid = to_pid(identifier());
auto process = Process::from_pid(pid); auto process = Process::from_pid(pid);
if (process) { if (process) {
metadata.uid = process->sys$getuid(); metadata.uid = process->sys$getuid();
@ -1088,6 +1113,17 @@ InodeMetadata ProcFSInode::metadata() const
metadata.uid = 0; metadata.uid = 0;
metadata.gid = 0; metadata.gid = 0;
} }
} else if (is_thread_related_file(identifier())) {
ThreadID tid = to_tid(identifier());
auto thread = Thread::from_tid(tid);
if (thread) {
metadata.uid = thread->process().sys$getuid();
metadata.gid = thread->process().sys$getgid();
} else {
// TODO: How to handle this?
metadata.uid = 0;
metadata.gid = 0;
}
} }
if (proc_parent_directory == PDI_PID_fd) { if (proc_parent_directory == PDI_PID_fd) {
@ -1111,6 +1147,7 @@ InodeMetadata ProcFSInode::metadata() const
break; break;
case FI_PID: case FI_PID:
case FI_PID_fd: case FI_PID_fd:
case FI_PID_stacks:
metadata.mode = S_IFDIR | S_IRUSR | S_IXUSR; metadata.mode = S_IFDIR | S_IRUSR | S_IXUSR;
break; break;
default: default:
@ -1152,6 +1189,10 @@ ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes
callback_tmp = procfs$pid_fd_entry; callback_tmp = procfs$pid_fd_entry;
read_callback = &callback_tmp; read_callback = &callback_tmp;
break; break;
case PDI_PID_stacks:
callback_tmp = procfs$tid_stack;
read_callback = &callback_tmp;
break;
case PDI_Root_sys: case PDI_Root_sys:
switch (SysVariable::for_inode(identifier()).type) { switch (SysVariable::for_inode(identifier()).type) {
case SysVariable::Type::Invalid: case SysVariable::Type::Invalid:
@ -1209,7 +1250,6 @@ KResult ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntr
if (!Kernel::is_directory(identifier())) if (!Kernel::is_directory(identifier()))
return KResult(-ENOTDIR); return KResult(-ENOTDIR);
auto pid = to_pid(identifier());
auto proc_file_type = to_proc_file_type(identifier()); auto proc_file_type = to_proc_file_type(identifier());
auto parent_id = to_parent_id(identifier()); auto parent_id = to_parent_id(identifier());
@ -1248,6 +1288,7 @@ KResult ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntr
break; break;
case FI_PID: { case FI_PID: {
auto pid = to_pid(identifier());
auto process = Process::from_pid(pid); auto process = Process::from_pid(pid);
if (!process) if (!process)
return KResult(-ENOENT); return KResult(-ENOENT);
@ -1262,6 +1303,7 @@ KResult ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntr
} break; } break;
case FI_PID_fd: { case FI_PID_fd: {
auto pid = to_pid(identifier());
auto process = Process::from_pid(pid); auto process = Process::from_pid(pid);
if (!process) if (!process)
return KResult(-ENOENT); return KResult(-ENOENT);
@ -1274,6 +1316,21 @@ KResult ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntr
callback({ name, name_length, to_identifier_with_fd(fsid(), pid, i), 0 }); callback({ name, name_length, to_identifier_with_fd(fsid(), pid, i), 0 });
} }
} break; } break;
case FI_PID_stacks: {
auto pid = to_pid(identifier());
auto process = Process::from_pid(pid);
if (!process)
return KResult(-ENOENT);
process->for_each_thread([&](Thread& thread) -> IterationDecision {
int tid = thread.tid().value();
char name[16];
size_t name_length = (size_t)sprintf(name, "%d", tid);
callback({ name, name_length, to_identifier_with_stack(fsid(), tid), 0 });
return IterationDecision::Continue;
});
} break;
default: default:
return KSuccess; return KSuccess;
} }
@ -1367,6 +1424,25 @@ RefPtr<Inode> ProcFSInode::lookup(StringView name)
if (fd_exists) if (fd_exists)
return fs().get_inode(to_identifier_with_fd(fsid(), to_pid(identifier()), name_as_number.value())); return fs().get_inode(to_identifier_with_fd(fsid(), to_pid(identifier()), name_as_number.value()));
} }
if (proc_file_type == FI_PID_stacks) {
auto name_as_number = name.to_int();
if (!name_as_number.has_value())
return {};
int tid = name_as_number.value();
if (tid <= 0) {
return {};
}
bool thread_exists = false;
{
auto process = Process::from_pid(to_pid(identifier()));
auto thread = Thread::from_tid(tid);
thread_exists = process && thread && process->pid() == thread->pid();
}
if (thread_exists)
return fs().get_inode(to_identifier_with_stack(fsid(), tid));
}
return {}; return {};
} }
@ -1416,6 +1492,8 @@ ssize_t ProcFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, F
KResultOr<NonnullRefPtr<Custody>> ProcFSInode::resolve_as_link(Custody& base, RefPtr<Custody>* out_parent, int options, int symlink_recursion_level) const KResultOr<NonnullRefPtr<Custody>> ProcFSInode::resolve_as_link(Custody& base, RefPtr<Custody>* out_parent, int options, int symlink_recursion_level) const
{ {
// The only links are in pid directories, so it's safe to ignore
// unrelated files and the thread-specific stacks/ directory.
if (!is_process_related_file(identifier())) if (!is_process_related_file(identifier()))
return Inode::resolve_as_link(base, out_parent, options, symlink_recursion_level); return Inode::resolve_as_link(base, out_parent, options, symlink_recursion_level);
@ -1600,7 +1678,7 @@ ProcFS::ProcFS()
m_entries[FI_PID_vm] = { "vm", FI_PID_vm, false, procfs$pid_vm }; m_entries[FI_PID_vm] = { "vm", FI_PID_vm, false, procfs$pid_vm };
m_entries[FI_PID_vmobjects] = { "vmobjects", FI_PID_vmobjects, true, procfs$pid_vmobjects }; m_entries[FI_PID_vmobjects] = { "vmobjects", FI_PID_vmobjects, true, procfs$pid_vmobjects };
m_entries[FI_PID_stack] = { "stack", FI_PID_stack, false, procfs$pid_stack }; m_entries[FI_PID_stacks] = { "stacks", FI_PID_stacks, false };
m_entries[FI_PID_fds] = { "fds", FI_PID_fds, false, procfs$pid_fds }; m_entries[FI_PID_fds] = { "fds", FI_PID_fds, false, procfs$pid_fds };
m_entries[FI_PID_exe] = { "exe", FI_PID_exe, false, procfs$pid_exe }; m_entries[FI_PID_exe] = { "exe", FI_PID_exe, false, procfs$pid_exe };
m_entries[FI_PID_cwd] = { "cwd", FI_PID_cwd, false, procfs$pid_cwd }; m_entries[FI_PID_cwd] = { "cwd", FI_PID_cwd, false, procfs$pid_cwd };
@ -1621,5 +1699,4 @@ KResult ProcFSInode::chown(uid_t, gid_t)
{ {
return KResult(-EPERM); return KResult(-EPERM);
} }
} }