From: Tulio A M Mendes Date: Wed, 11 Feb 2026 22:39:04 +0000 (-0300) Subject: feat: /proc per-process directories (/proc/[pid]/status, maps) X-Git-Url: https://projects.tadryanom.me/docs/POSIX_ROADMAP.md?a=commitdiff_plain;h=d85ef30319b8612fd7532581c5192935e36f27f6;p=AdrOS.git feat: /proc per-process directories (/proc/[pid]/status, maps) - /proc/[pid]/status: shows Pid, PPid, Pgrp, Session, State, signals, heap - /proc/[pid]/maps: shows heap range and mmap regions - /proc root readdir now lists numeric PID entries alongside self/uptime/meminfo - /proc root finddir resolves numeric names to per-PID directory nodes - Uses small static pool of fs_node_t (8 slots) for dynamic PID nodes - proc_find_pid helper iterates ready queue to find process by PID - cppcheck clean, 19/19 smoke tests pass --- diff --git a/src/kernel/procfs.c b/src/kernel/procfs.c index 7ced30d..744a949 100644 --- a/src/kernel/procfs.c +++ b/src/kernel/procfs.c @@ -14,8 +14,25 @@ static fs_node_t g_proc_self_status; static fs_node_t g_proc_uptime; static fs_node_t g_proc_meminfo; +#define PID_NODE_POOL 8 +static fs_node_t g_pid_dir[PID_NODE_POOL]; +static fs_node_t g_pid_status[PID_NODE_POOL]; +static fs_node_t g_pid_maps[PID_NODE_POOL]; +static uint32_t g_pid_pool_idx = 0; + extern struct process* ready_queue_head; +static struct process* proc_find_pid(uint32_t pid) { + if (!ready_queue_head) return NULL; + struct process* it = ready_queue_head; + const struct process* start = it; + do { + if (it->pid == pid) return it; + it = it->next; + } while (it && it != start); + return NULL; +} + static int proc_snprintf(char* buf, uint32_t sz, const char* key, uint32_t val) { if (sz < 2) return 0; uint32_t w = 0; @@ -124,6 +141,146 @@ static uint32_t proc_meminfo_read(fs_node_t* node, uint32_t offset, uint32_t siz return size; } +/* --- per-PID status read (inode == target pid) --- */ + +static uint32_t proc_pid_status_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { + uint32_t pid = node->inode; + struct process* p = proc_find_pid(pid); + if (!p) return 0; + + char tmp[512]; + uint32_t len = 0; + + len += (uint32_t)proc_snprintf(tmp + len, sizeof(tmp) - len, "Pid:\t", p->pid); + len += (uint32_t)proc_snprintf(tmp + len, sizeof(tmp) - len, "PPid:\t", p->parent_pid); + len += (uint32_t)proc_snprintf(tmp + len, sizeof(tmp) - len, "Pgrp:\t", p->pgrp_id); + len += (uint32_t)proc_snprintf(tmp + len, sizeof(tmp) - len, "Session:\t", p->session_id); + + const char* state_str = "unknown\n"; + switch (p->state) { + case PROCESS_READY: state_str = "R (ready)\n"; break; + case PROCESS_RUNNING: state_str = "R (running)\n"; break; + case PROCESS_BLOCKED: state_str = "S (blocked)\n"; break; + case PROCESS_SLEEPING: state_str = "S (sleeping)\n"; break; + case PROCESS_ZOMBIE: state_str = "Z (zombie)\n"; break; + } + const char* s = "State:\t"; + while (*s && len + 1 < sizeof(tmp)) tmp[len++] = *s++; + s = state_str; + while (*s && len + 1 < sizeof(tmp)) tmp[len++] = *s++; + + len += (uint32_t)proc_snprintf(tmp + len, sizeof(tmp) - len, "SigPnd:\t", p->sig_pending_mask); + len += (uint32_t)proc_snprintf(tmp + len, sizeof(tmp) - len, "SigBlk:\t", p->sig_blocked_mask); + len += (uint32_t)proc_snprintf(tmp + len, sizeof(tmp) - len, "HeapStart:\t", (uint32_t)p->heap_start); + len += (uint32_t)proc_snprintf(tmp + len, sizeof(tmp) - len, "HeapBreak:\t", (uint32_t)p->heap_break); + + if (offset >= len) return 0; + uint32_t avail = len - offset; + if (size > avail) size = avail; + memcpy(buffer, tmp + offset, size); + return size; +} + +/* --- per-PID maps read (inode == target pid) --- */ + +static uint32_t proc_pid_maps_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { + uint32_t pid = node->inode; + struct process* p = proc_find_pid(pid); + if (!p) return 0; + + char tmp[1024]; + uint32_t len = 0; + + if (p->heap_start && p->heap_break > p->heap_start) { + len += (uint32_t)proc_snprintf(tmp + len, sizeof(tmp) - len, "heap:\t", (uint32_t)p->heap_start); + len += (uint32_t)proc_snprintf(tmp + len, sizeof(tmp) - len, "brk:\t", (uint32_t)p->heap_break); + } + + for (int i = 0; i < PROCESS_MAX_MMAPS; i++) { + if (p->mmaps[i].length == 0) continue; + len += (uint32_t)proc_snprintf(tmp + len, sizeof(tmp) - len, "mmap:\t", (uint32_t)p->mmaps[i].base); + len += (uint32_t)proc_snprintf(tmp + len, sizeof(tmp) - len, "len:\t", p->mmaps[i].length); + } + + if (len == 0) { + const char* msg = "(empty)\n"; + while (*msg && len + 1 < sizeof(tmp)) tmp[len++] = *msg++; + } + + if (offset >= len) return 0; + uint32_t avail = len - offset; + if (size > avail) size = avail; + memcpy(buffer, tmp + offset, size); + return size; +} + +/* --- per-PID directory --- */ + +static fs_node_t* proc_pid_finddir(fs_node_t* node, const char* name) { + uint32_t pid = node->inode; + uint32_t slot = g_pid_pool_idx; + + if (strcmp(name, "status") == 0) { + g_pid_pool_idx = (slot + 1) % PID_NODE_POOL; + memset(&g_pid_status[slot], 0, sizeof(fs_node_t)); + strcpy(g_pid_status[slot].name, "status"); + g_pid_status[slot].flags = FS_FILE; + g_pid_status[slot].inode = pid; + g_pid_status[slot].read = proc_pid_status_read; + return &g_pid_status[slot]; + } + if (strcmp(name, "maps") == 0) { + g_pid_pool_idx = (slot + 1) % PID_NODE_POOL; + memset(&g_pid_maps[slot], 0, sizeof(fs_node_t)); + strcpy(g_pid_maps[slot].name, "maps"); + g_pid_maps[slot].flags = FS_FILE; + g_pid_maps[slot].inode = pid; + g_pid_maps[slot].read = proc_pid_maps_read; + return &g_pid_maps[slot]; + } + return NULL; +} + +static int proc_pid_readdir(fs_node_t* node, uint32_t* inout_index, void* buf, uint32_t buf_len) { + (void)node; + if (!inout_index || !buf) return -1; + if (buf_len < sizeof(struct vfs_dirent)) return -1; + + static const char* entries[] = { "status", "maps" }; + uint32_t idx = *inout_index; + if (idx >= 2) return 0; + + struct vfs_dirent* d = (struct vfs_dirent*)buf; + d->d_ino = 300 + idx; + d->d_type = FS_FILE; + d->d_reclen = sizeof(struct vfs_dirent); + { + const char* s = entries[idx]; + uint32_t j = 0; + while (s[j] && j + 1 < sizeof(d->d_name)) { d->d_name[j] = s[j]; j++; } + d->d_name[j] = 0; + } + *inout_index = idx + 1; + return (int)sizeof(struct vfs_dirent); +} + +static fs_node_t* proc_get_pid_dir(uint32_t pid) { + if (!proc_find_pid(pid)) return NULL; + uint32_t slot = g_pid_pool_idx; + g_pid_pool_idx = (slot + 1) % PID_NODE_POOL; + memset(&g_pid_dir[slot], 0, sizeof(fs_node_t)); + char num[16]; + itoa(pid, num, 10); + strcpy(g_pid_dir[slot].name, num); + g_pid_dir[slot].flags = FS_DIRECTORY; + g_pid_dir[slot].inode = pid; + g_pid_dir[slot].finddir = proc_pid_finddir; + g_pid_dir[slot].readdir = proc_pid_readdir; + return &g_pid_dir[slot]; +} + +/* --- /proc/self --- */ + static fs_node_t* proc_self_finddir(fs_node_t* node, const char* name) { (void)node; if (strcmp(name, "status") == 0) return &g_proc_self_status; @@ -153,11 +310,24 @@ static int proc_self_readdir(fs_node_t* node, uint32_t* inout_index, void* buf, return (int)sizeof(struct vfs_dirent); } +static int is_numeric(const char* s) { + if (!s || !*s) return 0; + while (*s) { if (*s < '0' || *s > '9') return 0; s++; } + return 1; +} + +static uint32_t parse_uint(const char* s) { + uint32_t v = 0; + while (*s >= '0' && *s <= '9') { v = v * 10 + (uint32_t)(*s - '0'); s++; } + return v; +} + static fs_node_t* proc_root_finddir(fs_node_t* node, const char* name) { (void)node; if (strcmp(name, "self") == 0) return &g_proc_self; if (strcmp(name, "uptime") == 0) return &g_proc_uptime; if (strcmp(name, "meminfo") == 0) return &g_proc_meminfo; + if (is_numeric(name)) return proc_get_pid_dir(parse_uint(name)); return NULL; } @@ -166,22 +336,47 @@ static int proc_root_readdir(fs_node_t* node, uint32_t* inout_index, void* buf, if (!inout_index || !buf) return -1; if (buf_len < sizeof(struct vfs_dirent)) return -1; - static const char* entries[] = { "self", "uptime", "meminfo" }; uint32_t idx = *inout_index; - if (idx >= 3) return 0; - struct vfs_dirent* d = (struct vfs_dirent*)buf; - d->d_ino = 200 + idx; - d->d_type = (idx == 0) ? 2 : 0; - d->d_reclen = sizeof(struct vfs_dirent); - { - const char* s = entries[idx]; + + static const char* fixed[] = { "self", "uptime", "meminfo" }; + if (idx < 3) { + d->d_ino = 200 + idx; + d->d_type = (idx == 0) ? FS_DIRECTORY : FS_FILE; + d->d_reclen = sizeof(struct vfs_dirent); + const char* s = fixed[idx]; uint32_t j = 0; while (s[j] && j + 1 < sizeof(d->d_name)) { d->d_name[j] = s[j]; j++; } d->d_name[j] = 0; + *inout_index = idx + 1; + return (int)sizeof(struct vfs_dirent); } - *inout_index = idx + 1; - return (int)sizeof(struct vfs_dirent); + + /* After fixed entries, list numeric PIDs */ + uint32_t pi = idx - 3; + uint32_t count = 0; + if (ready_queue_head) { + struct process* it = ready_queue_head; + const struct process* start = it; + do { + if (count == pi) { + char num[16]; + itoa(it->pid, num, 10); + d->d_ino = 400 + it->pid; + d->d_type = FS_DIRECTORY; + d->d_reclen = sizeof(struct vfs_dirent); + uint32_t j = 0; + while (num[j] && j + 1 < sizeof(d->d_name) && j < sizeof(num) - 1) { d->d_name[j] = num[j]; j++; } + d->d_name[j] = 0; + *inout_index = idx + 1; + return (int)sizeof(struct vfs_dirent); + } + count++; + it = it->next; + } while (it && it != start); + } + + return 0; } fs_node_t* procfs_create_root(void) {