diff --git a/minix/fs/procfs/glo.h b/minix/fs/procfs/glo.h index 03d573d71..fbb09d45f 100644 --- a/minix/fs/procfs/glo.h +++ b/minix/fs/procfs/glo.h @@ -1,8 +1,6 @@ #ifndef _PROCFS_GLO_H #define _PROCFS_GLO_H -#include - /* pid.c */ extern struct file pid_files[]; @@ -10,8 +8,6 @@ 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 */ diff --git a/minix/fs/procfs/inc.h b/minix/fs/procfs/inc.h index a28fe3359..5ef36958b 100644 --- a/minix/fs/procfs/inc.h +++ b/minix/fs/procfs/inc.h @@ -2,6 +2,8 @@ #define _PROCFS_INC_H #include +#include +#include #include #include #include @@ -11,9 +13,7 @@ #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" diff --git a/minix/fs/procfs/pid.c b/minix/fs/procfs/pid.c index 871047776..df80eb9fa 100644 --- a/minix/fs/procfs/pid.c +++ b/minix/fs/procfs/pid.c @@ -5,10 +5,6 @@ #include #include -#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); @@ -34,214 +30,106 @@ static int 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. + */ +int +get_proc_data(pid_t pid, struct minix_proc_data * mpd) +{ + int mib[4] = { CTL_MINIX, MINIX_PROC, PROC_DATA, pid }; + size_t oldlen; + + oldlen = sizeof(*mpd); + if (__sysctl(mib, __arraycount(mib), mpd, &oldlen, NULL, 0) != 0) + return -errno; + + return OK; +} + +/* + * 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 -pid_psinfo(int i) +pid_psinfo(int slot) { - int pi, task, state, type, p_state, f_state; - char name[PROC_NAME_LEN+1], *p; + struct minix_proc_data mpd; struct vm_usage_info vui; - pid_t ppid; + pid_t pid; + uid_t uid; + char *p; + int task, type, state; - pi = i - NR_TASKS; - task = proc[i].p_nr < 0; + if ((pid = pid_from_slot(slot)) == 0) + return; - /* 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; + if (get_proc_data(pid, &mpd) != OK) + return; + + task = (slot < NR_TASKS); /* Get the type of the process. */ if (task) type = TYPE_TASK; - else if (mproc[i].mp_flags & PRIV_PROC) + else if (mpd.mpd_flags & MPDF_SYSTEM) 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. + /* + * 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. */ - buf_printf("%d %c %d %s %c %d %d %lu %lu %lu %lu", + 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; + + /* Get the process's effective user ID. */ + if (!task) + uid = proc_list[slot - NR_TASKS].mpl_uid; + else + uid = 0; + + /* 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); + + /* Spaces in the process name would mess up the output format. */ + if ((p = strchr(mpd.mpd_name, ' ')) != NULL) + *p = '\0'; + + /* 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 */ - (int)proc[i].p_endpoint, /* process endpoint */ - name, /* process name */ + mpd.mpd_endpoint, /* process endpoint */ + mpd.mpd_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) + 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 */ ); - - 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"); -} - -/* - * If we allocated memory dynamically during a call to get_frame(), free it up - * here. - */ -static void -put_frame(void) -{ - - if (frame != s_frame) - free(frame); -} - -/* - * 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 (proc[slot].p_nr < 0 || is_zombie(slot)) - return FALSE; - - /* - * 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(). - */ - 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 */ - - nargs = *(size_t *)frame; - if (nargs < 1 || - sizeof(size_t) + sizeof(char *) * (nargs + 1) > size) { - put_frame(); - - return FALSE; - } - - *basep = base; - *sizep = size; - *nargsp = nargs; - - /* The caller now has to called put_frame() to clean up. */ - return TRUE; } /* @@ -251,28 +139,24 @@ get_frame(int slot, vir_bytes * basep, vir_bytes * sizep, size_t * nargsp) 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)]; + mib[2] = proc_list[slot - NR_TASKS].mpl_pid; - for (i = 0; i < nargs; i++) { - ptr = (vir_bytes)argv[i] - base; + /* TODO: zero-copy into the main output buffer */ + oldlen = sizeof(buf); - /* Check for bad pointers. */ - if ((long)ptr < 0L || ptr >= size) - break; + if (__sysctl(mib, __arraycount(mib), buf, &oldlen, NULL, 0) != 0) + return; - len = strlen(&frame[ptr]) + 1; - - buf_append(&frame[ptr], len); - } - - put_frame(); + buf_append(buf, oldlen); } /* @@ -282,59 +166,51 @@ pid_cmdline(int slot) 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]; + mib[2] = proc_list[slot - NR_TASKS].mpl_pid; - for (;;) { - /* Make sure there is no buffer overrun. */ - if (off + sizeof(char *) > size) - break; + /* TODO: zero-copy into the main output buffer */ + oldlen = sizeof(buf); - ptr = (vir_bytes) *envp; + if (__sysctl(mib, __arraycount(mib), buf, &oldlen, NULL, 0) != 0) + return; - /* Stop at the terminating NULL pointer. */ - if (ptr == 0L) - break; - - ptr -= base; - - /* 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++; - } - - 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) @@ -352,19 +228,3 @@ dump_regions(int slot) } } 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); -} diff --git a/minix/fs/procfs/proto.h b/minix/fs/procfs/proto.h index c9dcde0f5..7e73d4dfa 100644 --- a/minix/fs/procfs/proto.h +++ b/minix/fs/procfs/proto.h @@ -23,6 +23,7 @@ int getdents_hook(struct inode *inode, cbdata_t cbdata); 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 */ diff --git a/minix/fs/procfs/tree.c b/minix/fs/procfs/tree.c index d6a673aec..aae250f7c 100644 --- a/minix/fs/procfs/tree.c +++ b/minix/fs/procfs/tree.c @@ -2,36 +2,27 @@ #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); } /* @@ -47,8 +38,8 @@ check_owner(struct inode * node, int slot) 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); } /* @@ -68,8 +59,8 @@ make_stat(struct inode_stat * stat, int slot, int index) 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; @@ -88,72 +79,18 @@ dir_is_pid(struct inode *node) } /* - * Get the process table from the kernel. Check the magic number in the table - * entries. + * Get the process listing from the MIB service. */ 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. - */ -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; } @@ -168,7 +105,7 @@ init_tree(void) { int i, r; - if ((r = update_tables()) != OK) + if ((r = update_list()) != OK) return r; /* @@ -232,20 +169,14 @@ construct_pid_dirs(void) /* * 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 @@ -262,7 +193,7 @@ construct_pid_dirs(void) /* 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; /* @@ -276,7 +207,7 @@ construct_pid_dirs(void) 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); @@ -360,7 +291,7 @@ construct_pid_entries(struct inode * parent, char * name) 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; @@ -434,7 +365,7 @@ lookup_hook(struct inode * parent, char * name, cbdata_t __unused cbdata) now = getticks(); if (last_update != now) { - update_tables(); + update_list(); last_update = now; } @@ -473,7 +404,7 @@ getdents_hook(struct inode * node, cbdata_t __unused cbdata) { if (node == get_root_inode()) { - update_tables(); + update_list(); construct_pid_dirs(); } else if (dir_is_pid(node)) diff --git a/minix/include/minix/endpoint.h b/minix/include/minix/endpoint.h index 74ba24053..0cf3f3bb7 100644 --- a/minix/include/minix/endpoint.h +++ b/minix/include/minix/endpoint.h @@ -2,8 +2,6 @@ #ifndef _MINIX_ENDPOINT_H #define _MINIX_ENDPOINT_H 1 -#ifdef _MINIX_SYSTEM - #include #include #include @@ -70,6 +68,4 @@ #define _ENDPOINT_P(e) \ ((((e)+MAX_NR_TASKS) & (_ENDPOINT_GENERATION_SIZE - 1)) - MAX_NR_TASKS) -#endif /* _MINIX_SYSTEM */ - #endif diff --git a/minix/include/minix/procfs.h b/minix/include/minix/procfs.h index 7194da7d6..a382ea647 100644 --- a/minix/include/minix/procfs.h +++ b/minix/include/minix/procfs.h @@ -1,7 +1,8 @@ #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 @@ -9,7 +10,7 @@ * 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' @@ -18,23 +19,8 @@ /* 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 */ diff --git a/minix/include/minix/sysctl.h b/minix/include/minix/sysctl.h index 839392ea0..ebd1bfda9 100644 --- a/minix/include/minix/sysctl.h +++ b/minix/include/minix/sysctl.h @@ -4,6 +4,7 @@ /* MINIX3-specific sysctl(2) extensions. */ #include +#include /* Special values. */ #define SYSCTL_NODE_FN ((sysctlfn)0x1) /* node is function-driven */ @@ -26,6 +27,7 @@ */ #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 @@ -50,4 +52,44 @@ #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 */ diff --git a/minix/lib/libminc/Makefile b/minix/lib/libminc/Makefile index 804c8b358..7b545093b 100644 --- a/minix/lib/libminc/Makefile +++ b/minix/lib/libminc/Makefile @@ -289,7 +289,7 @@ CLEANFILES+= ${f:C/\.o/.bc/} 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} diff --git a/minix/servers/mib/mib.h b/minix/servers/mib/mib.h index 089628435..e9c598aef 100644 --- a/minix/servers/mib/mib.h +++ b/minix/servers/mib/mib.h @@ -276,6 +276,10 @@ ssize_t mib_kern_proc2(struct mib_call *, struct mib_node *, struct mib_oldp *, 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 *); diff --git a/minix/servers/mib/minix.c b/minix/servers/mib/minix.c index dbcbdcdcf..683d95063 100644 --- a/minix/servers/mib/minix.c +++ b/minix/servers/mib/minix.c @@ -52,6 +52,15 @@ static struct mib_node mib_minix_mib_table[] = { "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, @@ -60,6 +69,8 @@ static struct mib_node mib_minix_table[] = { #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"), }; /* diff --git a/minix/servers/mib/proc.c b/minix/servers/mib/proc.c index 1c031872a..277497ff0 100644 --- a/minix/servers/mib/proc.c +++ b/minix/servers/mib/proc.c @@ -1167,3 +1167,119 @@ mib_kern_proc_args(struct mib_call * call, struct mib_node * node __unused, 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)); +} diff --git a/minix/usr.bin/mtop/mtop.c b/minix/usr.bin/mtop/mtop.c index cafa384ab..858d9e8da 100644 --- a/minix/usr.bin/mtop/mtop.c +++ b/minix/usr.bin/mtop/mtop.c @@ -1,6 +1,5 @@ /* Author: Ben Gras 17 march 2006 */ -/* Modified for ProcFS by Alen Stojanov and David van Moolenbroek */ #define _MINIX_SYSTEM 1 @@ -78,7 +77,7 @@ struct proc { 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; @@ -87,15 +86,14 @@ struct proc { 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); @@ -119,8 +117,9 @@ static void parse_file(pid_t 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; } @@ -135,48 +134,19 @@ static void parse_file(pid_t pid) 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; @@ -558,8 +528,15 @@ static void showtop(int cputimemode, int r) } 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); @@ -694,7 +671,7 @@ int main(int argc, char *argv[]) putchar('\r'); return 0; break; - case 'o': + case ORDERKEY: order++; if(order > ORDER_HIGHEST) order = 0;