#ifndef _PROCFS_GLO_H
#define _PROCFS_GLO_H
-#include <minix/param.h>
-
/* pid.c */
extern struct file pid_files[];
extern struct file root_files[];
/* tree.c */
-extern struct proc proc[NR_PROCS + NR_TASKS]; /* process table from kernel */
-extern struct mproc mproc[NR_PROCS]; /* process table from PM */
-extern struct fproc fproc[NR_PROCS]; /* process table from VFS */
+extern struct minix_proc_list proc_list[NR_PROCS];
#endif /* _PROCFS_GLO_H */
#define _PROCFS_INC_H
#include <minix/drivers.h>
+#include <minix/param.h>
+#include <minix/sysctl.h>
#include <minix/sysinfo.h>
#include <minix/vtreefs.h>
#include <minix/procfs.h>
#include "kernel/const.h"
#include "kernel/type.h"
#include "kernel/proc.h"
-#include "pm/mproc.h"
#include "vfs/const.h"
-#include "vfs/fproc.h"
#include "vfs/dmap.h"
#include "const.h"
#include <sys/mman.h>
#include <minix/vm.h>
-#define S_FRAME_SIZE 4096 /* use malloc if larger than this */
-static char s_frame[S_FRAME_SIZE]; /* static storage for process frame */
-static char *frame; /* pointer to process frame buffer */
-
static void pid_psinfo(int slot);
static void pid_cmdline(int slot);
static void pid_environ(int slot);
is_zombie(int slot)
{
- return (slot >= NR_TASKS &&
- (mproc[slot - NR_TASKS].mp_flags & (TRACE_ZOMBIE | ZOMBIE)));
+ return (slot >= NR_TASKS &&
+ (proc_list[slot - NR_TASKS].mpl_flags & MPLF_ZOMBIE));
}
/*
- * Print information used by ps(1) and top(1).
+ * Get MINIX3-specific process data for the process identified by the given
+ * kernel slot. Return OK or a negative error code.
*/
-static void
-pid_psinfo(int i)
+int
+get_proc_data(pid_t pid, struct minix_proc_data * mpd)
{
- int pi, task, state, type, p_state, f_state;
- char name[PROC_NAME_LEN+1], *p;
- struct vm_usage_info vui;
- pid_t ppid;
+ int mib[4] = { CTL_MINIX, MINIX_PROC, PROC_DATA, pid };
+ size_t oldlen;
- pi = i - NR_TASKS;
- task = proc[i].p_nr < 0;
+ oldlen = sizeof(*mpd);
+ if (__sysctl(mib, __arraycount(mib), mpd, &oldlen, NULL, 0) != 0)
+ return -errno;
- /* Get the name of the process. Spaces would mess up the format.. */
- if (task || mproc[i].mp_name[0] == 0)
- strncpy(name, proc[i].p_name, sizeof(name) - 1);
- else
- strncpy(name, mproc[pi].mp_name, sizeof(name) - 1);
- name[sizeof(name) - 1] = 0;
- if ((p = strchr(name, ' ')) != NULL)
- p[0] = 0;
-
- /* Get the type of the process. */
- if (task)
- type = TYPE_TASK;
- else if (mproc[i].mp_flags & PRIV_PROC)
- type = TYPE_SYSTEM;
- else
- type = TYPE_USER;
-
- /* Get the state of the process. */
- if (!task) {
- if (is_zombie(i))
- state = STATE_ZOMBIE; /* zombie */
- else if (mproc[pi].mp_flags & TRACE_STOPPED)
- state = STATE_STOP; /* stopped (traced) */
- else if (proc[i].p_rts_flags == 0)
- state = STATE_RUN; /* in run-queue */
- else if (fp_is_blocked(&fproc[pi]) ||
- (mproc[pi].mp_flags & (WAITING | SIGSUSPENDED)))
- state = STATE_SLEEP; /* sleeping */
- else
- state = STATE_WAIT; /* waiting */
- } else {
- if (proc[i].p_rts_flags == 0)
- state = STATE_RUN; /* in run-queue */
- else
- state = STATE_WAIT; /* other i.e. waiting */
- }
-
- /* We assume that even if a process has become a zombie, its kernel
- * proc entry still contains the old (although valid) information.
- * Currently this is true, but in the future we may have to filter some
- * fields.
- */
- buf_printf("%d %c %d %s %c %d %d %lu %lu %lu %lu",
- PSINFO_VERSION, /* information version */
- type, /* process type */
- (int)proc[i].p_endpoint, /* process endpoint */
- name, /* process name */
- state, /* process state letter */
- (int)P_BLOCKEDON(&proc[i]), /* endpt blocked on, or NONE */
- (int)proc[i].p_priority, /* process priority */
- (long)proc[i].p_user_time, /* user time */
- (long)proc[i].p_sys_time, /* system time */
- ex64hi(proc[i].p_cycles), /* execution cycles */
- ex64lo(proc[i].p_cycles)
- );
-
- memset(&vui, 0, sizeof(vui));
-
- if (!is_zombie(i)) {
- /* We don't care if this fails. */
- (void)vm_info_usage(proc[i].p_endpoint, &vui);
- }
-
- /* If the process is not a kernel task, we add some extra info. */
- if (!task) {
- if (mproc[pi].mp_flags & WAITING)
- p_state = PSTATE_WAITING;
- else if (mproc[pi].mp_flags & SIGSUSPENDED)
- p_state = PSTATE_SIGSUSP;
- else
- p_state = '-';
-
- if (mproc[pi].mp_parent == pi)
- ppid = NO_PID;
- else
- ppid = mproc[mproc[pi].mp_parent].mp_pid;
-
- switch (fproc[pi].fp_blocked_on) {
- case FP_BLOCKED_ON_NONE: f_state = FSTATE_NONE; break;
- case FP_BLOCKED_ON_PIPE: f_state = FSTATE_PIPE; break;
- case FP_BLOCKED_ON_LOCK: f_state = FSTATE_LOCK; break;
- case FP_BLOCKED_ON_POPEN: f_state = FSTATE_POPEN; break;
- case FP_BLOCKED_ON_SELECT: f_state = FSTATE_SELECT; break;
- case FP_BLOCKED_ON_OTHER: f_state = FSTATE_TASK; break;
- default: f_state = FSTATE_UNKNOWN;
- }
-
- buf_printf(" %lu %lu %lu %c %d %u %u %u %d %c %d %llu",
- vui.vui_total, /* total memory */
- vui.vui_common, /* common memory */
- vui.vui_shared, /* shared memory */
- p_state, /* sleep state */
- ppid, /* parent PID */
- mproc[pi].mp_realuid, /* real UID */
- mproc[pi].mp_effuid, /* effective UID */
- mproc[pi].mp_procgrp, /* process group */
- mproc[pi].mp_nice, /* nice value */
- f_state, /* VFS block state */
- (int)(fproc[pi].fp_blocked_on == FP_BLOCKED_ON_OTHER) ?
- fproc[pi].fp_task : NONE, /* block proc */
- fproc[pi].fp_tty /* controlling tty */
- );
- }
-
- /* Always add kernel cycles. */
- buf_printf(" %lu %lu %lu %lu",
- ex64hi(proc[i].p_kipc_cycles),
- ex64lo(proc[i].p_kipc_cycles),
- ex64hi(proc[i].p_kcall_cycles),
- ex64lo(proc[i].p_kcall_cycles));
-
- /* Add total memory for tasks at the end. */
- if (task)
- buf_printf(" %lu", vui.vui_total);
-
- /* Newline at the end of the file. */
- buf_printf("\n");
+ return OK;
}
/*
- * If we allocated memory dynamically during a call to get_frame(), free it up
- * here.
+ * Print process information. This feature is now used only by mtop(1), and as
+ * a result, we only provide information that mtop(1) actually uses. In the
+ * future, this file may be extended with additional fields again.
*/
static void
-put_frame(void)
+pid_psinfo(int slot)
{
+ struct minix_proc_data mpd;
+ struct vm_usage_info vui;
+ pid_t pid;
+ uid_t uid;
+ char *p;
+ int task, type, state;
- if (frame != s_frame)
- free(frame);
-}
+ if ((pid = pid_from_slot(slot)) == 0)
+ return;
-/*
- * Get the execution frame from the top of the given process's stack. It may
- * be very large, in which case we temporarily allocate memory for it (up to a
- * certain size).
- */
-static int
-get_frame(int slot, vir_bytes * basep, vir_bytes * sizep, size_t * nargsp)
-{
- vir_bytes base, size;
- size_t nargs;
+ if (get_proc_data(pid, &mpd) != OK)
+ return;
+
+ task = (slot < NR_TASKS);
- if (proc[slot].p_nr < 0 || is_zombie(slot))
- return FALSE;
+ /* Get the type of the process. */
+ if (task)
+ type = TYPE_TASK;
+ else if (mpd.mpd_flags & MPDF_SYSTEM)
+ type = TYPE_SYSTEM;
+ else
+ type = TYPE_USER;
/*
- * Get the frame base address and size. Limit the size to whatever we
- * can handle. If our static buffer is not sufficiently large to store
- * the entire frame, allocate memory dynamically. It is then later
- * freed by put_frame().
+ * Get the (rudimentary) state of the process. The zombie flag is also
+ * in the proc_list entry but it just may be set since we obtained that
+ * entry, in which case we'd end up with the wrong state here.
*/
- base = mproc[slot - NR_TASKS].mp_frame_addr;
- size = mproc[slot - NR_TASKS].mp_frame_len;
-
- if (size < sizeof(size_t)) return FALSE;
-
- if (size > ARG_MAX) size = ARG_MAX;
-
- if (size > sizeof(s_frame)) {
- frame = malloc(size);
-
- if (frame == NULL)
- return FALSE;
- } else
- frame = s_frame;
-
- /* Copy in the complete process frame. */
- if (sys_datacopy(proc[slot].p_endpoint, base, SELF, (vir_bytes)frame,
- (phys_bytes)size) != OK) {
- put_frame();
-
- return FALSE;
- }
-
- frame[size] = 0; /* terminate any last string */
+ if (mpd.mpd_flags & MPDF_ZOMBIE)
+ state = STATE_ZOMBIE;
+ else if (mpd.mpd_flags & MPDF_RUNNABLE)
+ state = STATE_RUN;
+ else if (mpd.mpd_flags & MPDF_STOPPED)
+ state = STATE_STOP;
+ else
+ state = STATE_SLEEP;
- nargs = *(size_t *)frame;
- if (nargs < 1 ||
- sizeof(size_t) + sizeof(char *) * (nargs + 1) > size) {
- put_frame();
+ /* Get the process's effective user ID. */
+ if (!task)
+ uid = proc_list[slot - NR_TASKS].mpl_uid;
+ else
+ uid = 0;
- return FALSE;
- }
+ /* Get memory usage. We do not care if this fails. */
+ memset(&vui, 0, sizeof(vui));
+ if (!(mpd.mpd_flags & MPDF_ZOMBIE))
+ (void)vm_info_usage(mpd.mpd_endpoint, &vui);
- *basep = base;
- *sizep = size;
- *nargsp = nargs;
+ /* Spaces in the process name would mess up the output format. */
+ if ((p = strchr(mpd.mpd_name, ' ')) != NULL)
+ *p = '\0';
- /* The caller now has to called put_frame() to clean up. */
- return TRUE;
+ /* Print all the information. */
+ buf_printf("%d %c %d %s %c %d %d %u %u "
+ "%"PRIu64" %"PRIu64" %"PRIu64" %lu %d %u\n",
+ PSINFO_VERSION, /* information version */
+ type, /* process type */
+ mpd.mpd_endpoint, /* process endpoint */
+ mpd.mpd_name, /* process name */
+ state, /* process state letter */
+ mpd.mpd_blocked_on, /* endpt blocked on, or NONE */
+ mpd.mpd_priority, /* process priority */
+ mpd.mpd_user_time, /* user time */
+ mpd.mpd_sys_time, /* system time */
+ mpd.mpd_cycles, /* execution cycles */
+ mpd.mpd_kipc_cycles, /* kernel IPC cycles */
+ mpd.mpd_kcall_cycles, /* kernel call cycles */
+ vui.vui_total, /* total memory */
+ mpd.mpd_nice, /* nice value */
+ uid /* effective user ID */
+ );
}
/*
static void
pid_cmdline(int slot)
{
- vir_bytes base, size, ptr;
- size_t i, len, nargs;
- char **argv;
+ char buf[BUF_SIZE];
+ int mib[] = { CTL_KERN, KERN_PROC_ARGS, 0, KERN_PROC_ARGV };
+ size_t oldlen;
+ pid_t pid;
- if (!get_frame(slot, &base, &size, &nargs))
+ /* Kernel tasks and zombies have no memory. */
+ if ((pid = pid_from_slot(slot)) <= 0 || is_zombie(slot))
return;
- argv = (char **)&frame[sizeof(size_t)];
-
- for (i = 0; i < nargs; i++) {
- ptr = (vir_bytes)argv[i] - base;
+ mib[2] = proc_list[slot - NR_TASKS].mpl_pid;
- /* Check for bad pointers. */
- if ((long)ptr < 0L || ptr >= size)
- break;
+ /* TODO: zero-copy into the main output buffer */
+ oldlen = sizeof(buf);
- len = strlen(&frame[ptr]) + 1;
-
- buf_append(&frame[ptr], len);
- }
+ if (__sysctl(mib, __arraycount(mib), buf, &oldlen, NULL, 0) != 0)
+ return;
- put_frame();
+ buf_append(buf, oldlen);
}
/*
static void
pid_environ(int slot)
{
- vir_bytes base, size, ptr;
- size_t nargs, off, len;
- char **envp;
+ char buf[BUF_SIZE];
+ int mib[] = { CTL_KERN, KERN_PROC_ARGS, 0, KERN_PROC_ENV };
+ size_t oldlen;
+ pid_t pid;
- if (!get_frame(slot, &base, &size, &nargs))
+ /* Kernel tasks and zombies have no memory. */
+ if ((pid = pid_from_slot(slot)) <= 0 || is_zombie(slot))
return;
- off = sizeof(size_t) + sizeof(char *) * (nargs + 1);
- envp = (char **)&frame[off];
-
- for (;;) {
- /* Make sure there is no buffer overrun. */
- if (off + sizeof(char *) > size)
- break;
-
- ptr = (vir_bytes) *envp;
-
- /* Stop at the terminating NULL pointer. */
- if (ptr == 0L)
- break;
+ mib[2] = proc_list[slot - NR_TASKS].mpl_pid;
- ptr -= base;
+ /* TODO: zero-copy into the main output buffer */
+ oldlen = sizeof(buf);
- /* Check for bad pointers. */
- if ((long)ptr < 0L || ptr >= size)
- break;
-
- len = strlen(&frame[ptr]) + 1;
-
- buf_append(&frame[ptr], len);
-
- off += sizeof(char *);
- envp++;
- }
+ if (__sysctl(mib, __arraycount(mib), buf, &oldlen, NULL, 0) != 0)
+ return;
- put_frame();
+ buf_append(buf, oldlen);
}
/*
* Print the virtual memory regions of a process.
*/
static void
-dump_regions(int slot)
+pid_map(int slot)
{
+ struct minix_proc_data mpd;
struct vm_region_info vri[MAX_VRI_COUNT];
vir_bytes next;
+ pid_t pid;
int i, r, count;
+ /* Kernel tasks and zombies have no memory. */
+ if ((pid = pid_from_slot(slot)) <= 0 || is_zombie(slot))
+ return;
+
+ /* Get the process endpoint. */
+ if (get_proc_data(pid, &mpd) != OK)
+ return;
+
count = 0;
next = 0;
do {
- r = vm_info_region(proc[slot].p_endpoint, vri, MAX_VRI_COUNT,
+ r = vm_info_region(mpd.mpd_endpoint, vri, MAX_VRI_COUNT,
&next);
if (r <= 0)
}
} while (r == MAX_VRI_COUNT);
}
-
-/*
- * Print a memory map of the process. Obtain the information from VM.
- */
-static void
-pid_map(int slot)
-{
-
- /* Zombies have no memory. */
- if (is_zombie(slot))
- return;
-
- /* Kernel tasks also have no memory. */
- if (proc[slot].p_nr >= 0)
- dump_regions(slot);
-}
ssize_t read_hook(struct inode *inode, char *ptr, size_t len, off_t off,
cbdata_t cbdata);
int rdlink_hook(struct inode *inode, char *ptr, size_t max, cbdata_t cbdata);
+pid_t pid_from_slot(int slot);
void out_of_inodes(void);
/* util.c */
#include "inc.h"
-typedef struct proc ixfer_proc_t;
-typedef struct fproc ixfer_fproc_t;
-typedef struct mproc ixfer_mproc_t;
-
-ixfer_proc_t proc[NR_PROCS + NR_TASKS];
-ixfer_mproc_t mproc[NR_PROCS];
-ixfer_fproc_t fproc[NR_PROCS];
+struct minix_proc_list proc_list[NR_PROCS];
static int nr_pid_entries;
/*
- * Return whether the given slot is in use by a process.
+ * Return a PID for the given slot, or 0 if the slot is not in use.
*/
-static int
-slot_in_use(int slot)
+pid_t
+pid_from_slot(int slot)
{
- /*
- * For kernel tasks, check only the kernel slot. Tasks do not have a
- * PM/VFS process slot.
- */
+ /* All kernel tasks are always present.*/
if (slot < NR_TASKS)
- return (proc[slot].p_rts_flags != RTS_SLOT_FREE);
+ return (pid_t)(slot - NR_TASKS);
+
+ /* For regular processes, check the process list. */
+ if (proc_list[slot - NR_TASKS].mpl_flags & MPLF_IN_USE)
+ return proc_list[slot - NR_TASKS].mpl_pid;
+ else
+ return 0;
- /* For regular processes, check only the PM slot. Do not check the
- * kernel slot, because that would skip zombie processes. The PID
- * check should be redundant, but if it fails, procfs could crash.
- */
- return ((mproc[slot - NR_TASKS].mp_flags & IN_USE) &&
- mproc[slot - NR_TASKS].mp_pid != 0);
}
/*
get_inode_stat(node, &stat);
- return (stat.uid == mproc[slot - NR_TASKS].mp_effuid &&
- stat.gid == mproc[slot - NR_TASKS].mp_effgid);
+ return (stat.uid == proc_list[slot - NR_TASKS].mpl_uid &&
+ stat.gid == proc_list[slot - NR_TASKS].mpl_gid);
}
/*
stat->uid = SUPER_USER;
stat->gid = SUPER_USER;
} else {
- stat->uid = mproc[slot - NR_TASKS].mp_effuid;
- stat->gid = mproc[slot - NR_TASKS].mp_effgid;
+ stat->uid = proc_list[slot - NR_TASKS].mpl_uid;
+ stat->gid = proc_list[slot - NR_TASKS].mpl_gid;
}
stat->size = 0;
}
/*
- * Get the process table from the kernel. Check the magic number in the table
- * entries.
- */
-static int
-update_proc_table(void)
-{
- int r, slot;
-
- if ((r = sys_getproctab(proc)) != OK) return r;
-
- for (slot = 0; slot < NR_PROCS + NR_TASKS; slot++) {
- if (proc[slot].p_magic != PMAGIC) {
- printf("PROCFS: system version mismatch!\n");
-
- return EINVAL;
- }
- }
-
- return OK;
-}
-
-/*
- * Get the process table from PM. Check the magic number in the table entries.
- */
-static int
-update_mproc_table(void)
-{
- int r, slot;
-
- r = getsysinfo(PM_PROC_NR, SI_PROC_TAB, mproc, sizeof(mproc));
- if (r != OK) return r;
-
- for (slot = 0; slot < NR_PROCS; slot++) {
- if (mproc[slot].mp_magic != MP_MAGIC) {
- printf("PROCFS: PM version mismatch!\n");
-
- return EINVAL;
- }
- }
-
- return OK;
-}
-
-/*
- * Get the process table from VFS.
+ * Get the process listing from the MIB service.
*/
static int
-update_fproc_table(void)
-{
-
- return getsysinfo(VFS_PROC_NR, SI_PROC_TAB, fproc, sizeof(fproc));
-}
-
-/*
- * Get the process tables from the kernel, PM, and VFS.
- */
-static int
-update_tables(void)
+update_list(void)
{
+ const int mib[] = { CTL_MINIX, MINIX_PROC, PROC_LIST };
+ size_t size;
int r;
- if ((r = update_proc_table()) != OK) return r;
-
- if ((r = update_mproc_table()) != OK) return r;
-
- if ((r = update_fproc_table()) != OK) return r;
+ size = sizeof(proc_list);
+ if (__sysctl(mib, __arraycount(mib), proc_list, &size, NULL, 0) != 0)
+ printf("ProcFS: unable to obtain process list (%d)\n", -errno);
return OK;
}
{
int i, r;
- if ((r = update_tables()) != OK)
+ if ((r = update_list()) != OK)
return r;
/*
/*
* If the process slot is not in use, delete the associated
- * inode.
+ * inode. Otherwise, get the process ID.
*/
- if (!slot_in_use(i)) {
+ if ((pid = pid_from_slot(i)) == 0) {
delete_inode(node);
continue;
}
- /* Otherwise, get the process ID. */
- if (i < NR_TASKS)
- pid = (pid_t)(i - NR_TASKS);
- else
- pid = mproc[i - NR_TASKS].mp_pid;
-
/*
* If there is an old entry, see if the pid matches the current
* entry, and the owner is still the same. Otherwise, delete
/* Second pass: add new entries. */
for (i = 0; i < NR_PROCS + NR_TASKS; i++) {
/* If the process slot is not in use, skip this slot. */
- if (!slot_in_use(i))
+ if ((pid = pid_from_slot(i)) == 0)
continue;
/*
if (i < NR_TASKS)
pid = (pid_t)(i - NR_TASKS);
else
- pid = mproc[i - NR_TASKS].mp_pid;
+ pid = proc_list[i - NR_TASKS].mpl_pid;
/* Add the entry for the process slot. */
snprintf(name, PNAME_MAX + 1, "%d", pid);
assert(slot >= 0 && slot < NR_TASKS + NR_PROCS);
/* If this process is already gone, delete the directory now. */
- if (!slot_in_use(slot)) {
+ if (pid_from_slot(slot) == 0) {
delete_inode(parent);
return;
now = getticks();
if (last_update != now) {
- update_tables();
+ update_list();
last_update = now;
}
{
if (node == get_root_inode()) {
- update_tables();
+ update_list();
construct_pid_dirs();
} else if (dir_is_pid(node))
#ifndef _MINIX_ENDPOINT_H
#define _MINIX_ENDPOINT_H 1
-#ifdef _MINIX_SYSTEM
-
#include <minix/sys_config.h>
#include <minix/com.h>
#include <limits.h>
#define _ENDPOINT_P(e) \
((((e)+MAX_NR_TASKS) & (_ENDPOINT_GENERATION_SIZE - 1)) - MAX_NR_TASKS)
-#endif /* _MINIX_SYSTEM */
-
#endif
#ifndef _MINIX_PROCFS_H
#define _MINIX_PROCFS_H
-/* The compatibility model is as follows. The current format should be retained
+/*
+ * The compatibility model is as follows. The current format should be retained
* for as long as possible; new fields can be added at the end of the line,
* because ps/top only read as much as they know of from the start of the line.
* Once fields (really) have to be removed, or the whole line becomes too big
* increased PSINFO_VERSION at the beginning. That way, older ps/top copies
* will not misinterpret the new fields, but rather fail cleanly.
*/
-#define PSINFO_VERSION 0
+#define PSINFO_VERSION 1
/* Process types. */
#define TYPE_TASK 'T'
/* General process states. */
#define STATE_SLEEP 'S'
-#define STATE_WAIT 'W'
#define STATE_ZOMBIE 'Z'
#define STATE_RUN 'R'
#define STATE_STOP 'T'
-/* PM sleep states. */
-#define PSTATE_NONE '-'
-#define PSTATE_WAITING 'W'
-#define PSTATE_SIGSUSP 'S'
-
-/* VFS block states. */
-#define FSTATE_NONE '-'
-#define FSTATE_PIPE 'P'
-#define FSTATE_LOCK 'L'
-#define FSTATE_POPEN 'O'
-#define FSTATE_SELECT 'S'
-#define FSTATE_TASK 'T'
-#define FSTATE_UNKNOWN '?'
-
#endif /* _MINIX_PROCFS_H */
/* MINIX3-specific sysctl(2) extensions. */
#include <sys/sysctl.h>
+#include <minix/endpoint.h>
/* Special values. */
#define SYSCTL_NODE_FN ((sysctlfn)0x1) /* node is function-driven */
*/
#define MINIX_TEST 0
#define MINIX_MIB 1
+#define MINIX_PROC 2
/*
* These identifiers, under MINIX_TEST, are used by test87 to test the MIB
#define MIB_NODES 1
#define MIB_OBJECTS 2
+/* Identifiers for subnodes of MINIX_PROC. */
+#define PROC_LIST 1
+#define PROC_DATA 2
+
+/* Structure used for PROC_LIST. Not part of the ABI. Used by ProcFS only. */
+struct minix_proc_list {
+ uint32_t mpl_flags; /* process flags (MPLF_) */
+ pid_t mpl_pid; /* process PID */
+ uid_t mpl_uid; /* effective user ID */
+ gid_t mpl_gid; /* effective group ID */
+};
+#define MPLF_IN_USE 0x01 /* process slot is in use */
+#define MPLF_ZOMBIE 0x02 /* process is a zombie */
+
+/* Structure used for PROC_DATA. Not part of the ABI. Used by ProcFS only. */
+struct minix_proc_data {
+ endpoint_t mpd_endpoint; /* process endpoint */
+ uint32_t mpd_flags; /* procses flags (MPDF_) */
+ endpoint_t mpd_blocked_on; /* blocked on other process, or NONE */
+ uint32_t mpd_priority; /* current process priority */
+ uint32_t mpd_user_time; /* user time, in clock ticks */
+ uint32_t mpd_sys_time; /* system time, in clock ticks */
+ uint64_t mpd_cycles; /* cycles spent by the process */
+ uint64_t mpd_kipc_cycles; /* cycles spent on kernel IPC */
+ uint64_t mpd_kcall_cycles; /* cycles spent on kernel calls */
+ uint32_t mpd_nice; /* nice value */
+ char mpd_name[16]; /* short process name */
+};
+#define MPDF_SYSTEM 0x01 /* process is a system service */
+#define MPDF_ZOMBIE 0x02 /* process is a zombie */
+#define MPDF_RUNNABLE 0x04 /* process is runnable */
+#define MPDF_STOPPED 0x08 /* process is stopped */
+
+/*
+ * Expose sysctl(2) to system services (ProcFS in particular), so as to avoid
+ * including the CTL_USER subtree handling of sysctl(3) as well.
+ */
+int __sysctl(const int *, unsigned int, void *, size_t *, const void *,
+ size_t);
+
#endif /* !_MINIX_SYSCTL_H */
mmap.o nanosleep.o open.o pread.o pwrite.o read.o sbrk.o \
select.o setuid.o sigprocmask.o stack_utils.o stat.o stime.o \
svrctl.o syscall.o _ucontext.o umask.o unlink.o wait4.o write.o \
- kill.o
+ kill.o __sysctl.o
${f} ${f:C/\.o/.bc/}: ${LIBMINIXCDIR}/sys/${f:C/\.o/.c/}
OBJS+= ${f}
CLEANFILES+= ${f}
struct mib_newp *);
ssize_t mib_kern_proc_args(struct mib_call *, struct mib_node *,
struct mib_oldp *, struct mib_newp *);
+ssize_t mib_minix_proc_list(struct mib_call *, struct mib_node *,
+ struct mib_oldp *, struct mib_newp *);
+ssize_t mib_minix_proc_data(struct mib_call *, struct mib_node *,
+ struct mib_oldp *, struct mib_newp *);
/* subtree modules */
void mib_kern_init(struct mib_node *);
"dynamically allocated MIB objects"),
};
+static struct mib_node mib_minix_proc_table[] = {
+/* 1*/ [PROC_LIST] = MIB_FUNC(_P | _RO | CTLTYPE_STRUCT, 0,
+ mib_minix_proc_list, "list",
+ "Process list"),
+/* 2*/ [PROC_DATA] = MIB_FUNC(_P | _RO | CTLTYPE_NODE, 0,
+ mib_minix_proc_data, "data",
+ "Process data"),
+};
+
static struct mib_node mib_minix_table[] = {
#if MINIX_TEST_SUBTREE
/* 0*/ [MINIX_TEST] = MIB_NODE(_RW | CTLFLAG_HIDDEN,
#endif /* MINIX_TEST_SUBTREE */
/* 1*/ [MINIX_MIB] = MIB_NODE(_P | _RO, mib_minix_mib_table,
"mib", "MIB service information"),
+/* 2*/ [MINIX_PROC] = MIB_NODE(_P | _RO, mib_minix_proc_table,
+ "proc", "Process information for ProcFS"),
};
/*
assert(off <= oldlen);
return off;
}
+
+/*
+ * Implementation of CTL_MINIX MINIX_PROC PROC_LIST.
+ */
+ssize_t
+mib_minix_proc_list(struct mib_call * call __unused,
+ struct mib_node * node __unused, struct mib_oldp * oldp,
+ struct mib_newp * newp __unused)
+{
+ struct minix_proc_list mpl[NR_PROCS];
+ struct minix_proc_list *mplp;
+ struct mproc *mp;
+ unsigned int mslot;
+
+ if (oldp == NULL)
+ return sizeof(mpl);
+
+ if (!update_tables())
+ return EINVAL;
+
+ memset(&mpl, 0, sizeof(mpl));
+
+ mplp = mpl;
+ mp = mproc_tab;
+
+ for (mslot = 0; mslot < NR_PROCS; mslot++, mplp++, mp++) {
+ if (!(mp->mp_flags & IN_USE) || mp->mp_pid <= 0)
+ continue;
+
+ mplp->mpl_flags = MPLF_IN_USE;
+ if (mp->mp_flags & (TRACE_ZOMBIE | ZOMBIE))
+ mplp->mpl_flags |= MPLF_ZOMBIE;
+ mplp->mpl_pid = mp->mp_pid;
+ mplp->mpl_uid = mp->mp_effuid;
+ mplp->mpl_gid = mp->mp_effgid;
+ }
+
+ return mib_copyout(oldp, 0, &mpl, sizeof(mpl));
+}
+
+/*
+ * Implementation of CTL_MINIX MINIX_PROC PROC_DATA.
+ */
+ssize_t
+mib_minix_proc_data(struct mib_call * call, struct mib_node * node __unused,
+ struct mib_oldp * oldp, struct mib_newp * newp __unused)
+{
+ struct minix_proc_data mpd;
+ struct proc *kp;
+ int kslot, mslot = 0;
+ unsigned int mflags;
+ pid_t pid;
+
+ /*
+ * It is currently only possible to retrieve the process data for a
+ * particular PID, which must be given as the last name component.
+ */
+ if (call->call_namelen != 1)
+ return EINVAL;
+
+ pid = (pid_t)call->call_name[0];
+
+ if (!update_tables())
+ return EINVAL;
+
+ /*
+ * Unlike the CTL_KERN nodes, we use the ProcFS semantics here: if the
+ * given PID is negative, it is a kernel task; otherwise, it identifies
+ * a user process. A request for PID 0 will result in ESRCH.
+ */
+ if (pid < 0) {
+ if (pid < -NR_TASKS)
+ return ESRCH;
+
+ kslot = pid + NR_TASKS;
+ assert(kslot < NR_TASKS);
+ } else {
+ if ((mslot = get_mslot(pid)) == NO_SLOT)
+ return ESRCH;
+
+ kslot = NR_TASKS + mslot;
+ }
+
+ if (oldp == NULL)
+ return sizeof(mpd);
+
+ kp = &proc_tab[kslot];
+
+ mflags = (pid > 0) ? mproc_tab[mslot].mp_flags : 0;
+
+ memset(&mpd, 0, sizeof(mpd));
+ mpd.mpd_endpoint = kp->p_endpoint;
+ if (mflags & PRIV_PROC)
+ mpd.mpd_flags |= MPDF_SYSTEM;
+ if (mflags & (TRACE_ZOMBIE | ZOMBIE))
+ mpd.mpd_flags |= MPDF_ZOMBIE;
+ else if ((mflags & TRACE_STOPPED) || RTS_ISSET(kp, RTS_P_STOP))
+ mpd.mpd_flags |= MPDF_STOPPED;
+ else if (proc_is_runnable(kp))
+ mpd.mpd_flags |= MPDF_RUNNABLE;
+ mpd.mpd_blocked_on = P_BLOCKEDON(kp);
+ mpd.mpd_priority = kp->p_priority;
+ mpd.mpd_user_time = kp->p_user_time;
+ mpd.mpd_sys_time = kp->p_sys_time;
+ mpd.mpd_cycles = kp->p_cycles;
+ mpd.mpd_kipc_cycles = kp->p_kipc_cycles;
+ mpd.mpd_kcall_cycles = kp->p_kcall_cycles;
+ if (kslot >= NR_TASKS) {
+ mpd.mpd_nice = mproc_tab[mslot].mp_nice;
+ strlcpy(mpd.mpd_name, mproc_tab[mslot].mp_name,
+ sizeof(mpd.mpd_name));
+ } else
+ strlcpy(mpd.mpd_name, kp->p_name, sizeof(mpd.mpd_name));
+
+ return mib_copyout(oldp, 0, &mpd, sizeof(mpd));
+}
/* Author: Ben Gras <beng@few.vu.nl> 17 march 2006 */
-/* Modified for ProcFS by Alen Stojanov and David van Moolenbroek */
#define _MINIX_SYSTEM 1
u64_t p_cpucycles[CPUTIMENAMES];
int p_priority;
endpoint_t p_blocked;
- time_t p_user_time;
+ clock_t p_user_time;
vir_bytes p_memory;
uid_t p_effuid;
int p_nice;
struct proc *proc = NULL, *prev_proc = NULL;
-static void parse_file(pid_t pid)
+static void
+parse_file(pid_t pid)
{
char path[PATH_MAX], name[256], type, state;
- int version, endpt, effuid;
- unsigned long cycles_hi, cycles_lo;
+ int version, endpt;
FILE *fp;
struct proc *p;
int slot;
- int i;
sprintf(path, "%d/psinfo", pid);
slot = SLOT_NR(endpt);
- if(slot < 0 || slot >= nr_total) {
- fprintf(stderr, "top: unreasonable endpoint number %d\n", endpt);
+ if (slot < 0 || slot >= nr_total) {
+ fprintf(stderr, "top: unreasonable endpoint number %d\n",
+ endpt);
fclose(fp);
return;
}
p->p_endpoint = endpt;
p->p_pid = pid;
- if (fscanf(fp, " %255s %c %d %d %llu %*u %lu %lu",
- name, &state, &p->p_blocked, &p->p_priority,
- &p->p_user_time, &cycles_hi, &cycles_lo) != 7) {
-
+ if (fscanf(fp, " %255s %c %d %d %u %*u %"PRIu64" %"PRIu64" %"PRIu64
+ " %lu %d %u",
+ name, &state, &p->p_blocked, &p->p_priority, &p->p_user_time,
+ &p->p_cpucycles[0], &p->p_cpucycles[1], &p->p_cpucycles[2],
+ &p->p_memory, &p->p_nice, &p->p_effuid) != 11) {
fclose(fp);
return;
}
- strncpy(p->p_name, name, sizeof(p->p_name)-1);
- p->p_name[sizeof(p->p_name)-1] = 0;
+ strlcpy(p->p_name, name, sizeof(p->p_name));
if (state != STATE_RUN)
p->p_flags |= BLOCKED;
- p->p_cpucycles[0] = make64(cycles_lo, cycles_hi);
- p->p_memory = 0L;
-
- if (!(p->p_flags & IS_TASK)) {
- int j;
- if ((j=fscanf(fp, " %lu %*u %*u %*c %*d %*u %u %*u %d %*c %*d %*u",
- &p->p_memory, &effuid, &p->p_nice)) != 3) {
-
- fclose(fp);
- return;
- }
-
- p->p_effuid = effuid;
- } else p->p_effuid = 0;
-
- for(i = 1; i < CPUTIMENAMES; i++) {
- if(fscanf(fp, " %lu %lu",
- &cycles_hi, &cycles_lo) == 2) {
- p->p_cpucycles[i] = make64(cycles_lo, cycles_hi);
- } else {
- p->p_cpucycles[i] = 0;
- }
- }
-
- if ((p->p_flags & IS_TASK)) {
- if(fscanf(fp, " %lu", &p->p_memory) != 1) {
- p->p_memory = 0;
- }
- }
p->p_flags |= USED;
}
get_procs();
- if (prev_proc == NULL)
+ if (prev_proc == NULL) {
+ /*
+ * A delay short enough to be unnoticable but long enough to
+ * allow for accumulation of sufficient data for the initial
+ * display not to show wildly inaccurate numbers.
+ */
+ usleep(100000);
get_procs();
+ }
if((nloads = getloadavg(loads, NLOADS)) != NLOADS) {
fprintf(stderr, "getloadavg() failed - %d loads\n", nloads);
putchar('\r');
return 0;
break;
- case 'o':
+ case ORDERKEY:
order++;
if(order > ORDER_HIGHEST)
order = 0;