Plan 9 from Bell Labs’s /usr/web/sources/patch/sorry/top/top.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>

typedef struct Proc Proc;
struct Proc {
	char pid[32];
	char name[32];
	char user[32];
	long cpri;
	long bpri;
	long promil;
	long usr;
	long sys;
	long mem;
	long pusr;
	long psys;
	long pmem;
};

enum { 
	Mcpu,
	Mmem,
	Muser,
	Mprio,
	Mexit, 
};

char *menustr[] = {
	"cpu",
	"mem",
	"user",
	"prio",
	"exit", 
	nil 
};
Menu menu = { 
	menustr, 
	nil, 
	-1 
};

int (*cmp)(void *, void *);

Image *normal;
Image *title;

int procallo;
int nproc, sleeptime = 5000;
int sort = Mcpu;
Proc *procs;

void updater(int fd);

void
usage(void)
{
	fprint(2, "usage: %s [-f font]\n", argv0);
	exits("usage");
}

int
cpucmp(void *aptr, void *bptr)
{
	Proc *a, *b;
	a = aptr;
	b = bptr;
	return b->promil - a->promil;
}

int
memcmpr(void *aptr, void *bptr)
{
	Proc *a, *b;
	a = aptr;
	b = bptr;
	return b->mem - a->mem;
}

int
usercmp(void *aptr, void *bptr)
{
	Proc *a, *b;
	a = aptr;
	b = bptr;
	return strcmp(a->user, b->user);
}

int
priocmp(void *aptr, void *bptr)
{
	Proc *a, *b;
	a = aptr;
	b = bptr;
	return b->cpri - a->cpri;
}

void
main(int argc, char **argv)
{
	Event e;
	char path[64];
	char *font = nil;
	int kupd, k, p[2], pid, fd;
	
	ARGBEGIN{
	case 'f':
		font = EARGF(usage());
		break;
	case 'T':
		sleeptime = atoi(EARGF(usage()));
		if(sleeptime <= 0)
			sysfatal("bad sleep time: %d\n", sleeptime);
		break;
	default:
		usage();
	}ARGEND

	if(font == nil)
		font = getenv("font");

	if(initdraw(nil, font, "top") == -1)
		sysfatal("initdraw");

	normal = allocimagemix(display, DPalebluegreen, DWhite);
	title = allocimagemix(display, DPalegreyblue, DWhite);

	if(normal == nil || title == nil)
		sysfatal("allocimagemix");

	pipe(p);
	pid = rfork(RFPROC|RFMEM);
	if(!pid)
		updater(p[0]);

	cmp = cpucmp;

	einit(Ekeyboard|Emouse);
	kupd = estart(0, p[1], 1);
	eresized(0);
	for(;;)
	switch(k = event(&e)){
	default:
		if(k == kupd){
			eresized(0);
			write(p[1], &k, 1); /* release */
		}
		break;
	case Ekeyboard:
		switch(e.kbdc){
		default:
			break;
		case 0x7f:
		case 'q':
			goto casequit;
		}
		break;
	case Emouse:
		if(e.mouse.buttons & 4)
		switch(emenuhit(3, &e.mouse, &menu)){
		default:
			break;
		case Mcpu:
			cmp = cpucmp;
			break;
		case Mmem:
			cmp = memcmpr;
			break;
		case Muser:
			cmp = usercmp;
			break;
		case Mprio:
			cmp = priocmp;
			break;
		case Mexit:
		casequit:
			snprint(path, sizeof path, "/proc/%d/note", pid);
			fd = open(path, OWRITE);
			write(fd, "die", 3);
			close(fd);
			exits(0);
		}
	}
}

long 
msec(void)
{
	vlong ms;
	ms = nsec();
	ms /= 1000000LL;
	return (long)ms;
}

void
updater(int syncfd)
{
	static char buf[256];
	long prev, now, elaps;

	prev = msec();
	for(;;){
		int fd, proci;
		long i, j, n, ndir;
		Dir *dir;
		fd = open("/proc", OREAD);
		ndir = dirreadall(fd, &dir);
		close(fd);
		chdir("/proc");
		if(procallo < ndir){
			procallo = ndir;
			/*
			 * allocate for worst case: all old processes died and as many
			 * new ones were created
			 */
			procs = realloc(procs, 2 * sizeof(Proc) * procallo);
		}
		now = msec();
		elaps = now - prev;
		if(elaps == 0)
			elaps = 1;
		proci = 0;

		for(i = 0; i < nproc; i++)
			*procs[i].name = 0;
		for(i = 0; i < ndir; i++){
			char *tok[12];
			if(*dir[i].name < '0' || *dir[i].name > '9')
				continue;

			chdir(dir[i].name);
			fd = open("status", OREAD);
			if(fd == -1)
				continue;
			n = read(fd, buf, sizeof buf - 1);
			close(fd);
			chdir("..");

			buf[n] = 0;
			tokenize(buf, tok, nelem(tok));
			for(j = 0; j < nproc; j++) {
				if(!strcmp(procs[j].pid, dir[i].name)){
					long dif;
					strncpy(procs[j].user, tok[1], 31);
					procs[j].user[31] = '\0';
					procs[j].pusr = procs[j].usr;
					procs[j].psys = procs[j].sys;
					procs[j].pmem = procs[j].mem;
					procs[j].usr = atol(tok[3]) + atol(tok[6]);
					procs[j].sys = atol(tok[4]) + atol(tok[7]);
					procs[j].mem = atol(tok[9]);
					procs[j].bpri = atol(tok[10]);
					procs[j].cpri = atol(tok[11]);
					strncpy(procs[j].name, tok[0], 32);
					dif = procs[j].usr + procs[j].sys;
					dif -= procs[j].pusr + procs[j].psys;
					procs[j].promil = (dif * 1000) / elaps;
					break;
				}
			}
			if(j == nproc){
				strncpy(procs[nproc].pid, dir[i].name, 32);
				strncpy(procs[nproc].name, tok[0], 32);
				strncpy(procs[j].user, tok[1], 31);
				procs[j].user[31] = '\0';
				procs[nproc].promil = 0;
				procs[nproc].usr = atol(tok[3]) + atol(tok[6]);
				procs[nproc].sys = atol(tok[4]) + atol(tok[7]);
				procs[nproc].mem = atol(tok[9]);
				procs[nproc].pusr = atol(tok[3]) + atol(tok[6]);
				procs[nproc].psys = atol(tok[4]) + atol(tok[7]);
				procs[nproc].pmem = atol(tok[9]);
				procs[nproc].bpri = atol(tok[10]);
				procs[nproc].cpri = atol(tok[11]);
				nproc++;
			}
			proci++;
		}
		j = 0;
		for(i = 0; i < nproc; i++)
			if(*procs[i].name != 0)
				memmove(&procs[j++], &procs[i], sizeof procs[0]);
		nproc = j;

		qsort(procs, nproc, sizeof(Proc), cmp);
		nproc = proci;
		free(dir);
		write(syncfd, buf, 1);
		read(syncfd, buf, 1);
		prev = now;
		sleep(sleeptime);
	}
}

