]> Zhao Yanbai Git Server - minix.git/commitdiff
ProcFS: get process information from MIB service 55/3255/2
authorDavid van Moolenbroek <david@minix3.org>
Sun, 8 Nov 2015 11:56:52 +0000 (11:56 +0000)
committerLionel Sambuc <lionel.sambuc@gmail.com>
Wed, 13 Jan 2016 19:32:54 +0000 (20:32 +0100)
Instead of pulling in process tables itself, ProcFS now queries the
MIB service for process information.  This reduces ProcFS's memory
usage by about 1MB.  The change does have two negative consequences.

First, getting all the original /proc/<pid>/psinfo fields filled in
would take a lot of extra effort.  Since the only program that uses
those files at all is mtop(1), we reformat psinfo to expose only the
information used by mtop(1).  This means that with this patch, older
copies of MINIX3 ps and top will cease to work.

Second, since both MIB and ProcFS update their own view of the
process list only once per clock tick, ProcFS' view may now be
outdated by up to two clock ticks.  This is unlikely to pose a
problem in practice.

Change-Id: Iaa6b60450c8fb52d092962394d33d08bd638bc01

13 files changed:
minix/fs/procfs/glo.h
minix/fs/procfs/inc.h
minix/fs/procfs/pid.c
minix/fs/procfs/proto.h
minix/fs/procfs/tree.c
minix/include/minix/endpoint.h
minix/include/minix/procfs.h
minix/include/minix/sysctl.h
minix/lib/libminc/Makefile
minix/servers/mib/mib.h
minix/servers/mib/minix.c
minix/servers/mib/proc.c
minix/usr.bin/mtop/mtop.c

index 03d573d71f3dec279a0c7f1aaf0effe6f2bc3256..fbb09d45fe49a9e76267c491493b5d8cbe3be52e 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _PROCFS_GLO_H
 #define _PROCFS_GLO_H
 
-#include <minix/param.h>
-
 /* 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 */
index a28fe3359dbe422be77a111fbe0f00fe92e31822..5ef36958b668112cfbbfa2231d8e39f9ecb0ede8 100644 (file)
@@ -2,6 +2,8 @@
 #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>
@@ -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"
index 8710477761da696f190c5bbf501a34974dcf160f..df80eb9fadfaf6ec6bd4d452df1e5620d4650248 100644 (file)
@@ -5,10 +5,6 @@
 #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);
@@ -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.
  */
-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 */
+       );
 }
 
 /*
@@ -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)];
-
-       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);
 }
 
 /*
@@ -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];
-
-       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)
@@ -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);
-}
index c9dcde0f53bf1283e45cf4286718d4a6fbb526e3..7e73d4dfacb6ae57d2d29ddea75fbbc24b32f188 100644 (file)
@@ -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 */
index d6a673aecc943669bf6075be0c419cfc825736b4..aae250f7c1646419d250d0d9c2f7d9567446e483 100644 (file)
@@ -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.
- */
-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;
 }
@@ -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))
index 74ba24053b4bd5549cc568aa96632f5c7101a9d4..0cf3f3bb7f73a7bcc2c24eaaf1cc8c0711aca81e 100644 (file)
@@ -2,8 +2,6 @@
 #ifndef _MINIX_ENDPOINT_H
 #define _MINIX_ENDPOINT_H 1
 
-#ifdef _MINIX_SYSTEM
-
 #include <minix/sys_config.h>
 #include <minix/com.h>
 #include <limits.h>
@@ -70,6 +68,4 @@
 #define _ENDPOINT_P(e) \
        ((((e)+MAX_NR_TASKS) & (_ENDPOINT_GENERATION_SIZE - 1)) - MAX_NR_TASKS)
 
-#endif /* _MINIX_SYSTEM */
-
 #endif
index 7194da7d67ff723f86aa5222dc5549899f8435b9..a382ea647b0b23d7777ecd1364910a128e32dfd8 100644 (file)
@@ -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'
 
 /* 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 */
index 839392ea0295ba99d51ed4147fa3cdeeecd11068..ebd1bfda9788fd4311c46af136bd81546fe8ac6c 100644 (file)
@@ -4,6 +4,7 @@
 /* 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 */
@@ -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
 #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 */
index 804c8b35833e4658ea9f75ff44f814402025e6ed..7b545093b668b43d0174196671bddc042f3d4829 100644 (file)
@@ -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}
index 0896284350780fa093dd4a29464c0a808db39afe..e9c598aef8520445cd5b83b193a78f177c323e63 100644 (file)
@@ -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 *);
index dbcbdcdcfb8bb650800e0fe24f962d27c64d4c29..683d9506319b17a601b8f747e03078120e52b262 100644 (file)
@@ -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"),
 };
 
 /*
index 1c031872aec6c0dd79ed03403346fae4470b0b40..277497ff08fc6583e776eb15aca91e8ab8ecde8b 100644 (file)
@@ -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));
+}
index cafa384ab0380a5f339c76b7ff9652e6c19e6fb3..858d9e8da946433ee28ee437de7f73b180424f8f 100644 (file)
@@ -1,6 +1,5 @@
 
 /* Author: Ben Gras <beng@few.vu.nl>  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;