Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ See [docs/architecture.md](docs/architecture.md) for the full architecture refer
| Time | clock_gettime, gettimeofday, nanosleep, utimensat, timer_create/settime/gettime/delete |
| Terminal | Full PTY support (/dev/ptmx + /dev/pts/N), line discipline, canonical/raw mode, 16 terminal ioctls |
| Virtual devices | /dev/null, /dev/zero, /dev/urandom, /dev/full, /dev/fd/N, /dev/tty, /dev/ptmx, /dev/pts/* |
| Procfs | /proc/self, /proc/\<pid\>/stat, status, cmdline, environ, maps, fd/\*, /proc/net/tcp, unix |
| Procfs (partial Linux compatibility) | /proc/stat, /proc/meminfo, /proc/self, /proc/\<pid\>/{stat,status,statm,task,cmdline,environ,maps,fd/\*}, /proc/net/{tcp,unix}; virtual size is logical address-space size, while CPU, RSS, and system-memory zeroes mean accounting is unavailable |
| IPC | SysV msg queues, semaphores, shared memory; POSIX mqueues |
| Event/Notification | eventfd, timerfd, signalfd |
| Poll/Select | poll, ppoll, pselect6, epoll (host-intercepted in browser) |
Expand Down
35 changes: 35 additions & 0 deletions crates/kernel/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,15 @@ pub trait HostIO {
let _ = handle;
Ok(events)
}
/// Query readiness for a host-delegated file descriptor.
///
/// Native hosts that do not distinguish delegated descriptor readiness
/// retain the legacy ready behavior. `WasmHostIO` overrides this and uses
/// a tagged call over the existing `host_net_poll` ABI import.
fn host_fd_poll(&mut self, handle: i64, events: i16) -> Result<i16, Errno> {
let _ = handle;
Ok(events)
}
fn host_net_close(&mut self, handle: i32) -> Result<(), Errno>;
/// Notify the host that an AF_INET socket is now listening, so the host
/// can open a real TCP server on the given port.
Expand Down Expand Up @@ -390,6 +399,8 @@ pub struct ThreadInfo {
pub stack_ptr: usize,
pub tls_ptr: usize,
pub tidptr: usize, // set_tid_address pointer
/// Linux thread name set by `prctl(PR_SET_NAME)`.
pub thread_name: [u8; 16],
/// Per-thread signal state: directed-pending set + blocked mask + RT queue.
/// Handlers remain process-wide and live on [`Process::signals`].
pub signals: PerThreadSignalState,
Expand All @@ -403,6 +414,7 @@ impl ThreadInfo {
stack_ptr,
tls_ptr,
tidptr: 0,
thread_name: [0u8; 16],
signals: PerThreadSignalState::new(),
}
}
Expand Down Expand Up @@ -822,6 +834,29 @@ impl Process {
self.threads.iter_mut().find(|t| t.tid == tid)
}

/// Return the Linux thread name storage for `tid`.
///
/// The main thread's name remains on [`Process::thread_name`]. Worker
/// names live on their [`ThreadInfo`] records so a pthread rename cannot
/// change `/proc/<pid>/stat` for the thread-group leader.
pub fn thread_name_for(&self, tid: u32) -> Option<&[u8; 16]> {
if self.is_main_thread(tid) {
Some(&self.thread_name)
} else {
self.get_thread(tid).map(|thread| &thread.thread_name)
}
}

/// Mutable counterpart to [`Process::thread_name_for`].
pub fn thread_name_for_mut(&mut self, tid: u32) -> Option<&mut [u8; 16]> {
if self.is_main_thread(tid) {
Some(&mut self.thread_name)
} else {
self.get_thread_mut(tid)
.map(|thread| &mut thread.thread_name)
}
}

/// True if `tid` names the process's main thread. The main thread's TID
/// equals the process PID (Linux convention) and is not tracked in
/// [`Process::threads`]; per-thread signal state for the main thread lives
Expand Down
25 changes: 25 additions & 0 deletions crates/kernel/src/process_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,19 @@ impl ProcessTable {
self.processes.keys().copied().collect()
}

/// Collect PIDs that represent user-visible procfs processes.
///
/// Running processes and unreaped Exited zombies remain visible. Limbo
/// records are resource-free process-group identity placeholders, not
/// processes, so exposing them as `/proc/<pid>` would invent state.
pub fn procfs_pids(&self) -> Vec<u32> {
self.processes
.iter()
.filter(|(_, process)| process.state != ProcessState::Limbo)
.map(|(&pid, _)| pid)
.collect()
}

/// Collect PIDs of all processes in a given process group.
pub fn pids_in_group(&self, pgid: u32) -> Vec<u32> {
self.processes
Expand Down Expand Up @@ -957,6 +970,18 @@ impl ProcessTable {
mod wait_tests {
use super::*;

#[test]
fn procfs_pids_retain_zombies_but_exclude_limbo_placeholders() {
let mut table = ProcessTable::new();
table.create_process(100).unwrap();
table.create_process(101).unwrap();
table.processes.get_mut(&100).unwrap().state = ProcessState::Exited;
table.processes.get_mut(&1).unwrap().state = ProcessState::Limbo;

assert_eq!(table.procfs_pids(), vec![100, 101]);
assert_eq!(table.all_pids(), vec![1, 100, 101]);
}

#[test]
fn spawn_pid_allocation_does_not_reuse_reaped_pid() {
let mut table = ProcessTable::new();
Expand Down
Loading
Loading