void
eresized(int new)
{
	Point p, dp;
	int i, wid, namewid, userwid, memwid, difwid, priwid;
	long t;
	char str[256];
	Image *bnc;

	if(new)
	if(getwindow(display, Refmesg) == -1)
		sysfatal("can't reattach window");

	priwid = namewid = userwid = memwid = difwid = 0;
	p = screen->r.min;
	for(i = 0; i < nproc; i++){
		wid = stringwidth(font, procs[i].name);
		if(wid > namewid) 
			namewid = wid;

		wid = stringwidth(font, procs[i].user);
		if(wid > userwid) 
			userwid = wid;

		t = procs[i].promil;
		snprint(str, sizeof str, "%ld.%01ld%%", t / 10, t % 10);
		wid = stringwidth(font, str);
		if(wid > difwid) 
			difwid = wid;

		t = procs[i].mem;
		snprint(str, sizeof str, "%ld.%01ldM", t / 1000, (t % 1000) / 100);
		wid = stringwidth(font, str);
		if(wid > memwid) 
			memwid = wid;

		t = procs[i].cpri;
		snprint(str, sizeof str, "%ld", t);
		wid = stringwidth(font, str);
		if(wid > priwid) 
			priwid = wid;
	}
	wid = stringwidth(font, "prio");
	if(priwid < wid)
		priwid = wid;
	priwid += 10;
	namewid += 10;
	userwid += 10;
	memwid += 10;
	difwid += 10;

	bnc = allocimage(display, Rect(0,0, Dx(screen->r), font->height), screen->chan, 0, DOpaque);
	dp = screen->r.min;
	p = bnc->r.min;
	p.x += 10;
	draw(bnc, bnc->r, title, nil, ZP);
	string(bnc, p, display->black, ZP, font, "name");
	p.x += namewid;

	string(bnc, p, display->black, ZP, font, "user");
	p.x += userwid;


	wid = stringwidth(font, "%cpu");
	p.x += difwid - wid;
	string(bnc, p, display->black, ZP, font, "%cpu");
	p.x += wid;

	wid = stringwidth(font, "mem");
	p.x += memwid - wid;
	string(bnc, p, display->black, ZP, font, "mem");
	p.x += wid;

	wid = stringwidth(font, "prio");
	p.x += priwid - wid;
	string(bnc, p, display->black, ZP, font, "prio");
	p.x += wid;

	border(bnc, bnc->r, 1, display->black, ZP);
	draw(screen, Rpt(dp, addpt(dp, Pt(Dx(bnc->r), font->height))), bnc, nil, ZP);
	dp.y += Dy(bnc->r) + 2;

	for(i = 0; dp.y < screen->r.max.y && i < nproc; i++){
		p = bnc->r.min;
		p.x += 10;
		draw(bnc, bnc->r, normal, nil, ZP);
		string(bnc, p, display->black, ZP, font, procs[i].name);
		p.x += namewid;

		string(bnc, p, display->black, ZP, font, procs[i].user);
		p.x += userwid;

		t = procs[i].promil;
		snprint(str, sizeof str, "%ld.%01ld%%", t / 10, t % 10);
		wid = stringwidth(font, str);
		p.x += difwid - wid;
		string(bnc, p, display->black, ZP, font, str);
		p.x += wid;

		t = procs[i].mem;
		snprint(str, sizeof str, "%ld.%01ldM", t / 1000, (t % 1000) / 100);
		wid = stringwidth(font, str);
		p.x += memwid - wid;
		string(bnc, p, display->black, ZP, font, str);
		p.x += wid;

		t = procs[i].cpri;
		snprint(str, sizeof str, "%ld", t);
		wid = stringwidth(font, str);
		p.x += priwid - wid;
		string(bnc, p, display->black, ZP, font, str);
		p.x += wid;

		border(bnc, bnc->r, 1, display->black, ZP);

		draw(screen, Rpt(dp, addpt(dp, Pt(Dx(bnc->r), font->height))), bnc, nil, ZP);

		dp.y += Dy(bnc->r) + 2;
	}
	if(dp.y < screen->r.max.y)
		draw(screen, Rpt(dp, screen->r.max), display->white, nil, ZP);
	freeimage(bnc);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.