home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
zip
/
mint
/
mntutl95.lzh
/
MNTUTL95
/
TOP.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-03
|
14KB
|
576 lines
/*
ps.c: a program to print MiNT process statuses
Coded: 3/24/1991 by Tony Reynolds, cctony@sgisci1.ocis.olemiss.edu
For use with: MiNT release 0.7
Updated: 3/29/1991 by Eric Smith for MiNT version 0.8
Updated and completely revised from 'ps' into 'top' by AKP 8/91.
Link with -lcurses and -ltermcap. Beware! Bammi's GNU curses
makefile actually links the termcap object files into curses.olb,
so changing them and recompiling only termcap.olb will have no effect!
Updated some more 11/91 by Allan Pratt for MiNT version 0.9
*/
#include <stdio.h>
#include <stdlib.h>
#include <osbind.h>
#include <errno.h>
#include <basepage.h>
#include <ioctl.h>
#include <time.h>
#include <curses.h>
#include <signal.h>
#include <mintbind.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#ifndef PCTXTSIZE
#define PCTXTSIZE (('P'<<8)|3)
#endif
#define MINWIDTH 36 /* this is the width of everything before the command */
#define DEF_PTABSIZ 99 /* this is how many process' worth of table to have */
struct status { /* defines values for internal->external process states */
int mint; /* what MiNT knows */
char desc[6]; /* a textual description for above */
} proc_stat[] = {
0, "Run ", /* really "run" but "top" is always running! */
0x01, "Run ",
0x20, "Wait ",
0x21, "Sleep",
0x22, "Exit ",
0x02, "TSR ",
0x24, "Stop ",
-1, "?????"
};
typedef struct _context {
long regs[15]; /* registers d0-d7, a0-a6 */
long usp; /* user stack pointer (a7) */
short sr; /* status register */
long pc; /* program counter */
long ssp; /* supervisor stack pointer */
long term_vec; /* GEMDOS terminate vector (0x102) */
/* these fields were added in MiNT 0.9 -- ERS */
char fstate[216]; /* FPU internal state */
char fregs[12*8]; /* registers fp0-fp7 */
long fctrl[3]; /* FPCR/FPSR/FPIAR */
short sfmt; /* stack frame format identifier */
long iar; /* instruction address */
short internal[4]; /* four words of internal info */
} CONTEXT;
struct pinfo {
long magic;
char *base;
short pid, ppid, pgrp;
short ruid, rgid;
short euid, egid;
short flags;
short pri;
short wait_q;
long wait_cond;
unsigned long systime, usrtime, chldstime, chldutime;
unsigned long maxmem, maxdata, maxcore, maxcpu;
short domain;
short curpri;
};
/* open the process named "name" */
int
open_proc(name)
char *name;
{
static char pname[32] = "u:\\proc\\";
strcpy(pname+8, name);
return open(pname, 0);
}
struct ptab {
short pid;
short used;
long lasttime;
char line[2]; /* make sure sizeof(struct ptab) is even */
} *ptab; /* an array of these gets malloc'ed */
#define INCPTAB(p) ((struct ptab *)(((char *)p) + sizeof(struct ptab) + width))
int garbage = 0; /* when set, screen needs total update */
void
quit(sig)
long sig;
{
/* move to bottom of screen */
mvcur(0, COLS - 1, LINES - 1, 0);
endwin();
exit(0);
}
void
usage()
{
puts("Usage: top [-s sleeptime] [-w width] [-n nlines] [-r]");
puts("-r sorts procs in decreasing PID order; usually increasing PID.");
puts("TOP ONLY RUNS UNDER MiNT. Use '?' to get help.");
exit(1);
}
void
dokill(s)
char *s;
{
int signum = SIGTERM;
int pid;
char *p;
char hold;
while (isspace(*s)) s++;
if (*s == '-') {
p = ++s;
while (*p && !isspace(*p)) p++;
hold = *p;
*p = '\0';
if (p != s) signum = atoi(s);
*p = hold;
if (!signum) signum = SIGTERM;
s = p;
}
while (isspace(*s)) s++;
while (*s) {
p = s;
while (*p && !isspace(*p)) p++;
hold = *p;
*p = '\0';
pid = atoi(s);
*p = hold;
s = p;
if (pid) (void)Pkill(pid,signum);
while (isspace(*s)) s++;
}
}
void
dorenice(s)
char *s;
{
int niceval;
int pid;
char *p;
char hold;
while (isspace(*s)) s++;
p = s;
while (*p && !isspace(*p)) p++;
hold = *p;
*p = '\0';
niceval = atoi(s);
*p = hold;
s = p;
while (isspace(*s)) s++;
while (*s) {
p = s;
while (*p && !isspace(*p)) p++;
hold = *p;
*p = '\0';
pid = atoi(s);
*p = hold;
s = p;
if (pid) (void)Prenice(pid,niceval);
while (isspace(*s)) s++;
}
}
int
cmp_incr_pid(void *p1, void *p2)
{
struct ptab *pt1 = p1, *pt2 = p2;
int pid1 = pt1->pid, pid2 = pt2->pid;
if (pid1 == -1 && pid2 == -1) return 0;
if (pid1 == -1) return 1; /* send invalid procs to bottom */
if (pid2 == -1) return -1;
return pid1 - pid2;
}
int
cmp_decr_pid(void *p1, void *p2)
{
struct ptab *pt1 = p1, *pt2 = p2;
int pid1 = pt1->pid, pid2 = pt2->pid;
if (pid1 == -1 && pid2 == -1) return 0;
if (pid1 == -1) return 1; /* send invalid procs to bottom */
if (pid2 == -1) return -1;
return pid2 - pid1;
}
char helpstr[] =
" s[leeptime] w[idth] n[lines] k[ill] r[enice] h[elp] p[riority] q[uit]\r";
void
main(argc, argv)
int argc;
char **argv;
{
int repeat_time = 0;
_DTA mydta;
int fd;
int fserror=0;
long place, procaddr;
int pid, ppid;
char *cmdline;
struct status *statp;
char bpage[sizeof(BASEPAGE)];
struct pinfo proc;
int thispid;
struct ptab *pt;
char *c;
unsigned long ptime, hour, min, sec, frac;
long realtime;
long lastclock = clock();
long thisclock;
int i;
long deltime;
long ctxtsize;
int nprocs, nrunning;
long cummemory, idletime;
int width = 0;
long readfds;
char ibuf[80];
int ichar;
int taillen, cmdlen;
int tailstart;
int nlines = 0;
int helpline = 0;
int ptabsiz = DEF_PTABSIZ;
int len;
int (*cmpfunc)();
extern int __mint;
int ppid_mode = 1;
cmpfunc = cmp_incr_pid;
if (!__mint) usage();
--argc, ++argv;
while (argc) {
if (**argv != '-') usage();
switch(argv[0][1]) {
case 'r': cmpfunc = cmp_decr_pid;
break;
case 's': if (argc == 0) usage();
if ((repeat_time = atoi(argv[1])) == 0) usage();
++argv, --argc;
break;
case 'w': if (argc == 0) usage();
if ((width = atoi(argv[1])) <= 0) usage();
if (width < MINWIDTH) width = MINWIDTH;
++argv, --argc;
break;
case 'n': if (argc == 0) usage();
if ((nlines = atoi(argv[1])) <= 0) usage();
++argv, --argc;
break;
default: usage();
}
--argc, ++argv;
}
Fsetdta(&mydta); /* give the OS my new DTA */
initscr();
if (!width) width = COLS-1; /* default if it's unset */
width &= ~1; /* make sure width is even, too */
if (!repeat_time) repeat_time = 5;
if (LINES < 4) {
puts("top: can't run on a screen with < 4 lines");
exit(1);
}
if (nlines == 0 || nlines > (LINES-3)) nlines = LINES-3;
/* struct ptab ends with char line[2] so there's already padding for '\0' */
if ((ptab = malloc((sizeof(struct ptab) + width) * ptabsiz)) == NULL) {
puts("top: can't get memory for process structures");
exit(1);
}
cbreak();
noecho();
signal(SIGINT,quit);
signal(SIGQUIT,quit);
signal(SIGHUP,quit);
signal(SIGTERM,quit);
for (i = ptabsiz, pt = ptab; i; i--, pt = INCPTAB(pt)) {
pt->pid = -1;
pt->used = 0;
}
while (1) {
fserror=Fsfirst("u:\\proc\\*.*", -1);
if (fserror < 0) {
fprintf(stderr, "top: cannot list processes ?!");
exit(1);
}
erase();
/* top line is printed later */
if (ppid_mode) {
printw("\n\nPID PPID STATUS SIZE TIME %% COMMAND\n");
}
else {
printw("\n\nPID PRI CUR STATUS SIZE TIME %% COMMAND\n");
}
nprocs = 0;
nrunning = 0;
idletime = 0;
cummemory = 0;
thisclock = clock();
realtime = (thisclock - lastclock) * (1000/CLOCKS_PER_SEC);
lastclock = thisclock;
/* okay, now run the Fsnext bit through the wringer */
fserror = E_OK; /* set up for the loop */
while (fserror == E_OK ) {
fd = open_proc(mydta.dta_name);
if (fd < 0) goto getnext;
/* cut name off at '.' */
for (cmdline = mydta.dta_name;
*cmdline && *cmdline != '.';
cmdline++)
/* do nothing */ ;
*cmdline = 0;
ioctl(fd, PPROCADDR, &procaddr);
if (ioctl(fd, PCTXTSIZE, &ctxtsize) < 0)
lseek(fd, procaddr+4+2*sizeof(CONTEXT), 0);
else
lseek(fd, procaddr, 0);
read(fd, &proc, sizeof(proc));
pid = proc.pid;
ppid = proc.ppid;
ioctl(fd, PBASEADDR, &place);
lseek(fd, place, 0);
read(fd, bpage, sizeof(bpage));
close(fd);
cmdline = bpage+128;
if (*cmdline) *cmdline = ' ';
/* span cmdline turning control chars into question marks */
for (c = cmdline; *c; c++) if (*c < ' ') *c = '?';
taillen = c - cmdline;
thispid = proc.pid;
if (ppid < 0) ppid = 0;
statp = proc_stat; /* hunt down string referring to
process status */
while (statp->mint != mydta.dta_attribute &&
statp->mint >= 0) statp++;
ptime = proc.systime + proc.usrtime;
/* set deltime to the time used since last time we checked */
for (i = ptabsiz, pt = ptab; i; i--, pt = INCPTAB(pt)) {
if (pt->pid == thispid) {
pt->used = 1;
deltime = ptime - pt->lasttime;
pt->lasttime = ptime;
goto found;
}
}
/* fell out: didn't find the process */
for (i = ptabsiz, pt = ptab; i; i--, pt = INCPTAB(pt)) {
if (pt->pid == -1) {
/* use this slot */
pt->used = 1;
pt->pid = thispid;
pt->lasttime = ptime;
deltime = (ptime > realtime ? realtime : ptime);
goto found;
}
}
/* fell out again - can't keep track of this process (sorry!) */
deltime = 0;
pt = NULL;
found:
if (thispid == 0) {
/* idle time is charged to process zero */
idletime = deltime;
strcpy(mydta.dta_name,"(idle)");
}
hour = (ptime/1000/60/60);
min = (ptime/1000/60)%60;
sec = (ptime/1000)%60;
frac = (ptime%1000) / 10; /* (never anything in .001 digit) */
if (ppid_mode) {
len = sprintf(pt->line,"%03d %03d %-5s %8ld ",
pid, ppid, statp->desc, mydta.dta_size);
}
else {
len = sprintf(pt->line,"%03d %3d %3d %-5s %8ld ",
pid, proc.pri, proc.curpri, statp->desc, mydta.dta_size);
}
if (hour)
len += sprintf(pt->line + len,"%2ld:%02ld:%02ld",hour,min,sec);
else
len += sprintf(pt->line + len,"%2ld:%02ld.%02ld",min,sec,frac);
len += sprintf(pt->line + len," %3ld ",(deltime * 100) / realtime);
/* if the line's too long, cut off the tail so the total is width */
cmdlen = strlen(mydta.dta_name);
tailstart = len+cmdlen;
if (width < tailstart) cmdline[0] = 0;
else if (tailstart+taillen > width) {
cmdline[width-tailstart] = '\0';
}
sprintf(pt->line + len,"%s%s",mydta.dta_name,cmdline);
nprocs++;
cummemory += mydta.dta_size;
if (deltime) nrunning++;
getnext:
fserror = Fsnext();
}
/*
* Now zero out those slots which weren't used in the last pass, and zero
* all "used" fields
*/
for (i = nlines, pt = ptab; i; i--, pt = INCPTAB(pt)) {
if (!pt->used) pt->pid = -1;
else pt->used = 0;
}
/*
* Now all processes are in the ptab array, their lines stored. Sort them
* into printing order and print nlines of them.
*/
qsort(ptab,nlines,sizeof(struct ptab) + width,cmpfunc);
if (nprocs < nlines) i = nprocs;
else i = nlines;
for (pt = ptab; i; i--, pt = INCPTAB(pt)) {
printw("%s\n",pt->line);
}
/* compute idle percentage into idletime */
idletime = (idletime * 100) / realtime;
move(0,0);
printw("Sample time: %5ld; %3ld%% idle; %3d processes, %3d running"
"; %ld bytes used\n",
realtime,idletime,nprocs,nrunning,cummemory);
if (helpline) printw(helpstr);
if (garbage) wrefresh(curscr);
else refresh();
garbage = 0;
/* Fall asleep for repeat_time seconds or until a key comes in. */
/* We want zero to mean "no time" not "forever" so add one. */
readfds = 1;
if (Fselect(repeat_time * 1000 + 1,&readfds,0L,0L)) {
/* input waiting */
if (helpline) {
clrtoeol();
refresh();
helpline = 0;
}
ichar = getch();
switch(ichar) {
case 'L'-'@':
garbage = 1;
break;
case 's':
printw("sleep time: ");
refresh();
echo();
getstr(ibuf);
noecho();
if (*ibuf) repeat_time = atoi(ibuf);
if (repeat_time < 0) repeat_time = 0;
break;
case 'w':
printw("width: ");
refresh();
echo();
getstr(ibuf);
noecho();
if (*ibuf) width = atoi(ibuf);
if (width < MINWIDTH) width = MINWIDTH;
width &= ~1; /* make sure width is even */
break;
case 'n':
printw("nlines: ");
refresh();
echo();
getstr(ibuf);
noecho();
if (*ibuf) nlines = atoi(ibuf);
if (nlines == 0 || nlines > (LINES-3)) nlines = (LINES-3);
break;
case 'k':
printw("kill ");
refresh();
echo();
getstr(ibuf);
noecho();
if (*ibuf) dokill(ibuf);
break;
case 'r':
printw("renice ");
refresh();
echo();
getstr(ibuf);
noecho();
if (*ibuf) dorenice(ibuf);
break;
case 'p':
/* toggle ppid_mode */
ppid_mode ^= 1;
break;
case 'h':
case '?':
helpline = 1;
break;
case 'q': quit();
default: ;
}
}
}
}