v29i102: top-3.4 - top process display, V3.4, Part01/22

21 views
Skip to first unread message

William Lefebvre

unread,
Sep 1, 1996, 3:00:00 AM9/1/96
to

Submitted-By: w...@groupsys.com (William Lefebvre)
Posting-Number: Volume 29, Issue 102
Archive-Name: top-3.4/part01

#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 1 (of 22)."
# Contents: top-3.4 top-3.4/ADVERTISEMENT top-3.4/DISCLAIMER
# top-3.4/Make.desc.X top-3.4/Makefile.X top-3.4/boolean.h
# top-3.4/display.h top-3.4/getans top-3.4/getopt.c top-3.4/install
# top-3.4/layout.h top-3.4/loadavg.h top-3.4/machine
# top-3.4/machine.h top-3.4/machine/m_386bsd.man
# top-3.4/machine/m_aix41.man top-3.4/machine/m_aux3.man
# top-3.4/machine/m_bsd44.man top-3.4/machine/m_bsd44a.man
# top-3.4/machine/m_bsdos2.man top-3.4/machine/m_convex.man
# top-3.4/machine/m_dcosx.man top-3.4/machine/m_dgux.man
# top-3.4/machine/m_dynix.man top-3.4/machine/m_freebsd20.man
# top-3.4/machine/m_ftx.man top-3.4/machine/m_hpux9.man
# top-3.4/machine/m_linux.man top-3.4/machine/m_ncr3000.man
# top-3.4/machine/m_netbsd08.man top-3.4/machine/m_next40.c
# top-3.4/machine/m_next_task.h top-3.4/machine/m_sco.man
# top-3.4/machine/m_sunos4.man top-3.4/machine/m_sunos5.man
# top-3.4/machine/m_sunos54.c top-3.4/machine/m_svr4.man
# top-3.4/machine/m_svr42.man top-3.4/machine/m_umax.man
# top-3.4/metatop top-3.4/os.h top-3.4/patchlevel.h top-3.4/prime.c
# top-3.4/screen.h top-3.4/sigconv.awk top-3.4/top.h
# top-3.4/top.local.H top-3.4/utils.h top-3.4/version.c
# Wrapped by lefebvre@acapulco on Fri Aug 30 12:35:49 1996
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test ! -d 'top-3.4' ; then
echo shar: Creating directory \"'top-3.4'\"
mkdir 'top-3.4'
fi
if test -f 'top-3.4/ADVERTISEMENT' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/ADVERTISEMENT'\"
else
echo shar: Extracting \"'top-3.4/ADVERTISEMENT'\" \(784 characters\)
sed "s/^X//" >'top-3.4/ADVERTISEMENT' <<'END_OF_FILE'
X William LeFebvre
X Group sys Consulting
X w...@groupsys.com
X +1-770-813-3224
X
X
XWilliam LeFebvre is available for consulting and teaching engagements
Xthrough the company Group sys Consulting. William's specialties are:
X
X Unix system administration issues
X Local area network design
X Design of safe connections to the Internet
X Domain Name Service
X Unix and Internet security
X INN news server configuration
X SunOS to Solaris migration
X Troubleshooting
X
X
XAlthough located in the Atlanta metropolitan area, William can easily
Xtravel to any location in the United States and Canada. Trips to
Xother countries can be arranged as well.
X
XIf you are interested in having William work for your organization,
Xcontact him at +1-770-813-3224 or via the address "w...@groupsys.com".
X
END_OF_FILE
if test 784 -ne `wc -c <'top-3.4/ADVERTISEMENT'`; then
echo shar: \"'top-3.4/ADVERTISEMENT'\" unpacked with wrong size!
fi
# end of 'top-3.4/ADVERTISEMENT'
fi
if test -f 'top-3.4/DISCLAIMER' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/DISCLAIMER'\"
else
echo shar: Extracting \"'top-3.4/DISCLAIMER'\" \(1498 characters\)
sed "s/^X//" >'top-3.4/DISCLAIMER' <<'END_OF_FILE'
XDISCLAIMER
X
X"top" is distributed free of charge. It should not be considered an
Xofficial product of Argonne National Laboratory. William LeFebvre
Xsupports "top" in his spare time and as time permits.
X
XNO WARRANTY:
X
XBECAUSE "top" IS DISTRIBUTED FREE OF CHARGE, THERE IS ABSOLUTELY NO
XWARRANTY PROVIDED, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW.
XEXCEPT WHEN OTHERWISE STATED IN WRITING, ARGONNE NATIONAL LABORATORY,
XNORTHWESTERN UNIVERSITY, WILLIAM N. LeFEBVRE AND/OR OTHER PARTIES
XPROVIDE "top" "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
XOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
XMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
XAS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD
XTHE "top" PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
XNECESSARY SERVICING, REPAIR OR CORRECTION.
X
XIN NO EVENT WILL ARGONNE NATIONAL LABORATORY, NORTHWESTERN UNIVERSITY,
XWILLIAM N. LeFEBVRE, AND/OR ANY OTHER PARTY WHO MAY MODIFY AND
XREDISTRIBUTE "top", BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST
XPROFITS, LOST MONIES, OR OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL
XDAMAGES ARISING OUT OF THE USE OR INABILITY TO USE (INCLUDING BUT NOT
XLIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES
XSUSTAINED BY THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH
XOTHER PROGRAMS) THE PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE
XPOSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
X
XSo there!
END_OF_FILE
if test 1498 -ne `wc -c <'top-3.4/DISCLAIMER'`; then
echo shar: \"'top-3.4/DISCLAIMER'\" unpacked with wrong size!
fi
# end of 'top-3.4/DISCLAIMER'
fi
if test -f 'top-3.4/Make.desc.X' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/Make.desc.X'\"
else
echo shar: Extracting \"'top-3.4/Make.desc.X'\" \(673 characters\)
sed "s/^X//" >'top-3.4/Make.desc.X' <<'END_OF_FILE'
X# Makefile for .desc files
X
X# This makefile is the prototype for "Make.desc", which is used by
X# top's Configure script to build .desc files and the SYNOPSIS file.
X# Configure then uses these files to ask appropriate questions.
X
X# Written by William LeFebvre, Argonne National Laboratory
X# (formerly of Northwestern University and Rice University)
X
X# DO NOT EDIT "Make.desc"!!! Make changes to "Make.desc.X",
X# then "make veryclean", then run "Configure".
X
XDESCS=%descs%
X
X.SUFFIXES: .desc
X
X.c.desc:
X sed -e '/^$$/,$$d' -e 's,^[/ *]*,,' $< > $@
X
Xall: SYNOPSIS
X
XSYNOPSIS: $(DESCS)
X grep SYNOPSIS: $(DESCS) | sed -e 's@^machine/m_@@' -e 's@.desc:.[^:]*: *@:@' >SYNOPSIS
END_OF_FILE
if test 673 -ne `wc -c <'top-3.4/Make.desc.X'`; then
echo shar: \"'top-3.4/Make.desc.X'\" unpacked with wrong size!
fi
# end of 'top-3.4/Make.desc.X'
fi
if test -f 'top-3.4/Makefile.X' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/Makefile.X'\"
else
echo shar: Extracting \"'top-3.4/Makefile.X'\" \(3841 characters\)
sed "s/^X//" >'top-3.4/Makefile.X' <<'END_OF_FILE'
X# Makefile for "top", a top 10 process display for Unix
X#
X# This makefile is for top, version 3
X#
X# Written by William LeFebvre, Argonne National Laboratory
X# (formerly of Northwestern University and Rice University)
X
X# DO NOT EDIT "Makefile"!!!! Make changes to "Makefile.X" and rerun
X# Configure.
X
X# Executables (these should be obvious):
X
XSHELL = %shell%
XCC = %cc%
XAWK = %awk%
XINSTALL = %install%
X
X# installation information:
X# OWNER - name (or uid) for the installed executable's owner
X# GROUP - group name (or gid) for the installed executable's group
X# MODE - mode for the installed executable (should start with a 0)
X# BINDIR - directory where the executable should live
X# MANDIR - directory where the manual page should live
X# MANEXT - installed man pages end in .$(MANEXT)
X# MANSTY - "man" or "catman" depending on what's to be installed
X# SIGNAL - <signal.h> or <sys/signal.h>; the one with signal definitions
X# TROFF - most appropriate troff command
X
XOWNER = %owner%
XGROUP = %group%
XMODE = %mode%
XBINDIR = %bindir%
XMANDIR = %mandir%
XMANEXT = %manext%
XMANSTY = %mansty%
XSIGNAL = %signal%
X
X# Values for the two defaults in "top":
X# TOPN - default number of processes to display
X# DELAY - default delay between updates
X#
X# set TOPN to -1 to indicate infinity (so that top will display as many
X# as the screen will hold).
X
XTOPN = %topn%
XDELAY = %delay%
X
XTARFILES = README INSTALL DISCLAIMER FAQ ADVERTISEMENT \
X Changes Configure Porting \
X Makefile.X Make.desc.X getans install \
X top.c commands.c display.c screen.c username.c \
X utils.c version.c getopt.c prime.c \
X boolean.h display.h layout.h loadavg.h screen.h \
X machine.h patchlevel.h top.h top.local.H os.h utils.h \
X sigconv.awk top.X m-template metatop \
X machine
XCFILES = top.c commands.c display.c screen.c username.c \
X utils.c version.c getopt.c machine.c
XOBJS = top.o commands.o display.o screen.o username.o \
X utils.o version.o getopt.o machine.o
X
XCDEFS = %cdefs%
XLIBS = %libs%
XTERMCAP = %termcap%
X
XCFLAGS = %cflgs% $(CDEFS)
XLINTFLAGS = -x $(CDEFS)
X
Xall: Makefile top.local.h top
X
XMakefile: Makefile.X
X @echo 'You need to run the script "Configure" before running "make".'
X exit 10
X
Xtop.local.h: top.local.H
X @echo 'You need to run the script "Configure" before running "make".'
X exit 10
X
Xtop: $(OBJS)
X rm -f top
X $(CC) -o top $(OBJS) $(TERMCAP) -lm $(LIBS)
X
Xlint: sigdesc.h
X $(LINT) $(LINTFLAGS) $(CFILES)
X
X# include file dependencies
Xtop.o: boolean.h display.h screen.h top.h top.local.h utils.h machine.h
Xcommands.o: boolean.h sigdesc.h utils.h
Xdisplay.o: boolean.h display.h layout.h screen.h top.h top.local.h utils.h
Xmachine.o: top.h machine.h utils.h
Xscreen.o: boolean.h screen.h
Xutils.o: top.h
Xversion.o: top.h patchlevel.h
Xusername.o: top.local.h utils.h
X
X# automatically built include file
Xsigdesc.h: sigconv.awk $(SIGNAL)
X $(AWK) -f sigconv.awk $(SIGNAL) >sigdesc.h
X
Xtar:
X rm -f top.tar machine/*.desc machine/*~
X tar cvf top.tar $(TARFILES)
X
Xshar:
X rm -f top.shar* machine/*.desc
X makekit -ntop.shar. -t"Now read README and INSTALL, then run Configure" machine $(TARFILES)/*
X
Xclean:
X rm -f *.o top core core.* sigdesc.h
X
Xveryclean: clean
X rm -f Make.desc machine/*.desc .defaults top.tar SYNOPSIS Makefile top.local.h top.1 machine.c prime
X
Xinstall: top top.1 install-top install-$(MANSTY)
X
Xinstall-top:
X $(INSTALL) -o $(OWNER) -m $(MODE) -g $(GROUP) top $(BINDIR)
X
Xinstall-man:
X $(INSTALL) top.1 $(MANDIR)/top.$(MANEXT)
X
Xinstall-catman:
X tbl top.1 | nroff -man > $(MANDIR)/top.$(MANEXT)
X
Xinstallmeta: top top.1
X $(INSTALL) -o $(OWNER) -m 755 -g $(GROUP) metatop $(BINDIR)/top
X @echo $(INSTALL) -o $(OWNER) -m $(MODE) -g $(GROUP) top $(BINDIR)/top-`uname -m`-`uname -r`
X @$(INSTALL) -o $(OWNER) -m $(MODE) -g $(GROUP) \
X top $(BINDIR)/top-`uname -m`-`uname -r`
X $(INSTALL) top.1 $(MANDIR)/top.$(MANEXT)
END_OF_FILE
if test 3841 -ne `wc -c <'top-3.4/Makefile.X'`; then
echo shar: \"'top-3.4/Makefile.X'\" unpacked with wrong size!
fi
# end of 'top-3.4/Makefile.X'
fi
if test -f 'top-3.4/boolean.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/boolean.h'\"
else
echo shar: Extracting \"'top-3.4/boolean.h'\" \(125 characters\)
sed "s/^X//" >'top-3.4/boolean.h' <<'END_OF_FILE'
X/* My favorite names for boolean values */
X#define No 0
X#define Yes 1
X#define Maybe 2 /* tri-state boolean, actually */
X
END_OF_FILE
if test 125 -ne `wc -c <'top-3.4/boolean.h'`; then
echo shar: \"'top-3.4/boolean.h'\" unpacked with wrong size!
fi
# end of 'top-3.4/boolean.h'
fi
if test -f 'top-3.4/display.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/display.h'\"
else
echo shar: Extracting \"'top-3.4/display.h'\" \(135 characters\)
sed "s/^X//" >'top-3.4/display.h' <<'END_OF_FILE'
X/* constants needed for display.c */
X
X/* "type" argument for new_message function */
X
X#define MT_standout 1
X#define MT_delayed 2
X
END_OF_FILE
if test 135 -ne `wc -c <'top-3.4/display.h'`; then
echo shar: \"'top-3.4/display.h'\" unpacked with wrong size!
fi
# end of 'top-3.4/display.h'
fi
if test -f 'top-3.4/getans' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/getans'\"
else
echo shar: Extracting \"'top-3.4/getans'\" \(1618 characters\)
sed "s/^X//" >'top-3.4/getans' <<'END_OF_FILE'
X#!/bin/csh -f
Xset ny = (no yes)
Xif ($2 == "yesno") then
X @ i = $3 + 1
X set pmpt = "$1 [$ny[$i]]: "
Xelse
X if ("$3" == "") then
X set pmpt = "${1}"
X else
X set pmpt = "$1 [$3]: "
X endif
Xendif
Xrpt:
Xecho -n "$pmpt"
Xset input = $<
Xswitch ($2)
X case number:
X set tmp = `echo $input | tr -d 0123456789.`
X if ("x$tmp" != x) then
X echo "Invalid number. Please try again."
X goto rpt
X endif
X breaksw
X
X case integer:
X set tmp = `echo $input | tr -d 0123456789`
X if ("x$tmp" != x) then
X echo "Invalid integer. Please try again."
X goto rpt
X endif
X breaksw
X
X case neginteger:
X if ("x$input" != x-1) then
X set tmp = `echo $input | tr -d 0123456789`
X if ("x$tmp" != x) then
X echo "Invalid integer. Please try again."
X goto rpt
X endif
X endif
X breaksw
X
X case file:
X if ("x$input" == "x") then
X set input = $3
X endif
X if (! -e "$input") then
X echo The file $input "does not exist. Please try again."
X goto rpt
X endif
X breaksw
X
X case path:
X if ("x$input" == "x") then
X set input = "$3"
X endif
X if (! -e "$input") then
X foreach elt ($path)
X if (-e "$elt/$input") breaksw
X end
X echo The command $input "was not found. Please try again."
X goto rpt
X endif
X breaksw
X
X case yesno:
X if ("x$input" == xy || "x$input" == xyes) then
X set input = 1
X else if ("x$input" == xn || "x$input" == xno) then
X set input = 0
X else if ("x$input" != x) then
X echo 'Please answer "yes" or "no".'
X goto rpt
X endif
X breaksw
X
X default:
X breaksw
X
Xendsw
X
Xif ("x$input" == x) then
X set input = "$3"
Xendif
X
Xecho $input > $4
END_OF_FILE
if test 1618 -ne `wc -c <'top-3.4/getans'`; then
echo shar: \"'top-3.4/getans'\" unpacked with wrong size!
fi
chmod +x 'top-3.4/getans'
# end of 'top-3.4/getans'
fi
if test -f 'top-3.4/getopt.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/getopt.c'\"
else
echo shar: Extracting \"'top-3.4/getopt.c'\" \(1872 characters\)
sed "s/^X//" >'top-3.4/getopt.c' <<'END_OF_FILE'
X/*
X * "getopt" routine customized for top.
X */
X
X/*
X * Many modern-day Unix implementations already have this function
X * in libc. The standard "getopt" is perfectly sufficient for top's
X * needs. If such a function exists in libc then you certainly don't
X * need to compile this one in. To prevent this function from being
X * compiled, define "HAVE_GETOPT". This is usually done in the "CFLAGS"
X * line of the corresponding machine module.
X */
X
X/*
X * This empty declaration exists solely to placate overexhuberant C
X * compilers that like to warn you about content-free files.
X */
Xstatic void __empty();
X
X#ifndef HAVE_GETOPT
X
X/*LINTLIBRARY*/
X
X#include "os.h"
X#ifndef NULL
X#define NULL 0
X#endif
X#ifndef EOF
X#define EOF (-1)
X#endif
X#define ERR(s, c) if(opterr){\
X extern int write();\
X char errbuf[2];\
X errbuf[0] = c; errbuf[1] = '\n';\
X (void) write(2, argv[0], strlen(argv[0]));\
X (void) write(2, s, strlen(s));\
X (void) write(2, errbuf, 2);}
X
X
Xint opterr = 1;
Xint optind = 1;
Xint optopt;
Xchar *optarg;
X
Xint
Xgetopt(argc, argv, opts)
Xint argc;
Xchar **argv, *opts;
X{
X static int sp = 1;
X register int c;
X register char *cp;
X
X if(sp == 1)
X if(optind >= argc ||
X argv[optind][0] != '-' || argv[optind][1] == '\0')
X return(EOF);
X else if(strcmp(argv[optind], "--") == 0) {
X optind++;
X return(EOF);
X }
X optopt = c = argv[optind][sp];
X if(c == ':' || (cp=strchr(opts, c)) == NULL) {
X ERR(": unknown option, -", c);
X if(argv[optind][++sp] == '\0') {
X optind++;
X sp = 1;
X }
X return('?');
X }
X if(*++cp == ':') {
X if(argv[optind][sp+1] != '\0')
X optarg = &argv[optind++][sp+1];
X else if(++optind >= argc) {
X ERR(": argument missing for -", c);
X sp = 1;
X return('?');
X } else
X optarg = argv[optind++];
X sp = 1;
X } else {
X if(argv[optind][++sp] == '\0') {
X sp = 1;
X optind++;
X }
X optarg = NULL;
X }
X return(c);
X}
X#endif /* HAVE_GETOPT */
END_OF_FILE
if test 1872 -ne `wc -c <'top-3.4/getopt.c'`; then
echo shar: \"'top-3.4/getopt.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/getopt.c'
fi
if test -f 'top-3.4/install' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/install'\"
else
echo shar: Extracting \"'top-3.4/install'\" \(928 characters\)
sed "s/^X//" >'top-3.4/install' <<'END_OF_FILE'
X#!/bin/sh
X#
X# this shell script is amazingly similar to the old and lamented
X# BSD "install" command. It recognized the following options:
X#
X# -o target file owner
X# -m target file mode
X# -g target file group owner
X#
X#
X# scan the options
X#
Xwhile [ $# -gt 0 ]; do
X case $1 in
X -o)
X owner=$2
X shift ; shift
X ;;
X
X -m)
X mode=$2
X shift; shift
X ;;
X
X -g)
X group=$2
X shift ; shift
X ;;
X
X -*)
X echo "install: unknown option $1"
X exit
X ;;
X
X *)
X break
X ;;
X esac
Xdone
X#
X# we need two more: filename and destination
X#
Xif [ $# -ne 2 ]; then
X echo "Usage: install [ -o owner ] [ -m mode ] [ -g group ] file destination"
X exit
Xfi
X#
X# first, copy
X#
Xcp $1 $2
X#
X# normalize the name
X#
Xdest=$2
Xif [ -d $2 ]; then
X dest=$2/`basename $1`
Xfi
X#
X# do optional things
X#
Xif [ "$owner" ]; then
X chown $owner $dest
Xfi
Xif [ "$group" ]; then
X chgrp $group $dest
Xfi
Xif [ "$mode" ]; then
X chmod $mode $dest
Xfi
END_OF_FILE
if test 928 -ne `wc -c <'top-3.4/install'`; then
echo shar: \"'top-3.4/install'\" unpacked with wrong size!
fi
chmod +x 'top-3.4/install'
# end of 'top-3.4/install'
fi
if test -f 'top-3.4/layout.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/layout.h'\"
else
echo shar: Extracting \"'top-3.4/layout.h'\" \(621 characters\)
sed "s/^X//" >'top-3.4/layout.h' <<'END_OF_FILE'
X/*
X * Top - a top users display for Berkeley Unix
X *
X * This file defines the locations on tne screen for various parts of the
X * display. These definitions are used by the routines in "display.c" for
X * cursor addressing.
X */
X
X#define x_lastpid 10
X#define y_lastpid 0
X#define x_loadave 33
X#define x_loadave_nompid 15
X#define y_loadave 0
X#define x_procstate 0
X#define y_procstate 1
X#define x_brkdn 15
X#define y_brkdn 1
X#define x_mem 8
X#define y_mem 3
X#define y_message 4
X#define x_header 0
X#define y_header 5
X#define x_idlecursor 0
X#define y_idlecursor 4
X#define y_procs 6
X
X#define y_cpustates 2
END_OF_FILE
if test 621 -ne `wc -c <'top-3.4/layout.h'`; then
echo shar: \"'top-3.4/layout.h'\" unpacked with wrong size!
fi
# end of 'top-3.4/layout.h'
fi
if test -f 'top-3.4/loadavg.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/loadavg.h'\"
else
echo shar: Extracting \"'top-3.4/loadavg.h'\" \(1492 characters\)
sed "s/^X//" >'top-3.4/loadavg.h' <<'END_OF_FILE'
X/*
X * Top - a top users display for Berkeley Unix
X *
X * Defines required to access load average figures.
X *
X * This include file sets up everything we need to access the load average
X * values in the kernel in a machine independent way. First, it sets the
X * typedef "load_avg" to be either double or long (depending on what is
X * needed), then it defines these macros appropriately:
X *
X * loaddouble(la) - convert load_avg to double.
X * intload(i) - convert integer to load_avg.
X */
X
X/*
X * We assume that if FSCALE is defined, then avenrun and ccpu are type long.
X * If your machine is an exception (mips, perhaps?) then make adjustments
X * here.
X *
X * Defined types: load_avg for load averages, pctcpu for cpu percentages.
X */
X#if defined(mips) && !defined(NetBSD)
X# include <sys/fixpoint.h>
X# if defined(FBITS) && !defined(FSCALE)
X# define FSCALE (1 << FBITS) /* mips */
X# endif
X#endif
X
X#ifdef FSCALE
X# define FIXED_LOADAVG FSCALE
X# define FIXED_PCTCPU FSCALE
X#endif
X
X#ifdef ibm032
X# undef FIXED_LOADAVG
X# undef FIXED_PCTCPU
X# define FIXED_PCTCPU PCT_SCALE
X#endif
X
X
X#ifdef FIXED_PCTCPU
X typedef long pctcpu;
X# define pctdouble(p) ((double)(p) / FIXED_PCTCPU)
X#else
Xtypedef double pctcpu;
X# define pctdouble(p) (p)
X#endif
X
X#ifdef FIXED_LOADAVG
X typedef long load_avg;
X# define loaddouble(la) ((double)(la) / FIXED_LOADAVG)
X# define intload(i) ((int)((i) * FIXED_LOADAVG))
X#else
X typedef double load_avg;
X# define loaddouble(la) (la)
X# define intload(i) ((double)(i))
X#endif
END_OF_FILE
if test 1492 -ne `wc -c <'top-3.4/loadavg.h'`; then
echo shar: \"'top-3.4/loadavg.h'\" unpacked with wrong size!
fi
# end of 'top-3.4/loadavg.h'
fi
if test ! -d 'top-3.4/machine' ; then
echo shar: Creating directory \"'top-3.4/machine'\"
mkdir 'top-3.4/machine'
fi
if test -f 'top-3.4/machine.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine.h'\"
else
echo shar: Extracting \"'top-3.4/machine.h'\" \(1349 characters\)
sed "s/^X//" >'top-3.4/machine.h' <<'END_OF_FILE'
X/*
X * This file defines the interface between top and the machine-dependent
X * module. It is NOT machine dependent and should not need to be changed
X * for any specific machine.
X */
X
X/*
X * the statics struct is filled in by machine_init
X */
Xstruct statics
X{
X char **procstate_names;
X char **cpustate_names;
X char **memory_names;
X#ifdef ORDER
X char **order_names;
X#endif
X};
X
X/*
X * the system_info struct is filled in by a machine dependent routine.
X */
X
Xstruct system_info
X{
X int last_pid;
X double load_avg[NUM_AVERAGES];
X int p_total;
X int p_active; /* number of procs considered "active" */
X int *procstates;
X int *cpustates;
X int *memory;
X};
X
X/* cpu_states is an array of percentages * 10. For example,
X the (integer) value 105 is 10.5% (or .105).
X */
X
X/*
X * the process_select struct tells get_process_info what processes we
X * are interested in seeing
X */
X
Xstruct process_select
X{
X int idle; /* show idle processes */
X int system; /* show system processes */
X int uid; /* only this uid (unless uid == -1) */
X char *command; /* only this command (unless == NULL) */
X};
X
X/* routines defined by the machine dependent module */
X
Xchar *format_header();
Xchar *format_next_process();
X
X/* non-int routines typically used by the machine dependent module */
Xchar *printable();
END_OF_FILE
if test 1349 -ne `wc -c <'top-3.4/machine.h'`; then
echo shar: \"'top-3.4/machine.h'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine.h'
fi
if test -f 'top-3.4/machine/m_386bsd.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_386bsd.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_386bsd.man'\" \(194 characters\)
sed "s/^X//" >'top-3.4/machine/m_386bsd.man' <<'END_OF_FILE'
X.SH "386BSD NOTES"
XThe 386BSD port was adapted by Steve Hocking from a module
Xoriginally written by Christos Zoulas. The port was later updated
Xby Andrew Herbert (and...@werple.apana.org.au).
END_OF_FILE
if test 194 -ne `wc -c <'top-3.4/machine/m_386bsd.man'`; then
echo shar: \"'top-3.4/machine/m_386bsd.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_386bsd.man'
fi
if test -f 'top-3.4/machine/m_aix41.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_aix41.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_aix41.man'\" \(181 characters\)
sed "s/^X//" >'top-3.4/machine/m_aix41.man' <<'END_OF_FILE'
X.SH "AIX 4.1 NOTES"
XThe "last pid" is not displayed, as I couldn't figure out how to
Xobtain it from the kernel.
X.LP
XThe AIX4.1 port was written by Joep Vesseur <jo...@fwi.uva.nl>.
END_OF_FILE
if test 181 -ne `wc -c <'top-3.4/machine/m_aix41.man'`; then
echo shar: \"'top-3.4/machine/m_aix41.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_aix41.man'
fi
if test -f 'top-3.4/machine/m_aux3.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_aux3.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_aux3.man'\" \(567 characters\)
sed "s/^X//" >'top-3.4/machine/m_aux3.man' <<'END_OF_FILE'
X.SH "A/UX NOTES"
XThere is no obvious way to find the amount of memory per process
Xthat is currently resident. The percent cpu usage is not
Xmaintained by the operating system, so we fake one.
XThe last pid number is not plucked from the operating system
Xeither. The number given is based on the information collected
Xin the process snapshots.
X.LP
XAlthough AUX does not generally have a renice system call,
Xthere is a compile-time option that may have been enabled
Xwhen the program was installed.
X.LP
XThe A/UX 3.1 port was written by Richard Henderson <r...@tamu.edu>.
END_OF_FILE
if test 567 -ne `wc -c <'top-3.4/machine/m_aux3.man'`; then
echo shar: \"'top-3.4/machine/m_aux3.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_aux3.man'
fi
if test -f 'top-3.4/machine/m_bsd44.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_bsd44.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_bsd44.man'\" \(138 characters\)
sed "s/^X//" >'top-3.4/machine/m_bsd44.man' <<'END_OF_FILE'
X.SH "4.4 BSD DIFFERENCES"
XThe 4.4 BSD port is said to work at least as well as ps does.
X
XThe 4.4 BSD port was written by Christos Zoulas.
END_OF_FILE
if test 138 -ne `wc -c <'top-3.4/machine/m_bsd44.man'`; then
echo shar: \"'top-3.4/machine/m_bsd44.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_bsd44.man'
fi
if test -f 'top-3.4/machine/m_bsd44a.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_bsd44a.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_bsd44a.man'\" \(150 characters\)
sed "s/^X//" >'top-3.4/machine/m_bsd44a.man' <<'END_OF_FILE'
X.SH "4.4 BSD DIFFERENCES"
XThe 4.4 BSD alpha port is said to work at least as well as ps does.
X
XThe 4.4 BSD alpha port was written by Christos Zoulas.
END_OF_FILE
if test 150 -ne `wc -c <'top-3.4/machine/m_bsd44a.man'`; then
echo shar: \"'top-3.4/machine/m_bsd44a.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_bsd44a.man'
fi
if test -f 'top-3.4/machine/m_bsdos2.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_bsdos2.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_bsdos2.man'\" \(202 characters\)
sed "s/^X//" >'top-3.4/machine/m_bsdos2.man' <<'END_OF_FILE'
X.SH "BSD/OS 2.X DIFFERENCES"
XThe BSD/OS port is said to work at least as well as ps does.
X
XThe BSD/OS 2.X port was done by Jeff Polk <po...@BSDI.COM>
Xbased on the 4.4BSD port written by Christos Zoulas.
END_OF_FILE
if test 202 -ne `wc -c <'top-3.4/machine/m_bsdos2.man'`; then
echo shar: \"'top-3.4/machine/m_bsdos2.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_bsdos2.man'
fi
if test -f 'top-3.4/machine/m_convex.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_convex.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_convex.man'\" \(319 characters\)
sed "s/^X//" >'top-3.4/machine/m_convex.man' <<'END_OF_FILE'
X.SH "CONVEX DIFFERENCES"
XThe size field may be smaller then that of ps. I believe the
Xdifference is due to mmap memory.
X
XThe Convex OS 11.X port was done by William L. Jones. Most of it was
Xwas taken from the SunOS 4 port written by William LeFebvre.
XMinor formatting changes by Warren Vosper <war...@convex.com>
END_OF_FILE
if test 319 -ne `wc -c <'top-3.4/machine/m_convex.man'`; then
echo shar: \"'top-3.4/machine/m_convex.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_convex.man'
fi
if test -f 'top-3.4/machine/m_dcosx.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_dcosx.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_dcosx.man'\" \(64 characters\)
sed "s/^X//" >'top-3.4/machine/m_dcosx.man' <<'END_OF_FILE'
X.SH "DC/OSX CREDITS"
XThe DC/OSX port was written by Phillip Wu.
END_OF_FILE
if test 64 -ne `wc -c <'top-3.4/machine/m_dcosx.man'`; then
echo shar: \"'top-3.4/machine/m_dcosx.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_dcosx.man'
fi
if test -f 'top-3.4/machine/m_dgux.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_dgux.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_dgux.man'\" \(977 characters\)
sed "s/^X//" >'top-3.4/machine/m_dgux.man' <<'END_OF_FILE'
X.SH "DG/UX 5.4 DIFFERENCES"
XThe WCPU and SIZE columns are not shown, nor is the "last pid" display, as
Xthis information is not available from the kernel.
XA "processor utilization" column is added, with the heading C. This number
Xreflects a process' relative interactivity, represented by an integer from
X0 to 7. A process with 7 is highly interactive. A process with 0 is not
Xconsidered interactive, but uses mostly CPU resources.
XThe "nice" processor time is not shown, but a "io_wait" processor state is
Xadded, represented the time spent waiting on I/O operations. This is
Xcurrently always set to zero.
X
XProcess are considered "idle" unless they are in "run" or "wait" state.
XProcess are considered to be "system" processes if they have uid=0 and
Xppid=1.
XPercent CPU is not maintained by the kernel, and has to be calculated by
Xtop, by dividing the difference in system+user time by the delay period.
X
XThe DG/UX 5.4 port was written by Mike Williams <mi...@inform.co.nz>.
END_OF_FILE
if test 977 -ne `wc -c <'top-3.4/machine/m_dgux.man'`; then
echo shar: \"'top-3.4/machine/m_dgux.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_dgux.man'
fi
if test -f 'top-3.4/machine/m_dynix.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_dynix.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_dynix.man'\" \(319 characters\)
sed "s/^X//" >'top-3.4/machine/m_dynix.man' <<'END_OF_FILE'
X.SH "DYNIX DIFFERENCES"
XOne the Sequent DYNIX operating system, there is a distinction between runable
Xand running on a processor. The STATE column reflects this by showing "run"
Xwhen the process is runable, and "RUN" when the process is actually running
Xon a processor.
X
XThe DYNIX port was written by Daniel Trinkle.
END_OF_FILE
if test 319 -ne `wc -c <'top-3.4/machine/m_dynix.man'`; then
echo shar: \"'top-3.4/machine/m_dynix.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_dynix.man'
fi
if test -f 'top-3.4/machine/m_freebsd20.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_freebsd20.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_freebsd20.man'\" \(677 characters\)
sed "s/^X//" >'top-3.4/machine/m_freebsd20.man' <<'END_OF_FILE'
X.SH "FreeBSD 2.0 NOTES"
XLast pid is compiler depended.
X
X$ strings /kernel | grep _nextpid
X
X.SH "DESCRIPTION OF MEMORY"
XMemory: 10M Act 1208K Inact 3220K Wired 132K Free 25% Swap, 2924Kin 2604Kout
X
X.TP
X.B K:
XKilobyte
X.TP
X.B M:
XMegabyte
X.TP
X.B %:
X1/100
X
X.TP
X.B Act:
Xnumber of pages active
X.TP
X.B Incat:
Xnumber of pages inactive
X.TP
X.B Wired:
Xnumber of pages wired down
X.TP
X.B Free:
Xnumber of pages free
X
X.TP
X.B Swap:
Xswap usage
X.TP
X.B Kin:
Xkilobytes swap pager pages paged in (last interval)
X.TP
X.B Kout:
Xkilobytes swap pager pages paged out (last interval)
X
X.PP
XSee /usr/include/sys/vmmeter.h and /sys/vm/vm_meter.c.
X
X.PP
XWolfram Schneider <wo...@cs.tu-berlin.de>
END_OF_FILE
if test 677 -ne `wc -c <'top-3.4/machine/m_freebsd20.man'`; then
echo shar: \"'top-3.4/machine/m_freebsd20.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_freebsd20.man'
fi
if test -f 'top-3.4/machine/m_ftx.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_ftx.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_ftx.man'\" \(301 characters\)
sed "s/^X//" >'top-3.4/machine/m_ftx.man' <<'END_OF_FILE'
X.SH "FTX CREDITS"
XThe SVR4 port was initially written by Andrew Herbert. He was guided by a SVR4
Xport of top version 2.1 which was done by Andy Crump (an...@bucky.intel.com).
XRobert Boucher (bou...@sofkin.ca) adapted it to top version 3.1.
XSteve Scherf further adapted the SVR4 port to Stratus FTX.
END_OF_FILE
if test 301 -ne `wc -c <'top-3.4/machine/m_ftx.man'`; then
echo shar: \"'top-3.4/machine/m_ftx.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_ftx.man'
fi
if test -f 'top-3.4/machine/m_hpux9.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_hpux9.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_hpux9.man'\" \(463 characters\)
sed "s/^X//" >'top-3.4/machine/m_hpux9.man' <<'END_OF_FILE'
X.SH "HPUX 9 INFORMATION"
XUnder HP/UX 9, the kernel symbol _ccpu was eliminated. The author
Xbelieve that _cexp is a suitable substitute, but cannot be positive.
XThis seems to be confirmed by the fact that information produced using
Xthis assumption correlates well with that produced by HP's version of top.
X
XThis port was adapted from the port for HP/UX version 8 (written by
XChristos Zoulas). The adaptation was performed by Kevin Schmidt
X<ke...@mcl.ucsb.edu>.
END_OF_FILE
if test 463 -ne `wc -c <'top-3.4/machine/m_hpux9.man'`; then
echo shar: \"'top-3.4/machine/m_hpux9.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_hpux9.man'
fi
if test -f 'top-3.4/machine/m_linux.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_linux.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_linux.man'\" \(221 characters\)
sed "s/^X//" >'top-3.4/machine/m_linux.man' <<'END_OF_FILE'
X.SH "LINUX NOTES"
XThe Linux port was written by Richard Henderson <r...@tamu.edu>.
XThe CPU% calculation was brazenly stolen from the Solaris 2
Xport and should be attributed to one of the many names listed
Xin its man page.
END_OF_FILE
if test 221 -ne `wc -c <'top-3.4/machine/m_linux.man'`; then
echo shar: \"'top-3.4/machine/m_linux.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_linux.man'
fi
if test -f 'top-3.4/machine/m_ncr3000.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_ncr3000.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_ncr3000.man'\" \(345 characters\)
sed "s/^X//" >'top-3.4/machine/m_ncr3000.man' <<'END_OF_FILE'
X.SH "NCR System 3000 CREDITS"
XThe SVR4 port was initially written by Andrew Herbert. He was guided by a SVR4
Xport of top version 2.1 which was done by Andy Crump (an...@bucky.intel.com).
XRobert Boucher (bou...@sofkin.ca) adapted it to top version 3.1.
XJeff Janvrin (jeff.j...@columbiasc.ncr.com) ported version 3.3 to
Xthe /stats filesystem
END_OF_FILE
if test 345 -ne `wc -c <'top-3.4/machine/m_ncr3000.man'`; then
echo shar: \"'top-3.4/machine/m_ncr3000.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_ncr3000.man'
fi
if test -f 'top-3.4/machine/m_netbsd08.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_netbsd08.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_netbsd08.man'\" \(129 characters\)
sed "s/^X//" >'top-3.4/machine/m_netbsd08.man' <<'END_OF_FILE'
X.SH "NetBSD NOTES"
X
XOnly tested with NetBSD/i386. Someone should check the memory size stuff.
XStolen back from the m_386bsd.c...
END_OF_FILE
if test 129 -ne `wc -c <'top-3.4/machine/m_netbsd08.man'`; then
echo shar: \"'top-3.4/machine/m_netbsd08.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_netbsd08.man'
fi
if test -f 'top-3.4/machine/m_next40.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_next40.c'\"
else
echo shar: Extracting \"'top-3.4/machine/m_next40.c'\" \(1204 characters\)
sed "s/^X//" >'top-3.4/machine/m_next40.c' <<'END_OF_FILE'
X/*
X * top - a top users display for Unix
X * NEXTSTEP v.0.3 2/14/1996 tpugh
X *
X * SYNOPSIS: any hppa or sparc NEXTSTEP v3.3 system
X *
X * DESCRIPTION:
X * This is the machine-dependent module for NEXTSTEP v3.x/4.x
X * Reported to work for:
X * NEXTSTEP v3.2 on HP machines.
X * NEXTSTEP v3.3 on HP and Sparc machines.
X * Has not been tested for NEXTSTEP v4.0 machines, although it should work.
X * Install "top" with the permissions 4755.
X * tsunami# chmod 4755 top
X * tsunami# ls -lg top
X * -rwsr-xr-x 1 root kmem 121408 Sep 1 10:14 top*
X * With the kmem group sticky bit set, we can read kernal memory without problems,
X * but to communicate with the Mach kernal for task and thread info, it requires
X * root privileges.
X *
X * LIBS:
X *
X * Need the compiler flag, "-DSHOW_UTT", to see the user task and thread task
X * data structures to report process info.
X * Need the compiler flag, "-DNEXTSTEP40", to use the proper task structure.
X * Need -I. for all the top include files which are searched for in machine/,
X * because of the way include "file" finds files.
X *
X * CFLAGS: -I. -DSHOW_UTT -DNEXTSTEP40
X *
X *
X * AUTHORS: Tim Pugh <tp...@oce.orst.edu>
X */
X
X#include "machine/m_next32.c"
END_OF_FILE
if test 1204 -ne `wc -c <'top-3.4/machine/m_next40.c'`; then
echo shar: \"'top-3.4/machine/m_next40.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_next40.c'
fi
if test -f 'top-3.4/machine/m_next_task.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_next_task.h'\"
else
echo shar: Extracting \"'top-3.4/machine/m_next_task.h'\" \(3392 characters\)
sed "s/^X//" >'top-3.4/machine/m_next_task.h' <<'END_OF_FILE'
X/*
X * This is a stripped-down and hacked version of task.h from NextStep 2.1
X * from the Informer.app by Max Tardiveau.
X *
X * tpugh 2/14/1996
X * I've modify this task structure to account some unknown variables in
X * NeXT's new (unpublished) task structure, so I can get to the utask structure.
X * tmp1[3] is in the right place, but tmp2[3] may not be in the right place.
X * So do not be surprised if any other variable in the structure, except utask,
X * is incorrectly aligned.
X *
X */
X
X
X#import <mach/boolean.h>
X#import <mach/port.h>
X#import <mach/time_value.h>
X#import <kernserv/lock.h>
X#import <kernserv/queue.h>
X#import <mach/mach_param.h>
X#import <mach/mach_types.h>
X
Xstruct task {
X#ifdef NEXTSTEP40
X int tmp1[3];
X#endif
X /* Synchronization/destruction information */
X char lock[4];
X int ref_count; /* Number of references to me */
X boolean_t active; /* Task has not been terminated */
X
X /* Miscellaneous */
X char map[4]; /* Address space description */
X queue_chain_t pset_tasks; /* list of tasks assigned to pset */
X int suspend_count; /* Internal scheduling only */
X
X /* Thread information */
X queue_head_t thread_list; /* list of threads */
X int thread_count; /* number of threads */
X char thread_list_lock[4]; /* XXX thread_list lock */
X processor_set_t processor_set; /* processor set for new threads */
X#ifdef NEXTSTEP40
X int tmp2[3];
X#endif
X boolean_t may_assign; /* can assigned pset be changed? */
X boolean_t assign_active; /* waiting for may_assign */
X
X /* Garbage */
X struct utask *u_address;
X#if NeXT
X struct proc *proc; /* corresponding process */
X#else NeXT
X int proc_index; /* corresponding process, by index */
X#endif NeXT
X
X /* User-visible scheduling information */
X int user_stop_count; /* outstanding stops */
X int priority; /* for new threads */
X
X /* Information for kernel-internal tasks */
X#if NeXT
X boolean_t kernel_privilege; /* Is a kernel task */
X#endif NeXT
X boolean_t kernel_ipc_space; /* Uses kernel's port names? */
X boolean_t kernel_vm_space; /* Uses kernel's pmap? */
X
X /* Statistics */
X time_value_t total_user_time;
X /* total user time for dead threads */
X time_value_t total_system_time;
X /* total system time for dead threads */
X
X /* Special ports */
X port_t task_self; /* Port representing the task */
X port_t task_tself; /* What the task thinks is task_self */
X port_t task_notify; /* Where notifications get sent */
X port_t exception_port; /* Where exceptions are sent */
X port_t bootstrap_port; /* Port passed on for task startup */
X
X /* IPC structures */
X boolean_t ipc_privilege; /* Can use kernel resource pools? */
X char ipc_translation_lock[4];
X queue_head_t ipc_translations; /* Per-task port naming */
X boolean_t ipc_active; /* Can IPC rights be added? */
X port_name_t ipc_next_name; /* Next local name to use */
X#if MACH_IPC_XXXHACK
X kern_set_t ipc_enabled; /* Port set for PORT_ENABLED */
X#endif MACH_IPC_XXXHACK
X
X#if MACH_IPC_TCACHE
X#define OBJ_CACHE_MAX 010 /* Number of cache lines */
X#define OBJ_CACHE_MASK 007 /* Mask for name->line */
X
X struct {
X port_name_t name;
X kern_obj_t object;
X } obj_cache[OBJ_CACHE_MAX];
X /* Fast object translation cache */
X#endif MACH_IPC_TCACHE
X
X /* IPC compatibility garbage */
X boolean_t ipc_intr_msg; /* Send signal upon message arrival? */
X#define TASK_PORT_REGISTER_MAX 4 /* Number of "registered" ports */
X port_t ipc_ports_registered[TASK_PORT_REGISTER_MAX];
X};
END_OF_FILE
if test 3392 -ne `wc -c <'top-3.4/machine/m_next_task.h'`; then
echo shar: \"'top-3.4/machine/m_next_task.h'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_next_task.h'
fi
if test -f 'top-3.4/machine/m_sco.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_sco.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_sco.man'\" \(433 characters\)
sed "s/^X//" >'top-3.4/machine/m_sco.man' <<'END_OF_FILE'
X.SH "SCO UNIX NOTES"
XThe SCO Unix port was written by Gregory Shilin <shi...@onyx.co.il>.
XSCO Unix is almost totally different from normal Unix'es. Yes, there
Xis a variable avenrun in kernel, but its length is 8, so it cannot be
Xa 3 element array. And there is no variable cp_time at all. Also there
Xis no function setpriority() in SCO. All attempts to set a process's
Xpriority (such as with the internal renice command) will fail.
END_OF_FILE
if test 433 -ne `wc -c <'top-3.4/machine/m_sco.man'`; then
echo shar: \"'top-3.4/machine/m_sco.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_sco.man'
fi
if test -f 'top-3.4/machine/m_sunos4.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_sunos4.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_sunos4.man'\" \(1281 characters\)
sed "s/^X//" >'top-3.4/machine/m_sunos4.man' <<'END_OF_FILE'
X.SH "SUNOS 4 DIFFERENCES"
XOn multiprocessor machines, the amount of time the processors spend in
Xa spin lock is displayed along with the other processor state
Xpercentages. The percentages shown for processor states are averages
Xacross all processors. A process in run state also has its current
Xprocessor displayed in the STATE column, for example "run/2" indicates
Xrunning on processor 2. There is an extra column in the process
Xdisplay indicating which processor each running process is assigned
Xto. Information about physical memory is displayed on the memory
Xstatus line, but information about virtual memory is not available.
X
XDue to incompatabilities in kernel data structures, a top executable
Xcompiled on a Sun 4 multiprocessor architecture machine (sun4m) will
Xnot run correctly on a uniprocessor architecture machine (sun4), and
Xvice versa. You will have to compile and maintain separate executables
Xfor these architectures. Yeah, I don't like it either.
X
XSome processes may show up with a resident set size (RES column) larger
Xthan total virtual memory size (SIZE column). This seems odd at first,
Xbut is a consequence of shared libraries: shared memory is counted as
Xresident but is not counted in total size.
X
XThe SunOS 4 port was written by William LeFebvre.
END_OF_FILE
if test 1281 -ne `wc -c <'top-3.4/machine/m_sunos4.man'`; then
echo shar: \"'top-3.4/machine/m_sunos4.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_sunos4.man'
fi
if test -f 'top-3.4/machine/m_sunos5.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_sunos5.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_sunos5.man'\" \(366 characters\)
sed "s/^X//" >'top-3.4/machine/m_sunos5.man' <<'END_OF_FILE'
X.SH "SUNOS 5 NOTES"
XThe SunOS 5 (Solaris 2) port was written by Torsten Kasch,
X<tor...@techfak.uni-bielefeld.de>. Support for multi-cpu,
Xcalculation of CPU% and memory stats provided by
XRobert Boucher <bou...@sofkin.ca>, Marc Cohen <ma...@aai.com>,
XCharles Hedrick <hed...@geneva.rutgers.edu>,
XWilliam L. Jones <jones@chpc>, and Casper Dik <cas...@fwi.uva.nl>.
END_OF_FILE
if test 366 -ne `wc -c <'top-3.4/machine/m_sunos5.man'`; then
echo shar: \"'top-3.4/machine/m_sunos5.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_sunos5.man'
fi
if test -f 'top-3.4/machine/m_sunos54.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_sunos54.c'\"
else
echo shar: Extracting \"'top-3.4/machine/m_sunos54.c'\" \(1081 characters\)
sed "s/^X//" >'top-3.4/machine/m_sunos54.c' <<'END_OF_FILE'
X/*
X * top - a top users display for Unix
X *
X * SYNOPSIS: Any Sun running SunOS 5.4 (Solaris 2.4) or later.
X *
X * DESCRIPTION:
X * This is the machine-dependent module for SunOS 5.4 and 5.5.
X * There is some support for MP architectures.
X * This makes top work on the following systems:
X * SunOS 5.4
X * SunOS 5.5
X *
X * Tested on a SS20/61 w/ SunPRO C 2.0.1 running Solaris 2.4/SPARC and
X * a P90 running Solaris 2.4/x86.
X *
X * LIBS: -lkvm -lelf -lkstat
X *
X * Need -I. for all the top include files which are searched for in machine/,
X * because of the way include "file" finds files.
X *
X * CFLAGS: -I. -DHAVE_GETOPT -DORDER -DSOLARIS24
X *
X * AUTHORS: Torsten Kasch <tor...@techfak.uni-bielefeld.de>
X * Robert Boucher <bou...@sofkin.ca>
X * CONTRIBUTORS: Marc Cohen <ma...@aai.com>
X * Charles Hedrick <hed...@geneva.rutgers.edu>
X * William L. Jones <jones@chpc>
X * Petri Kutvonen <kutv...@cs.helsinki.fi>
X * Casper Dik <cas...@fwi.uva.nl>
X */
X#include "machine/m_sunos5.c"
END_OF_FILE
if test 1081 -ne `wc -c <'top-3.4/machine/m_sunos54.c'`; then
echo shar: \"'top-3.4/machine/m_sunos54.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_sunos54.c'
fi
if test -f 'top-3.4/machine/m_svr4.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_svr4.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_svr4.man'\" \(328 characters\)
sed "s/^X//" >'top-3.4/machine/m_svr4.man' <<'END_OF_FILE'
X.SH "SVR4 CREDITS"
XThe SVR4 port was initially written by Andrew Herbert. He was guided by a SVR4
Xport of top version 2.1 which was done by Andy Crump (an...@bucky.intel.com).
XRobert Boucher (bou...@sofkin.ca) adapted it to top version 3.1.
XPorted to System 3000 Release 2.03 by
XJeff Janvrin (jeff.janvrinColumbiaSC.NCR.COM)
END_OF_FILE
if test 328 -ne `wc -c <'top-3.4/machine/m_svr4.man'`; then
echo shar: \"'top-3.4/machine/m_svr4.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_svr4.man'
fi
if test -f 'top-3.4/machine/m_svr42.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_svr42.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_svr42.man'\" \(118 characters\)
sed "s/^X//" >'top-3.4/machine/m_svr42.man' <<'END_OF_FILE'
X.SH "SVR42 CREDITS"
XThe SVR42 port was hacked by David Cutter from the SVR4 port initially
Xwritten by Andrew Herbert.
END_OF_FILE
if test 118 -ne `wc -c <'top-3.4/machine/m_svr42.man'`; then
echo shar: \"'top-3.4/machine/m_svr42.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_svr42.man'
fi
if test -f 'top-3.4/machine/m_umax.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_umax.man'\"
else
echo shar: Extracting \"'top-3.4/machine/m_umax.man'\" \(1024 characters\)
sed "s/^X//" >'top-3.4/machine/m_umax.man' <<'END_OF_FILE'
X.SH "MULTIMAX DIFFERENCES"
XThe umax operating system does not assign process ids sequentially, so
Xthere is no "last pid" display. Process state names are: run, exec,
Xwait, event, start, stop. Information about physical memory is
Xdisplayed on the memory status line, but information about virtual
Xmemory is not available. WCPU is not displayed. Percent CPU is
Xcalculated ove the entire life of the process and is a measure of the
Xpercentage of the process's life time spent running. This is very
Xdifferent from the typical Unix measure of percent cpu, but is the
Xbest that can be done with the information available. Also, no
Xattempt is made to determine if a process is currently "idle", thus
Xthe -I flag is assumed to always be true (idle processes are displayed).
X
XThe multimax port is not thorough and not complete. It was done more
Xas an exercise in porting top than as an effort to create something
Xuseful. Currently cpu state percentages are not calculated.
X
XThe Multimax port was written by William LeFebvre.
END_OF_FILE
if test 1024 -ne `wc -c <'top-3.4/machine/m_umax.man'`; then
echo shar: \"'top-3.4/machine/m_umax.man'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_umax.man'
fi
if test -f 'top-3.4/metatop' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/metatop'\"
else
echo shar: Extracting \"'top-3.4/metatop'\" \(1331 characters\)
sed "s/^X//" >'top-3.4/metatop' <<'END_OF_FILE'
X#! /bin/sh
X#
X# Top is very sensitive to differences in the kernel, so much so that an
X# executable created on one sub-architecture may not work on others. It
X# is also quite common for a minor OS revision to require recompilation of
X# top. Both of these problems are especially prevalent on Suns. For
X# example, a top executable made under SunOS 4.1.1 will not run correctly
X# under SunOS 4.1.2, and vice versa. "metatop" attempts to solve this
X# problem by choosing one of several possible top executables to run then
X# executing it.
X#
X# To use metatop your operating system needs to have the command "uname"
X# as part of the standard OS release. MAKE SURE IT DOES before proceeding.
X# It will try to execute the command "top-`uname -m`-`uname -r`" For
X# example, on a sparcstation 1 running SunOS 4.1.1, it will try to run
X# "top-sun4c-4.1.1".
X#
X# INSTALLATION is easy. Just compile top as normal. Then use the command
X# "make metainstall" (on the same machine!) instead of the usual. "make"
X# will insure that this shell script is installed correctly then will install
X# the most recently made top executable with the correct name. Remember:
X# you will need to "make clean" and "make metainstall" on every different
X# combination of sub-architecture and OS version that you have.
X#
Xexec $0-`uname -m`-`uname -r` "$@"
END_OF_FILE
if test 1331 -ne `wc -c <'top-3.4/metatop'`; then
echo shar: \"'top-3.4/metatop'\" unpacked with wrong size!
fi
chmod +x 'top-3.4/metatop'
# end of 'top-3.4/metatop'
fi
if test -f 'top-3.4/os.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/os.h'\"
else
echo shar: Extracting \"'top-3.4/os.h'\" \(780 characters\)
sed "s/^X//" >'top-3.4/os.h' <<'END_OF_FILE'
X#include <sys/types.h>
X#include <sys/param.h> /* This defines BSD */
X#if defined(BSD) && !defined(BSD4_4) && !defined(__osf__)
X# include <stdio.h>
X# include <strings.h>
X# define strchr(a, b) index((a), (b))
X# define strrchr(a, b) rindex((a), (b))
X# define memcpy(a, b, c) bcopy((b), (a), (c))
X# define memzero(a, b) bzero((a), (b))
X# define memcmp(a, b, c) bcmp((a), (b), (c))
X#if defined(NeXT)
X typedef void sigret_t;
X#else
X typedef int sigret_t;
X#endif
X
X/* system routines that don't return int */
Xchar *getenv();
Xcaddr_t malloc();
X
X#else
X# include <stdio.h>
X# define setbuffer(f, b, s) setvbuf((f), (b), (b) ? _IOFBF : _IONBF, (s))
X# include <string.h>
X# include <memory.h>
X# include <stdlib.h>
X# define memzero(a, b) memset((a), 0, (b))
X typedef void sigret_t;
X#endif
END_OF_FILE
if test 780 -ne `wc -c <'top-3.4/os.h'`; then
echo shar: \"'top-3.4/os.h'\" unpacked with wrong size!
fi
# end of 'top-3.4/os.h'
fi
if test -f 'top-3.4/patchlevel.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/patchlevel.h'\"
else
echo shar: Extracting \"'top-3.4/patchlevel.h'\" \(21 characters\)
sed "s/^X//" >'top-3.4/patchlevel.h' <<'END_OF_FILE'
X#define PATCHLEVEL 4
END_OF_FILE
if test 21 -ne `wc -c <'top-3.4/patchlevel.h'`; then
echo shar: \"'top-3.4/patchlevel.h'\" unpacked with wrong size!
fi
# end of 'top-3.4/patchlevel.h'
fi
if test -f 'top-3.4/prime.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/prime.c'\"
else
echo shar: Extracting \"'top-3.4/prime.c'\" \(458 characters\)
sed "s/^X//" >'top-3.4/prime.c' <<'END_OF_FILE'
X/*
X * Prime number generator. It prints on stdout the next prime number
X * higher than the number specified as argv[1].
X */
X
X#include <math.h>
X
Xmain(argc, argv)
X
Xint argc;
Xchar *argv[];
X
X{
X double i, j;
X int f;
X
X if (argc < 2)
X {
X exit(1);
X }
X
X i = atoi(argv[1]);
X while (i++)
X {
X f=1;
X for (j=2; j<i; j++)
X {
X if ((i/j)==floor(i/j))
X {
X f=0;
X break;
X }
X }
X if (f)
X {
X printf("%.0f\n", i);
X exit(0);
X }
X }
X}
END_OF_FILE
if test 458 -ne `wc -c <'top-3.4/prime.c'`; then
echo shar: \"'top-3.4/prime.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/prime.c'
fi
if test -f 'top-3.4/screen.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/screen.h'\"
else
echo shar: Extracting \"'top-3.4/screen.h'\" \(991 characters\)
sed "s/^X//" >'top-3.4/screen.h' <<'END_OF_FILE'
X/*
X * top - a top users display for Unix 4.2
X *
X * This file contains all the definitions necessary to use the hand-written
X * screen package in "screen.c"
X */
X
X#define TCputs(str) tputs(str, 1, putstdout)
X#define putcap(str) (void)((str) != NULL ? TCputs(str) : 0)
X#define Move_to(x, y) TCputs(tgoto(cursor_motion, x, y))
X
X/* declare return values for termcap functions */
Xchar *tgetstr();
Xchar *tgoto();
X
Xextern char ch_erase; /* set to the user's erase character */
Xextern char ch_kill; /* set to the user's kill character */
Xextern char smart_terminal; /* set if the terminal has sufficient termcap
X capabilities for normal operation */
X
X/* These are some termcap strings for use outside of "screen.c" */
Xextern char *cursor_motion;
Xextern char *clear_line;
Xextern char *clear_to_end;
X
X/* rows and columns on the screen according to termcap */
Xextern int screen_length;
Xextern int screen_width;
X
X/* a function that puts a single character on stdout */
Xint putstdout();
END_OF_FILE
if test 991 -ne `wc -c <'top-3.4/screen.h'`; then
echo shar: \"'top-3.4/screen.h'\" unpacked with wrong size!
fi
# end of 'top-3.4/screen.h'
fi
if test -f 'top-3.4/sigconv.awk' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/sigconv.awk'\"
else
echo shar: Extracting \"'top-3.4/sigconv.awk'\" \(1098 characters\)
sed "s/^X//" >'top-3.4/sigconv.awk' <<'END_OF_FILE'
XBEGIN {
X nsig = 0;
X j = 0;
X print "/* This file was automatically generated */"
X print "/* by the awk script \"sigconv.awk\". */\n"
X print "struct sigdesc {"
X print " char *name;"
X print " int number;"
X print "};\n"
X print "struct sigdesc sigdesc[] = {"
X }
X
X/^#define[ \t][ \t]*SIG[A-Z]/ {
X
X j = sprintf("%d", $3);
X str = $2;
X
X if (nsig < j)
X nsig = j;
X
X siglist[j] = sprintf("\"%s\",\t%2d,", \
X substr(str, 4), j);
X }
X/^#[ \t]*define[ \t][ \t]*SIG[A-Z]/ {
X
X j = sprintf("%d", $4);
X str = $3;
X
X if (nsig < j)
X nsig = j;
X
X siglist[j] = sprintf("\"%s\",\t%2d,", \
X substr(str, 4), j);
X }
X/^#[ \t]*define[ \t][ \t]*_SIG[A-Z]/ {
X
X j = sprintf("%d", $4);
X str = $3;
X
X if (nsig < j)
X nsig = j;
X
X siglist[j] = sprintf("\"%s\",\t%2d,", \
X substr(str, 5), j);
X }
X
XEND {
X for (n = 1; n <= nsig; n++)
X if (siglist[n] != "")
X printf(" %s\n", siglist[n]);
X
X printf(" NULL,\t 0\n};\n");
X }
END_OF_FILE
if test 1098 -ne `wc -c <'top-3.4/sigconv.awk'`; then
echo shar: \"'top-3.4/sigconv.awk'\" unpacked with wrong size!
fi
# end of 'top-3.4/sigconv.awk'
fi
if test -f 'top-3.4/top.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/top.h'\"
else
echo shar: Extracting \"'top-3.4/top.h'\" \(721 characters\)
sed "s/^X//" >'top-3.4/top.h' <<'END_OF_FILE'
X/*
X * Top - a top users display for Berkeley Unix
X *
X * General (global) definitions
X */
X
X/* Current major version number */
X#define VERSION 3
X
X/* Number of lines of header information on the standard screen */
X#define Header_lines 6
X
X/* Maximum number of columns allowed for display */
X#define MAX_COLS 128
X
X/* Log base 2 of 1024 is 10 (2^10 == 1024) */
X#define LOG1024 10
X
Xchar *itoa();
Xchar *itoa7();
X
Xchar *version_string();
X
X/* Special atoi routine returns either a non-negative number or one of: */
X#define Infinity -1
X#define Invalid -2
X
X/* maximum number we can have */
X#define Largest 0x7fffffff
X
X/*
X * The entire display is based on these next numbers being defined as is.
X */
X
X#define NUM_AVERAGES 3
X
END_OF_FILE
if test 721 -ne `wc -c <'top-3.4/top.h'`; then
echo shar: \"'top-3.4/top.h'\" unpacked with wrong size!
fi
# end of 'top-3.4/top.h'
fi
if test -f 'top-3.4/top.local.H' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/top.local.H'\"
else
echo shar: Extracting \"'top-3.4/top.local.H'\" \(2458 characters\)
sed "s/^X//" >'top-3.4/top.local.H' <<'END_OF_FILE'
X/*
X * Top - a top users display for Berkeley Unix
X *
X * Definitions for things that might vary between installations.
X */
X
X/*
X * The space command forces an immediate update. Sometimes, on loaded
X * systems, this update will take a significant period of time (because all
X * the output is buffered). So, if the short-term load average is above
X * "LoadMax", then top will put the cursor home immediately after the space
X * is pressed before the next update is attempted. This serves as a visual
X * acknowledgement of the command. On Suns, "LoadMax" will get multiplied by
X * "FSCALE" before being compared to avenrun[0]. Therefore, "LoadMax"
X * should always be specified as a floating point number.
X */
X#ifndef LoadMax
X#define LoadMax %LoadMax%
X#endif
X
X/*
X * "Table_size" defines the size of the hash tables used to map uid to
X * username. The number of users in /etc/passwd CANNOT be greater than
X * this number. If the error message "table overflow: too many users"
X * is printed by top, then "Table_size" needs to be increased. Things will
X * work best if the number is a prime number that is about twice the number
X * of lines in /etc/passwd.
X */
X#ifndef Table_size
X#define Table_size %TableSize%
X#endif
X
X/*
X * "Nominal_TOPN" is used as the default TOPN when Default_TOPN is Infinity
X * and the output is a dumb terminal. If we didn't do this, then
X * installations who use a default TOPN of Infinity will get every
X * process in the system when running top on a dumb terminal (or redirected
X * to a file). Note that Nominal_TOPN is a default: it can still be
X * overridden on the command line, even with the value "infinity".
X */
X#ifndef Nominal_TOPN
X#define Nominal_TOPN %NominalTopn%
X#endif
X
X#ifndef Default_TOPN
X#define Default_TOPN %topn%
X#endif
X
X#ifndef Default_DELAY
X#define Default_DELAY %delay%
X#endif
X
X/*
X * If the local system's getpwnam interface uses random access to retrieve
X * a record (i.e.: 4.3 systems, Sun "yellow pages"), then defining
X * RANDOM_PW will take advantage of that fact. If RANDOM_PW is defined,
X * then getpwnam is used and the result is cached. If not, then getpwent
X * is used to read and cache the password entries sequentially until the
X * desired one is found.
X *
X * We initially set RANDOM_PW to something which is controllable by the
X * Configure script. Then if its value is 0, we undef it.
X */
X
X#define RANDOM_PW %random%
X#if RANDOM_PW == 0
X#undef RANDOM_PW
X#endif
END_OF_FILE
if test 2458 -ne `wc -c <'top-3.4/top.local.H'`; then
echo shar: \"'top-3.4/top.local.H'\" unpacked with wrong size!
fi
# end of 'top-3.4/top.local.H'
fi
if test -f 'top-3.4/utils.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/utils.h'\"
else
echo shar: Extracting \"'top-3.4/utils.h'\" \(522 characters\)
sed "s/^X//" >'top-3.4/utils.h' <<'END_OF_FILE'
X/*
X * Top users/processes display for Unix
X * Version 3
X *
X * This program may be freely redistributed,
X * but this entire comment MUST remain intact.
X *
X * Copyright (c) 1984, 1989, William LeFebvre, Rice University
X * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
X */
X
X/* prototypes for functions found in utils.c */
X
Xint atoiwi();
Xchar *itoa();
Xchar *itoa7();
Xint digits();
Xchar *strecpy();
Xchar **argparse();
Xlong percentages();
Xchar *errmsg();
Xchar *format_time();
Xchar *format_k();
END_OF_FILE
if test 522 -ne `wc -c <'top-3.4/utils.h'`; then
echo shar: \"'top-3.4/utils.h'\" unpacked with wrong size!
fi
# end of 'top-3.4/utils.h'
fi
if test -f 'top-3.4/version.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/version.c'\"
else
echo shar: Extracting \"'top-3.4/version.c'\" \(520 characters\)
sed "s/^X//" >'top-3.4/version.c' <<'END_OF_FILE'
X/*
X * Top users/processes display for Unix
X * Version 3
X *
X * This program may be freely redistributed,
X * but this entire comment MUST remain intact.
X *
X * Copyright (c) 1984, 1989, William LeFebvre, Rice University
X * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
X */
X
X#include "top.h"
X#include "patchlevel.h"
X
Xstatic char version[16];
X
Xchar *version_string()
X
X{
X sprintf(version, "%d.%d", VERSION, PATCHLEVEL);
X#ifdef BETA
X strcat(version, BETA);
X#endif
X return(version);
X}
END_OF_FILE
if test 520 -ne `wc -c <'top-3.4/version.c'`; then
echo shar: \"'top-3.4/version.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/version.c'
fi
echo shar: End of archive 1 \(of 22\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 22 archives.
echo "Now read README and INSTALL, then run Configure"
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0


William Lefebvre

unread,
Sep 1, 1996, 3:00:00 AM9/1/96
to

Submitted-By: w...@groupsys.com (William Lefebvre)
Posting-Number: Volume 29, Issue 111
Archive-Name: top-3.4/part10

#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:

# "End of archive 10 (of 22)."
# Contents: top-3.4/machine/m_aix32.c top-3.4/machine/m_dynix.c
# top-3.4/machine/m_dynix32.c
# Wrapped by lefebvre@acapulco on Fri Aug 30 12:35:50 1996


PATH=/bin:/usr/bin:/usr/ucb ; export PATH

if test -f 'top-3.4/machine/m_aix32.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_aix32.c'\"
else
echo shar: Extracting \"'top-3.4/machine/m_aix32.c'\" \(17513 characters\)
sed "s/^X//" >'top-3.4/machine/m_aix32.c' <<'END_OF_FILE'


X/*
X * top - a top users display for Unix
X *

X * SYNOPSIS: POWER and POWER2 running AIX 3.2.5.0


X *
X * DESCRIPTION:

X * This is the machine-dependent module for AIX 3.2.5.0
X * It is tested on all POWER architectures.
X *
X * TERMCAP: -lcurses
X *
X * CFLAGS: -DORDER
X *
X * AUTHOR: Erik Deumens <deu...@qtp.ufl.edu>
X */
X
X#include <stdlib.h>
X#include <stdio.h>
X#include <fcntl.h>
X#include <nlist.h>
X#include <sys/sysinfo.h>
X#include <procinfo.h>
X#include <sys/proc.h>
X/*
X#include <sys/var.h>
X*/
X#include <pwd.h>
X#include "top.h"
X#include "machine.h"
X
X
X#define PROCRESS(p) (((p)->u.ui_trss + (p)->u.ui_drss)*4)
X#define PROCSIZE(p) (((p)->u.ui_tsize/1024+(p)->u.ui_dvm)*4)
X#define PROCTIME(pi) (pi->u.ui_ru.ru_utime.tv_sec + pi->u.ui_ru.ru_stime.tv_sec)
X
X/*
X * structure procsinfo exists in AIX 4.1 and is constructed here by combining
X * procinfo and userinfo which exists in AIX 3.2 also.
X */
Xstruct procsinfo {
X struct procinfo p;
X struct userinfo u;
X};
X
X/*
X * structure definition taken from 'monitor' by Jussi Maki (jm...@hut.fi)
X */
Xstruct vmker {
X uint n0,n1,n2,n3,n4,n5,n6,n7,n8;
X uint totalmem;
X uint badmem; /* this is used in RS/6000 model 220 */
X uint freemem;
X uint n12;
X uint numperm; /* this seems to keep other than text and data segment
X usage; name taken from /usr/lpp/bos/samples/vmtune.c */
X uint totalvmem,freevmem;
X uint n15, n16, n17, n18, n19;
X};
X
X
X#define KMEM "/dev/kmem"
X
X/* Indices in the nlist array */
X#define X_AVENRUN 0
X#define X_SYSINFO 1
X#define X_VMKER 2
X#define X_PROC 3
X#define X_V 4
X
Xstatic struct nlist nlst[] = {
X { "avenrun", 0, 0, 0, 0, 0 }, /* 0 */
X { "sysinfo", 0, 0, 0, 0, 0 }, /* 1 */
X { "vmker", 0, 0, 0, 0, 0 }, /* 2 */
X { "proc", 0, 0, 0, 0, 0 }, /* 3 */
X { "v", 0, 0, 0, 0, 0 }, /* 4 */
X { NULL, 0, 0, 0, 0, 0 }
X};
X
X
X/* get_process_info returns handle. definition is here */
Xstruct handle
X{
X struct procsinfo **next_proc;
X int remaining;
X};
X
X/*
X * These definitions control the format of the per-process area
X */
Xstatic char header[] =
X " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";
X/* 0123456 -- field to fill in starts at header+6 */
X#define UNAME_START 6
X
X#define Proc_format \
X "%5d %-8.8s %3d %4d %5d%c %4d%c %-5s %6s %5.2f%% %5.2f%% %.14s%s"
X
X
X/* these are for detailing the process states */
Xint process_states[9];
Xchar *procstatenames[] = {
X " none, ", " sleeping, ", " state2, ", " runnable, ",
X " idle, ", " zombie, ", " stopped, ", " running, ", " swapped, ",
X NULL
X};
X
X
X/* these are for detailing the cpu states */
Xint cpu_states[4];
Xchar *cpustatenames[] = {
X "idle", "user", "kernel", "wait",
X NULL
X};
X
X/* these are for detailing the memory statistics */
Xint memory_stats[7];
Xchar *memorynames[] = {
X "M Total. Real: ", "M, ", "M Free, ", "M Buffers. Virtual: ", "M, ", "M Free, ", NULL
X};
X#define M_TOTAL 0
X#define M_REAL 1
X#define M_REALFREE 2
X#define M_BUFFERS 3
X#define M_VIRTUAL 4
X#define M_VIRTFREE 5
X
Xchar *state_abbrev[] = {
X "", "sleep", "", "run", "sleep", "zomb", "stop", "run", "swap"
X};
X
X/* sorting orders. first is default */
Xchar *ordernames[] = {
X "cpu", "size", "res", "time", "pri", NULL
X};
X
X/* compare routines */
Xint compare_cpu(), compare_size(), compare_res(), compare_time(),
X compare_prio();
X
Xint (*proc_compares[])() = {
X compare_cpu,
X compare_size,
X compare_res,
X compare_time,
X compare_prio,
X NULL
X};
X
X/* useful externals */
Xextern int errno;
Xextern char *sys_errlist[];
Xlong lseek();
Xlong time();
Xlong percentages();
X
X
X/* useful globals */
Xint kmem; /* file descriptor */
X
X/* offsets in kernel */
Xstatic unsigned long avenrun_offset;
Xstatic unsigned long sysinfo_offset;
Xstatic unsigned long vmker_offset;
Xstatic unsigned long proc_offset;
Xstatic unsigned long v_offset;
X
X/* used for calculating cpu state percentages */
Xstatic long cp_time[CPU_NTIMES];
Xstatic long cp_old[CPU_NTIMES];
Xstatic long cp_diff[CPU_NTIMES];
X
X/* the runqueue length is a cumulative value. keep old value */
Xlong old_runque;
X
X/* process info */
X/*struct var v_info;*/ /* to determine nprocs */
Xint nprocs; /* maximum nr of procs in proctab */
Xint ncpus; /* nr of cpus installed */
X
Xint ptsize; /* size of process table in bytes */
Xstruct proc *p_proc; /* a copy of the process table */
Xstruct procsinfo *p_info; /* needed for vm and ru info */
Xstruct procinfo *p_infop; /* return array for getproc call */
Xstruct procsinfo **pref; /* processes selected for display */
Xint pref_len; /* number of processes selected */
X
X/* needed to calculate WCPU */
Xunsigned long curtime;
X
X
X/*
X * Initialize globals, get kernel offsets and stuff...
X */
Xmachine_init(statics)
X struct statics *statics;
X{
X if ((kmem = open(KMEM, O_RDONLY)) == -1) {
X perror(KMEM);
X return -1;
X }
X
X /* get kernel symbol offsets */
X if (knlist(nlst, 5, sizeof(struct nlist)) != 0) {
X perror("knlist");
X return -1;
X }
X avenrun_offset = nlst[X_AVENRUN].n_value;
X sysinfo_offset = nlst[X_SYSINFO].n_value;
X vmker_offset = nlst[X_VMKER].n_value;
X proc_offset = nlst[X_PROC].n_value;
X v_offset = nlst[X_V].n_value;
X
X ncpus = 1; /* number of cpus, AIX 3.2 has only 1 CPU */
X nprocs = PROCMASK(NPROC);
X
X ptsize = nprocs * sizeof (struct proc);
X p_proc = (struct proc *)malloc(ptsize);
X p_info = (struct procsinfo *)malloc(nprocs * sizeof (struct procsinfo));
X p_infop = (struct procinfo *)malloc(nprocs * sizeof (struct procinfo));
X pref = (struct procsinfo **)malloc(nprocs * sizeof (struct procsinfo *));
X
X if (!p_proc || !p_info || !p_infop || !pref) {
X fprintf(stderr, "top: not enough memory\n");
X return -1;
X }
X
X statics->procstate_names = procstatenames;
X statics->cpustate_names = cpustatenames;
X statics->memory_names = memorynames;
X statics->order_names = ordernames;
X
X return(0);
X}
X
X
X
Xchar *format_header(uname_field)
X register char *uname_field;
X{
X register char *ptr;
X
X ptr = header + UNAME_START;
X while (*uname_field != '\0')
X {
X *ptr++ = *uname_field++;
X }
X
X return(header);
X}
X
X
X
X
Xget_system_info(si)
X struct system_info *si;
X{
X int load_avg[3];
X struct sysinfo s_info;
X struct vmker m_info;
X int i;
X double total = 0;
X
X /* get the load avarage array */
X getkval(avenrun_offset, (caddr_t)load_avg, sizeof load_avg, "avenrun");
X
X /* get the sysinfo structure */
X getkval(sysinfo_offset, (caddr_t)&s_info, sizeof s_info, "sysinfo");
X
X /* get vmker structure */
X getkval(vmker_offset, (caddr_t)&m_info, sizeof m_info, "vmker");
X
X /* convert load avarages to doubles */
X for (i = 0; i < 3; i++)
X si->load_avg[i] = (double)load_avg[i]/65536.0;
X
X /* calculate cpu state in percentages */
X for (i = 0; i < CPU_NTIMES; i++) {
X cp_old[i] = cp_time[i];
X cp_time[i] = s_info.cpu[i];
X cp_diff[i] = cp_time[i] - cp_old[i];
X total += cp_diff[i];
X }
X
X total = total/1000.0; /* top itself will correct this */
X for (i = 0; i < CPU_NTIMES; i++) {
X cpu_states[i] = cp_diff[i] / total;
X }
X
X /* calculate memory statistics, scale 4K pages to megabytes */
X#define PAGE_TO_MB(a) ((a)*4/1024)
X memory_stats[M_TOTAL] = PAGE_TO_MB(m_info.totalmem+m_info.totalvmem);
X memory_stats[M_REAL] = PAGE_TO_MB(m_info.totalmem);
X memory_stats[M_REALFREE] = PAGE_TO_MB(m_info.freemem);
X memory_stats[M_BUFFERS] = PAGE_TO_MB(m_info.numperm);
X memory_stats[M_VIRTUAL] = PAGE_TO_MB(m_info.totalvmem);
X memory_stats[M_VIRTFREE] = PAGE_TO_MB(m_info.freevmem);
X
X /* runnable processes */
X process_states[0] = s_info.runque - old_runque;
X old_runque = s_info.runque;
X
X si->cpustates = cpu_states;
X si->memory = memory_stats;
X}
X
Xstatic struct handle handle;
X
Xcaddr_t get_process_info(si, sel, compare)
X struct system_info *si;
X struct process_select *sel;
X int (*compare)();
X{
X int i, nproc, st;
X int active_procs = 0, total_procs = 0;
X struct procsinfo *pp, **p_pref = pref;
X unsigned long pctcpu;
X pid_t procsindex = 0;
X struct proc *p;
X
X si->procstates = process_states;
X
X curtime = time(0);
X
X /* get the procinfo structures of all running processes */
X nproc = getproc(p_infop, nprocs, sizeof (struct procinfo));
X if (nproc < 0) {
X perror("getproc");
X exit(1);
X }
X for (i=0; i<nproc; i++) {
X st = getuser(&p_infop[i],sizeof(struct procinfo),
X &p_info[i].u,sizeof(struct userinfo));
X if (st==-1) p_infop[i].pi_stat = SZOMB;
X memcpy (&p_info[i].p,&p_infop[i],sizeof(struct procinfo));
X }
X
X /* the swapper has no cmd-line attached */
X strcpy(p_info[0].u.ui_comm, "swapper");
X
X /* get proc table */
X getkval(proc_offset, (caddr_t)p_proc, ptsize, "proc");
X
X memset(process_states, 0, sizeof process_states);
X
X /* build a list of pointers to processes to show. walk through the
X * list of procsinfo structures instead of the proc table since the
X * mapping of procsinfo -> proctable is easy, the other way around
X * is cumbersome
X */
X for (pp = p_info, i = 0; i < nproc; pp++, i++) {
X
X p = &p_proc[PROCMASK(pp->p.pi_pid)];
X
X if (pp->p.pi_stat && (sel->system || ((pp->p.pi_flag & SKPROC) == 0))) {
X total_procs++;
X process_states[p->p_stat]++;
X if ( (pp->p.pi_stat != SZOMB) &&
X (sel->idle || p->p_cpticks != 0 /*|| (p->p_stat == SACTIVE)*/)
X && (sel->uid == -1 || pp->p.pi_uid == (uid_t)sel->uid)) {
X *p_pref++ = pp;
X active_procs++;
X }
X }
X }
X
X /* the pref array now holds pointers to the procsinfo structures in
X * the p_info array that were selected for display
X */
X
X /* sort if requested */
X if (compare != NULL)
X qsort((char *)pref, active_procs, sizeof (struct procsinfo *),
X compare);
X
X si->last_pid = -1; /* no way to figure out last used pid */
X si->p_total = total_procs;
X si->p_active = pref_len = active_procs;
X
X handle.next_proc = pref;
X handle.remaining = active_procs;
X
X return((caddr_t)&handle);
X}
X
Xchar fmt[128]; /* static area where result is built */
X
X/* define what weighted cpu is. use definition of %CPU from 'man ps(1)' */
X#define weighted_cpu(pp) (PROCTIME(pp) == 0 ? 0.0 : \
X (((PROCTIME(pp)*100.0)/(curtime-pi->u.ui_start)/ncpus)))
X#define double_pctcpu(p) ((double)p->p_pctcpu/(double)FLT_MODULO)
X
Xchar *format_next_process(handle, get_userid)
X caddr_t handle;
X char *(*get_userid)();
X{
X register struct handle *hp;
X register struct procsinfo *pi;
X register struct proc *p;
X char *uname;
X long cpu_time;
X int proc_size, proc_ress;
X char size_unit = 'K';
X char ress_unit = 'K';
X
X hp = (struct handle *)handle;
X if (hp->remaining == 0) { /* safe guard */
X fmt[0] = '\0';
X return fmt;
X }
X pi = *(hp->next_proc++);
X hp->remaining--;
X p = &p_proc[PROCMASK(pi->p.pi_pid)];
X
X cpu_time = PROCTIME(pi);
X
X /* we disply sizes up to 10M in KiloBytes, beyond 10M in MegaBytes */
X if ((proc_size = (pi->u.ui_tsize/1024+pi->u.ui_dvm)*4) > 10240) {
X proc_size /= 1024;
X size_unit = 'M';
X }
X if ((proc_ress = (pi->u.ui_trss + pi->u.ui_drss)*4) > 10240) {
X proc_ress /= 1024;
X ress_unit = 'M';
X }
X
X sprintf(fmt, Proc_format ,
X pi->p.pi_pid, /* PID */
X (*get_userid)(pi->u.ui_uid), /* login name */
X getpriority(PRIO_PROCESS, pi->p.pi_pid),
X EXTRACT_NICE(p), /* fixed or vari */
X proc_size, /* size */
X size_unit, /* K or M */
X proc_ress, /* resident */
X ress_unit, /* K or M */
X state_abbrev[p->p_stat], /* process state */
X format_time(cpu_time), /* time used */
X weighted_cpu(pi), /* WCPU */
X 100.0 * double_pctcpu(p), /* CPU */
X printable(pi->u.ui_comm), /* COMM */
X (pi->p.pi_flag & SKPROC) == 0 ? "" : " (sys)" /* kernel process? */
X );
X return(fmt);
X}
X
X
X/*
X * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
X * "offset" is the byte offset into the kernel for the desired value,
X * "ptr" points to a buffer into which the value is retrieved,
X * "size" is the size of the buffer (and the object to retrieve),
X * "refstr" is a reference string used when printing error meessages,
X * if "refstr" starts with a '!', then a failure on read will not
X * be fatal (this may seem like a silly way to do things, but I
X * really didn't want the overhead of another argument).
X *
X */
Xgetkval(offset, ptr, size, refstr)
X unsigned long offset;
X caddr_t ptr;
X int size;
X char *refstr;
X{
X int upper_2gb = 0;
X
X /* reads above 2Gb are done by seeking to offset%2Gb, and supplying
X * 1 (opposed to 0) as fourth parameter to readx (see 'man kmem')
X */
X if (offset > 1<<31) {
X upper_2gb = 1;
X offset &= 0x7fffffff;
X }
X
X if (lseek(kmem, offset, SEEK_SET) != offset) {
X fprintf(stderr, "top: lseek failed\n");
X exit(-1);
X }
X
X if (readx(kmem, ptr, size, upper_2gb) != size) {
X if (*refstr == '!')
X return 0;
X else {
X fprintf(stderr, "top: kvm_read for %s: %s\n", refstr,
X sys_errlist[errno]);
X exit(-1);
X }
X }
X
X return 1 ;
X}
X
X/* comparison routine for qsort */
X/*
X * The following code is taken from the solaris module and adjusted
X * for AIX -- JV .
X */
X
X#define ORDERKEY_PCTCPU \
X if (lresult = p2->p_pctcpu - p1->p_pctcpu, \
X (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
X
X#define ORDERKEY_CPTICKS \
X if ((result = PROCTIME(pi2) - PROCTIME(pi1)) == 0)
X
X
X#define ORDERKEY_STATE \
X if ((result = sorted_state[p2->p_stat] \
X - sorted_state[p1->p_stat]) == 0)
X
X/* Nice values directly reflect the process' priority, and are always >0 ;-) */
X#define ORDERKEY_PRIO \
X if ((result = EXTRACT_NICE(p1) - EXTRACT_NICE(p2)) == 0)
X
X#define ORDERKEY_RSSIZE \
X if ((result = PROCRESS(pi2) - PROCRESS(pi1)) == 0)
X#define ORDERKEY_MEM \
X if ((result = PROCSIZE(pi2) - PROCSIZE(pi1)) == 0)
X
Xstatic unsigned char sorted_state[] =
X{
X 0, /* not used */
X 0,
X 0,
X 0,
X 3, /* sleep */
X 1, /* zombie */
X 4, /* stop */
X 6, /* run */
X 2, /* swap */
X};
X
X/* compare_cpu - the comparison function for sorting by cpu percentage */
X
Xint
Xcompare_cpu(ppi1, ppi2)
X struct procsinfo **ppi1;
X struct procsinfo **ppi2;
X{
X register struct procsinfo *pi1 = *ppi1, *pi2 = *ppi2;
X register struct proc *p1;
X register struct proc *p2;
X register int result;
X register long lresult;
X
X p1 = &p_proc[PROCMASK(pi1->p.pi_pid)];
X p2 = &p_proc[PROCMASK(pi2->p.pi_pid)];
X
X ORDERKEY_PCTCPU
X ORDERKEY_CPTICKS
X ORDERKEY_STATE
X ORDERKEY_PRIO
X ORDERKEY_RSSIZE
X ORDERKEY_MEM
X ;
X
X return result;
X}
X
X
X/* compare_size - the comparison function for sorting by total memory usage */
X
Xint
Xcompare_size(ppi1, ppi2)
X struct procsinfo **ppi1;
X struct procsinfo **ppi2;
X{
X register struct procsinfo *pi1 = *ppi1, *pi2 = *ppi2;
X register struct proc *p1;
X register struct proc *p2;
X register int result;
X register long lresult;
X
X p1 = &p_proc[PROCMASK(pi1->p.pi_pid)];
X p2 = &p_proc[PROCMASK(pi2->p.pi_pid)];
X
X ORDERKEY_MEM
X ORDERKEY_RSSIZE
X ORDERKEY_PCTCPU
X ORDERKEY_CPTICKS
X ORDERKEY_STATE
X ORDERKEY_PRIO
X ;
X
X return result;
X}
X
X
X/* compare_res - the comparison function for sorting by resident set size */
X
Xint
Xcompare_res(ppi1, ppi2)
X struct procsinfo **ppi1;
X struct procsinfo **ppi2;
X{
X register struct procsinfo *pi1 = *ppi1, *pi2 = *ppi2;
X register struct proc *p1;
X register struct proc *p2;
X register int result;
X register long lresult;
X
X p1 = &p_proc[PROCMASK(pi1->p.pi_pid)];
X p2 = &p_proc[PROCMASK(pi2->p.pi_pid)];
X
X ORDERKEY_RSSIZE
X ORDERKEY_MEM
X ORDERKEY_PCTCPU
X ORDERKEY_CPTICKS
X ORDERKEY_STATE
X ORDERKEY_PRIO
X ;
X
X return result;
X}
X
X
X/* compare_time - the comparison function for sorting by total cpu time */
X
Xint
Xcompare_time(ppi1, ppi2)
X struct procsinfo **ppi1;
X struct procsinfo **ppi2;
X{
X register struct procsinfo *pi1 = *ppi1, *pi2 = *ppi2;
X register struct proc *p1;
X register struct proc *p2;
X register int result;
X register long lresult;
X
X p1 = &p_proc[PROCMASK(pi1->p.pi_pid)];
X p2 = &p_proc[PROCMASK(pi2->p.pi_pid)];
X
X ORDERKEY_CPTICKS
X ORDERKEY_PCTCPU
X ORDERKEY_STATE
X ORDERKEY_PRIO
X ORDERKEY_MEM
X ORDERKEY_RSSIZE
X ;
X
X return result;
X}
X
X
X/* compare_prio - the comparison function for sorting by cpu percentage */
X
Xint
Xcompare_prio(ppi1, ppi2)
X struct procsinfo **ppi1;
X struct procsinfo **ppi2;
X{
X register struct procsinfo *pi1 = *ppi1, *pi2 = *ppi2;
X register struct proc *p1;
X register struct proc *p2;
X register int result;
X register long lresult;
X
X p1 = &p_proc[PROCMASK(pi1->p.pi_pid)];
X p2 = &p_proc[PROCMASK(pi2->p.pi_pid)];
X
X ORDERKEY_PRIO
X ORDERKEY_PCTCPU
X ORDERKEY_CPTICKS
X ORDERKEY_STATE
X ORDERKEY_RSSIZE
X ORDERKEY_MEM
X ;
X
X return result;
X}
X
X
Xproc_owner(pid)
Xint pid;
X{
X int uid;
X register struct procsinfo **prefp = pref;
X register int cnt = pref_len;
X
X while (--cnt >= 0) {
X if ((*prefp)->p.pi_pid == pid)
X return (*prefp)->p.pi_uid;
X prefp++;
X }
X
X return(-1);
X}
X
END_OF_FILE
if test 17513 -ne `wc -c <'top-3.4/machine/m_aix32.c'`; then
echo shar: \"'top-3.4/machine/m_aix32.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_aix32.c'
fi
if test -f 'top-3.4/machine/m_dynix.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_dynix.c'\"
else
echo shar: Extracting \"'top-3.4/machine/m_dynix.c'\" \(17512 characters\)
sed "s/^X//" >'top-3.4/machine/m_dynix.c' <<'END_OF_FILE'


X/*
X * top - a top users display for Unix
X *

X * SYNOPSIS: any Sequent Running Dynix 3.0.x


X *
X * DESCRIPTION:

X * This is the machine-dependent module for Sequent Dynix 3


X * This makes top work on the following systems:

X * Sequent Semmetry, Dynix 3.0.12
X * Sequent Balance, Dynix 3.0.4
X *
X * AUTHOR: Daniel Trinkle <tri...@cs.purdue.edu>
X */
X
X#include <sys/types.h>
X#include <sys/signal.h>
X#include <sys/param.h>
X
X#include <stdio.h>
X#include <nlist.h>
X#include <math.h>
X#include <sys/dir.h>
X#include <sys/user.h>
X#include <sys/proc.h>
X#include <sys/dk.h>
X#include <sys/vm.h>
X#include <machine/pte.h>
X#include <machine/plocal.h>
X#include <machine/engine.h>
X#include <sys/file.h>
X
X#include "top.h"
X#include "machine.h"
X#include "utils.h"
X
X#ifndef uid_t
X/* some early versions of DYNIX don't have uid_t */
X#define uid_t int
X#endif
X
Xstruct engine *engine;
Xstruct engine *pengine;
Xstruct plocal **pplocal;
Xint Nengine;
X
X/* get_process_info passes back a handle. This is what it looks like: */
X
Xstruct handle
X{
X struct proc **next_proc; /* points to next valid proc pointer */
X int remaining; /* number of pointers remaining */
X};
X
X/* declarations for load_avg */
Xtypedef long load_avg;
Xtypedef long pctcpu;
X#define loaddouble(la) ((double)(la) / FSCALE)
X#define intload(i) ((int)((i) * FSCALE))
X#define pctdouble(p) ((double)(p) / FSCALE)
X
X/* define what weighted cpu is. */
X#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
X ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
X
X/* what we consider to be process size: */
X#define PROCSIZE(pp) ((pp)->p_dsize + (pp)->p_ssize)
X
X/* definitions for indices in the nlist array */
X#define X_AVENRUN 0
X#define X_CCPU 1
X#define X_MPID 2
X#define X_NPROC 3
X#define X_PROC 4
X#define X_TOTAL 5
X#define X_ENGINE 6
X#define X_NENGINE 7
X
Xstatic struct nlist nlst[] = {
X { "_avenrun" }, /* 0 */
X { "_ccpu" }, /* 1 */
X { "_mpid" }, /* 2 */
X { "_nproc" }, /* 3 */
X { "_proc" }, /* 4 */
X { "_total" }, /* 5 */
X { "_engine" }, /* 6 */
X { "_Nengine" }, /* 7 */
X { 0 }
X};
X
X/*
X * These definitions control the format of the per-process area
X */
X
Xstatic char header[] =
X " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";
X/* 0123456 -- field to fill in starts at header+6 */
X#define UNAME_START 6
X
X#define Proc_format \
X "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %.16s"
X
X
X/* process state names for the "STATE" column of the display */
X/* the extra nulls in the string "run" are for adding a slash and
X the processor number when needed */
X
Xchar *state_abbrev[] =
X{
X "", "sleep", "WAIT", "run", "start", "zomb", "stop", "RUN"
X};
X
X/* values that we stash away in _init and use in later routines */
X
Xstatic double logcpu;
X
X#define VMUNIX "/dynix"
X#define KMEM "/dev/kmem"
X#define MEM "/dev/mem"
X
Xstatic int kmem = -1;
Xstatic int mem = -1;
X
Xstruct vmtotal total;
X
X/* these are retrieved from the kernel in _init */
X
Xstatic unsigned long proc;
Xstatic int nproc;
Xstatic load_avg ccpu;
X
X/* these are offsets obtained via nlist and used in the get_ functions */
X
Xstatic unsigned long mpid_offset;
Xstatic unsigned long avenrun_offset;
Xstatic unsigned long total_offset;
X
X/* these are for calculating cpu state percentages */
X
Xstatic long cp_time[CPUSTATES];
Xstatic long cp_old[CPUSTATES];
Xstatic long cp_diff[CPUSTATES];
X
X/* these are for detailing the process states */
X
Xint process_states[8];
Xchar *procstatenames[] = {
X "", " sleeping, ", " ABANDONED, ", " runable, ", " starting, ",
X " zombie, ", " stopped, ", " running, ",
X NULL
X};
X
X/* these are for detailing the cpu states */
X
Xint cpu_states[CPUSTATES];
Xchar *cpustatenames[] = {
X "user", "nice", "system", "idle",
X NULL
X};
X
X/* these are for detailing the memory statistics */
X
Xint memory_stats[5];
Xchar *memorynames[] = {
X "K (", "K) real, ", "K (", "K) virtual, ", "K free", NULL
X};
X
X/* these are for keeping track of the proc array */
X
Xstatic int bytes;
Xstatic int pref_len;
Xstatic struct proc *pbase;
Xstatic struct proc **pref;
X
X#define pagetok(size) ((size) << (PGSHIFT - LOG1024))
X
X/* useful externals */
Xextern int errno;
Xextern char *sys_errlist[];
X
Xlong lseek();
X
Xmachine_init(statics)
X
Xstruct statics *statics;
X
X{
X register int i;
X
X /* open kernel memory */
X if ((kmem = open(KMEM, 0)) < 0)
X {
X perror(KMEM);
X exit(20);
X }
X if ((mem = open(MEM, 0)) < 0)
X {
X perror(MEM);
X exit(21);
X }
X
X /* get the list of symbols we want to access in the kernel */
X if ((i = nlist(VMUNIX, nlst)) < 0)
X {
X fprintf(stderr, "top: nlist failed\n");
X return(-1);
X }
X
X /* make sure they were all found */
X if (i > 0 && check_nlist(nlst) > 0)
X {
X return(-1);
X }
X
X /* get the symbol values out of kmem */
X (void) getkval(nlst[X_PROC].n_value, (int *)(&proc), sizeof(proc),
X nlst[X_PROC].n_name);
X (void) getkval(nlst[X_NPROC].n_value, &nproc, sizeof(nproc),
X nlst[X_NPROC].n_name);
X (void) getkval(nlst[X_CCPU].n_value, (int *)(&ccpu), sizeof(ccpu),
X nlst[X_CCPU].n_name);
X (void) getkval(nlst[X_NENGINE].n_value, &Nengine, sizeof(int),
X nlst[X_NENGINE].n_name);
X (void) getkval(nlst[X_ENGINE].n_value, &pengine, sizeof(struct engine *),
X nlst[X_ENGINE].n_name);
X
X engine = (struct engine *)calloc(Nengine, sizeof(struct engine));
X if (engine == NULL)
X {
X fprintf(stderr, "Cannot allocate memory for engine structure\n");
X exit(2);
X }
X (void) getkval(pengine, &engine[0], Nengine * sizeof(struct engine),
X "engine array");
X pplocal = (struct plocal **)calloc(Nengine, sizeof(struct plocal *));
X if (pplocal == NULL)
X {
X fprintf(stderr, "Cannot allocate memory for plocal structures\n");
X exit(2);
X }
X for (i = 0; i < Nengine; i++) {
X pplocal[i] = (struct plocal *)&engine[i].e_local->pp_local[0][0];
X }
X
X /* stash away certain offsets for later use */
X mpid_offset = nlst[X_MPID].n_value;
X avenrun_offset = nlst[X_AVENRUN].n_value;
X total_offset = nlst[X_TOTAL].n_value;
X
X /* this is used in calculating WCPU -- calculate it ahead of time */
X logcpu = log(loaddouble(ccpu));
X
X /* allocate space for proc structure array and array of pointers */
X bytes = nproc * sizeof(struct proc);
X pbase = (struct proc *)malloc(bytes);
X pref = (struct proc **)malloc(nproc * sizeof(struct proc *));
X
X /* Just in case ... */
X if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
X {
X fprintf(stderr, "top: can't allocate sufficient memory\n");
X return(-1);
X }
X
X /* fill in the statics information */
X statics->procstate_names = procstatenames;
X statics->cpustate_names = cpustatenames;
X statics->memory_names = memorynames;
X
X /* all done! */
X return(0);
X}
X
Xchar *format_header(uname_field)
X
Xregister char *uname_field;
X
X{
X register char *ptr;
X
X ptr = header + UNAME_START;
X while (*uname_field != '\0')
X {
X *ptr++ = *uname_field++;
X }
X
X return(header);
X}
X
Xget_system_info(si)
X
Xstruct system_info *si;
X
X{
X load_avg avenrun[3];
X struct plocal plocal;
X register int i, j;
X
X /* get the cp_time array */
X for (j = 0; j < CPUSTATES; j++)
X cp_time[j] = 0L;
X for (i = 0; i < Nengine; i++) {
X (void) getkval(pplocal[i], &plocal, sizeof(struct plocal), "plocal array");
X for (j = 0; j < CPUSTATES; j++)
X cp_time[j] += (long)plocal.cnt.v_time[j];
X }
X
X /* get load average array */
X (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
X "_avenrun");
X
X /* get mpid -- process id of last process */
X (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
X "_mpid");
X
X /* convert load averages to doubles */
X {
X register int i;
X register double *infoloadp;
X register load_avg *sysloadp;
X
X infoloadp = si->load_avg;
X sysloadp = avenrun;
X for (i = 0; i < 3; i++)
X {
X *infoloadp++ = loaddouble(*sysloadp++);
X }
X }
X
X /* convert cp_time counts to percentages */
X (void) percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
X
X /* get total -- systemwide main memory usage structure */
X (void) getkval(total_offset, (int *)(&total), sizeof(total),
X "_total");
X /* convert memory stats to Kbytes */
X memory_stats[0] = pagetok(total.t_rm);
X memory_stats[1] = pagetok(total.t_arm);
X memory_stats[2] = pagetok(total.t_vm);
X memory_stats[3] = pagetok(total.t_avm);
X memory_stats[4] = pagetok(total.t_free);
X
X /* set arrays and strings */
X si->cpustates = cpu_states;
X si->memory = memory_stats;
X}
X
Xstatic struct handle handle;
X
Xcaddr_t get_process_info(si, sel, compare)
X
Xstruct system_info *si;
Xstruct process_select *sel;
Xint (*compare)();
X
X{
X register int i;
X register int total_procs;
X register int active_procs;
X register struct proc **prefp;
X register struct proc *pp;
X
X /* these are copied out of sel for speed */
X int show_idle;
X int show_system;
X int show_uid;
X
X /* read all the proc structures in one fell swoop */
X (void) getkval(proc, (int *)pbase, bytes, "proc array");
X
X /* get a pointer to the states summary array */
X si->procstates = process_states;
X
X /* set up flags which define what we are going to select */
X show_idle = sel->idle;
X show_system = sel->system;
X show_uid = sel->uid != -1;
X
X /* count up process states and get pointers to interesting procs */
X total_procs = 0;
X active_procs = 0;
X bzero((char *)process_states, sizeof(process_states));
X prefp = pref;
X for (pp = pbase, i = 0; i < nproc; pp++, i++)
X {
X /*
X * Place pointers to each valid proc structure in pref[].
X * Process slots that are actually in use have a non-zero
X * status field. Processes with SSYS set are system
X * processes---these get ignored unless show_sysprocs is set.
X */
X if (pp->p_stat != 0 &&
X (show_system || ((pp->p_flag & SSYS) == 0)))
X {
X total_procs++;
X process_states[pp->p_stat]++;
X if ((pp->p_stat != SZOMB) &&
X (show_idle || (pp->p_pctcpu != 0) || (pp->p_stat == SRUN)) &&
X (!show_uid || pp->p_uid == (uid_t)sel->uid))
X {
X *prefp++ = pp;
X active_procs++;
X }
X }
X }
X
X /* if requested, sort the "interesting" processes */
X if (compare != NULL)
X {
X qsort((char *)pref, active_procs, sizeof(struct proc *), compare);
X }
X
X /* remember active and total counts */
X si->p_total = total_procs;
X si->p_active = pref_len = active_procs;
X
X /* pass back a handle */
X handle.next_proc = pref;
X handle.remaining = active_procs;
X return((caddr_t)&handle);
X}
X
Xchar fmt[MAX_COLS]; /* static area where result is built */
X
Xchar *format_next_process(handle, get_userid)
X
Xcaddr_t handle;
Xchar *(*get_userid)();
X
X{
X register struct proc *pp;
X register long cputime;
X register double pct;
X struct user u;
X struct handle *hp;
X
X /* find and remember the next proc structure */
X hp = (struct handle *)handle;
X pp = *(hp->next_proc++);
X hp->remaining--;
X
X
X /* get the process's user struct and set cputime */
X if (getu(pp, &u) == -1)
X {
X (void) strcpy(u.u_comm, "<swapped>");
X cputime = 0;
X }
X else
X {
X /* set u_comm for system processes */
X if (u.u_comm[0] == '\0')
X {
X if (pp->p_pid == 0)
X {
X (void) strcpy(u.u_comm, "Swapper");
X }
X else if (pp->p_pid == 2)
X {
X (void) strcpy(u.u_comm, "Pager");
X }
X }
X
X cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
X }
X
X /* calculate the base for cpu percentages */
X pct = pctdouble(pp->p_pctcpu);
X
X /* format this entry */
X sprintf(fmt,
X Proc_format,
X pp->p_pid,
X (*get_userid)(pp->p_uid),
X pp->p_pri - PZERO,
X pp->p_nice - NZERO,
X format_k(pagetok(PROCSIZE(pp))),
X format_k(pagetok(pp->p_rssize)),
X state_abbrev[pp->p_stat],
X format_time(cputime),
X 100.0 * weighted_cpu(pct, pp),
X 100.0 * pct,
X printable(u.u_comm));
X
X /* return the result */
X return(fmt);
X}
X
X/*
X * getu(p, u) - get the user structure for the process whose proc structure
X * is pointed to by p. The user structure is put in the buffer pointed
X * to by u. Return 0 if successful, -1 on failure (such as the process
X * being swapped out).
X */
X
Xgetu(p, u)
X
Xregister struct proc *p;
Xstruct user *u;
X
X{
X struct pte uptes[UPAGES];
X register caddr_t upage;
X register struct pte *pte;
X register nbytes, n;
X
X /*
X * Check if the process is currently loaded or swapped out. The way we
X * get the u area is totally different for the two cases. For this
X * application, we just don't bother if the process is swapped out.
X */
X if ((p->p_flag & SLOAD) == 0)
X {
X return(-1);
X }
X
X /*
X * Process is currently in memory, we hope!
X */
X#ifdef ns32000
X if (!getkval(p->p_upte, uptes, sizeof(uptes), "!p->p_upte"))
X#else
X if (!getkval(p->p_pttop, uptes, sizeof(uptes), "!p->p_upte"))
X#endif
X {
X /* we can't seem to get to it, so pretend it's swapped out */
X return(-1);
X }
X upage = (caddr_t)u;
X pte = uptes;
X for (nbytes = sizeof(struct user); nbytes > 0; nbytes -= NBPG)
X {
X (void) lseek(mem, (long)(pte++->pg_pfnum * NBPG), 0);
X n = MIN(nbytes, NBPG);
X if (read(mem, upage, n) != n)
X {
X /* we can't seem to get to it, so pretend it's swapped out */
X return(-1);
X }
X upage += n;
X }
X return(0);
X}
X
X/*
X * check_nlist(nlst) - checks the nlist to see if any symbols were not
X * found. For every symbol that was not found, a one-line
X * message is printed to stderr. The routine returns the
X * number of symbols NOT found.
X */
X
Xint check_nlist(nlst)
X
Xregister struct nlist *nlst;
X
X{
X register int i;
X
X /* check to see if we got ALL the symbols we requested */
X /* this will write one line to stderr for every symbol not found */
X
X i = 0;
X while (nlst->n_name != NULL)
X {
X if (nlst->n_type == 0)
X {
X /* this one wasn't found */
X fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
X i = 1;
X }
X nlst++;
X }
X
X return(i);
X}
X
X
X/*
X * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
X * "offset" is the byte offset into the kernel for the desired value,
X * "ptr" points to a buffer into which the value is retrieved,
X * "size" is the size of the buffer (and the object to retrieve),
X * "refstr" is a reference string used when printing error meessages,
X * if "refstr" starts with a '!', then a failure on read will not
X * be fatal (this may seem like a silly way to do things, but I
X * really didn't want the overhead of another argument).


X *
X */
X

Xgetkval(offset, ptr, size, refstr)
X
Xunsigned long offset;
Xint *ptr;
Xint size;
Xchar *refstr;
X
X{
X if (lseek(kmem, (long)offset, 0) == -1)
X {
X if (*refstr == '!')
X {
X refstr++;
X }
X fprintf(stderr, "%s: lseek to %s: %s\n",
X KMEM, refstr, sys_errlist[errno]);
X quit(22);
X }
X if (read(kmem, (char *)ptr, size) == -1)
X {
X if (*refstr == '!')
X {
X /* we lost the race with the kernel, process isn't in memory */
X return(0);
X }
X else
X {
X fprintf(stderr, "%s: reading %s: %s\n",
X KMEM, refstr, sys_errlist[errno]);
X quit(23);
X }
X }
X return(1);
X}
X
X/* comparison routine for qsort */
X
X/*
X * proc_compare - comparison function for "qsort"
X * Compares the resource consumption of two processes using five
X * distinct keys. The keys (in descending order of importance) are:
X * percent cpu, cpu ticks, state, resident set size, total virtual
X * memory usage. The process states are ordered as follows (from least
X * to most important): WAIT, zombie, sleep, stop, start, run. The
X * array declaration below maps a process state index into a number
X * that reflects this ordering.
X */
X
Xstatic unsigned char sorted_state[] =
X{
X 0, /* not used */
X 3, /* sleep */
X 1, /* ABANDONED (WAIT) */
X 6, /* run */
X 5, /* start */
X 2, /* zombie */
X 4, /* stop */
X 7 /* RUN */
X};
X
Xproc_compare(pp1, pp2)
X
Xstruct proc **pp1;
Xstruct proc **pp2;
X
X{
X register struct proc *p1;
X register struct proc *p2;
X register int result;
X register pctcpu lresult;
X
X /* remove one level of indirection */
X p1 = *pp1;
X p2 = *pp2;
X
X /* compare percent cpu (pctcpu) */
X if ((lresult = p2->p_pctcpu - p1->p_pctcpu) == 0)
X {
X /* use cpticks to break the tie */
X if ((result = p2->p_cpticks - p1->p_cpticks) == 0)
X {
X /* use process state to break the tie */
X if ((result = sorted_state[p2->p_stat] -
X sorted_state[p1->p_stat]) == 0)
X {
X /* use priority to break the tie */
X if ((result = p2->p_pri - p1->p_pri) == 0)
X {
X /* use resident set size (rssize) to break the tie */
X if ((result = p2->p_rssize - p1->p_rssize) == 0)
X {
X /* use total memory to break the tie */
X result = PROCSIZE(p2) - PROCSIZE(p1);
X }
X }
X }
X }
X }
X else
X {
X result = lresult < 0 ? -1 : 1;
X }
X
X return(result);
X}
X
X
X/*
X * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
X * the process does not exist.
X * It is EXTREMLY IMPORTANT that this function work correctly.
X * If top runs setuid root (as in SVR4), then this function
X * is the only thing that stands in the way of a serious
X * security problem. It validates requests for the "kill"
X * and "renice" commands.
X */
X
Xint proc_owner(pid)
X
Xint pid;
X
X{
X register int cnt;
X register struct proc **prefp;
X register struct proc *pp;
X
X prefp = pref;
X cnt = pref_len;
X while (--cnt >= 0)
X {
X if ((pp = *prefp++)->p_pid == (pid_t)pid)
X {
X return((int)pp->p_uid);
X }
X }
X return(-1);
X}
END_OF_FILE
if test 17512 -ne `wc -c <'top-3.4/machine/m_dynix.c'`; then
echo shar: \"'top-3.4/machine/m_dynix.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_dynix.c'
fi
if test -f 'top-3.4/machine/m_dynix32.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_dynix32.c'\"
else
echo shar: Extracting \"'top-3.4/machine/m_dynix32.c'\" \(17571 characters\)
sed "s/^X//" >'top-3.4/machine/m_dynix32.c' <<'END_OF_FILE'


X/*
X * top - a top users display for Unix
X *

X * SYNOPSIS: any Sequent Running Dynix 3.2.x


X *
X * DESCRIPTION:

X * This is the machine-dependent module for Sequent Dynix 3.2.0


X * This makes top work on the following systems:

X * Dynix 3.2.0 and perhaps later versions
X *
X * CFLAGS: -DBSD
X *
X * AUTHOR: Daniel Trinkle <tri...@cs.purdue.edu>
X */
X
X#include <sys/types.h>
X#include <sys/signal.h>
X#include <sys/param.h>
X
X#include <stdio.h>
X#include <nlist.h>
X#include <math.h>
X#include <sys/dir.h>
X#include <sys/user.h>
X#include <sys/proc.h>
X#include <sys/dk.h>
X#include <sys/vm.h>
X#include <machine/pte.h>
X#include <machine/plocal.h>
X#include <machine/engine.h>
X#include <sys/file.h>
X
X#include "top.h"
X#include "machine.h"
X#include "utils.h"
X
X#ifndef uid_t
X/* some early versions of DYNIX don't have uid_t */
X#define uid_t int
X#endif
X
X#ifndef pid_t
X/* ditto pid_t */
X#define pid_t short
X#endif
X
Xstruct engine *engine;
Xstruct engine *pengine;
Xstruct plocal **pplocal;
Xint Nengine;
X
X/* get_process_info passes back a handle. This is what it looks like: */
X
Xstruct handle
X{
X struct proc **next_proc; /* points to next valid proc pointer */
X int remaining; /* number of pointers remaining */
X};
X
X/* declarations for load_avg */
Xtypedef long load_avg;
Xtypedef long pctcpu;
X#define loaddouble(la) ((double)(la) / FSCALE)
X#define intload(i) ((int)((i) * FSCALE))
X#define pctdouble(p) ((double)(p) / FSCALE)
X
X/* define what weighted cpu is. */
X#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
X ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
X
X/* what we consider to be process size: */
X#define PROCSIZE(pp) ((pp)->p_dsize + (pp)->p_ssize)
X
X/* definitions for indices in the nlist array */
X#define X_AVENRUN 0
X#define X_CCPU 1
X#define X_MPID 2
X#define X_NPROC 3
X#define X_PROC 4
X#define X_TOTAL 5
X#define X_ENGINE 6
X#define X_NENGINE 7
X
Xstatic struct nlist nlst[] = {
X { "_avenrun" }, /* 0 */
X { "_ccpu" }, /* 1 */
X { "_mpid" }, /* 2 */
X { "_nproc" }, /* 3 */
X { "_proc" }, /* 4 */
X { "_total" }, /* 5 */
X { "_engine" }, /* 6 */
X { "_Nengine" }, /* 7 */
X { 0 }
X};
X
X/*
X * These definitions control the format of the per-process area
X */
X
Xstatic char header[] =
X " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";
X/* 0123456 -- field to fill in starts at header+6 */
X#define UNAME_START 6
X
X#define Proc_format \
X "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %.14s"
X
X
X/* process state names for the "STATE" column of the display */
X/* the extra nulls in the string "run" are for adding a slash and
X the processor number when needed */
X
Xchar *state_abbrev[] =
X{
X "", "sleep", "WAIT", "run", "start", "zomb", "stop", "RUN"
X};
X
X/* values that we stash away in _init and use in later routines */
X
Xstatic double logcpu;
X
X#define VMUNIX "/dynix"
X#define KMEM "/dev/kmem"
X#define MEM "/dev/mem"
X
Xstatic int kmem = -1;
Xstatic int mem = -1;
X
Xstruct vmtotal total;
X
X/* these are retrieved from the kernel in _init */
X
Xstatic unsigned long proc;
Xstatic int nproc;
Xstatic load_avg ccpu;
X
X/* these are offsets obtained via nlist and used in the get_ functions */
X
Xstatic unsigned long mpid_offset;
Xstatic unsigned long avenrun_offset;
Xstatic unsigned long total_offset;
X
X/* these are for calculating cpu state percentages */
X
Xstatic long cp_time[CPUSTATES];
Xstatic long cp_old[CPUSTATES];
Xstatic long cp_diff[CPUSTATES];
X
X/* these are for detailing the process states */
X
Xint process_states[8];
Xchar *procstatenames[] = {
X "", " sleeping, ", " ABANDONED, ", " runable, ", " starting, ",
X " zombie, ", " stopped, ", " running, ",
X NULL
X};
X
X/* these are for detailing the cpu states */
X
Xint cpu_states[CPUSTATES];
Xchar *cpustatenames[] = {
X "user", "nice", "system", "idle",
X NULL
X};
X
X/* these are for detailing the memory statistics */
X
Xint memory_stats[5];
Xchar *memorynames[] = {
X "K (", "K) real, ", "K (", "K) virtual, ", "K free", NULL
X};
X
X/* these are for keeping track of the proc array */
X
Xstatic int bytes;
Xstatic int pref_len;
Xstatic struct proc *pbase;
Xstatic struct proc **pref;
X
X#define pagetok(size) ((size) << (PGSHIFT - LOG1024))
X
X/* useful externals */
Xextern int errno;
Xextern char *sys_errlist[];
X
Xlong lseek();
X
Xmachine_init(statics)
X
Xstruct statics *statics;
X
X{
X register int i;
X
X /* open kernel memory */
X if ((kmem = open(KMEM, 0)) < 0)
X {
X perror(KMEM);
X exit(20);
X }
X if ((mem = open(MEM, 0)) < 0)
X {
X perror(MEM);
X exit(21);
X }
X
X /* get the list of symbols we want to access in the kernel */
X if ((i = nlist(VMUNIX, nlst)) < 0)
X {
X fprintf(stderr, "top: nlist failed\n");
X return(-1);
X }
X
X /* make sure they were all found */
X if (i > 0 && check_nlist(nlst) > 0)
X {
X return(-1);
X }
X
X /* get the symbol values out of kmem */
X (void) getkval(nlst[X_PROC].n_value, (int *)(&proc), sizeof(proc),
X nlst[X_PROC].n_name);
X (void) getkval(nlst[X_NPROC].n_value, &nproc, sizeof(nproc),
X nlst[X_NPROC].n_name);
X (void) getkval(nlst[X_CCPU].n_value, (int *)(&ccpu), sizeof(ccpu),
X nlst[X_CCPU].n_name);
X (void) getkval(nlst[X_NENGINE].n_value, &Nengine, sizeof(int),
X nlst[X_NENGINE].n_name);
X (void) getkval(nlst[X_ENGINE].n_value, &pengine, sizeof(struct engine *),
X nlst[X_ENGINE].n_name);
X
X engine = (struct engine *)calloc(Nengine, sizeof(struct engine));
X if (engine == NULL)
X {
X fprintf(stderr, "Cannot allocate memory for engine structure\n");
X exit(2);
X }
X (void) getkval(pengine, &engine[0], Nengine * sizeof(struct engine),
X "engine array");
X pplocal = (struct plocal **)calloc(Nengine, sizeof(struct plocal *));
X if (pplocal == NULL)
X {
X fprintf(stderr, "Cannot allocate memory for plocal structures\n");
X exit(2);
X }
X for (i = 0; i < Nengine; i++) {
X pplocal[i] = (struct plocal *)&engine[i].e_local->pp_local[0][0];
X }
X
X /* stash away certain offsets for later use */
X mpid_offset = nlst[X_MPID].n_value;
X avenrun_offset = nlst[X_AVENRUN].n_value;
X total_offset = nlst[X_TOTAL].n_value;
X
X /* this is used in calculating WCPU -- calculate it ahead of time */
X logcpu = log(loaddouble(ccpu));
X
X /* allocate space for proc structure array and array of pointers */
X bytes = nproc * sizeof(struct proc);
X pbase = (struct proc *)malloc(bytes);
X pref = (struct proc **)malloc(nproc * sizeof(struct proc *));
X
X /* Just in case ... */
X if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
X {
X fprintf(stderr, "top: can't allocate sufficient memory\n");
X return(-1);
X }
X
X /* fill in the statics information */
X statics->procstate_names = procstatenames;
X statics->cpustate_names = cpustatenames;
X statics->memory_names = memorynames;
X
X /* all done! */
X return(0);
X}
X
Xchar *format_header(uname_field)
X
Xregister char *uname_field;
X
X{
X register char *ptr;
X
X ptr = header + UNAME_START;
X while (*uname_field != '\0')
X {
X *ptr++ = *uname_field++;
X }
X
X return(header);
X}
X
Xget_system_info(si)
X
Xstruct system_info *si;
X
X{
X load_avg avenrun[3];
X struct plocal plocal;
X register int i, j;
X
X /* get the cp_time array */
X for (j = 0; j < CPUSTATES; j++)
X cp_time[j] = 0L;
X for (i = 0; i < Nengine; i++) {
X (void) getkval(pplocal[i], &plocal, sizeof(struct plocal), "plocal array");
X for (j = 0; j < CPUSTATES; j++)
X cp_time[j] += (long)plocal.cnt.v_time[j];
X }
X
X /* get load average array */
X (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
X "_avenrun");
X
X /* get mpid -- process id of last process */
X (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
X "_mpid");
X
X /* convert load averages to doubles */
X {
X register int i;
X register double *infoloadp;
X register load_avg *sysloadp;
X
X infoloadp = si->load_avg;
X sysloadp = avenrun;
X for (i = 0; i < 3; i++)
X {
X *infoloadp++ = loaddouble(*sysloadp++);
X }
X }
X
X /* convert cp_time counts to percentages */
X (void) percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
X
X /* get total -- systemwide main memory usage structure */
X (void) getkval(total_offset, (int *)(&total), sizeof(total),
X "_total");
X /* convert memory stats to Kbytes */
X memory_stats[0] = pagetok(total.t_rm);
X memory_stats[1] = pagetok(total.t_arm);
X memory_stats[2] = pagetok(total.t_vm);
X memory_stats[3] = pagetok(total.t_avm);
X memory_stats[4] = pagetok(total.t_free);
X
X /* set arrays and strings */
X si->cpustates = cpu_states;
X si->memory = memory_stats;
X}
X
Xstatic struct handle handle;
X
Xcaddr_t get_process_info(si, sel, compare)
X
Xstruct system_info *si;
Xstruct process_select *sel;
Xint (*compare)();
X
X{
X register int i;
X register int total_procs;
X register int active_procs;
X register struct proc **prefp;
X register struct proc *pp;
X
X /* these are copied out of sel for speed */
X int show_idle;
X int show_system;
X int show_uid;
X
X /* read all the proc structures in one fell swoop */
X (void) getkval(proc, (int *)pbase, bytes, "proc array");
X
X /* get a pointer to the states summary array */
X si->procstates = process_states;
X
X /* set up flags which define what we are going to select */
X show_idle = sel->idle;
X show_system = sel->system;
X show_uid = sel->uid != -1;
X
X /* count up process states and get pointers to interesting procs */
X total_procs = 0;
X active_procs = 0;
X bzero((char *)process_states, sizeof(process_states));
X prefp = pref;
X for (pp = pbase, i = 0; i < nproc; pp++, i++)
X {
X /*
X * Place pointers to each valid proc structure in pref[].
X * Process slots that are actually in use have a non-zero
X * status field. Processes with SSYS set are system
X * processes---these get ignored unless show_sysprocs is set.
X */
X if (pp->p_stat != 0 &&
X (show_system || ((pp->p_flag & SSYS) == 0)))
X {
X total_procs++;
X process_states[pp->p_stat]++;
X if ((pp->p_stat != SZOMB) &&
X (show_idle || (pp->p_pctcpu != 0) || (pp->p_stat == SRUN)) &&
X (!show_uid || pp->p_uid == (uid_t)sel->uid))
X {
X *prefp++ = pp;
X active_procs++;
X }
X }
X }
X
X /* if requested, sort the "interesting" processes */
X if (compare != NULL)
X {
X qsort((char *)pref, active_procs, sizeof(struct proc *), compare);
X }
X
X /* remember active and total counts */
X si->p_total = total_procs;
X si->p_active = pref_len = active_procs;
X
X /* pass back a handle */
X handle.next_proc = pref;
X handle.remaining = active_procs;
X return((caddr_t)&handle);
X}
X
Xchar fmt[MAX_COLS]; /* static area where result is built */
X
Xchar *format_next_process(handle, get_userid)
X
Xcaddr_t handle;
Xchar *(*get_userid)();
X
X{
X register struct proc *pp;
X register long cputime;
X register double pct;
X struct user u;
X struct handle *hp;
X
X /* find and remember the next proc structure */
X hp = (struct handle *)handle;
X pp = *(hp->next_proc++);
X hp->remaining--;
X
X
X /* get the process's user struct and set cputime */
X if (getu(pp, &u) == -1)
X {
X (void) strcpy(u.u_comm, "<swapped>");
X cputime = 0;
X }
X else
X {
X /* set u_comm for system processes */
X if (u.u_comm[0] == '\0')
X {
X if (pp->p_pid == 0)
X {
X (void) strcpy(u.u_comm, "Swapper");
X }
X else if (pp->p_pid == 2)
X {
X (void) strcpy(u.u_comm, "Pager");
X }
X }
X
X cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
X }
X
X /* calculate the base for cpu percentages */
X pct = pctdouble(pp->p_pctcpu);
X
X /* format this entry */
X sprintf(fmt,
X Proc_format,
X pp->p_pid,
X (*get_userid)(pp->p_uid),
X pp->p_pri - PZERO,
X pp->p_nice - NZERO,
X format_k(pagetok(PROCSIZE(pp))),
X format_k(pagetok(pp->p_rssize)),
X state_abbrev[pp->p_stat],
X format_time(cputime),
X 100.0 * weighted_cpu(pct, pp),
X 100.0 * pct,
X printable(u.u_comm));
X
X /* return the result */
X return(fmt);
X}
X
X/*
X * getu(p, u) - get the user structure for the process whose proc structure
X * is pointed to by p. The user structure is put in the buffer pointed
X * to by u. Return 0 if successful, -1 on failure (such as the process
X * being swapped out).
X */
X
Xgetu(p, u)
X
Xregister struct proc *p;
Xstruct user *u;
X
X{
X struct pte uptes[UPAGES];
X register caddr_t upage;
X register struct pte *pte;
X register nbytes, n;
X
X /*
X * Check if the process is currently loaded or swapped out. The way we
X * get the u area is totally different for the two cases. For this
X * application, we just don't bother if the process is swapped out.
X */
X if ((p->p_flag & SLOAD) == 0)
X {
X return(-1);
X }
X
X /*
X * Process is currently in memory, we hope!
X */
X#ifdef ns32000
X if (!getkval(p->p_upte, uptes, sizeof(uptes), "!p->p_upte"))
X#else
X if (!getkval(p->p_pttop, uptes, sizeof(uptes), "!p->p_upte"))
X#endif
X {
X /* we can't seem to get to it, so pretend it's swapped out */
X return(-1);
X }
X upage = (caddr_t)u;
X pte = uptes;
X for (nbytes = sizeof(struct user); nbytes > 0; nbytes -= NBPG)
X {
X (void) lseek(mem, (long)(pte++->pg_pfnum * NBPG), 0);
X n = MIN(nbytes, NBPG);
X if (read(mem, upage, n) != n)
X {
X /* we can't seem to get to it, so pretend it's swapped out */
X return(-1);
X }
X upage += n;
X }
X return(0);
X}
X
X/*
X * check_nlist(nlst) - checks the nlist to see if any symbols were not
X * found. For every symbol that was not found, a one-line
X * message is printed to stderr. The routine returns the
X * number of symbols NOT found.
X */
X
Xint check_nlist(nlst)
X
Xregister struct nlist *nlst;
X
X{
X register int i;
X
X /* check to see if we got ALL the symbols we requested */
X /* this will write one line to stderr for every symbol not found */
X
X i = 0;
X while (nlst->n_name != NULL)
X {
X if (nlst->n_type == 0)
X {
X /* this one wasn't found */
X fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
X i = 1;
X }
X nlst++;
X }
X
X return(i);
X}
X
X
X/*
X * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
X * "offset" is the byte offset into the kernel for the desired value,
X * "ptr" points to a buffer into which the value is retrieved,
X * "size" is the size of the buffer (and the object to retrieve),
X * "refstr" is a reference string used when printing error meessages,
X * if "refstr" starts with a '!', then a failure on read will not
X * be fatal (this may seem like a silly way to do things, but I
X * really didn't want the overhead of another argument).


X *
X */
X

Xgetkval(offset, ptr, size, refstr)
X
Xunsigned long offset;
Xint *ptr;
Xint size;
Xchar *refstr;
X
X{
X if (lseek(kmem, (long)offset, 0) == -1)
X {
X if (*refstr == '!')
X {
X refstr++;
X }
X fprintf(stderr, "%s: lseek to %s: %s\n",
X KMEM, refstr, sys_errlist[errno]);
X quit(22);
X }
X if (read(kmem, (char *)ptr, size) == -1)
X {
X if (*refstr == '!')
X {
X /* we lost the race with the kernel, process isn't in memory */
X return(0);
X }
X else
X {
X fprintf(stderr, "%s: reading %s: %s\n",
X KMEM, refstr, sys_errlist[errno]);
X quit(23);
X }
X }
X return(1);
X}
X
X/* comparison routine for qsort */
X
X/*
X * proc_compare - comparison function for "qsort"
X * Compares the resource consumption of two processes using five
X * distinct keys. The keys (in descending order of importance) are:
X * percent cpu, cpu ticks, state, resident set size, total virtual
X * memory usage. The process states are ordered as follows (from least
X * to most important): WAIT, zombie, sleep, stop, start, run. The
X * array declaration below maps a process state index into a number
X * that reflects this ordering.
X */
X
Xstatic unsigned char sorted_state[] =
X{
X 0, /* not used */
X 3, /* sleep */
X 1, /* ABANDONED (WAIT) */
X 6, /* run */
X 5, /* start */
X 2, /* zombie */
X 4, /* stop */
X 7 /* RUN */
X};
X
Xproc_compare(pp1, pp2)
X
Xstruct proc **pp1;
Xstruct proc **pp2;
X
X{
X register struct proc *p1;
X register struct proc *p2;
X register int result;
X register pctcpu lresult;
X
X /* remove one level of indirection */
X p1 = *pp1;
X p2 = *pp2;
X
X /* compare percent cpu (pctcpu) */
X if ((lresult = p2->p_pctcpu - p1->p_pctcpu) == 0)
X {
X /* use cpticks to break the tie */
X if ((result = p2->p_cpticks - p1->p_cpticks) == 0)
X {
X /* use process state to break the tie */
X if ((result = sorted_state[p2->p_stat] -
X sorted_state[p1->p_stat]) == 0)
X {
X /* use priority to break the tie */
X if ((result = p2->p_pri - p1->p_pri) == 0)
X {
X /* use resident set size (rssize) to break the tie */
X if ((result = p2->p_rssize - p1->p_rssize) == 0)
X {
X /* use total memory to break the tie */
X result = PROCSIZE(p2) - PROCSIZE(p1);
X }
X }
X }
X }
X }
X else
X {
X result = lresult < 0 ? -1 : 1;
X }
X
X return(result);
X}
X
X
X/*
X * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
X * the process does not exist.
X * It is EXTREMLY IMPORTANT that this function work correctly.
X * If top runs setuid root (as in SVR4), then this function
X * is the only thing that stands in the way of a serious
X * security problem. It validates requests for the "kill"
X * and "renice" commands.
X */
X
Xint proc_owner(pid)
X
Xint pid;
X
X{
X register int cnt;
X register struct proc **prefp;
X register struct proc *pp;
X
X prefp = pref;
X cnt = pref_len;
X while (--cnt >= 0)
X {
X if ((pp = *prefp++)->p_pid == (pid_t)pid)
X {
X return((int)pp->p_uid);
X }
X }
X return(-1);
X}
END_OF_FILE
if test 17571 -ne `wc -c <'top-3.4/machine/m_dynix32.c'`; then
echo shar: \"'top-3.4/machine/m_dynix32.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_dynix32.c'
fi
echo shar: End of archive 10 \(of 22\).
cp /dev/null ark10isdone

William Lefebvre

unread,
Sep 1, 1996, 3:00:00 AM9/1/96
to

Submitted-By: w...@groupsys.com (William Lefebvre)
Posting-Number: Volume 29, Issue 112
Archive-Name: top-3.4/part11

#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:

# "End of archive 11 (of 22)."
# Contents: top-3.4/machine/m_bsd43.c top-3.4/machine/m_osmp41a.c
# Wrapped by lefebvre@acapulco on Fri Aug 30 12:35:50 1996


PATH=/bin:/usr/bin:/usr/ucb ; export PATH

if test -f 'top-3.4/machine/m_bsd43.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_bsd43.c'\"
else
echo shar: Extracting \"'top-3.4/machine/m_bsd43.c'\" \(18437 characters\)
sed "s/^X//" >'top-3.4/machine/m_bsd43.c' <<'END_OF_FILE'


X/*
X * top - a top users display for Unix
X *

X * SYNOPSIS: any generic 4.3BSD system


X *
X * DESCRIPTION:

X * This is the machine-dependent module for BSD4.3
X * Works for:
X * 4.3 BSD
X * AOS4.3, IBM rt/pc
X * mtXinu, vax


X *
X * LIBS:
X *

X * AUTHOR: Christos Zoulas <chri...@ee.cornell.edu>


X */
X
X#include <sys/types.h>
X#include <sys/signal.h>
X#include <sys/param.h>
X
X#include <stdio.h>
X#include <nlist.h>
X#include <math.h>
X#include <sys/dir.h>
X#include <sys/user.h>
X#include <sys/proc.h>
X#include <sys/dk.h>
X#include <sys/vm.h>

X#include <sys/file.h>
X#include <sys/time.h>
X#include <machine/pte.h>
X
X
X#define DOSWAP


X
X#include "top.h"
X#include "machine.h"
X#include "utils.h"
X

Xextern int errno, sys_nerr;
Xextern char *sys_errlist[];
X#define strerror(e) (((e) >= 0 && (e) < sys_nerr) ? sys_errlist[(e)] : "Unknown error")
X
X#define VMUNIX "/vmunix"


X#define KMEM "/dev/kmem"
X#define MEM "/dev/mem"

X#ifdef DOSWAP
X#define SWAP "/dev/drum"
X#endif


X
X/* get_process_info passes back a handle. This is what it looks like: */
X
Xstruct handle
X{
X struct proc **next_proc; /* points to next valid proc pointer */
X int remaining; /* number of pointers remaining */
X};
X
X/* declarations for load_avg */

X#include "loadavg.h"


X
X/* define what weighted cpu is. */
X#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
X ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
X
X/* what we consider to be process size: */

X#define PROCSIZE(pp) ((pp)->p_tsize + (pp)->p_dsize + (pp)->p_ssize)


X
X/* definitions for indices in the nlist array */
X#define X_AVENRUN 0
X#define X_CCPU 1

X#define X_NPROC 2
X#define X_PROC 3
X#define X_TOTAL 4
X#define X_CP_TIME 5
X#define X_MPID 6
X#define X_HZ 7


X
Xstatic struct nlist nlst[] = {
X { "_avenrun" }, /* 0 */
X { "_ccpu" }, /* 1 */

X { "_nproc" }, /* 2 */
X { "_proc" }, /* 3 */
X { "_total" }, /* 4 */
X { "_cp_time" }, /* 5 */
X { "_mpid" }, /* 6 */
X { "_hz" }, /* 7 */
X { 0 }
X};
X
X/*


X * These definitions control the format of the per-process area
X */
X
Xstatic char header[] =
X " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";

X/* 0123456 -- field to fill in starts at header+6 */
X#define UNAME_START 6
X
X#define Proc_format \
X "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %.14s"
X
X
X/* process state names for the "STATE" column of the display */
X/* the extra nulls in the string "run" are for adding a slash and
X the processor number when needed */
X
Xchar *state_abbrev[] =
X{

X "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"
X};
X
X
Xstatic int kmem, mem;
X#ifdef DOSWAP
Xstatic int swap;
X#endif


X
X/* values that we stash away in _init and use in later routines */
X
Xstatic double logcpu;
X

X/* these are retrieved from the kernel in _init */
X
Xstatic unsigned long proc;
Xstatic int nproc;

Xstatic long hz;
Xstatic load_avg ccpu;
Xstatic int ncpu = 0;


X
X/* these are offsets obtained via nlist and used in the get_ functions */
X

Xstatic unsigned long avenrun_offset;
Xstatic unsigned long mpid_offset;
Xstatic unsigned long total_offset;
Xstatic unsigned long cp_time_offset;


X
X/* these are for calculating cpu state percentages */
X
Xstatic long cp_time[CPUSTATES];
Xstatic long cp_old[CPUSTATES];
Xstatic long cp_diff[CPUSTATES];
X
X/* these are for detailing the process states */
X

Xint process_states[7];
Xchar *procstatenames[] = {
X "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",


X " zombie, ", " stopped, ",

X NULL
X};
X
X/* these are for detailing the cpu states */
X

Xint cpu_states[4];
Xchar *cpustatenames[] = {

X "user", "nice", "system", "idle", NULL


X};
X
X/* these are for detailing the memory statistics */
X

Xint memory_stats[8];
Xchar *memorynames[] = {
X "Real: ", "K/", "K act/tot ", "Virtual: ", "K/",
X "K act/tot ", "Free: ", "K", NULL


X};
X
X/* these are for keeping track of the proc array */
X
Xstatic int bytes;
Xstatic int pref_len;
Xstatic struct proc *pbase;
Xstatic struct proc **pref;
X

X/* these are for getting the memory statistics */
X
Xstatic int pageshift; /* log base 2 of the pagesize */
X
X/* define pagetok in terms of pageshift */
X
X#define pagetok(size) ((size) << pageshift)


X
X/* useful externals */
Xextern int errno;
Xextern char *sys_errlist[];
X
Xlong lseek();

Xlong time();


X
Xmachine_init(statics)
X
Xstruct statics *statics;
X
X{

X register int i = 0;
X register int pagesize;


X
X if ((kmem = open(KMEM, O_RDONLY)) == -1) {
X perror(KMEM);

X return(-1);
X }
X if ((mem = open(MEM, O_RDONLY)) == -1) {
X perror(MEM);
X return(-1);
X }
X
X#ifdef DOSWAP
X if ((swap = open(SWAP, O_RDONLY)) == -1) {
X perror(SWAP);
X return(-1);
X }
X#endif


X
X /* get the list of symbols we want to access in the kernel */

X (void) nlist(VMUNIX, nlst);
X if (nlst[0].n_type == 0)


X {
X fprintf(stderr, "top: nlist failed\n");
X return(-1);
X }
X
X /* make sure they were all found */
X if (i > 0 && check_nlist(nlst) > 0)
X {
X return(-1);
X }
X
X /* get the symbol values out of kmem */
X (void) getkval(nlst[X_PROC].n_value, (int *)(&proc), sizeof(proc),
X nlst[X_PROC].n_name);
X (void) getkval(nlst[X_NPROC].n_value, &nproc, sizeof(nproc),
X nlst[X_NPROC].n_name);

X (void) getkval(nlst[X_HZ].n_value, (int *)(&hz), sizeof(hz),
X nlst[X_HZ].n_name);


X (void) getkval(nlst[X_CCPU].n_value, (int *)(&ccpu), sizeof(ccpu),
X nlst[X_CCPU].n_name);
X

X /* stash away certain offsets for later use */
X mpid_offset = nlst[X_MPID].n_value;
X avenrun_offset = nlst[X_AVENRUN].n_value;
X total_offset = nlst[X_TOTAL].n_value;

X cp_time_offset = nlst[X_CP_TIME].n_value;


X
X /* this is used in calculating WCPU -- calculate it ahead of time */
X logcpu = log(loaddouble(ccpu));
X
X /* allocate space for proc structure array and array of pointers */
X bytes = nproc * sizeof(struct proc);
X pbase = (struct proc *)malloc(bytes);
X pref = (struct proc **)malloc(nproc * sizeof(struct proc *));
X
X /* Just in case ... */
X if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
X {
X fprintf(stderr, "top: can't allocate sufficient memory\n");
X return(-1);
X }
X

X /* get the page size with "getpagesize" and calculate pageshift from it */
X pagesize = getpagesize();
X pageshift = 0;
X while (pagesize > 1)
X {
X pageshift++;
X pagesize >>= 1;
X }
X
X /* we only need the amount of log(2)1024 for our conversion */
X pageshift -= LOG1024;

X long total;


X
X /* get the cp_time array */

X (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
X "_cp_time");
X


X /* get load average array */
X (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
X "_avenrun");
X
X /* get mpid -- process id of last process */
X (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
X "_mpid");
X
X /* convert load averages to doubles */
X {
X register int i;
X register double *infoloadp;
X register load_avg *sysloadp;
X
X infoloadp = si->load_avg;
X sysloadp = avenrun;
X for (i = 0; i < 3; i++)
X {
X *infoloadp++ = loaddouble(*sysloadp++);
X }
X }
X
X /* convert cp_time counts to percentages */

X total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
X
X /* sum memory statistics */
X {
X struct vmtotal total;


X
X /* get total -- systemwide main memory usage structure */
X (void) getkval(total_offset, (int *)(&total), sizeof(total),
X "_total");
X /* convert memory stats to Kbytes */

X memory_stats[0] = -1;


X memory_stats[1] = pagetok(total.t_arm);

X memory_stats[2] = pagetok(total.t_rm);
X memory_stats[3] = -1;
X memory_stats[4] = pagetok(total.t_avm);
X memory_stats[5] = pagetok(total.t_vm);
X memory_stats[6] = -1;
X memory_stats[7] = pagetok(total.t_free);
X }

X int show_command;


X
X /* read all the proc structures in one fell swoop */
X (void) getkval(proc, (int *)pbase, bytes, "proc array");
X
X /* get a pointer to the states summary array */
X si->procstates = process_states;
X
X /* set up flags which define what we are going to select */
X show_idle = sel->idle;
X show_system = sel->system;
X show_uid = sel->uid != -1;

X show_command = sel->command != NULL;


X
X /* count up process states and get pointers to interesting procs */
X total_procs = 0;
X active_procs = 0;

X memset((char *)process_states, 0, sizeof(process_states));

X int where;


X struct user u;
X struct handle *hp;
X
X /* find and remember the next proc structure */
X hp = (struct handle *)handle;
X pp = *(hp->next_proc++);
X hp->remaining--;
X
X
X /* get the process's user struct and set cputime */

X where = getu(pp, &u);
X if (where == -1)


X {
X (void) strcpy(u.u_comm, "<swapped>");
X cputime = 0;
X }
X else
X {
X
X
X /* set u_comm for system processes */
X if (u.u_comm[0] == '\0')
X {
X if (pp->p_pid == 0)
X {
X (void) strcpy(u.u_comm, "Swapper");
X }
X else if (pp->p_pid == 2)
X {
X (void) strcpy(u.u_comm, "Pager");
X }
X }

X if (where == 1) {
X /*
X * Print swapped processes as <pname>
X */
X char buf[sizeof(u.u_comm)];
X (void) strncpy(buf, u.u_comm, sizeof(u.u_comm));
X u.u_comm[0] = '<';
X (void) strncpy(&u.u_comm[1], buf, sizeof(u.u_comm) - 2);
X u.u_comm[sizeof(u.u_comm) - 2] = '\0';
X (void) strncat(u.u_comm, ">", sizeof(u.u_comm) - 1);
X u.u_comm[sizeof(u.u_comm) - 1] = '\0';

X}
X
X/*


X * getu(p, u) - get the user structure for the process whose proc structure
X * is pointed to by p. The user structure is put in the buffer pointed
X * to by u. Return 0 if successful, -1 on failure (such as the process
X * being swapped out).
X */
X

X#ifdef ibm032
Xstatic struct alignuser {
X char userfill[UPAGES*NBPG-sizeof (struct user)];
X struct user user;
X} au;
X# define USERSIZE sizeof(struct alignuser)
X# define GETUSER(b) (&au)
X# define SETUSER(b) *(b) = au.user
X#else
X# define USERSIZE sizeof(struct user)
X# define GETUSER(b) (b)
X# define SETUSER(b) /* Nothing */
X#endif


X
Xgetu(p, u)
X
Xregister struct proc *p;
Xstruct user *u;
X
X{
X struct pte uptes[UPAGES];
X register caddr_t upage;
X register struct pte *pte;
X register nbytes, n;
X
X /*
X * Check if the process is currently loaded or swapped out. The way we
X * get the u area is totally different for the two cases. For this
X * application, we just don't bother if the process is swapped out.
X */

X if ((p->p_flag & SLOAD) == 0) {
X#ifdef DOSWAP
X if (lseek(swap, (long)dtob(p->p_swaddr), 0) == -1) {
X perror("lseek(swap)");
X return(-1);
X }
X if (read(swap, (char *) GETUSER(u), USERSIZE) != USERSIZE) {
X perror("read(swap)");
X return(-1);
X }
X SETUSER(u);
X return (1);
X#else
X return(-1);
X#endif


X }
X
X /*
X * Process is currently in memory, we hope!
X */

X if (!getkval((unsigned long)p->p_addr, (int *)uptes, sizeof(uptes),
X "!p->p_addr"))
X {
X#ifdef DEBUG
X perror("getkval(uptes)");
X#endif


X /* we can't seem to get to it, so pretend it's swapped out */
X return(-1);
X }

X upage = (caddr_t) GETUSER(u);
X pte = uptes;
X for (nbytes = USERSIZE; nbytes > 0; nbytes -= NBPG) {


X (void) lseek(mem, (long)(pte++->pg_pfnum * NBPG), 0);

X#ifdef DEBUG
X perror("lseek(mem)");
X#endif


X n = MIN(nbytes, NBPG);

X if (read(mem, upage, n) != n) {
X#ifdef DEBUG
X perror("read(mem)");
X#endif


X /* we can't seem to get to it, so pretend it's swapped out */
X return(-1);
X }
X upage += n;
X }

X SETUSER(u);
X return(0);
X}
X
X/*

X
X
X/*


X * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
X * "offset" is the byte offset into the kernel for the desired value,
X * "ptr" points to a buffer into which the value is retrieved,
X * "size" is the size of the buffer (and the object to retrieve),
X * "refstr" is a reference string used when printing error meessages,
X * if "refstr" starts with a '!', then a failure on read will not
X * be fatal (this may seem like a silly way to do things, but I
X * really didn't want the overhead of another argument).

X *
X */
X

Xgetkval(offset, ptr, size, refstr)
X
Xunsigned long offset;
Xint *ptr;
Xint size;
Xchar *refstr;
X
X{

X if (lseek(kmem, (long)offset, L_SET) == -1) {


X if (*refstr == '!')

X refstr++;
X (void) fprintf(stderr, "%s: lseek to %s: %s\n", KMEM,
X refstr, strerror(errno));
X quit(23);
X }
X if (read(kmem, (char *) ptr, size) == -1) {


X if (*refstr == '!')

X return(0);
X else {
X (void) fprintf(stderr, "%s: reading %s: %s\n", KMEM,
X refstr, strerror(errno));


X quit(23);
X }
X }
X return(1);
X}
X

X/* comparison routine for qsort */
X
X/*


X * proc_compare - comparison function for "qsort"
X * Compares the resource consumption of two processes using five
X * distinct keys. The keys (in descending order of importance) are:
X * percent cpu, cpu ticks, state, resident set size, total virtual
X * memory usage. The process states are ordered as follows (from least
X * to most important): WAIT, zombie, sleep, stop, start, run. The
X * array declaration below maps a process state index into a number
X * that reflects this ordering.
X */
X
Xstatic unsigned char sorted_state[] =
X{
X 0, /* not used */
X 3, /* sleep */
X 1, /* ABANDONED (WAIT) */
X 6, /* run */
X 5, /* start */
X 2, /* zombie */

X 4 /* stop */

X}
X
X/*

if test 18437 -ne `wc -c <'top-3.4/machine/m_bsd43.c'`; then
echo shar: \"'top-3.4/machine/m_bsd43.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_bsd43.c'
fi
if test -f 'top-3.4/machine/m_osmp41a.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_osmp41a.c'\"
else
echo shar: Extracting \"'top-3.4/machine/m_osmp41a.c'\" \(17788 characters\)
sed "s/^X//" >'top-3.4/machine/m_osmp41a.c' <<'END_OF_FILE'


X/*
X * top - a top users display for Unix
X *

X * SYNOPSIS: any Solbourne running OS/MP 4.1A


X *
X * DESCRIPTION:

X * This is the machine-dependent module for OS/MP 4.1A


X * This makes top work on the following systems:

X * Solbourne machines running OS/MP 4.1A only


X *
X * LIBS: -lkvm

X *
X * AUTHOR: William LeFebvre <ph...@eecs.nwu.edu>
X * Brett McCoy <brt...@maverick.ksu.ksu.edu>


X */
X
X#include <sys/types.h>
X#include <sys/signal.h>

X/* make sure param.h gets loaded with KERNEL defined to get PZERO & NZERO */
X#define KERNEL
X#include <sys/param.h>
X#undef KERNEL
X
X#include <stdio.h>
X#include <kvm.h>


X#include <nlist.h>
X#include <math.h>
X#include <sys/dir.h>
X#include <sys/user.h>
X#include <sys/proc.h>
X#include <sys/dk.h>
X#include <sys/vm.h>

X#include <sys/file.h>
X#include <sys/time.h>
X#include <vm/page.h>


X
X#include "top.h"
X#include "machine.h"
X#include "utils.h"
X

X/* declarations for load_avg */

X#include "loadavg.h"


X
X/* get_process_info passes back a handle. This is what it looks like: */
X
Xstruct handle
X{
X struct proc **next_proc; /* points to next valid proc pointer */
X int remaining; /* number of pointers remaining */
X};
X

X/* define what weighted cpu is. */
X#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
X ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
X
X/* what we consider to be process size: */

X#define PROCSIZE(pp) ((pp)->p_tsize + (pp)->p_dsize + (pp)->p_ssize)


X
X/* definitions for indices in the nlist array */
X#define X_AVENRUN 0
X#define X_CCPU 1
X#define X_MPID 2
X#define X_NPROC 3
X#define X_PROC 4
X#define X_TOTAL 5

X#define X_CP_TIME 6
X#define X_PAGES 7
X#define X_EPAGES 8
X#define X_NCPUS 9
X#define X_CP_MP_TIME 10


X
Xstatic struct nlist nlst[] = {
X { "_avenrun" }, /* 0 */
X { "_ccpu" }, /* 1 */
X { "_mpid" }, /* 2 */
X { "_nproc" }, /* 3 */
X { "_proc" }, /* 4 */
X { "_total" }, /* 5 */

X { "_cp_time" }, /* 6 */
X { "_pages" }, /* 7 */
X { "_epages" }, /* 8 */
X { "_ncpus" }, /* 9 */
X { "_cp_mp_time" }, /* 10 */
X { 0 }
X};
X
X/*


X * These definitions control the format of the per-process area
X */
X
Xstatic char header[] =

X " PID X PRI NI SIZE RES STATE TIME WCPU CPU COMMAND";


X/* 0123456 -- field to fill in starts at header+6 */
X#define UNAME_START 6
X
X#define Proc_format \

X "%5d %-8.8s %3d %3d %5s %5s %-5s %6s %5.2f%% %5.2f%% %.16s"


X
X
X/* process state names for the "STATE" column of the display */
X/* the extra nulls in the string "run" are for adding a slash and
X the processor number when needed */
X
Xchar *state_abbrev[] =
X{

X "", "sleep", "WAIT", "run/\0\0", "start", "zomb", "stop"


X};
X
X/* values that we stash away in _init and use in later routines */
X
Xstatic double logcpu;

Xkvm_t *kd;


X
X/* these are retrieved from the kernel in _init */
X
Xstatic unsigned long proc;
Xstatic int nproc;
Xstatic load_avg ccpu;

Xstatic unsigned long pages;
Xstatic unsigned long epages;
Xstatic int ncpus;


X
X/* these are offsets obtained via nlist and used in the get_ functions */
X
Xstatic unsigned long mpid_offset;
Xstatic unsigned long avenrun_offset;
Xstatic unsigned long total_offset;

Xstatic unsigned long cp_time_offset;
Xstatic unsigned long cp_mp_time_offset;


X
X/* these are for calculating cpu state percentages */
X
Xstatic long cp_time[CPUSTATES];
Xstatic long cp_old[CPUSTATES];
Xstatic long cp_diff[CPUSTATES];

Xstatic long cp_mp_time[MAXNCPUS][CPUSTATES];
Xstatic long cp_mp_old[MAXNCPUS][CPUSTATES];
Xstatic long cp_mp_diff[MAXNCPUS][CPUSTATES];
Xint which_cpu_states = 9;


X
X/* these are for detailing the process states */
X

Xint process_states[7];
Xchar *procstatenames[] = {
X "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",


X " zombie, ", " stopped, ",

X NULL
X};
X
X/* these are for detailing the cpu states */
X

Xint cpu_states[5];
Xint cpu_mp_states[MAXNCPUS][5];


Xchar *cpustatenames[] = {
X "user", "nice", "system", "idle",
X NULL
X};
X
X/* these are for detailing the memory statistics */
X

Xint memory_stats[4];
Xchar *memorynames[] = {
X "K available, ", "K in use, ", "K free, ", "K locked", NULL


X};
X
X/* these are for keeping track of the proc array */
X
Xstatic int bytes;
Xstatic int pref_len;
Xstatic struct proc *pbase;
Xstatic struct proc **pref;
X

X/* these are for getting the memory statistics */
X
Xstatic struct page *physpage;
Xstatic int bytesize;
Xstatic int count;
Xstatic int pageshift; /* log base 2 of the pagesize */
X
X/* define pagetok in terms of pageshift */
X
X#define pagetok(size) ((size) << pageshift)


X
X/* useful externals */
Xextern int errno;
Xextern char *sys_errlist[];
X
Xlong lseek();

Xlong time();


X
Xmachine_init(statics)
X
Xstruct statics *statics;
X
X{
X register int i;

X register int pagesize;
X
X /* initialize the kernel interface */
X if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "top")) == NULL)
X {
X perror("kvm_open");
X return(-1);
X }
X


X /* get the list of symbols we want to access in the kernel */

X if ((i = kvm_nlist(kd, nlst)) < 0)


X {
X fprintf(stderr, "top: nlist failed\n");
X return(-1);
X }
X
X /* make sure they were all found */
X if (i > 0 && check_nlist(nlst) > 0)
X {
X return(-1);
X }
X
X /* get the symbol values out of kmem */
X (void) getkval(nlst[X_PROC].n_value, (int *)(&proc), sizeof(proc),
X nlst[X_PROC].n_name);
X (void) getkval(nlst[X_NPROC].n_value, &nproc, sizeof(nproc),
X nlst[X_NPROC].n_name);
X (void) getkval(nlst[X_CCPU].n_value, (int *)(&ccpu), sizeof(ccpu),
X nlst[X_CCPU].n_name);

X (void) getkval(nlst[X_PAGES].n_value, (int *)(&pages), sizeof(pages),
X nlst[X_PAGES].n_name);
X (void) getkval(nlst[X_EPAGES].n_value, (int *)(&epages), sizeof(epages),
X nlst[X_EPAGES].n_name);


X
X /* stash away certain offsets for later use */
X mpid_offset = nlst[X_MPID].n_value;
X avenrun_offset = nlst[X_AVENRUN].n_value;
X total_offset = nlst[X_TOTAL].n_value;

X cp_time_offset = nlst[X_CP_TIME].n_value;
X cp_mp_time_offset = nlst[X_CP_MP_TIME].n_value;
X (void) getkval(nlst[X_NCPUS].n_value, (int *)(&ncpus), sizeof(ncpus),
X nlst[X_NCPUS].n_name);


X
X /* this is used in calculating WCPU -- calculate it ahead of time */
X logcpu = log(loaddouble(ccpu));
X
X /* allocate space for proc structure array and array of pointers */
X bytes = nproc * sizeof(struct proc);
X pbase = (struct proc *)malloc(bytes);
X pref = (struct proc **)malloc(nproc * sizeof(struct proc *));
X
X /* Just in case ... */
X if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
X {
X fprintf(stderr, "top: can't allocate sufficient memory\n");
X return(-1);
X }
X

X /* allocate a table to hold all the page structs */
X bytesize = epages - pages;
X count = bytesize / sizeof(struct page);
X physpage = (struct page *)malloc(epages - pages);
X if (physpage == NULL)
X {


X fprintf(stderr, "top: can't allocate sufficient memory\n");
X return(-1);
X }
X

X /* get the page size with "getpagesize" and calculate pageshift from it */
X pagesize = getpagesize();
X pageshift = 0;
X while (pagesize > 1)
X {
X pageshift++;
X pagesize >>= 1;
X }
X
X /* we only need the amount of log(2)1024 for our conversion */
X pageshift -= LOG1024;

X int i;
X int j;


X
X /* get the cp_time array */

X (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
X "_cp_time");
X
X /* get the cp_mp_time arrays as well */
X (void) getkval(cp_mp_time_offset, (int *) cp_mp_time, sizeof(cp_mp_time),
X "_cp_mp_time");
X


X /* get load average array */
X (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
X "_avenrun");
X
X /* get mpid -- process id of last process */
X (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
X "_mpid");
X

X /* get the array of physpage descriptors */
X (void) getkval(pages, (int *)physpage, bytesize, "array _page");


X
X /* convert load averages to doubles */
X {

X register double *infoloadp;
X register load_avg *sysloadp;
X
X infoloadp = si->load_avg;
X sysloadp = avenrun;
X for (i = 0; i < 3; i++)
X {
X *infoloadp++ = loaddouble(*sysloadp++);
X }
X }
X

X /* calculate percentages for each of the cpu's */
X for (i = 0; i < ncpus; i++)
X (void) percentages(CPUSTATES, cpu_mp_states[i], cp_mp_time[i],
X cp_mp_old[i], cp_mp_diff[i]);
X
X /* if the selected cpu doesn't exist show summary of all cpu's */
X /* otherwise, show stats for selected cpu */
X if (which_cpu_states >= ncpus) {
X for (i = 0; i < CPUSTATES; i++) {
X cpu_states[i] = 0;
X for (j = 0; j < ncpus; j++)
X cpu_states[i] += cpu_mp_states[j][i];
X cpu_states[i] /= ncpus;
X }
X } else {
X for (i = 0; i < CPUSTATES; i++) {
X cpu_states[i] = cpu_mp_states[which_cpu_states][i];
X }
X }
X
X /* sum memory statistics */
X {
X register struct page *pp;
X register int cnt;
X register int inuse;
X register int free;
X register int locked;
X
X /* bop thru the array counting page types */
X pp = physpage;
X inuse = free = locked = 0;
X for (cnt = count; --cnt >= 0; pp++)
X {
X if (pp->p_free)
X free++;
X else if (pp->p_lock || pp->p_keepcnt > 0)
X locked++;
X else
X inuse++;
X }
X


X /* convert memory stats to Kbytes */

X memory_stats[0] = pagetok(inuse + free);
X memory_stats[1] = pagetok(inuse);
X memory_stats[2] = pagetok(free);
X memory_stats[3] = pagetok(locked);
X }

X int show_command;


X
X /* read all the proc structures in one fell swoop */
X (void) getkval(proc, (int *)pbase, bytes, "proc array");
X
X /* get a pointer to the states summary array */
X si->procstates = process_states;
X
X /* set up flags which define what we are going to select */
X show_idle = sel->idle;
X show_system = sel->system;
X show_uid = sel->uid != -1;

X show_command = sel->command != NULL;

X state_abbrev[SRUN][4] = (pp->p_lastcpu) + '0';


X
X /* format this entry */
X sprintf(fmt,
X Proc_format,
X pp->p_pid,
X (*get_userid)(pp->p_uid),
X pp->p_pri - PZERO,
X pp->p_nice - NZERO,
X format_k(pagetok(PROCSIZE(pp))),
X format_k(pagetok(pp->p_rssize)),
X state_abbrev[pp->p_stat],
X format_time(cputime),
X 100.0 * weighted_cpu(pct, pp),
X 100.0 * pct,
X printable(u.u_comm));
X
X /* return the result */
X return(fmt);

X}
X
X/*


X * getu(p, u) - get the user structure for the process whose proc structure
X * is pointed to by p. The user structure is put in the buffer pointed
X * to by u. Return 0 if successful, -1 on failure (such as the process
X * being swapped out).
X */
X
Xgetu(p, u)
X
Xregister struct proc *p;
Xstruct user *u;
X
X{

X register struct user *lu;
X
X lu = kvm_getu(kd, p);
X if (lu == NULL)
X {
X return(-1);
X }
X else
X {
X *u = *lu;
X return(0);
X }
X}
X
X/*

X
X
X/*


X * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
X * "offset" is the byte offset into the kernel for the desired value,
X * "ptr" points to a buffer into which the value is retrieved,
X * "size" is the size of the buffer (and the object to retrieve),
X * "refstr" is a reference string used when printing error meessages,
X * if "refstr" starts with a '!', then a failure on read will not
X * be fatal (this may seem like a silly way to do things, but I
X * really didn't want the overhead of another argument).

X *
X */
X

Xgetkval(offset, ptr, size, refstr)
X
Xunsigned long offset;
Xint *ptr;
Xint size;
Xchar *refstr;
X
X{

X if (kvm_read(kd, offset, ptr, size) != size)


X {
X if (*refstr == '!')
X {

X return(0);
X }
X else
X {

X fprintf(stderr, "top: kvm_read for %s: %s\n",

X refstr, sys_errlist[errno]);
X quit(23);
X /*NOTREACHED*/


X }
X }
X return(1);
X}
X

X/* comparison routine for qsort */
X
X/*


X * proc_compare - comparison function for "qsort"
X * Compares the resource consumption of two processes using five
X * distinct keys. The keys (in descending order of importance) are:
X * percent cpu, cpu ticks, state, resident set size, total virtual
X * memory usage. The process states are ordered as follows (from least
X * to most important): WAIT, zombie, sleep, stop, start, run. The
X * array declaration below maps a process state index into a number
X * that reflects this ordering.
X */
X
Xstatic unsigned char sorted_state[] =
X{
X 0, /* not used */
X 3, /* sleep */
X 1, /* ABANDONED (WAIT) */
X 6, /* run */
X 5, /* start */
X 2, /* zombie */

X 4 /* stop */

X}
X
X/*

if test 17788 -ne `wc -c <'top-3.4/machine/m_osmp41a.c'`; then
echo shar: \"'top-3.4/machine/m_osmp41a.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_osmp41a.c'
fi
echo shar: End of archive 11 \(of 22\).
cp /dev/null ark11isdone

William Lefebvre

unread,
Sep 1, 1996, 3:00:00 AM9/1/96
to

Submitted-By: w...@groupsys.com (William Lefebvre)
Posting-Number: Volume 29, Issue 113
Archive-Name: top-3.4/part12

#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:

# "End of archive 12 (of 22)."
# Contents: top-3.4/machine/m_irix5.c top-3.4/machine/m_ncr3000.c
# Wrapped by lefebvre@acapulco on Fri Aug 30 12:35:50 1996


PATH=/bin:/usr/bin:/usr/ucb ; export PATH

if test -f 'top-3.4/machine/m_irix5.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_irix5.c'\"
else
echo shar: Extracting \"'top-3.4/machine/m_irix5.c'\" \(18699 characters\)
sed "s/^X//" >'top-3.4/machine/m_irix5.c' <<'END_OF_FILE'


X/*
X * top - a top users display for Unix
X *

X * SYNOPSIS: any uniprocessor, 32 bit SGI machine running IRIX 5.3


X *
X * DESCRIPTION:

X * This is the machine-dependent module for IRIX 5.3.
X * It has been tested on Indys running 5.3 and Indigos running 5.3XFS
X *
X * LIBS: -lmld
X * CFLAGS: -DHAVE_GETOPT
X *
X * AUTHOR: Sandeep Cariapa <car...@sgi.com>
X * This is not a supported product of Silicon Graphics, Inc.
X * Please do not call SGI for support.


X *
X */
X

X#define _KMEMUSER
X
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/stat.h>
X#include <sys/swap.h>
X#include <sys/proc.h>
X#include <sys/procfs.h>
X#include <sys/sysinfo.h>
X#include <sys/sysmp.h>
X#include <paths.h>
X#include <dirent.h>
X#include <stdio.h>
X#include <nlist.h>
X#include <unistd.h>
X#include <errno.h>
X#include <fcntl.h>


X#include "top.h"
X#include "machine.h"
X

X#ifdef IRIX64
X#define nlist nlist64
X#define lseek lseek64
X#define off_t off64_t
X#endif
X
X#define UNIX "/unix"
X#define KMEM "/dev/kmem"
X#define CPUSTATES 6
X
X#ifndef FSCALE
X#define FSHIFT 8 /* bits to right of fixed binary point */
X#define FSCALE (1<<FSHIFT)
X#endif /* FSCALE */


X
X#ifdef FIXED_LOADAVG
X typedef long load_avg;
X# define loaddouble(la) ((double)(la) / FIXED_LOADAVG)
X# define intload(i) ((int)((i) * FIXED_LOADAVG))
X#else
X typedef double load_avg;
X# define loaddouble(la) (la)
X# define intload(i) ((double)(i))
X#endif

X
X#define percent_cpu(pp) (*(double *)pp->pr_fill)
X#define weighted_cpu(pp) (*(double *)&pp->pr_fill[2])
X
Xstatic int pagesize;
X#define pagetok(size) ((size)*pagesize)
X
Xstatic int numcpus;


X
X/*
X * These definitions control the format of the per-process area
X */
X
Xstatic char header[] =
X " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";
X/* 0123456 -- field to fill in starts at header+6 */
X#define UNAME_START 6
X
X#define Proc_format \

X "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %.16s"


X
X/* these are for detailing the process states */

Xchar *state_abbrev[] =
X{"", "sleep", "run\0\0\0", "zombie", "stop", "idle", "", "swap"};
X
Xint process_states[8];
Xchar *procstatenames[] = {
X "", " sleeping, ", " running, ", " zombie, ", " stopped, ",
X " idle, ", "", " swapped, ",


X NULL
X};
X
X/* these are for detailing the cpu states */

Xint cpu_states[CPUSTATES];
Xchar *cpustatenames[] = {

X "idle", "usr", "ker", "wait", "swp", "intr",


X NULL
X};
X
X/* these are for detailing the memory statistics */
X

Xint memory_stats[5];
Xchar *memorynames[] = {
X "K max, ", "K avail, ", "K free, ", "K swap, ", "K free swap", NULL
X};
X


X/* useful externals */
Xextern int errno;

Xextern char *myname;
Xextern char *sys_errlist[];
Xextern char *format_k();
Xextern char *format_time();
Xextern long percentages();
X
X#define X_AVENRUN 0
X#define X_NPROC 1
X#define X_FREEMEM 2
X#define X_MAXMEM 3
X#define X_AVAILRMEM 4
X#define X_MPID 5


X
Xstatic struct nlist nlst[] = {

X{ "avenrun" }, /* 0. Array containing the 3 load averages. */
X{ "nproc" }, /* 1. Kernel parameter: Max number of processes. */
X{ "freemem" }, /* 2. Amount of free memory in system. */
X{ "maxmem" }, /* 3. Maximum amount of memory usable by system. */
X{ "availrmem" }, /* 4. Available real memory. */
X#ifndef IRIX64
X{ "mpid" }, /* 5. PID of last process. */
X#endif
X{ 0 }


X};
Xstatic unsigned long avenrun_offset;

Xstatic unsigned long nproc_offset;
Xstatic unsigned long freemem_offset;
Xstatic unsigned long maxmem_offset;
Xstatic unsigned long availrmem_offset;
Xstatic unsigned long mpid_offset;
Xdouble load[3];
Xchar fmt[MAX_COLS];
Xstatic int kmem;
Xstatic int nproc;
Xstatic int bytes;
Xstatic struct prpsinfo *pbase;
Xstatic struct prpsinfo **pref;
Xstatic DIR *procdir;


X
X/* get_process_info passes back a handle. This is what it looks like: */

Xstruct handle {
X struct prpsinfo **next_proc;/* points to next valid proc pointer */


X int remaining; /* number of pointers remaining */
X};
X

Xstatic struct handle handle;
Xvoid getptable();
X
X/*
X * Structure for keeping track of CPU times from last time around
X * the program. We keep these things in a hash table, which is
X * recreated at every cycle.
X */
Xstruct oldproc
X {
X pid_t oldpid;
X double oldtime;
X double oldpct;
X };
Xstatic int oldprocs; /* size of table */
Xstatic struct oldproc *oldbase;
X#define HASH(x) ((x << 1) % oldprocs)
X#define PRPSINFOSIZE (sizeof(struct prpsinfo))
X
Xint machine_init(statics)


X struct statics *statics;
X{

X struct oldproc *op, *endbase;


X
X if ((kmem = open(KMEM, O_RDONLY)) == -1) {
X perror(KMEM);
X return(-1);
X }
X

X /* get the list of symbols we want to access in the kernel */

X (void) nlist(UNIX, nlst);


X if (nlst[0].n_type == 0) {

X fprintf(stderr, "%s: nlist failed\n", myname);
X return(-1);
X }
X
X /* Check if we got all of 'em. */
X if (check_nlist(nlst) > 0) {
X return(-1);
X }


X avenrun_offset = nlst[X_AVENRUN].n_value;

X nproc_offset = nlst[X_NPROC].n_value;
X freemem_offset = nlst[X_FREEMEM].n_value;
X maxmem_offset = nlst[X_MAXMEM].n_value;
X availrmem_offset = nlst[X_AVAILRMEM].n_value;
X#ifndef IRIX64


X mpid_offset = nlst[X_MPID].n_value;

X#endif
X
X /* Got to do this first so that we can map real estate for the
X process array. */
X (void) getkval(nproc_offset, (int *) (&nproc), sizeof(nproc), "nproc");


X
X /* allocate space for proc structure array and array of pointers */

X bytes = nproc * sizeof (struct prpsinfo);
X pbase = (struct prpsinfo *) malloc (bytes);
X pref = (struct prpsinfo **) malloc (nproc * sizeof (struct prpsinfo *));
X oldbase = (struct oldproc *) malloc (2 * nproc * sizeof (struct oldproc));


X
X /* Just in case ... */

X if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL ||
X oldbase == (struct oldproc *)NULL) {
X (void) fprintf (stderr, "%s: can't allocate sufficient memory\n", myname);
X return (-1);
X }
X
X oldprocs = 2 * nproc;
X endbase = oldbase + oldprocs;
X for (op = oldbase; op < endbase; op++) {
X op->oldpid = -1;
X }
X
X if (!(procdir = opendir (_PATH_PROCFSPI))) {
X (void) fprintf (stderr, "Unable to open %s\n", _PATH_PROCFSPI);
X return (-1);
X }
X
X if (chdir (_PATH_PROCFSPI)) {
X /* handy for later on when we're reading it */
X (void) fprintf (stderr, "Unable to chdir to %s\n", _PATH_PROCFSPI);
X return (-1);
X }
X


X statics->procstate_names = procstatenames;
X statics->cpustate_names = cpustatenames;
X statics->memory_names = memorynames;
X

X pagesize = getpagesize()/1024;


X
X /* all done! */
X return(0);
X}
X
Xchar *format_header(uname_field)

X register char *uname_field;


X
X{
X register char *ptr;
X
X ptr = header + UNAME_START;
X while (*uname_field != '\0') {

X *ptr++ = *uname_field++;
X }
X
X return(header);
X}
X

Xvoid get_system_info(si)
X struct system_info *si;
X
X{
X register int i;
X int avenrun[3];
X static int freemem;
X static int maxmem;
X static int availrmem;
X struct sysinfo sysinfo;
X static long cp_new[CPUSTATES];
X static long cp_old[CPUSTATES];
X static long cp_diff[CPUSTATES]; /* for cpu state percentages */
X off_t fswap; /* current free swap in blocks */
X off_t tswap; /* total swap in blocks */
X
X (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun), "avenrun");


X for (i = 0; i < 3; i++) {

X si->load_avg[i] = loaddouble (avenrun[i]);
X si->load_avg[i] = si->load_avg[i]/1024.0;
X }
X
X (void) getkval(freemem_offset, (int *) (&freemem), sizeof(freemem),
X"freemem");
X (void) getkval(maxmem_offset, (int *) (&maxmem), sizeof(maxmem), "maxmem");
X (void) getkval(availrmem_offset, (int *) (&availrmem), sizeof(availrmem),
X"availrmem");
X#ifdef IRIX64
X si->last_pid = 0;
X#else
X (void) getkval(mpid_offset, &(si->last_pid), sizeof (si->last_pid), "mpid");
X#endif
X swapctl(SC_GETFREESWAP, &fswap);
X swapctl(SC_GETSWAPTOT, &tswap);
X memory_stats[0] = pagetok(maxmem);
X memory_stats[1] = pagetok(availrmem);
X memory_stats[2] = pagetok(freemem);
X memory_stats[3] = tswap / 2;
X memory_stats[4] = fswap / 2;
X
X /* use sysmp() to get current sysinfo usage. Can run into all kinds of
X problems if you try to nlist this kernel variable. */
X if (sysmp(MP_SAGET, MPSA_SINFO, &sysinfo, sizeof(struct sysinfo)) == -1) {
X perror("sysmp");
X return;
X }
X /* copy sysinfo.cpu to an array of longs, as expected by percentages() */
X for (i = 0; i < CPUSTATES; i++) {
X cp_new[i] = sysinfo.cpu[i];
X }
X (void) percentages (CPUSTATES, cpu_states, cp_new, cp_old, cp_diff);
X


X si->cpustates = cpu_states;
X si->memory = memory_stats;
X

X numcpus = sysmp(MP_NPROCS);
X
X /* add a slash to the "run" state abbreviation */
X if (numcpus > 1) {
X state_abbrev[SRUN][3] = '/';
X }
X
X return;
X}


X
Xcaddr_t get_process_info(si, sel, compare)

X struct system_info *si;
X struct process_select *sel;
X int (*compare)();

X{
X register int i;
X register int total_procs;
X register int active_procs;

X register struct prpsinfo **prefp;
X register struct prpsinfo *pp;


X
X /* these are copied out of sel for speed */
X int show_idle;
X int show_system;
X int show_uid;
X

X /* read all the proc structures */
X getptable (pbase);


X
X /* get a pointer to the states summary array */
X si->procstates = process_states;
X
X /* set up flags which define what we are going to select */
X show_idle = sel->idle;
X show_system = sel->system;
X show_uid = sel->uid != -1;
X

X /* count up process states and get pointers to interesting procs */
X total_procs = 0;
X active_procs = 0;

X (void) memset (process_states, 0, sizeof (process_states));


X prefp = pref;
X
X for (pp = pbase, i = 0; i < nproc; pp++, i++) {

X /*
X * Place pointers to each valid proc structure in pref[].
X * Process slots that are actually in use have a non-zero
X * status field. Processes with SSYS set are system

X * processes---these get ignored unless show_system is set.
X */
X if (pp->pr_state != 0 &&
X (show_system || ((pp->pr_flag & SSYS) == 0))) {
X total_procs++;
X process_states[pp->pr_state]++;
X if ((!pp->pr_zomb) &&
X (show_idle || (pp->pr_state == SRUN)) &&
X (!show_uid || pp->pr_uid == (uid_t) sel->uid)) {


X *prefp++ = pp;
X active_procs++;
X }
X }
X }
X
X /* if requested, sort the "interesting" processes */
X if (compare != NULL)

X qsort ((char *) pref, active_procs, sizeof (struct prpsinfo *), compare);


X
X /* remember active and total counts */
X si->p_total = total_procs;

X si->p_active = active_procs;


X
X /* pass back a handle */
X handle.next_proc = pref;
X handle.remaining = active_procs;
X return((caddr_t)&handle);
X}
X

Xchar *format_next_process(handle, get_userid)
X caddr_t handle;

X char *(*get_userid)();
X
X{
X register struct prpsinfo *pp;
X struct handle *hp;
X register long cputime;
X register double pctcpu;


X
X /* find and remember the next proc structure */
X hp = (struct handle *) handle;

X pp = *(hp->next_proc++);
X hp->remaining--;
X

X /* get the cpu usage and calculate the cpu percentages */
X cputime = pp->pr_time.tv_sec;
X pctcpu = percent_cpu (pp);
X
X if (numcpus > 1) {
X if (pp->pr_sonproc < 0)
X state_abbrev[SRUN][4] = '*';
X else
X state_abbrev[SRUN][4] = pp->pr_sonproc + '0';
X }


X
X /* format this entry */
X sprintf (fmt,
X Proc_format,

X pp->pr_pid,
X (*get_userid) (pp->pr_uid),
X pp->pr_pri - PZERO,
X pp->pr_nice - NZERO,
X format_k(pagetok(pp->pr_size)),
X format_k(pagetok(pp->pr_rssize)),
X state_abbrev[pp->pr_state],
X format_time(cputime),
X weighted_cpu (pp),
X pctcpu,
X pp->pr_fname);


X
X /* return the result */
X return(fmt);

X}
X
X/*


X * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
X * "offset" is the byte offset into the kernel for the desired value,
X * "ptr" points to a buffer into which the value is retrieved,
X * "size" is the size of the buffer (and the object to retrieve),
X * "refstr" is a reference string used when printing error meessages,
X * if "refstr" starts with a '!', then a failure on read will not
X * be fatal (this may seem like a silly way to do things, but I
X * really didn't want the overhead of another argument).

X *
X */
X

Xint getkval(offset, ptr, size, refstr)
X off_t offset;
X int *ptr;
X int size;
X char *refstr;
X
X{
X if (lseek(kmem, offset, SEEK_SET) == -1) {


X if (*refstr == '!')
X refstr++;
X (void) fprintf(stderr, "%s: lseek to %s: %s\n", KMEM,
X refstr, strerror(errno));

X exit(0);


X }
X if (read(kmem, (char *) ptr, size) == -1) {
X if (*refstr == '!')
X return(0);
X else {
X (void) fprintf(stderr, "%s: reading %s: %s\n", KMEM,
X refstr, strerror(errno));

X exit(0);
X }
X }
X return(1);
X}
X
X/*


X * proc_compare - comparison function for "qsort"
X * Compares the resource consumption of two processes using five
X * distinct keys. The keys (in descending order of importance) are:
X * percent cpu, cpu ticks, state, resident set size, total virtual
X * memory usage. The process states are ordered as follows (from least

X * to most important): WAIT, zombie, sleep, stop, idle, run. The


X * array declaration below maps a process state index into a number
X * that reflects this ordering.
X */
X
X

Xunsigned char sorted_state[] =


X{
X 0, /* not used */
X 3, /* sleep */

X 6, /* run */

X 2, /* zombie */

X 4, /* stop */

X 5, /* idle */


X 0, /* not used */

X 1 /* being swapped (WAIT) */
X};
X
Xint proc_compare (pp1, pp2)
X struct prpsinfo **pp1;
X struct prpsinfo **pp2;
X{
X register struct prpsinfo *p1;
X register struct prpsinfo *p2;
X register long result;


X
X /* remove one level of indirection */
X p1 = *pp1;
X p2 = *pp2;
X
X /* compare percent cpu (pctcpu) */

X if ((result = (long) (p2->pr_cpu - p1->pr_cpu)) == 0) {


X /* use cpticks to break the tie */

X if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0) {


X /* use process state to break the tie */

X if ((result = (long) (sorted_state[p2->pr_state] -
X sorted_state[p1->pr_state])) == 0) {


X /* use priority to break the tie */

X if ((result = p2->pr_oldpri - p1->pr_oldpri) == 0) {


X /* use resident set size (rssize) to break the tie */

X if ((result = p2->pr_rssize - p1->pr_rssize) == 0) {


X /* use total memory to break the tie */

X result = (p2->pr_size - p1->pr_size);
X }
X }
X }
X }
X }
X return (result);
X}
X
X/* return the owner of the specified process. */
Xuid_t proc_owner (pid)
X pid_t pid;
X{
X register struct prpsinfo *p;
X int i;
X
X for (i = 0, p = pbase; i < nproc; i++, p++)
X if (p->pr_pid == pid)
X return (p->pr_uid);
X
X return (-1);
X}
X
X/*


X * check_nlist(nlst) - checks the nlist to see if any symbols were not
X * found. For every symbol that was not found, a one-line
X * message is printed to stderr. The routine returns the
X * number of symbols NOT found.
X */
X
Xint check_nlist(nlst)

X register struct nlist *nlst;


X
X{
X register int i;
X
X /* check to see if we got ALL the symbols we requested */
X /* this will write one line to stderr for every symbol not found */
X
X i = 0;
X while (nlst->n_name != NULL) {

X if (nlst->n_type == 0) {

X /* this one wasn't found */
X fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
X i = 1;
X }
X nlst++;
X }
X
X return(i);
X}
X

X/* get process table */
Xvoid getptable (baseptr)
X struct prpsinfo *baseptr;
X{
X struct prpsinfo *currproc; /* pointer to current proc structure */
X int numprocs = 0;
X int i;
X struct dirent *directp;
X struct oldproc *op;
X static struct timeval lasttime =
X {0L, 0L};
X struct timeval thistime;
X struct timezone thiszone;
X double timediff;
X double alpha, beta;
X struct oldproc *endbase;
X
X gettimeofday (&thistime, &thiszone);
X
X /*
X * To avoid divides, we keep times in nanoseconds. This is
X * scaled by 1e7 rather than 1e9 so that when we divide we
X * get percent.
X */
X if (lasttime.tv_sec)
X timediff = ((double) thistime.tv_sec * 1.0e7 +
X ((double) thistime.tv_usec * 10.0)) -
X ((double) lasttime.tv_sec * 1.0e7 +
X ((double) lasttime.tv_usec * 10.0));
X else
X timediff = 1.0e7;
X
X /*
X * constants for exponential average. avg = alpha * new + beta * avg
X * The goal is 50% decay in 30 sec. However if the sample period
X * is greater than 30 sec, there's not a lot we can do.
X */
X if (timediff < 30.0e7)
X {
X alpha = 0.5 * (timediff / 30.0e7);
X beta = 1.0 - alpha;
X }
X else
X {
X alpha = 0.5;
X beta = 0.5;
X }
X
X endbase = oldbase + oldprocs;
X currproc = baseptr;
X
X
X for (rewinddir (procdir); directp = readdir (procdir);)
X {
X int fd;
X
X if ((fd = open (directp->d_name, O_RDONLY)) < 0)
X continue;
X
X currproc = &baseptr[numprocs];
X if (ioctl (fd, PIOCPSINFO, currproc) < 0)
X {
X (void) close (fd);
X continue;
X }
X
X /*
X * SVr4 doesn't keep track of CPU% in the kernel, so we have
X * to do our own. See if we've heard of this process before.
X * If so, compute % based on CPU since last time.
X */
X op = oldbase + HASH (currproc->pr_pid);
X while (1)
X {
X if (op->oldpid == -1) /* not there */
X break;
X if (op->oldpid == currproc->pr_pid)
X { /* found old data */
X percent_cpu (currproc) =
X ((currproc->pr_time.tv_sec * 1.0e9 +
X currproc->pr_time.tv_nsec)
X - op->oldtime) / timediff;
X weighted_cpu (currproc) =
X op->oldpct * beta + percent_cpu (currproc) * alpha;
X
X break;
X }
X op++; /* try next entry in hash table */
X if (op == endbase) /* table wrapped around */
X op = oldbase;
X }
X
X /* Otherwise, it's new, so use all of its CPU time */
X if (op->oldpid == -1)
X {
X if (lasttime.tv_sec)
X {
X percent_cpu (currproc) =
X (currproc->pr_time.tv_sec * 1.0e9 +
X currproc->pr_time.tv_nsec) / timediff;
X weighted_cpu (currproc) =
X percent_cpu (currproc);
X }
X else
X { /* first screen -- no difference is possible */
X percent_cpu (currproc) = 0.0;
X weighted_cpu (currproc) = 0.0;
X }
X }
X
X numprocs++;
X (void) close (fd);
X }
X
X if (nproc != numprocs)
X nproc = numprocs;
X
X /*
X * Save current CPU time for next time around
X * For the moment recreate the hash table each time, as the code
X * is easier that way.
X */
X oldprocs = 2 * nproc;
X endbase = oldbase + oldprocs;
X for (op = oldbase; op < endbase; op++)
X op->oldpid = -1;
X for (i = 0, currproc = baseptr;
X i < nproc;
X i++, currproc = (struct prpsinfo *) ((char *) currproc + PRPSINFOSIZE))
X {
X /* find an empty spot */
X op = oldbase + HASH (currproc->pr_pid);
X while (1)
X {
X if (op->oldpid == -1)
X break;
X op++;
X if (op == endbase)
X op = oldbase;
X }
X op->oldpid = currproc->pr_pid;
X op->oldtime = (currproc->pr_time.tv_sec * 1.0e9 +
X currproc->pr_time.tv_nsec);
X op->oldpct = weighted_cpu (currproc);
X }
X lasttime = thistime;
X
X}
X
END_OF_FILE
if test 18699 -ne `wc -c <'top-3.4/machine/m_irix5.c'`; then
echo shar: \"'top-3.4/machine/m_irix5.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_irix5.c'
fi
if test -f 'top-3.4/machine/m_ncr3000.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_ncr3000.c'\"
else
echo shar: Extracting \"'top-3.4/machine/m_ncr3000.c'\" \(18818 characters\)
sed "s/^X//" >'top-3.4/machine/m_ncr3000.c' <<'END_OF_FILE'


X/*
X * top - a top users display for Unix
X *

X * SYNOPSIS: For NCR 3000 series systems Release 2.00.02 and above -
X * works on 2.03.00 and earlier (and probably later) OS releases.
X * (Intel based System V Release 4)


X *
X * DESCRIPTION:

X * System V release 4 for NCR 3000 series OS Rel 02.03.00 and above
X *
X * LIBS: -lelf
X *
X * AUTHORS: Andrew Herbert <and...@werple.apana.org.au>


X * Robert Boucher <bou...@sofkin.ca>

X * Jeff Janvrin <jeff.j...@columbiasc.ncr.com>
X * did the port to statfs (2.03)


X */
X
X#include "top.h"

X#include "machine.h"
X#include "utils.h"
X#include <stdio.h>
X#include <fcntl.h>
X#include <unistd.h>
X#include <stdlib.h>
X#include <errno.h>
X#include <dirent.h>
X#include <nlist.h>
X#include <string.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/param.h>
X#include <sys/procfs.h>
X#include <sys/sysinfo.h>
X#include <sys/sysmacros.h>
X#include <sys/vmmeter.h>
X#include <vm/anon.h>
X#include <sys/priocntl.h>
X#include <sys/rtpriocntl.h>
X#include <sys/tspriocntl.h>
X#include <sys/procset.h>
X#include <sys/var.h>
X
X#define UNIX "/stand/unix"
X#define KMEM "/dev/kmem"
X#define PROCFS "/proc"
X#define CPUSTATES 5
X
X#ifndef PRIO_MAX
X#define PRIO_MAX 20
X#endif
X#ifndef PRIO_MIN
X#define PRIO_MIN -20
X#endif
X
X#ifndef FSCALE
X#define FSHIFT 8 /* bits to right of fixed binary point */
X#define FSCALE (1<<FSHIFT)
X#endif
X
X#define loaddouble(x) ((double)(x) / FSCALE)
X#define percent_cpu(x) ((double)(x)->pr_cpu / FSCALE)
X#define weighted_cpu(pct, pp) ( ((pp)->pr_time.tv_sec) == 0 ? 0.0 : \
X ((pp)->pr_cpu) / ((pp)->pr_time.tv_sec) )
X#define pagetok(size) ctob(size) >> LOG1024
X
X/* definitions for the index in the nlist array */
X#define X_AVENRUN 0
X#define X_MPID 1
X#define X_V 2
X#define X_NPROC 3
X#define X_ANONINFO 4
X#define X_TOTAL 5
X#define X_SYSINFO 6


X
Xstatic struct nlist nlst[] =
X{

X{"avenrun"}, /* 0 */
X{"mpid"}, /* 1 */
X{"v"}, /* 2 */
X{"nproc"}, /* 3 */
X{"anoninfo"}, /* 4 */
X{"total"}, /* 5 */
X{"sysinfo"}, /* 6 */
X{NULL}
X};


X
Xstatic unsigned long avenrun_offset;
Xstatic unsigned long mpid_offset;

Xstatic unsigned long nproc_offset;
Xstatic unsigned long anoninfo_offset;
Xstatic unsigned long total_offset;
Xstatic unsigned long sysinfo_offset;


X
X/* get_process_info passes back a handle. This is what it looks like: */
X
Xstruct handle
X {

X struct prpsinfo **next_proc;/* points to next valid proc pointer */


X int remaining; /* number of pointers remaining */

X };
X
X/*


X * These definitions control the format of the per-process area
X */
X
Xstatic char header[] =
X" PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";
X/* 0123456 -- field to fill in starts at header+6 */
X#define UNAME_START 6

X#define Proc_format \
X "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %3d.0%% %5.2f%% %.16s"
X
Xchar *state_abbrev[] =
X{"", "sleep", "run", "zombie", "stop", "start", "cpu", "swap"};


X
Xint process_states[8];
Xchar *procstatenames[] =

X{
X "", " sleeping, ", " running, ", " zombie, ", " stopped, ",
X " starting, ", " on cpu, ", " swapped, ",
X NULL
X};
X


Xint cpu_states[CPUSTATES];
Xchar *cpustatenames[] =

X{"idle", "user", "kernel", "wait", "swap", NULL};


X
X/* these are for detailing the memory statistics */
X

Xint memory_stats[5];
Xchar *memorynames[] =
X{"K real, ", "K active, ", "K free, ", "K swap, ", "K free swap", NULL};


X
Xstatic int kmem = -1;

Xstatic int nproc;
Xstatic int bytes;
Xstatic int use_stats = 0;
Xstatic struct prpsinfo *pbase;
Xstatic struct prpsinfo **pref;
Xstatic DIR *procdir;


X
X/* useful externals */
Xextern int errno;
Xextern char *sys_errlist[];

Xextern char *myname;
Xextern int check_nlist ();
Xextern int getkval ();
Xextern void perror ();
Xextern void getptable ();
Xextern void quit ();
Xextern int nlist ();
X
Xint
Xmachine_init (struct statics *statics)
X {
X static struct var v;


X
X /* fill in the statics information */
X statics->procstate_names = procstatenames;
X statics->cpustate_names = cpustatenames;
X statics->memory_names = memorynames;
X

X /* get the list of symbols we want to access in the kernel */

X if (nlist (UNIX, nlst))
X {
X (void) fprintf (stderr, "Unable to nlist %s\n", UNIX);
X return (-1);


X }
X
X /* make sure they were all found */

X if (check_nlist (nlst) > 0)
X return (-1);


X
X /* open kernel memory */

X if ((kmem = open (KMEM, O_RDONLY)) == -1)
X {
X perror (KMEM);
X return (-1);


X }
X
X /* get the symbol values out of kmem */

X /* NPROC Tuning parameter for max number of processes */
X (void) getkval (nlst[X_V].n_value, (int *) &v, sizeof (struct var), nlst[X_V].n_name);
X nproc = v.v_proc;


X
X /* stash away certain offsets for later use */
X mpid_offset = nlst[X_MPID].n_value;

X nproc_offset = nlst[X_NPROC].n_value;


X avenrun_offset = nlst[X_AVENRUN].n_value;

X anoninfo_offset = nlst[X_ANONINFO].n_value;


X total_offset = nlst[X_TOTAL].n_value;

X/* JJ this may need to be changed */


X sysinfo_offset = nlst[X_SYSINFO].n_value;

X
X /* allocate space for proc structure array and array of pointers */

X bytes = nproc * sizeof (struct prpsinfo);
X pbase = (struct prpsinfo *) malloc (bytes);
X pref = (struct prpsinfo **) malloc (nproc * sizeof (struct prpsinfo *));


X
X /* Just in case ... */

X if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL)
X {
X (void) fprintf (stderr, "%s: can't allocate sufficient memory\n", myname);
X return (-1);
X }
X
X if (!(procdir = opendir (PROCFS)))
X {
X (void) fprintf (stderr, "Unable to open %s\n", PROCFS);
X return (-1);
X }
X
X if (chdir (PROCFS))
X { /* handy for later on when we're reading it */
X (void) fprintf (stderr, "Unable to chdir to %s\n", PROCFS);
X return (-1);
X }


X
X /* all done! */
X return (0);
X }
X
Xchar *

Xformat_header (char *uname_field)


X{
X register char *ptr;
X
X ptr = header + UNAME_START;
X while (*uname_field != '\0')

X *ptr++ = *uname_field++;
X

X return (header);
X}
X
Xvoid
Xget_system_info (struct system_info *si)
X{
X long avenrun[3];
X struct sysinfo sysinfo;
X static struct sysinfo *mpinfo = NULL; /* array, per-processor sysinfo structures. */
X struct vmtotal total;
X struct anoninfo anoninfo;
X static time_t cp_old[CPUSTATES];
X static time_t cp_diff[CPUSTATES]; /* for cpu state percentages */
X static int num_cpus;
X static int fd_cpu = 0;
X register int i;
X
X if ( use_stats == 1) {
X if ( fd_cpu == 0 ) {
X if ((fd_cpu = open("/stats/cpuinfo", O_RDONLY)) == -1) {
X (void) fprintf (stderr, "%s: Open of /stats/cpuinfo failed\n", myname);
X quit(2);
X }
X if (read(fd_cpu, &num_cpus, sizeof(int)) != sizeof(int)) {
X (void) fprintf (stderr, "%s: Read of /stats/cpuinfo failed\n", myname);
X quit(2);
X }
X close(fd_cpu);
X }
X if (mpinfo == NULL) {
X mpinfo = (struct sysinfo *)calloc(num_cpus, sizeof(mpinfo[0]));
X if (mpinfo == NULL) {
X (void) fprintf (stderr, "%s: can't allocate space for per-processor sysinfos\n", myname);
X quit(12);
X }
X }
X /* Read the per cpu sysinfo structures into mpinfo struct. */
X read_sysinfos(num_cpus, mpinfo);
X /* Add up all of the percpu sysinfos to get global sysinfo */
X sysinfo_data(num_cpus, &sysinfo, mpinfo);
X } else {
X (void) getkval (sysinfo_offset, &sysinfo, sizeof (struct sysinfo), "sysinfo");


X }
X
X /* convert cp_time counts to percentages */

X (void) percentages (CPUSTATES, cpu_states, sysinfo.cpu, cp_old, cp_diff);
X


X /* get mpid -- process id of last process */
X (void) getkval (mpid_offset, &(si->last_pid), sizeof (si->last_pid),

X "mpid");


X
X /* get load average array */

X (void) getkval (avenrun_offset, (int *) avenrun, sizeof (avenrun), "avenrun");


X
X /* convert load averages to doubles */

X for (i = 0; i < 3; i++)

X si->load_avg[i] = loaddouble (avenrun[i]);
X


X /* get total -- systemwide main memory usage structure */

X (void) getkval (total_offset, (int *) (&total), sizeof (total), "total");


X /* convert memory stats to Kbytes */

X memory_stats[0] = pagetok (total.t_rm);
X memory_stats[1] = pagetok (total.t_arm);
X memory_stats[2] = pagetok (total.t_free);
X (void) getkval (anoninfo_offset, (int *) (&anoninfo), sizeof (anoninfo),
X "anoninfo");
X memory_stats[3] = pagetok (anoninfo.ani_max - anoninfo.ani_free);
X memory_stats[4] = pagetok (anoninfo.ani_max - anoninfo.ani_resv);


X
X /* set arrays and strings */
X si->cpustates = cpu_states;
X si->memory = memory_stats;
X}
X
Xstatic struct handle handle;
X
Xcaddr_t

Xget_process_info (
X struct system_info *si,
X struct process_select *sel,
X int (*compare) ())


X{
X register int i;
X register int total_procs;
X register int active_procs;

X register struct prpsinfo **prefp;
X register struct prpsinfo *pp;


X
X /* these are copied out of sel for speed */
X int show_idle;
X int show_system;
X int show_uid;
X

X /* Get current number of processes */
X (void) getkval (nproc_offset, (int *) (&nproc), sizeof (nproc), "nproc");
X
X /* read all the proc structures */
X getptable (pbase);


X
X /* get a pointer to the states summary array */
X si->procstates = process_states;
X
X /* set up flags which define what we are going to select */
X show_idle = sel->idle;
X show_system = sel->system;
X show_uid = sel->uid != -1;
X

X /* count up process states and get pointers to interesting procs */
X total_procs = 0;
X active_procs = 0;

X (void) memset (process_states, 0, sizeof (process_states));


X prefp = pref;
X
X for (pp = pbase, i = 0; i < nproc; pp++, i++)
X {
X /*
X * Place pointers to each valid proc structure in pref[].
X * Process slots that are actually in use have a non-zero
X * status field. Processes with SSYS set are system
X * processes---these get ignored unless show_sysprocs is set.
X */

X if (pp->pr_state != 0 &&
X (show_system || ((pp->pr_flag & SSYS) == 0)))
X {
X total_procs++;
X process_states[pp->pr_state]++;
X if ((!pp->pr_zomb) &&
X (show_idle || (pp->pr_state == SRUN) || (pp->pr_state == SONPROC)) &&
X (!show_uid || pp->pr_uid == (uid_t) sel->uid))


X {
X *prefp++ = pp;
X active_procs++;
X }
X }
X }
X
X /* if requested, sort the "interesting" processes */
X if (compare != NULL)

X qsort ((char *) pref, active_procs, sizeof (struct prpsinfo *), compare);


X
X /* remember active and total counts */
X si->p_total = total_procs;

X si->p_active = active_procs;


X
X /* pass back a handle */
X handle.next_proc = pref;
X handle.remaining = active_procs;
X return ((caddr_t) & handle);
X}
X
Xchar fmt[MAX_COLS]; /* static area where result is built */
X
Xchar *

Xformat_next_process (
X caddr_t handle,
X char *(*get_userid) ())
X{
X register struct prpsinfo *pp;
X struct handle *hp;
X register long cputime;
X register double pctcpu;


X
X /* find and remember the next proc structure */
X hp = (struct handle *) handle;

X pp = *(hp->next_proc++);
X hp->remaining--;
X

X /* get the cpu usage and calculate the cpu percentages */
X cputime = pp->pr_time.tv_sec;
X pctcpu = percent_cpu (pp);


X
X /* format this entry */

X (void) sprintf (fmt,
X Proc_format,
X pp->pr_pid,
X (*get_userid) (pp->pr_uid),
X pp->pr_pri - PZERO,
X pp->pr_nice - NZERO,
X format_k(pagetok (pp->pr_size)),
X format_k(pagetok (pp->pr_rssize)),
X state_abbrev[pp->pr_state],
X format_time(cputime),
X (pp->pr_cpu & 0377),
X 100.0 * pctcpu,
X pp->pr_fname);


X
X /* return the result */
X return (fmt);

X}
X
X/*


X * check_nlist(nlst) - checks the nlist to see if any symbols were not
X * found. For every symbol that was not found, a one-line
X * message is printed to stderr. The routine returns the
X * number of symbols NOT found.
X */

Xint
Xcheck_nlist (register struct nlist *nlst)


X{
X register int i;

X struct stat stat_buf;


X
X /* check to see if we got ALL the symbols we requested */
X /* this will write one line to stderr for every symbol not found */
X
X i = 0;
X while (nlst->n_name != NULL)
X {
X if (nlst->n_type == 0)
X {

X if (strcmp("sysinfo", nlst->n_name) == 0)
X {
X /* check to see if /stats file system exists. If so, */
X /* ignore error. */
X if ( !((stat("/stats/sysinfo", &stat_buf) == 0) &&
X (stat_buf.st_mode & S_IFREG)) )
X {
X (void) fprintf (stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
X i = 1;
X } else {
X use_stats = 1;
X }
X } else {
X


X /* this one wasn't found */

X (void) fprintf (stderr, "kernel: no symbol named `%s'\n", nlst->n_name);


X i = 1;
X }
X }

X nlst++;
X }
X return (i);
X}
X
X
X/*


X * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
X * "offset" is the byte offset into the kernel for the desired value,
X * "ptr" points to a buffer into which the value is retrieved,
X * "size" is the size of the buffer (and the object to retrieve),
X * "refstr" is a reference string used when printing error meessages,
X * if "refstr" starts with a '!', then a failure on read will not
X * be fatal (this may seem like a silly way to do things, but I
X * really didn't want the overhead of another argument).
X *
X */

Xint
Xgetkval (
X unsigned long offset,
X int *ptr,
X int size,
X char *refstr)
X{
X if (lseek (kmem, (long) offset, 0) == -1)


X {
X if (*refstr == '!')

X refstr++;
X (void) fprintf (stderr, "%s: lseek to %s: %s\n",
X myname, refstr, sys_errlist[errno]);
X quit (22);
X }
X if (read (kmem, (char *) ptr, size) == -1)


X if (*refstr == '!')

X /* we lost the race with the kernel, process isn't in memory */
X return (0);

X else
X {
X (void) fprintf (stderr, "%s: reading %s: %s\n",
X myname, refstr, sys_errlist[errno]);
X quit (23);
X }
X return (1);
X}
X
X/* comparison routine for qsort */
X
X/*


X * proc_compare - comparison function for "qsort"
X * Compares the resource consumption of two processes using five
X * distinct keys. The keys (in descending order of importance) are:
X * percent cpu, cpu ticks, state, resident set size, total virtual
X * memory usage. The process states are ordered as follows (from least
X * to most important): WAIT, zombie, sleep, stop, start, run. The
X * array declaration below maps a process state index into a number
X * that reflects this ordering.
X */
X
X

Xunsigned char sorted_state[] =


X{
X 0, /* not used */
X 3, /* sleep */

X 6, /* run */

X 2, /* zombie */

X 4, /* stop */


X 5, /* start */

X 7, /* run on a processor */
X 1 /* being swapped (WAIT) */
X};
X
Xint
Xproc_compare (
X struct prpsinfo **pp1,
X struct prpsinfo **pp2)
X{
X register struct prpsinfo *p1;
X register struct prpsinfo *p2;
X register long result;


X
X /* remove one level of indirection */
X p1 = *pp1;
X p2 = *pp2;
X
X /* compare percent cpu (pctcpu) */

X if ((result = (long) (p2->pr_cpu - p1->pr_cpu)) == 0)


X {
X /* use cpticks to break the tie */

X if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0)


X {
X /* use process state to break the tie */

X if ((result = (long) (sorted_state[p2->pr_state] -
X sorted_state[p1->pr_state])) == 0)


X {
X /* use priority to break the tie */

X if ((result = p2->pr_oldpri - p1->pr_oldpri) == 0)


X {
X /* use resident set size (rssize) to break the tie */

X if ((result = p2->pr_rssize - p1->pr_rssize) == 0)


X {
X /* use total memory to break the tie */

X result = (p2->pr_size - p1->pr_size);
X }
X }
X }
X }
X }
X return (result);
X }
X
X/*
Xget process table
X*/
Xvoid
Xgetptable (struct prpsinfo *baseptr)
X{
X struct prpsinfo *currproc; /* pointer to current proc structure */
X int numprocs = 0;
X struct dirent *direntp;
X
X for (rewinddir (procdir); direntp = readdir (procdir);)
X {
X int fd;
X
X if ((fd = open (direntp->d_name, O_RDONLY)) < 0)
X continue;
X
X currproc = &baseptr[numprocs];
X if (ioctl (fd, PIOCPSINFO, currproc) < 0)
X {
X (void) close (fd);
X continue;
X }
X
X numprocs++;
X (void) close (fd);
X }
X
X if (nproc != numprocs)
X nproc = numprocs;
X}
X
X/* return the owner of the specified process, for use in commands.c as we're
X running setuid root */
Xuid_t
Xproc_owner (pid_t pid)
X{
X register struct prpsinfo *p;
X int i;
X for (i = 0, p = pbase; i < nproc; i++, p++)
X if (p->pr_pid == pid)
X return (p->pr_uid);
X
X return (-1);
X}
X
Xint
Xsetpriority (int dummy, int who, int niceval)
X{
X int scale;
X int prio;
X pcinfo_t pcinfo;
X pcparms_t pcparms;
X tsparms_t *tsparms;
X
X strcpy (pcinfo.pc_clname, "TS");
X if (priocntl (0, 0, PC_GETCID, (caddr_t) & pcinfo) == -1)
X return (-1);
X
X prio = niceval;
X if (prio > PRIO_MAX)
X prio = PRIO_MAX;
X else if (prio < PRIO_MIN)
X prio = PRIO_MIN;
X
X tsparms = (tsparms_t *) pcparms.pc_clparms;
X scale = ((tsinfo_t *) pcinfo.pc_clinfo)->ts_maxupri;
X tsparms->ts_uprilim = tsparms->ts_upri = -(scale * prio) / 20;
X pcparms.pc_cid = pcinfo.pc_cid;
X
X if (priocntl (P_PID, who, PC_SETPARMS, (caddr_t) & pcparms) == -1)
X return (-1);
X
X return (0);
X}
X
X/****************************************************************
X * read_sysinfos() - *
X * Read all of the CPU specific sysinfo sturctures in from *
X * the /stats file system. *
X ****************************************************************/
Xread_sysinfos(num_cpus, buf)
X int num_cpus;
X struct sysinfo *buf;
X{
X
X static int fd1=0; /* file descriptor for /stats/sysinfo */
X int read_sz;
X
X /* Open /stats/sysinfo one time only and leave it open */
X if (fd1==0) {
X if ((fd1 = open("/stats/sysinfo", O_RDONLY)) == -1)
X (void) fprintf (stderr, "%s: Open of /stats/sysinfo failed\n", myname);
X }
X /* reset the read pointer to the beginning of the file */
X if (lseek(fd1, 0L, SEEK_SET) == -1)
X (void) fprintf (stderr, "%s: lseek to beginning of /stats/sysinfo failed\n", myname);
X read_sz = num_cpus * sizeof(buf[0]);
X if (read(fd1, buf, read_sz) != read_sz)
X (void) fprintf (stderr, "%s: Read of /stats/sysinfo failed\n", myname);
X}
X
X/****************************************************************
X * sysinfo_data() - *
X * Add up all of the CPU specific sysinfo sturctures to *
X * make the GLOBAL sysinfo. *
X ****************************************************************/
Xsysinfo_data(num_cpus, global_si, percpu_si)
X int num_cpus;
X struct sysinfo *global_si;
X struct sysinfo *percpu_si;
X{
X struct sysinfo *percpu_p;
X int cpu, i, *global, *src;
X
X /* null out the global statistics from last sample */
X memset(global_si, 0, sizeof(struct sysinfo));
X
X percpu_p = (struct sysinfo *)percpu_si;
X for(cpu = 0; cpu < num_cpus; cpu++) {
X global = (int *)global_si;
X src = (int *)percpu_p;
X
X /* assume sysinfo ends on an int boundary */
X /* Currently, all of the struct sysinfo members are the same
X * size as an int. If that changes, we may not be able to
X * do this. But this should be safe.
X */
X for(i=0; i<sizeof(struct sysinfo)/sizeof(int); i++) {
X *global++ += *src++;
X }
X percpu_p++;
X }
X}
END_OF_FILE
if test 18818 -ne `wc -c <'top-3.4/machine/m_ncr3000.c'`; then
echo shar: \"'top-3.4/machine/m_ncr3000.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_ncr3000.c'
fi
echo shar: End of archive 12 \(of 22\).
cp /dev/null ark12isdone

William Lefebvre

unread,
Sep 1, 1996, 3:00:00 AM9/1/96
to

Submitted-By: w...@groupsys.com (William Lefebvre)
Posting-Number: Volume 29, Issue 118
Archive-Name: top-3.4/part17

#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:

# "End of archive 17 (of 22)."
# Contents: top-3.4/machine/m_freebsd20.c top-3.4/top.c
# Wrapped by lefebvre@acapulco on Fri Aug 30 12:35:51 1996


PATH=/bin:/usr/bin:/usr/ucb ; export PATH

if test -f 'top-3.4/machine/m_freebsd20.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_freebsd20.c'\"
else
echo shar: Extracting \"'top-3.4/machine/m_freebsd20.c'\" \(21760 characters\)
sed "s/^X//" >'top-3.4/machine/m_freebsd20.c' <<'END_OF_FILE'


X/*
X * top - a top users display for Unix
X *

X * SYNOPSIS: For a FreeBSD-2.0 (4.4BSD) system
X * Note process resident sizes could be wrong, but ps shows
X * zero for them too..


X *
X * DESCRIPTION:

X * Originally written for BSD4.4 system by Christos Zoulas.
X * Ported to FreeBSD 2.0 by Steven Wallace && Wolfram Schneider
X *
X * This is the machine-dependent module for FreeBSD 2.0
X * Works for:
X * FreeBSD 2.0


X *
X * LIBS: -lkvm

X *
X * AUTHOR: Christos Zoulas <chri...@ee.cornell.edu>
X * Steven Wallace <swal...@freebsd.org>
X * Wolfram Schneider <wo...@cs.tu-berlin.de>
X *
X * $Id: machine.c,v 1.5 1995/01/06 02:04:39 swallace Exp $
X */
X
X
X
X#define LASTPID /**/ /* use last pid, compiler depended */
X/* #define LASTPID_FIXED /**/
X#define VM_REAL /**/ /* use the same values as vmstat -s */
X#define USE_SWAP /**/ /* use swap usage (pstat -s),
X need to much cpu time */
X/* #define DEBUG 1 /**/


X
X#include <sys/types.h>
X#include <sys/signal.h>
X#include <sys/param.h>
X

X#include "os.h"
X#include <stdio.h>
X#include <nlist.h>
X#include <math.h>
X#include <kvm.h>
X#include <sys/errno.h>
X#include <sys/sysctl.h>
X#include <sys/dir.h>
X#include <sys/dkstat.h>
X#include <sys/file.h>
X#include <sys/time.h>
X
X#ifdef USE_SWAP
X#include <stdlib.h>
X#include <sys/rlist.h>
X#include <sys/conf.h>
X#endif
X
Xstatic int check_nlist __P((struct nlist *));
Xstatic int getkval __P((unsigned long, int *, int, char *));
Xextern char* printable __P((char *));


X
X#include "top.h"
X#include "machine.h"
X

X
X/* get_process_info passes back a handle. This is what it looks like: */
X
Xstruct handle
X{

X struct kinfo_proc **next_proc; /* points to next valid proc pointer */


X int remaining; /* number of pointers remaining */
X};
X

X/* declarations for load_avg */
X#include "loadavg.h"
X

X#define PP(pp, field) ((pp)->kp_proc . field)
X#define EP(pp, field) ((pp)->kp_eproc . field)
X#define VP(pp, field) ((pp)->kp_eproc.e_vm . field)


X
X/* define what weighted cpu is. */

X#define weighted_cpu(pct, pp) (PP((pp), p_swtime) == 0 ? 0.0 : \
X ((pct) / (1.0 - exp(PP((pp), p_swtime) * logcpu))))


X
X/* what we consider to be process size: */

X#define PROCSIZE(pp) (VP((pp), vm_tsize) + VP((pp), vm_dsize) + VP((pp), vm_ssize))
X
X/* definitions for indices in the nlist array */
X


X
Xstatic struct nlist nlst[] = {

X#define X_CCPU 0
X { "_ccpu" }, /* 0 */
X#define X_CP_TIME 1
X { "_cp_time" }, /* 1 */
X#define X_HZ 2
X { "_hz" }, /* 2 */
X#define X_STATHZ 3
X { "_stathz" }, /* 3 */
X#define X_AVENRUN 4
X { "_averunnable" }, /* 4 */
X#ifdef USE_SWAP
X#define VM_SWAPLIST 5
X { "_swaplist" },/* list of free swap areas */
X#define VM_SWDEVT 6
X { "_swdevt" }, /* list of swap devices and sizes */
X#define VM_NSWAP 7
X { "_nswap" }, /* size of largest swap device */
X#define VM_NSWDEV 8
X { "_nswdev" }, /* number of swap devices */
X#define VM_DMMAX 9
X { "_dmmax" }, /* maximum size of a swap block */
X#endif
X#ifdef VM_REAL
X#ifdef USE_SWAP
X#define X_CNT 10
X#else
X#define X_CNT 5
X#endif
X { "_cnt" }, /* struct vmmeter cnt */
X#endif
X
X#ifdef LASTPID
X#if (defined USE_SWAP && defined VM_REAL)
X#define X_LASTPID 11
X#elif (defined VM_REAL)
X#define X_LASTPID 6
X#else
X#define X_LASTPID 5
X#endif
X#ifdef LASTPID_FIXED
X { "_nextpid" },
X#else
X { "_nextpid.178" }, /* lastpid, compiler depended
X * should be changed
X * in /sys/kern/kern_fork.c */
X#endif
X#endif
X
X { 0 }
X};
X
X/*


X * These definitions control the format of the per-process area
X */
X
Xstatic char header[] =
X " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";
X/* 0123456 -- field to fill in starts at header+6 */
X#define UNAME_START 6
X
X#define Proc_format \

X "%5d %-8.8s %3d %4d%7s %5s %-5s%7s %5.2f%% %5.2f%% %.14s"


X
X
X/* process state names for the "STATE" column of the display */
X/* the extra nulls in the string "run" are for adding a slash and
X the processor number when needed */

X
Xchar *state_abbrev[] =
X{

X "", "start", "run\0\0\0", "sleep", "stop", "zomb", "WAIT"
X};
X
X
Xstatic kvm_t *kd;


X
X/* values that we stash away in _init and use in later routines */
X
Xstatic double logcpu;
X
X/* these are retrieved from the kernel in _init */
X

Xstatic long hz;
Xstatic load_avg ccpu;

X
X/* these are offsets obtained via nlist and used in the get_ functions */
X

Xstatic unsigned long cp_time_offset;
Xstatic unsigned long avenrun_offset;
X#ifdef LASTPID
Xstatic unsigned long lastpid_offset;
Xstatic long lastpid;
X#endif
X#ifdef VM_REAL
Xstatic unsigned long cnt_offset;
Xstatic long cnt;
X#endif
X/* these are for calculating cpu state percentages */
X


Xstatic long cp_time[CPUSTATES];
Xstatic long cp_old[CPUSTATES];
Xstatic long cp_diff[CPUSTATES];

X
X/* these are for detailing the process states */
X

Xint process_states[7];
Xchar *procstatenames[] = {
X "", " starting, ", " running, ", " sleeping, ", " stopped, ",
X " zombie, ", " ABANDONED, ",


X NULL
X};
X
X/* these are for detailing the cpu states */

X
Xint cpu_states[CPUSTATES];
Xchar *cpustatenames[] = {

X "user", "nice", "system", "interrupt", "idle", NULL
X};
X


X/* these are for detailing the memory statistics */
X

Xint memory_stats[8];
Xchar *memorynames[] = {
X#ifndef VM_REAL
X "Real: ", "K/", "K ", "Virt: ", "K/",
X "K ", "Free: ", "K", NULL
X#else
X#if 0
X "K Act ", "K Inact ", "K Wired ", "K Free ", "% Swap, ",
X "K/", "K SWIO",
X#else
X "K Act ", "K Inact ", "K Wired ", "K Free ", "% Swap, ",
X "Kin ", "Kout",
X#endif
X NULL
X#endif
X};
X


X/* these are for keeping track of the proc array */
X

Xstatic int nproc;
Xstatic int onproc = -1;
Xstatic int pref_len;
Xstatic struct kinfo_proc *pbase;
Xstatic struct kinfo_proc **pref;
X
X/* these are for getting the memory statistics */
X


Xstatic int pageshift; /* log base 2 of the pagesize */
X
X/* define pagetok in terms of pageshift */
X
X#define pagetok(size) ((size) << pageshift)

X
X/* useful externals */

Xlong percentages();
X
Xint


Xmachine_init(statics)
X
Xstruct statics *statics;

X
X{
X register int i = 0;
X register int pagesize;
X
X if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL)
X return -1;


X
X
X /* get the list of symbols we want to access in the kernel */

X (void) kvm_nlist(kd, nlst);


X if (nlst[0].n_type == 0)

X {
X fprintf(stderr, "top: nlist failed\n");

X return(-1);
X }
X


X /* make sure they were all found */

X if (i > 0 && check_nlist(nlst) > 0)
X {

X return(-1);
X }
X


X /* get the symbol values out of kmem */

X (void) getkval(nlst[X_STATHZ].n_value, (int *)(&hz), sizeof(hz), "!");
X if (!hz) {


X (void) getkval(nlst[X_HZ].n_value, (int *)(&hz), sizeof(hz),
X nlst[X_HZ].n_name);
X }

X
X
X#if (defined DEBUG)
X fprintf(stderr, "Hertz: %d\n", hz);
X#endif
X


X (void) getkval(nlst[X_CCPU].n_value, (int *)(&ccpu), sizeof(ccpu),
X nlst[X_CCPU].n_name);

X
X /* stash away certain offsets for later use */

X cp_time_offset = nlst[X_CP_TIME].n_value;


X avenrun_offset = nlst[X_AVENRUN].n_value;

X#ifdef LASTPID
X lastpid_offset = nlst[X_LASTPID].n_value;
X#endif
X#ifdef VM_REAL
X cnt_offset = nlst[X_CNT].n_value;
X#endif
X


X /* this is used in calculating WCPU -- calculate it ahead of time */
X logcpu = log(loaddouble(ccpu));
X

X pbase = NULL;
X pref = NULL;
X nproc = 0;
X onproc = -1;


X /* get the page size with "getpagesize" and calculate pageshift from it */
X pagesize = getpagesize();
X pageshift = 0;
X while (pagesize > 1)
X {
X pageshift++;

X pagesize >>= 1;
X }
X


X /* we only need the amount of log(2)1024 for our conversion */
X pageshift -= LOG1024;

X
X /* fill in the statics information */
X statics->procstate_names = procstatenames;
X statics->cpustate_names = cpustatenames;
X statics->memory_names = memorynames;
X

X /* all done! */
X return(0);
X}
X
Xchar *format_header(uname_field)
X

Xregister char *uname_field;


X
X{
X register char *ptr;
X
X ptr = header + UNAME_START;
X while (*uname_field != '\0')

X {


X *ptr++ = *uname_field++;
X }
X
X return(header);
X}
X

Xstatic int swappgsin = -1;
Xstatic int swappgsout = -1;
Xextern struct timeval timeout;
X
Xvoid
Xget_system_info(si)
X
Xstruct system_info *si;
X
X{
X long total;
X load_avg avenrun[3];
X


X /* get the cp_time array */
X (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),

X nlst[X_CP_TIME].n_name);


X (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),

X nlst[X_AVENRUN].n_name);
X
X#ifdef LASTPID
X (void) getkval(lastpid_offset, (int *)(&lastpid), sizeof(lastpid),
X "!");
X#endif


X
X /* convert load averages to doubles */

X {
X register int i;
X register double *infoloadp;
X load_avg *avenrunp;
X
X#ifdef notyet
X struct loadavg sysload;
X int size;
X getkerninfo(KINFO_LOADAVG, &sysload, &size, 0);
X#endif


X
X infoloadp = si->load_avg;

X avenrunp = avenrun;


X for (i = 0; i < 3; i++)

X {
X#ifdef notyet
X *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
X#endif
X *infoloadp++ = loaddouble(*avenrunp++);
X }
X }
X


X /* convert cp_time counts to percentages */

X total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
X


X /* sum memory statistics */
X {
X

X#ifndef VM_REAL
X struct vmtotal total;
X int size = sizeof(total);
X static int mib[] = { CTL_VM, VM_METER };


X
X /* get total -- systemwide main memory usage structure */

X if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) {
X (void) fprintf(stderr, "top: sysctl failed: %s\n", strerror(errno));
X bzero(&total, sizeof(total));
X }


X /* convert memory stats to Kbytes */

X memory_stats[0] = -1;
X memory_stats[1] = pagetok(total.t_arm);
X memory_stats[2] = pagetok(total.t_rm);
X memory_stats[3] = -1;
X memory_stats[4] = pagetok(total.t_avm);
X memory_stats[5] = pagetok(total.t_vm);
X memory_stats[6] = -1;
X memory_stats[7] = pagetok(total.t_free);
X }

X#else
X struct vmmeter sum;
X static unsigned int swap_delay = 0;
X
X (void) getkval(cnt_offset, (int *)(&sum), sizeof(sum),
X "_cnt");
X


X /* convert memory stats to Kbytes */

X memory_stats[0] = pagetok(sum.v_active_count);
X memory_stats[1] = pagetok(sum.v_inactive_count);
X memory_stats[2] = pagetok(sum.v_wire_count);
X memory_stats[3] = pagetok(sum.v_free_count);
X
X if (swappgsin < 0) {
X memory_stats[5] = 0;
X memory_stats[6] = 0;
X } else {
X memory_stats[5] = pagetok(((sum.v_swappgsin - swappgsin)));
X memory_stats[6] = pagetok(((sum.v_swappgsout - swappgsout)));
X }
X swappgsin = sum.v_swappgsin;
X swappgsout = sum.v_swappgsout;
X
X#ifdef USE_SWAP
X if ((memory_stats[5] > 0 || memory_stats[6]) > 0 || swap_delay == 0) {
X memory_stats[4] = swapmode();
X }
X swap_delay++;
X#else
X memory_stats[4] = 0;
X#endif
X
X
X memory_stats[7] = -1;
X }
X#endif


X /* set arrays and strings */
X si->cpustates = cpu_states;
X si->memory = memory_stats;

X#ifdef LASTPID
X if(lastpid > 0) {
X si->last_pid = lastpid;
X } else {


X si->last_pid = -1;

X }
X#else


X si->last_pid = -1;

X#endif
X


X}
X
Xstatic struct handle handle;
X

Xcaddr_t get_process_info(si, sel, compare)
X
Xstruct system_info *si;
Xstruct process_select *sel;
Xint (*compare)();

X
X{
X register int i;

X register int total_procs;
X register int active_procs;

X register struct kinfo_proc **prefp;
X register struct kinfo_proc *pp;


X
X /* these are copied out of sel for speed */
X int show_idle;
X int show_system;
X int show_uid;

X int show_command;
X
X
X pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc);
X if (nproc > onproc)
X pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *)
X * (onproc = nproc));
X if (pref == NULL || pbase == NULL) {
X (void) fprintf(stderr, "top: Out of memory.\n");
X quit(23);


X }
X /* get a pointer to the states summary array */
X si->procstates = process_states;
X
X /* set up flags which define what we are going to select */
X show_idle = sel->idle;
X show_system = sel->system;
X show_uid = sel->uid != -1;

X show_command = sel->command != NULL;

X
X /* count up process states and get pointers to interesting procs */
X total_procs = 0;
X active_procs = 0;

X memset((char *)process_states, 0, sizeof(process_states));
X prefp = pref;


X for (pp = pbase, i = 0; i < nproc; pp++, i++)
X {
X /*
X * Place pointers to each valid proc structure in pref[].
X * Process slots that are actually in use have a non-zero

X * status field. Processes with P_SYSTEM set are system


X * processes---these get ignored unless show_sysprocs is set.
X */

X if (PP(pp, p_stat) != 0 &&
X (show_system || ((PP(pp, p_flag) & P_SYSTEM) == 0)))
X {
X total_procs++;
X process_states[(unsigned char) PP(pp, p_stat)]++;
X if ((PP(pp, p_stat) != SZOMB) &&
X (show_idle || (PP(pp, p_pctcpu) != 0) ||
X (PP(pp, p_stat) == SRUN)) &&
X (!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t)sel->uid))


X {
X *prefp++ = pp;
X active_procs++;
X }
X }
X }
X
X /* if requested, sort the "interesting" processes */
X if (compare != NULL)

X {
X qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare);
X }


X
X /* remember active and total counts */
X si->p_total = total_procs;

X si->p_active = pref_len = active_procs;


X
X /* pass back a handle */
X handle.next_proc = pref;
X handle.remaining = active_procs;
X return((caddr_t)&handle);
X}
X

Xchar fmt[128]; /* static area where result is built */
X


Xchar *format_next_process(handle, get_userid)
X
Xcaddr_t handle;

Xchar *(*get_userid)();
X
X{
X register struct kinfo_proc *pp;
X register long cputime;
X register double pct;


X struct handle *hp;
X

X /* find and remember the next proc structure */
X hp = (struct handle *)handle;
X pp = *(hp->next_proc++);
X hp->remaining--;
X
X

X /* get the process's user struct and set cputime */

X if ((PP(pp, p_flag) & P_INMEM) == 0) {


X /*
X * Print swapped processes as <pname>
X */

X char *comm = PP(pp, p_comm);
X#define COMSIZ sizeof(PP(pp, p_comm))
X char buf[COMSIZ];
X (void) strncpy(buf, comm, COMSIZ);
X comm[0] = '<';
X (void) strncpy(&comm[1], buf, COMSIZ - 2);
X comm[COMSIZ - 2] = '\0';
X (void) strncat(comm, ">", COMSIZ - 1);
X comm[COMSIZ - 1] = '\0';
X }
X
X#if 0
X /* This does not produce the correct results */
X cputime = PP(pp, p_uticks) + PP(pp, p_sticks) + PP(pp, p_iticks);
X#endif
X cputime = PP(pp, p_rtime).tv_sec; /* This does not count interrupts */


X
X /* calculate the base for cpu percentages */

X pct = pctdouble(PP(pp, p_pctcpu));


X
X /* format this entry */
X sprintf(fmt,
X Proc_format,

X PP(pp, p_pid),
X (*get_userid)(EP(pp, e_pcred.p_ruid)),
X PP(pp, p_priority) - PZERO,
X PP(pp, p_nice) - NZERO,
X format_k(pagetok(PROCSIZE(pp))),
X format_k(pagetok(VP(pp, vm_rssize))),
X state_abbrev[(unsigned char) PP(pp, p_stat)],
X format_time(cputime),
X 10000.0 * weighted_cpu(pct, pp) / hz,
X 10000.0 * pct / hz,
X printable(PP(pp, p_comm)));


X
X /* return the result */
X return(fmt);
X}

X
X
X/*


X * check_nlist(nlst) - checks the nlist to see if any symbols were not
X * found. For every symbol that was not found, a one-line
X * message is printed to stderr. The routine returns the
X * number of symbols NOT found.
X */
X

Xstatic int check_nlist(nlst)
X
Xregister struct nlist *nlst;


X
X{
X register int i;
X
X /* check to see if we got ALL the symbols we requested */
X /* this will write one line to stderr for every symbol not found */
X
X i = 0;
X while (nlst->n_name != NULL)

X {
X if (nlst->n_type == 0)
X {

X /* this one wasn't found */

X (void) fprintf(stderr, "kernel: no symbol named `%s'\n",
X nlst->n_name);


X i = 1;
X }
X nlst++;
X }
X
X return(i);
X}

X
X
X/*


X * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
X * "offset" is the byte offset into the kernel for the desired value,
X * "ptr" points to a buffer into which the value is retrieved,
X * "size" is the size of the buffer (and the object to retrieve),
X * "refstr" is a reference string used when printing error meessages,
X * if "refstr" starts with a '!', then a failure on read will not
X * be fatal (this may seem like a silly way to do things, but I
X * really didn't want the overhead of another argument).

X *
X */
X

Xstatic int getkval(offset, ptr, size, refstr)
X


Xunsigned long offset;
Xint *ptr;
Xint size;

Xchar *refstr;
X
X{
X if (kvm_read(kd, offset, (char *) ptr, size) != size)


X {
X if (*refstr == '!')

X {
X return(0);
X }
X else
X {
X fprintf(stderr, "top: kvm_read for %s: %s\n",
X refstr, strerror(errno));
X quit(23);


X }
X }
X return(1);
X}
X

X/* comparison routine for qsort */
X
X/*


X * proc_compare - comparison function for "qsort"
X * Compares the resource consumption of two processes using five
X * distinct keys. The keys (in descending order of importance) are:
X * percent cpu, cpu ticks, state, resident set size, total virtual
X * memory usage. The process states are ordered as follows (from least
X * to most important): WAIT, zombie, sleep, stop, start, run. The
X * array declaration below maps a process state index into a number
X * that reflects this ordering.
X */
X

Xstatic unsigned char sorted_state[] =


X{
X 0, /* not used */
X 3, /* sleep */

X 1, /* ABANDONED (WAIT) */


X 6, /* run */

X 5, /* start */

X 2, /* zombie */

X 4 /* stop */
X};
X

Xint


Xproc_compare(pp1, pp2)
X
Xstruct proc **pp1;
Xstruct proc **pp2;

X
X{
X register struct kinfo_proc *p1;
X register struct kinfo_proc *p2;


X register int result;
X register pctcpu lresult;

X
X /* remove one level of indirection */

X p1 = *(struct kinfo_proc **) pp1;
X p2 = *(struct kinfo_proc **) pp2;


X
X /* compare percent cpu (pctcpu) */

X if ((lresult = PP(p2, p_pctcpu) - PP(p1, p_pctcpu)) == 0)


X {
X /* use cpticks to break the tie */

X if ((result = PP(p2, p_cpticks) - PP(p1, p_cpticks)) == 0)


X {
X /* use process state to break the tie */

X if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] -
X sorted_state[(unsigned char) PP(p1, p_stat)]) == 0)


X {
X /* use priority to break the tie */

X if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0)


X {
X /* use resident set size (rssize) to break the tie */

X if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0)


X {
X /* use total memory to break the tie */

X result = PROCSIZE(p2) - PROCSIZE(p1);


X }
X }
X }
X }
X }

X else
X {
X result = lresult < 0 ? -1 : 1;
X }
X
X return(result);
X}

X
X
X/*


X * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
X * the process does not exist.
X * It is EXTREMLY IMPORTANT that this function work correctly.
X * If top runs setuid root (as in SVR4), then this function
X * is the only thing that stands in the way of a serious
X * security problem. It validates requests for the "kill"
X * and "renice" commands.
X */
X
Xint proc_owner(pid)
X
Xint pid;

X
X{
X register int cnt;
X register struct kinfo_proc **prefp;
X register struct kinfo_proc *pp;
X
X prefp = pref;


X cnt = pref_len;
X while (--cnt >= 0)
X {

X pp = *prefp++;
X if (PP(pp, p_pid) == (pid_t)pid)
X {
X return((int)EP(pp, e_pcred.p_ruid));
X }
X }


X return(-1);
X}
X
X

X#ifdef USE_SWAP
X/*
X * swapmode is based on a program called swapinfo written
X * by Kevin Lahey <k...@rokkaku.atl.ga.us>.
X */
X
X#define SVAR(var) __STRING(var) /* to force expansion */
X#define KGET(idx, var) \
X KGET1(idx, &var, sizeof(var), SVAR(var))
X#define KGET1(idx, p, s, msg) \
X KGET2(nlst[idx].n_value, p, s, msg)
X#define KGET2(addr, p, s, msg) \
X if (kvm_read(kd, (u_long)(addr), p, s) != s) \
X warnx("cannot read %s: %s", msg, kvm_geterr(kd))
X#define KGETRET(addr, p, s, msg) \
X if (kvm_read(kd, (u_long)(addr), p, s) != s) { \
X warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \


X return (0); \
X }
X
X

Xint
Xswapmode()
X{
X char *header;
X int hlen, nswap, nswdev, dmmax;
X int i, div, avail, nfree, npfree, used;
X struct swdevt *sw;
X long blocksize, *perdev;
X struct rlist head;
X struct rlist *swaplist;
X
X KGET(VM_NSWAP, nswap);
X KGET(VM_NSWDEV, nswdev);
X KGET(VM_DMMAX, dmmax);
X KGET(VM_SWAPLIST, swaplist);
X if ((sw = (struct swdevt *)malloc(nswdev * sizeof(*sw))) == NULL ||
X (perdev = (long *)malloc(nswdev * sizeof(*perdev))) == NULL)
X err(1, "malloc");
X KGET1(VM_SWDEVT, sw, nswdev * sizeof(*sw), "swdevt");
X
X /* Count up swap space. */
X nfree = 0;
X memset(perdev, 0, nswdev * sizeof(*perdev));
X while (swaplist) {
X int top, bottom, next_block;
X
X KGET2(swaplist, &head, sizeof(struct rlist), "swaplist");
X
X top = head.rl_end;
X bottom = head.rl_start;
X
X nfree += top - bottom + 1;
X
X /*
X * Swap space is split up among the configured disks.
X *
X * For interleaved swap devices, the first dmmax blocks
X * of swap space some from the first disk, the next dmmax
X * blocks from the next, and so on up to nswap blocks.
X *
X * The list of free space joins adjacent free blocks,
X * ignoring device boundries. If we want to keep track
X * of this information per device, we'll just have to
X * extract it ourselves.
X */
X while (top / dmmax != bottom / dmmax) {
X next_block = ((bottom + dmmax) / dmmax);
X perdev[(bottom / dmmax) % nswdev] +=
X next_block * dmmax - bottom;
X bottom = next_block * dmmax;
X }
X perdev[(bottom / dmmax) % nswdev] +=
X top - bottom + 1;
X
X swaplist = head.rl_next;
X }
X
X header = getbsize(&hlen, &blocksize);
X div = blocksize / 512;
X avail = npfree = 0;
X for (i = 0; i < nswdev; i++) {
X int xsize, xfree;
X
X /*
X * Don't report statistics for partitions which have not
X * yet been activated via swapon(8).
X */
X
X xsize = sw[i].sw_nblks;
X xfree = perdev[i];
X used = xsize - xfree;
X npfree++;
X avail += xsize;
X }
X
X /*
X * If only one partition has been set up via swapon(8), we don't
X * need to bother with totals.
X */
X used = avail - nfree;
X free(sw); free(perdev);
X return (int)(((double)used / (double)avail * 100.0) + 0.5);
X}
X
X#endif
X
END_OF_FILE
if test 21760 -ne `wc -c <'top-3.4/machine/m_freebsd20.c'`; then
echo shar: \"'top-3.4/machine/m_freebsd20.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_freebsd20.c'
fi
if test -f 'top-3.4/top.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/top.c'\"
else
echo shar: Extracting \"'top-3.4/top.c'\" \(21443 characters\)
sed "s/^X//" >'top-3.4/top.c' <<'END_OF_FILE'
Xchar *copyright =
X "Copyright (c) 1984 through 1996, William LeFebvre";
X


X/*
X * Top users/processes display for Unix
X * Version 3
X *
X * This program may be freely redistributed,
X * but this entire comment MUST remain intact.
X *
X * Copyright (c) 1984, 1989, William LeFebvre, Rice University
X * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
X */
X
X/*

X * See the file "Changes" for information on version-to-version changes.
X */
X
X/*
X * This file contains "main" and other high-level routines.
X */
X
X/*
X * The following preprocessor variables, when defined, are used to
X * distinguish between different Unix implementations:
X *
X * SIGHOLD - use SVR4 sighold function when defined
X * SIGRELSE - use SVR4 sigrelse function when defined
X * FD_SET - macros FD_SET and FD_ZERO are used when defined
X */
X
X#include "os.h"
X#include <signal.h>
X#include <setjmp.h>
X#include <ctype.h>
X#include <sys/time.h>
X
X/* includes specific to top */
X#include "display.h" /* interface to display package */
X#include "screen.h" /* interface to screen package */
X#include "top.h"
X#include "top.local.h"
X#include "boolean.h"


X#include "machine.h"
X#include "utils.h"
X

X/* Size of the stdio buffer given to stdout */
X#define Buffersize 2048
X
X/* The buffer that stdio will use */
Xchar stdoutbuf[Buffersize];
X
X/* build Signal masks */
X#define Smask(s) (1 << ((s) - 1))
X
X/* for system errors */
Xextern int errno;
X
X/* for getopt: */
Xextern int optind;
Xextern char *optarg;
X
X/* imported from screen.c */
Xextern int overstrike;
X
X/* signal handling routines */
Xsigret_t leave();
Xsigret_t onalrm();
Xsigret_t tstop();
X#ifdef SIGWINCH
Xsigret_t winch();
X#endif
X
X/* internal routines */
Xvoid quit();
X
X/* values which need to be accessed by signal handlers */
Xstatic int max_topn; /* maximum displayable processes */
X
X/* miscellaneous things */
Xchar *myname = "top";
Xjmp_buf jmp_int;
X
X/* routines that don't return int */
X
Xchar *username();
Xchar *ctime();
Xchar *kill_procs();
Xchar *renice_procs();
X
X#ifdef ORDER
Xextern int (*proc_compares[])();
X#else
Xextern int proc_compare();
X#endif
Xtime_t time();
X
Xcaddr_t get_process_info();
X
X/* different routines for displaying the user's identification */
X/* (values assigned to get_userid) */
Xchar *username();
Xchar *itoa7();
X
X/* display routines that need to be predeclared */
Xint i_loadave();
Xint u_loadave();
Xint i_procstates();
Xint u_procstates();
Xint i_cpustates();
Xint u_cpustates();
Xint i_memory();
Xint u_memory();
Xint i_message();
Xint u_message();
Xint i_header();
Xint u_header();
Xint i_process();
Xint u_process();
X
X/* pointers to display routines */
Xint (*d_loadave)() = i_loadave;
Xint (*d_procstates)() = i_procstates;
Xint (*d_cpustates)() = i_cpustates;
Xint (*d_memory)() = i_memory;
Xint (*d_message)() = i_message;
Xint (*d_header)() = i_header;
Xint (*d_process)() = i_process;
X


X
Xmain(argc, argv)
X
Xint argc;
Xchar *argv[];
X
X{

X register int i;
X register int active_procs;
X register int change;
X
X struct system_info system_info;
X struct statics statics;
X caddr_t processes;
X
X static char tempbuf1[50];
X static char tempbuf2[50];
X int old_sigmask; /* only used for BSD-style signals */
X int topn = Default_TOPN;
X int delay = Default_DELAY;
X int displays = 0; /* indicates unspecified */
X time_t curr_time;
X char *(*get_userid)() = username;
X char *uname_field = "USERNAME";
X char *header_text;
X char *env_top;
X char **preset_argv;
X int preset_argc = 0;
X char **av;
X int ac;
X char dostates = No;
X char do_unames = Yes;
X char interactive = Maybe;
X char warnings = 0;
X#if Default_TOPN == Infinity
X char topn_specified = No;
X#endif
X char ch;
X char *iptr;
X char no_command = 1;
X struct timeval timeout;
X struct process_select ps;
X#ifdef ORDER
X char *order_name = NULL;
X int order_index = 0;
X#endif
X#ifndef FD_SET
X /* FD_SET and friends are not present: fake it */
X typedef int fd_set;
X#define FD_ZERO(x) (*(x) = 0)
X#define FD_SET(f, x) (*(x) = f)
X#endif
X fd_set readfds;
X
X#ifdef ORDER
X static char command_chars[] = "\f qh?en#sdkriIuo";
X#else
X static char command_chars[] = "\f qh?en#sdkriIu";
X#endif
X/* these defines enumerate the "strchr"s of the commands in command_chars */
X#define CMD_redraw 0
X#define CMD_update 1
X#define CMD_quit 2
X#define CMD_help1 3
X#define CMD_help2 4
X#define CMD_OSLIMIT 4 /* terminals with OS can only handle commands */
X#define CMD_errors 5 /* less than or equal to CMD_OSLIMIT */
X#define CMD_number1 6
X#define CMD_number2 7
X#define CMD_delay 8
X#define CMD_displays 9
X#define CMD_kill 10
X#define CMD_renice 11
X#define CMD_idletog 12
X#define CMD_idletog2 13
X#define CMD_user 14
X#ifdef ORDER
X#define CMD_order 15
X#endif
X
X /* set the buffer for stdout */
X#ifdef DEBUG
X setbuffer(stdout, NULL, 0);
X#else
X setbuffer(stdout, stdoutbuf, Buffersize);
X#endif
X
X /* get our name */
X if (argc > 0)
X {
X if ((myname = strrchr(argv[0], '/')) == 0)
X {
X myname = argv[0];
X }
X else
X {
X myname++;
X }
X }
X
X /* initialize some selection options */
X ps.idle = Yes;
X ps.system = No;
X ps.uid = -1;
X ps.command = NULL;
X
X /* get preset options from the environment */
X if ((env_top = getenv("TOP")) != NULL)
X {
X av = preset_argv = argparse(env_top, &preset_argc);
X ac = preset_argc;
X
X /* set the dummy argument to an explanatory message, in case
X getopt encounters a bad argument */
X preset_argv[0] = "while processing environment";
X }
X
X /* process options */
X do {
X /* if we're done doing the presets, then process the real arguments */
X if (preset_argc == 0)
X {
X ac = argc;
X av = argv;
X
X /* this should keep getopt happy... */
X optind = 1;
X }
X
X while ((i = getopt(ac, av, "SIbinqus:d:U:o:")) != EOF)
X {
X switch(i)
X {
X case 'u': /* toggle uid/username display */
X do_unames = !do_unames;
X break;
X
X case 'U': /* display only username's processes */
X if ((ps.uid = userid(optarg)) == -1)
X {
X fprintf(stderr, "%s: unknown user\n", optarg);
X exit(1);
X }
X break;
X
X case 'S': /* show system processes */
X ps.system = !ps.system;
X break;
X
X case 'I': /* show idle processes */
X ps.idle = !ps.idle;
X break;
X
X case 'i': /* go interactive regardless */
X interactive = Yes;
X break;
X
X case 'n': /* batch, or non-interactive */
X case 'b':
X interactive = No;
X break;
X
X case 'd': /* number of displays to show */
X if ((i = atoiwi(optarg)) == Invalid || i == 0)
X {
X fprintf(stderr,
X "%s: warning: display count should be positive -- option ignored\n",
X myname);
X warnings++;
X }
X else
X {
X displays = i;
X }
X break;
X
X case 's':
X if ((delay = atoi(optarg)) < 0)
X {
X fprintf(stderr,
X "%s: warning: seconds delay should be non-negative -- using default\n",
X myname);
X delay = Default_DELAY;
X warnings++;
X }
X break;
X
X case 'q': /* be quick about it */
X /* only allow this if user is really root */
X if (getuid() == 0)
X {
X /* be very un-nice! */
X (void) nice(-20);
X }
X else
X {
X fprintf(stderr,
X "%s: warning: `-q' option can only be used by root\n",
X myname);
X warnings++;
X }
X break;
X
X case 'o': /* select sort order */
X#ifdef ORDER
X order_name = optarg;
X#else
X fprintf(stderr,
X "%s: this platform does not support arbitrary ordering. Sorry.\n",
X myname);
X warnings++;
X#endif
X break;
X
X default:
X fprintf(stderr, "\
XTop version %s\n\
XUsage: %s [-ISbinqu] [-d x] [-s x] [-o field] [-U username] [number]\n",
X version_string(), myname);


X exit(1);
X }
X }
X

X /* get count of top processes to display (if any) */
X if (optind < ac)
X {
X if ((topn = atoiwi(av[optind])) == Invalid)
X {
X fprintf(stderr,
X "%s: warning: process display count should be non-negative -- using default\n",
X myname);
X warnings++;
X }
X#if Default_TOPN == Infinity
X else
X {
X topn_specified = Yes;
X }
X#endif
X }
X
X /* tricky: remember old value of preset_argc & set preset_argc = 0 */
X i = preset_argc;
X preset_argc = 0;
X
X /* repeat only if we really did the preset arguments */
X } while (i != 0);
X
X /* set constants for username/uid display correctly */
X if (!do_unames)
X {
X uname_field = " UID ";
X get_userid = itoa7;
X }
X
X /* initialize the kernel memory interface */
X if (machine_init(&statics) == -1)


X {
X exit(1);
X }
X

X#ifdef ORDER
X /* determine sorting order index, if necessary */
X if (order_name != NULL)
X {
X if ((order_index = string_index(order_name, statics.order_names)) == -1)
X {
X char **pp;
X
X fprintf(stderr, "%s: '%s' is not a recognized sorting order.\n",
X myname, order_name);
X fprintf(stderr, "\tTry one of these:");
X pp = statics.order_names;
X while (*pp != NULL)
X {
X fprintf(stderr, " %s", *pp++);
X }
X fputc('\n', stderr);
X exit(1);
X }
X }
X#endif
X
X#ifdef no_initialization_needed
X /* initialize the hashing stuff */
X if (do_unames)
X {
X init_hash();
X }
X#endif
X
X /* initialize termcap */
X init_termcap(interactive);
X
X /* get the string to use for the process area header */
X header_text = format_header(uname_field);
X
X /* initialize display interface */
X if ((max_topn = display_init(&statics)) == -1)
X {
X fprintf(stderr, "%s: can't allocate sufficient memory\n", myname);
X exit(4);
X }
X
X /* print warning if user requested more processes than we can display */
X if (topn > max_topn)
X {
X fprintf(stderr,
X "%s: warning: this terminal can only display %d processes.\n",
X myname, max_topn);
X warnings++;
X }
X
X /* adjust for topn == Infinity */
X if (topn == Infinity)
X {
X /*
X * For smart terminals, infinity really means everything that can
X * be displayed, or Largest.
X * On dumb terminals, infinity means every process in the system!
X * We only really want to do that if it was explicitly specified.
X * This is always the case when "Default_TOPN != Infinity". But if
X * topn wasn't explicitly specified and we are on a dumb terminal
X * and the default is Infinity, then (and only then) we use
X * "Nominal_TOPN" instead.
X */
X#if Default_TOPN == Infinity
X topn = smart_terminal ? Largest :
X (topn_specified ? Largest : Nominal_TOPN);
X#else
X topn = Largest;
X#endif
X }
X
X /* set header display accordingly */
X display_header(topn > 0);
X
X /* determine interactive state */
X if (interactive == Maybe)
X {
X interactive = smart_terminal;
X }
X
X /* if # of displays not specified, fill it in */
X if (displays == 0)
X {
X displays = smart_terminal ? Infinity : 1;
X }
X
X /* hold interrupt signals while setting up the screen and the handlers */
X#ifdef SIGHOLD
X sighold(SIGINT);
X sighold(SIGQUIT);
X sighold(SIGTSTP);
X#else
X old_sigmask = sigblock(Smask(SIGINT) | Smask(SIGQUIT) | Smask(SIGTSTP));
X#endif
X init_screen();
X (void) signal(SIGINT, leave);
X (void) signal(SIGQUIT, leave);
X (void) signal(SIGTSTP, tstop);
X#ifdef SIGWINCH
X (void) signal(SIGWINCH, winch);
X#endif
X#ifdef SIGRELSE
X sigrelse(SIGINT);
X sigrelse(SIGQUIT);
X sigrelse(SIGTSTP);
X#else
X (void) sigsetmask(old_sigmask);
X#endif
X if (warnings)
X {
X fputs("....", stderr);
X fflush(stderr); /* why must I do this? */
X sleep((unsigned)(3 * warnings));
X fputc('\n', stderr);
X }
X
X /* setup the jump buffer for stops */
X if (setjmp(jmp_int) != 0)
X {
X /* control ends up here after an interrupt */
X reset_display();
X }
X
X /*
X * main loop -- repeat while display count is positive or while it
X * indicates infinity (by being -1)
X */
X
X while ((displays == -1) || (displays-- > 0))
X {
X /* get the current stats */
X get_system_info(&system_info);
X
X /* get the current set of processes */
X processes =
X get_process_info(&system_info,
X &ps,
X#ifdef ORDER
X proc_compares[order_index]);
X#else
X proc_compare);
X#endif
X
X /* display the load averages */
X (*d_loadave)(system_info.last_pid,
X system_info.load_avg);
X
X /* display the current time */
X /* this method of getting the time SHOULD be fairly portable */
X time(&curr_time);
X i_timeofday(&curr_time);
X
X /* display process state breakdown */
X (*d_procstates)(system_info.p_total,
X system_info.procstates);
X
X /* display the cpu state percentage breakdown */
X if (dostates) /* but not the first time */
X {
X (*d_cpustates)(system_info.cpustates);
X }
X else
X {
X /* we'll do it next time */
X if (smart_terminal)
X {
X z_cpustates();
X }
X else
X {
X putchar('\n');
X }
X dostates = Yes;
X }
X
X /* display memory stats */
X (*d_memory)(system_info.memory);
X
X /* handle message area */
X (*d_message)();
X
X /* update the header area */
X (*d_header)(header_text);
X
X if (topn > 0)
X {
X /* determine number of processes to actually display */
X /* this number will be the smallest of: active processes,
X number user requested, number current screen accomodates */
X active_procs = system_info.p_active;
X if (active_procs > topn)
X {
X active_procs = topn;
X }
X if (active_procs > max_topn)
X {
X active_procs = max_topn;
X }
X
X /* now show the top "n" processes. */
X for (i = 0; i < active_procs; i++)
X {
X (*d_process)(i, format_next_process(processes, get_userid));
X }
X }
X else
X {
X i = 0;
X }
X
X /* do end-screen processing */
X u_endscreen(i);
X
X /* now, flush the output buffer */
X fflush(stdout);
X
X /* only do the rest if we have more displays to show */
X if (displays)
X {
X /* switch out for new display on smart terminals */
X if (smart_terminal)
X {
X if (overstrike)
X {
X reset_display();
X }
X else
X {
X d_loadave = u_loadave;
X d_procstates = u_procstates;
X d_cpustates = u_cpustates;
X d_memory = u_memory;
X d_message = u_message;
X d_header = u_header;
X d_process = u_process;
X }
X }
X
X no_command = Yes;
X if (!interactive)
X {
X /* set up alarm */
X (void) signal(SIGALRM, onalrm);
X (void) alarm((unsigned)delay);
X
X /* wait for the rest of it .... */
X pause();
X }
X else while (no_command)
X {
X /* assume valid command unless told otherwise */
X no_command = No;
X
X /* set up arguments for select with timeout */
X FD_ZERO(&readfds);
X FD_SET(1, &readfds); /* for standard input */
X timeout.tv_sec = delay;
X timeout.tv_usec = 0;
X
X /* wait for either input or the end of the delay period */
X if (select(32, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timeout) > 0)
X {
X int newval;
X char *errmsg;
X
X /* something to read -- clear the message area first */
X clear_message();
X
X /* now read it and convert to command strchr */
X /* (use "change" as a temporary to hold strchr) */
X (void) read(0, &ch, 1);
X if ((iptr = strchr(command_chars, ch)) == NULL)
X {
X /* illegal command */
X new_message(MT_standout, " Command not understood");
X putchar('\r');
X no_command = Yes;
X }
X else
X {
X change = iptr - command_chars;
X if (overstrike && change > CMD_OSLIMIT)
X {
X /* error */
X new_message(MT_standout,
X " Command cannot be handled by this terminal");
X putchar('\r');
X no_command = Yes;
X }
X else switch(change)
X {
X case CMD_redraw: /* redraw screen */
X reset_display();
X break;
X
X case CMD_update: /* merely update display */
X /* is the load average high? */
X if (system_info.load_avg[0] > LoadMax)
X {
X /* yes, go home for visual feedback */
X go_home();
X fflush(stdout);
X }
X break;
X
X case CMD_quit: /* quit */
X quit(0);
X /*NOTREACHED*/
X break;
X
X case CMD_help1: /* help */
X case CMD_help2:
X reset_display();
X clear();
X show_help();
X standout("Hit any key to continue: ");
X fflush(stdout);
X (void) read(0, &ch, 1);
X break;
X
X case CMD_errors: /* show errors */
X if (error_count() == 0)
X {
X new_message(MT_standout,
X " Currently no errors to report.");
X putchar('\r');
X no_command = Yes;
X }
X else
X {
X reset_display();
X clear();
X show_errors();
X standout("Hit any key to continue: ");
X fflush(stdout);
X (void) read(0, &ch, 1);
X }
X break;
X
X case CMD_number1: /* new number */
X case CMD_number2:
X new_message(MT_standout,
X "Number of processes to show: ");
X newval = readline(tempbuf1, 8, Yes);
X if (newval > -1)
X {
X if (newval > max_topn)
X {
X new_message(MT_standout | MT_delayed,
X " This terminal can only display %d processes.",
X max_topn);
X putchar('\r');
X }
X
X if (newval == 0)
X {
X /* inhibit the header */
X display_header(No);
X }
X else if (newval > topn && topn == 0)
X {
X /* redraw the header */
X display_header(Yes);
X d_header = i_header;
X }
X topn = newval;
X }
X break;
X
X case CMD_delay: /* new seconds delay */
X new_message(MT_standout, "Seconds to delay: ");
X if ((i = readline(tempbuf1, 8, Yes)) > -1)
X {
X delay = i;
X }
X clear_message();
X break;
X
X case CMD_displays: /* change display count */
X new_message(MT_standout,
X "Displays to show (currently %s): ",
X displays == -1 ? "infinite" :
X itoa(displays));
X if ((i = readline(tempbuf1, 10, Yes)) > 0)
X {
X displays = i;
X }
X else if (i == 0)
X {
X quit(0);
X }
X clear_message();
X break;
X
X case CMD_kill: /* kill program */
X new_message(0, "kill ");
X if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
X {
X if ((errmsg = kill_procs(tempbuf2)) != NULL)
X {
X new_message(MT_standout, errmsg);
X putchar('\r');
X no_command = Yes;
X }
X }
X else
X {
X clear_message();
X }
X break;
X
X case CMD_renice: /* renice program */
X new_message(0, "renice ");
X if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
X {
X if ((errmsg = renice_procs(tempbuf2)) != NULL)
X {
X new_message(MT_standout, errmsg);
X putchar('\r');
X no_command = Yes;
X }
X }
X else
X {
X clear_message();
X }
X break;
X
X case CMD_idletog:
X case CMD_idletog2:
X ps.idle = !ps.idle;
X new_message(MT_standout | MT_delayed,
X " %sisplaying idle processes.",
X ps.idle ? "D" : "Not d");
X putchar('\r');
X break;
X
X case CMD_user:
X new_message(MT_standout,
X "Username to show: ");
X if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
X {
X if (tempbuf2[0] == '+' &&
X tempbuf2[1] == '\0')
X {
X ps.uid = -1;
X }
X else if ((i = userid(tempbuf2)) == -1)
X {
X new_message(MT_standout,
X " %s: unknown user", tempbuf2);
X no_command = Yes;
X }
X else
X {
X ps.uid = i;
X }
X putchar('\r');
X }
X else
X {
X clear_message();
X }
X break;
X
X#ifdef ORDER
X case CMD_order:
X new_message(MT_standout,
X "Order to sort: ");
X if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
X {
X if ((i = string_index(tempbuf2, statics.order_names)) == -1)
X {
X new_message(MT_standout,
X " %s: unrecognized sorting order", tempbuf2);
X no_command = Yes;
X }
X else
X {
X order_index = i;
X }
X putchar('\r');
X }
X else
X {
X clear_message();
X }
X break;
X#endif
X
X default:
X new_message(MT_standout, " BAD CASE IN SWITCH!");
X putchar('\r');
X }
X }
X
X /* flush out stuff that may have been written */
X fflush(stdout);


X }
X }
X }
X }
X

X quit(0);
X /*NOTREACHED*/
X}
X
X/*
X * reset_display() - reset all the display routine pointers so that entire
X * screen will get redrawn.
X */
X
Xreset_display()
X
X{
X d_loadave = i_loadave;
X d_procstates = i_procstates;
X d_cpustates = i_cpustates;
X d_memory = i_memory;
X d_message = i_message;
X d_header = i_header;
X d_process = i_process;
X}
X
X/*
X * signal handlers
X */
X
Xsigret_t leave() /* exit under normal conditions -- INT handler */
X
X{
X end_screen();
X exit(0);
X}
X
Xsigret_t tstop(i) /* SIGTSTP handler */
X
Xint i;
X
X{
X /* move to the lower left */
X end_screen();
X fflush(stdout);
X
X /* default the signal handler action */
X (void) signal(SIGTSTP, SIG_DFL);
X
X /* unblock the signal and send ourselves one */
X#ifdef SIGRELSE
X sigrelse(SIGTSTP);
X#else
X (void) sigsetmask(sigblock(0) & ~(1 << (SIGTSTP - 1)));
X#endif
X (void) kill(0, SIGTSTP);
X
X /* reset the signal handler */
X (void) signal(SIGTSTP, tstop);
X
X /* reinit screen */
X reinit_screen();
X
X /* jump to appropriate place */
X longjmp(jmp_int, 1);
X
X /*NOTREACHED*/
X}
X
X#ifdef SIGWINCH
Xsigret_t winch(i) /* SIGWINCH handler */
X
Xint i;
X
X{
X /* reascertain the screen dimensions */
X get_screensize();
X
X /* tell display to resize */
X max_topn = display_resize();
X
X /* reset the signal handler */
X (void) signal(SIGWINCH, winch);
X
X /* jump to appropriate place */
X longjmp(jmp_int, 1);
X}
X#endif
X
Xvoid quit(status) /* exit under duress */
X
Xint status;
X
X{
X end_screen();
X exit(status);
X /*NOTREACHED*/
X}
X
Xsigret_t onalrm() /* SIGALRM handler */
X
X{
X /* this is only used in batch mode to break out of the pause() */
X /* return; */
X}
X
END_OF_FILE
if test 21443 -ne `wc -c <'top-3.4/top.c'`; then
echo shar: \"'top-3.4/top.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/top.c'
fi
echo shar: End of archive 17 \(of 22\).
cp /dev/null ark17isdone

William Lefebvre

unread,
Sep 1, 1996, 3:00:00 AM9/1/96
to

Submitted-By: w...@groupsys.com (William Lefebvre)
Posting-Number: Volume 29, Issue 119
Archive-Name: top-3.4/part18

#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:

# "End of archive 18 (of 22)."
# Contents: top-3.4/display.c top-3.4/machine/m_sunos4.c
# Wrapped by lefebvre@acapulco on Fri Aug 30 12:35:51 1996


PATH=/bin:/usr/bin:/usr/ucb ; export PATH

if test -f 'top-3.4/display.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/display.c'\"
else
echo shar: Extracting \"'top-3.4/display.c'\" \(22989 characters\)
sed "s/^X//" >'top-3.4/display.c' <<'END_OF_FILE'


X/*
X * Top users/processes display for Unix
X * Version 3
X *
X * This program may be freely redistributed,
X * but this entire comment MUST remain intact.
X *
X * Copyright (c) 1984, 1989, William LeFebvre, Rice University
X * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
X */
X
X/*

X * This file contains the routines that display information on the screen.
X * Each section of the screen has two routines: one for initially writing
X * all constant and dynamic text, and one for only updating the text that
X * changes. The prefix "i_" is used on all the "initial" routines and the
X * prefix "u_" is used for all the "updating" routines.
X *
X * ASSUMPTIONS:
X * None of the "i_" routines use any of the termcap capabilities.
X * In this way, those routines can be safely used on terminals that
X * have minimal (or nonexistant) terminal capabilities.
X *
X * The routines are called in this order: *_loadave, i_timeofday,
X * *_procstates, *_cpustates, *_memory, *_message, *_header,
X * *_process, u_endscreen.


X */
X
X#include "os.h"

X#include <ctype.h>
X#include <time.h>
X


X#include "screen.h" /* interface to screen package */

X#include "layout.h" /* defines for screen position layout */
X#include "display.h"


X#include "top.h"
X#include "top.local.h"
X#include "boolean.h"

X#include "machine.h" /* we should eliminate this!!! */
X#include "utils.h"
X
X#ifdef DEBUG
XFILE *debug;
X#endif


X
X/* imported from screen.c */
Xextern int overstrike;
X

Xstatic int lmpid = 0;
Xstatic int last_hi = 0; /* used in u_process and u_endscreen */
Xstatic int lastline = 0;
Xstatic int display_width = MAX_COLS;
X
X#define lineindex(l) ((l)*display_width)
X
Xchar *printable();
X
X/* things initialized by display_init and used thruout */
X
X/* buffer of proc information lines for display updating */
Xchar *screenbuf = NULL;
X
Xstatic char **procstate_names;
Xstatic char **cpustate_names;
Xstatic char **memory_names;
X
Xstatic int num_procstates;
Xstatic int num_cpustates;
Xstatic int num_memory;
X
Xstatic int *lprocstates;
Xstatic int *lcpustates;
Xstatic int *lmemory;
X
Xstatic int *cpustate_columns;
Xstatic int cpustate_total_length;
X
Xstatic enum { OFF, ON, ERASE } header_status = ON;
X
Xstatic int string_count();
Xstatic void summary_format();
Xstatic void line_update();
X
Xint display_resize()
X
X{
X register int lines;
X
X /* first, deallocate any previous buffer that may have been there */
X if (screenbuf != NULL)
X {
X free(screenbuf);
X }
X
X /* calculate the current dimensions */
X /* if operating in "dumb" mode, we only need one line */
X lines = smart_terminal ? screen_length - Header_lines : 1;
X
X /* we don't want more than MAX_COLS columns, since the machine-dependent
X modules make static allocations based on MAX_COLS and we don't want
X to run off the end of their buffers */
X display_width = screen_width;
X if (display_width >= MAX_COLS)
X {
X display_width = MAX_COLS - 1;
X }
X
X /* now, allocate space for the screen buffer */
X screenbuf = (char *)malloc(lines * display_width);
X if (screenbuf == (char *)NULL)
X {
X /* oops! */
X return(-1);
X }
X
X /* return number of lines available */
X /* for dumb terminals, pretend like we can show any amount */
X return(smart_terminal ? lines : Largest);
X}
X
Xint display_init(statics)


X
Xstruct statics *statics;
X
X{

X register int lines;
X register char **pp;
X register int *ip;


X register int i;
X

X /* call resize to do the dirty work */
X lines = display_resize();
X
X /* only do the rest if we need to */
X if (lines > -1)
X {
X /* save pointers and allocate space for names */
X procstate_names = statics->procstate_names;
X num_procstates = string_count(procstate_names);
X lprocstates = (int *)malloc(num_procstates * sizeof(int));
X
X cpustate_names = statics->cpustate_names;
X num_cpustates = string_count(cpustate_names);
X lcpustates = (int *)malloc(num_cpustates * sizeof(int));
X cpustate_columns = (int *)malloc(num_cpustates * sizeof(int));
X
X memory_names = statics->memory_names;
X num_memory = string_count(memory_names);
X lmemory = (int *)malloc(num_memory * sizeof(int));
X
X /* calculate starting columns where needed */
X cpustate_total_length = 0;
X pp = cpustate_names;
X ip = cpustate_columns;


X while (*pp != NULL)
X {

X if ((i = strlen(*pp++)) > 0)
X {
X *ip++ = cpustate_total_length;
X cpustate_total_length += i + 8;
X }
X }
X }
X
X /* return number of lines available */
X return(lines);
X}
X
Xi_loadave(mpid, avenrun)
X
Xint mpid;
Xdouble *avenrun;


X
X{
X register int i;
X

X /* i_loadave also clears the screen, since it is first */
X clear();
X
X /* mpid == -1 implies this system doesn't have an _mpid */
X if (mpid != -1)
X {
X printf("last pid: %5d; ", mpid);
X }
X
X printf("load averages");
X


X for (i = 0; i < 3; i++)
X {

X printf("%c %5.2f",
X i == 0 ? ':' : ',',
X avenrun[i]);
X }
X lmpid = mpid;
X}
X
Xu_loadave(mpid, avenrun)
X
Xint mpid;
Xdouble *avenrun;


X
X{
X register int i;
X

X if (mpid != -1)
X {
X /* change screen only when value has really changed */
X if (mpid != lmpid)
X {
X Move_to(x_lastpid, y_lastpid);
X printf("%5d", mpid);
X lmpid = mpid;
X }
X
X /* i remembers x coordinate to move to */
X i = x_loadave;
X }
X else
X {
X i = x_loadave_nompid;
X }
X
X /* move into position for load averages */
X Move_to(i, y_loadave);
X
X /* display new load averages */
X /* we should optimize this and only display changes */
X for (i = 0; i < 3; i++)
X {
X printf("%s%5.2f",
X i == 0 ? "" : ", ",
X avenrun[i]);
X }
X}
X
Xi_timeofday(tod)
X
Xtime_t *tod;
X
X{
X /*
X * Display the current time.
X * "ctime" always returns a string that looks like this:
X *
X * Sun Sep 16 01:03:52 1973
X * 012345678901234567890123
X * 1 2
X *
X * We want indices 11 thru 18 (length 8).
X */
X
X if (smart_terminal)
X {
X Move_to(screen_width - 8, 0);
X }
X else
X {
X fputs(" ", stdout);
X }
X#ifdef DEBUG
X {
X char *foo;
X foo = ctime(tod);
X fputs(foo, stdout);
X }
X#endif
X printf("%-8.8s\n", &(ctime(tod)[11]));
X lastline = 1;
X}
X
Xstatic int ltotal = 0;
Xstatic char procstates_buffer[128];
X
X/*
X * *_procstates(total, brkdn, names) - print the process summary line
X *
X * Assumptions: cursor is at the beginning of the line on entry
X * lastline is valid
X */
X
Xi_procstates(total, brkdn)
X
Xint total;
Xint *brkdn;


X
X{
X register int i;
X

X /* write current number of processes and remember the value */
X printf("%d processes:", total);
X ltotal = total;
X
X /* put out enough spaces to get to column 15 */
X i = digits(total);
X while (i++ < 4)
X {
X putchar(' ');
X }
X
X /* format and print the process state summary */
X summary_format(procstates_buffer, brkdn, procstate_names);
X fputs(procstates_buffer, stdout);
X
X /* save the numbers for next time */
X memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
X}
X
Xu_procstates(total, brkdn)
X
Xint total;
Xint *brkdn;
X
X{
X static char new[128];


X register int i;
X

X /* update number of processes only if it has changed */
X if (ltotal != total)
X {
X /* move and overwrite */
X#if (x_procstate == 0)
X Move_to(x_procstate, y_procstate);
X#else
X /* cursor is already there...no motion needed */
X /* assert(lastline == 1); */
X#endif
X printf("%d", total);
X
X /* if number of digits differs, rewrite the label */
X if (digits(total) != digits(ltotal))
X {
X fputs(" processes:", stdout);
X /* put out enough spaces to get to column 15 */
X i = digits(total);
X while (i++ < 4)
X {
X putchar(' ');
X }
X /* cursor may end up right where we want it!!! */
X }
X
X /* save new total */
X ltotal = total;
X }
X
X /* see if any of the state numbers has changed */
X if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0)
X {
X /* format and update the line */
X summary_format(new, brkdn, procstate_names);
X line_update(procstates_buffer, new, x_brkdn, y_brkdn);
X memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
X }
X}
X
X/*
X * *_cpustates(states, names) - print the cpu state percentages
X *
X * Assumptions: cursor is on the PREVIOUS line
X */
X
Xstatic int cpustates_column;
X
X/* cpustates_tag() calculates the correct tag to use to label the line */
X
Xchar *cpustates_tag()
X
X{
X register char *use;
X
X static char *short_tag = "CPU: ";
X static char *long_tag = "CPU states: ";
X
X /* if length + strlen(long_tag) >= screen_width, then we have to
X use the shorter tag (we subtract 2 to account for ": ") */
X if (cpustate_total_length + (int)strlen(long_tag) - 2 >= screen_width)
X {
X use = short_tag;
X }
X else
X {
X use = long_tag;
X }
X
X /* set cpustates_column accordingly then return result */
X cpustates_column = strlen(use);
X return(use);
X}
X
Xi_cpustates(states)
X
Xregister int *states;


X
X{
X register int i = 0;

X register int value;
X register char **names = cpustate_names;
X register char *thisname;
X
X /* print tag and bump lastline */
X printf("\n%s", cpustates_tag());
X lastline++;
X
X /* now walk thru the names and print the line */
X while ((thisname = *names++) != NULL)
X {
X if (*thisname != '\0')
X {
X /* retrieve the value and remember it */
X value = *states++;
X
X /* if percentage is >= 1000, print it as 100% */
X printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"),
X i++ == 0 ? "" : ", ",
X ((float)value)/10.,
X thisname);
X }
X }
X
X /* copy over values into "last" array */
X memcpy(lcpustates, states, num_cpustates * sizeof(int));
X}
X
Xu_cpustates(states)
X
Xregister int *states;
X
X{
X register int value;
X register char **names = cpustate_names;
X register char *thisname;
X register int *lp;
X register int *colp;
X
X Move_to(cpustates_column, y_cpustates);
X lastline = y_cpustates;
X lp = lcpustates;
X colp = cpustate_columns;
X
X /* we could be much more optimal about this */
X while ((thisname = *names++) != NULL)
X {
X if (*thisname != '\0')
X {
X /* did the value change since last time? */
X if (*lp != *states)
X {
X /* yes, move and change */
X Move_to(cpustates_column + *colp, y_cpustates);
X lastline = y_cpustates;
X
X /* retrieve value and remember it */
X value = *states;
X
X /* if percentage is >= 1000, print it as 100% */
X printf((value >= 1000 ? "%4.0f" : "%4.1f"),
X ((double)value)/10.);
X
X /* remember it for next time */
X *lp = *states;
X }
X }
X
X /* increment and move on */
X lp++;
X states++;
X colp++;
X }
X}
X
Xz_cpustates()


X
X{
X register int i = 0;

X register char **names = cpustate_names;
X register char *thisname;
X register int *lp;
X
X /* show tag and bump lastline */
X printf("\n%s", cpustates_tag());
X lastline++;
X
X while ((thisname = *names++) != NULL)
X {
X if (*thisname != '\0')
X {
X printf("%s %% %s", i++ == 0 ? "" : ", ", thisname);
X }
X }
X
X /* fill the "last" array with all -1s, to insure correct updating */
X lp = lcpustates;
X i = num_cpustates;
X while (--i >= 0)
X {
X *lp++ = -1;
X }
X}
X
X/*
X * *_memory(stats) - print "Memory: " followed by the memory summary string
X *
X * Assumptions: cursor is on "lastline"
X * for i_memory ONLY: cursor is on the previous line
X */
X
Xchar memory_buffer[MAX_COLS];
X
Xi_memory(stats)
X
Xint *stats;
X
X{
X fputs("\nMemory: ", stdout);
X lastline++;
X
X /* format and print the memory summary */
X summary_format(memory_buffer, stats, memory_names);
X fputs(memory_buffer, stdout);
X}
X
Xu_memory(stats)
X
Xint *stats;
X
X{
X static char new[MAX_COLS];
X
X /* format the new line */
X summary_format(new, stats, memory_names);
X line_update(memory_buffer, new, x_mem, y_mem);
X}
X
X/*
X * *_message() - print the next pending message line, or erase the one
X * that is there.
X *
X * Note that u_message is (currently) the same as i_message.
X *
X * Assumptions: lastline is consistent
X */
X
X/*
X * i_message is funny because it gets its message asynchronously (with
X * respect to screen updates).
X */
X
Xstatic char next_msg[MAX_COLS + 5];
Xstatic int msglen = 0;
X/* Invariant: msglen is always the length of the message currently displayed
X on the screen (even when next_msg doesn't contain that message). */
X
Xi_message()
X
X{
X while (lastline < y_message)
X {
X fputc('\n', stdout);
X lastline++;
X }
X if (next_msg[0] != '\0')
X {
X standout(next_msg);
X msglen = strlen(next_msg);
X next_msg[0] = '\0';
X }
X else if (msglen > 0)
X {
X (void) clear_eol(msglen);
X msglen = 0;
X }
X}
X
Xu_message()
X
X{
X i_message();
X}
X
Xstatic int header_length;
X
X/*
X * *_header(text) - print the header for the process area
X *
X * Assumptions: cursor is on the previous line and lastline is consistent
X */
X
Xi_header(text)
X
Xchar *text;
X
X{
X header_length = strlen(text);
X if (header_status == ON)


X {
X putchar('\n');

X fputs(text, stdout);
X lastline++;
X }
X else if (header_status == ERASE)
X {
X header_status = OFF;
X }
X}
X
X/*ARGSUSED*/
Xu_header(text)
X
Xchar *text; /* ignored */
X
X{
X if (header_status == ERASE)


X {
X putchar('\n');

X lastline++;
X clear_eol(header_length);
X header_status = OFF;
X }
X}
X
X/*
X * *_process(line, thisline) - print one process line
X *
X * Assumptions: lastline is consistent
X */
X
Xi_process(line, thisline)
X
Xint line;
Xchar *thisline;
X
X{
X register char *p;
X register char *base;
X
X /* make sure we are on the correct line */
X while (lastline < y_procs + line)


X {
X putchar('\n');

X lastline++;
X }
X
X /* truncate the line to conform to our current screen width */
X thisline[display_width] = '\0';
X
X /* write the line out */
X fputs(thisline, stdout);
X
X /* copy it in to our buffer */
X base = smart_terminal ? screenbuf + lineindex(line) : screenbuf;
X p = strecpy(base, thisline);
X
X /* zero fill the rest of it */
X memzero(p, display_width - (p - base));
X}
X
Xu_process(line, newline)
X
Xint line;
Xchar *newline;
X
X{
X register char *optr;
X register int screen_line = line + Header_lines;
X register char *bufferline;
X
X /* remember a pointer to the current line in the screen buffer */
X bufferline = &screenbuf[lineindex(line)];
X
X /* truncate the line to conform to our current screen width */
X newline[display_width] = '\0';
X
X /* is line higher than we went on the last display? */
X if (line >= last_hi)
X {
X /* yes, just ignore screenbuf and write it out directly */
X /* get positioned on the correct line */
X if (screen_line - lastline == 1)


X {
X putchar('\n');

X lastline++;
X }
X else
X {
X Move_to(0, screen_line);
X lastline = screen_line;
X }
X
X /* now write the line */
X fputs(newline, stdout);
X
X /* copy it in to the buffer */
X optr = strecpy(bufferline, newline);
X
X /* zero fill the rest of it */
X memzero(optr, display_width - (optr - bufferline));
X }
X else
X {
X line_update(bufferline, newline, 0, line + Header_lines);
X }
X}
X
Xu_endscreen(hi)
X
Xregister int hi;
X
X{
X register int screen_line = hi + Header_lines;


X register int i;
X

X if (smart_terminal)
X {
X if (hi < last_hi)
X {
X /* need to blank the remainder of the screen */
X /* but only if there is any screen left below this line */
X if (lastline + 1 < screen_length)
X {
X /* efficiently move to the end of currently displayed info */
X if (screen_line - lastline < 5)
X {
X while (lastline < screen_line)


X {
X putchar('\n');

X lastline++;


X }
X }
X else
X {

X Move_to(0, screen_line);
X lastline = screen_line;
X }
X
X if (clear_to_end)
X {
X /* we can do this the easy way */
X putcap(clear_to_end);
X }
X else
X {
X /* use clear_eol on each line */
X i = hi;
X while ((void) clear_eol(strlen(&screenbuf[lineindex(i++)])), i < last_hi)


X {
X putchar('\n');
X }
X }

X }
X }
X last_hi = hi;
X
X /* move the cursor to a pleasant place */
X Move_to(x_idlecursor, y_idlecursor);
X lastline = y_idlecursor;
X }
X else
X {
X /* separate this display from the next with some vertical room */
X fputs("\n\n", stdout);
X }
X}
X
Xdisplay_header(t)
X
Xint t;
X
X{
X if (t)
X {
X header_status = ON;
X }
X else if (header_status == ON)
X {
X header_status = ERASE;
X }
X}
X
X/*VARARGS2*/
Xnew_message(type, msgfmt, a1, a2, a3)
X
Xint type;
Xchar *msgfmt;
Xcaddr_t a1, a2, a3;


X
X{
X register int i;
X

X /* first, format the message */
X (void) sprintf(next_msg, msgfmt, a1, a2, a3);
X
X if (msglen > 0)
X {
X /* message there already -- can we clear it? */
X if (!overstrike)
X {
X /* yes -- write it and clear to end */
X i = strlen(next_msg);
X if ((type & MT_delayed) == 0)
X {
X type & MT_standout ? standout(next_msg) :
X fputs(next_msg, stdout);
X (void) clear_eol(msglen - i);
X msglen = i;
X next_msg[0] = '\0';
X }
X }
X }
X else
X {
X if ((type & MT_delayed) == 0)
X {
X type & MT_standout ? standout(next_msg) : fputs(next_msg, stdout);
X msglen = strlen(next_msg);
X next_msg[0] = '\0';
X }
X }
X}
X
Xclear_message()
X
X{
X if (clear_eol(msglen) == 1)


X {
X putchar('\r');
X }
X}

X
Xreadline(buffer, size, numeric)
X
Xchar *buffer;
Xint size;
Xint numeric;
X
X{
X register char *ptr = buffer;
X register char ch;
X register char cnt = 0;
X register char maxcnt = 0;
X
X /* allow room for null terminator */
X size -= 1;
X
X /* read loop */
X while ((fflush(stdout), read(0, ptr, 1) > 0))
X {
X /* newline means we are done */
X if ((ch = *ptr) == '\n')
X {
X break;
X }
X
X /* handle special editing characters */
X if (ch == ch_kill)
X {
X /* kill line -- account for overstriking */
X if (overstrike)
X {
X msglen += maxcnt;
X }
X
X /* return null string */
X *buffer = '\0';
X putchar('\r');
X return(-1);
X }
X else if (ch == ch_erase)
X {
X /* erase previous character */
X if (cnt <= 0)
X {
X /* none to erase! */
X putchar('\7');
X }
X else
X {
X fputs("\b \b", stdout);
X ptr--;
X cnt--;
X }
X }
X /* check for character validity and buffer overflow */
X else if (cnt == size || (numeric && !isdigit(ch)) ||
X !isprint(ch))
X {
X /* not legal */
X putchar('\7');
X }
X else
X {
X /* echo it and store it in the buffer */
X putchar(ch);
X ptr++;
X cnt++;
X if (cnt > maxcnt)
X {
X maxcnt = cnt;
X }
X }
X }
X
X /* all done -- null terminate the string */
X *ptr = '\0';
X
X /* account for the extra characters in the message area */
X /* (if terminal overstrikes, remember the furthest they went) */
X msglen += overstrike ? maxcnt : cnt;
X
X /* return either inputted number or string length */
X putchar('\r');
X return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt);
X}
X
X/* internal support routines */
X
Xstatic int string_count(pp)
X
Xregister char **pp;


X
X{
X register int cnt;
X

X cnt = 0;
X while (*pp++ != NULL)
X {
X cnt++;
X }
X return(cnt);
X}
X
Xstatic void summary_format(str, numbers, names)
X
Xchar *str;
Xint *numbers;
Xregister char **names;
X
X{
X register char *p;
X register int num;
X register char *thisname;
X register int useM = No;
X
X /* format each number followed by its string */
X p = str;
X while ((thisname = *names++) != NULL)
X {
X /* get the number to format */
X num = *numbers++;
X
X /* display only non-zero numbers */
X if (num > 0)
X {
X /* is this number in kilobytes? */
X if (thisname[0] == 'K')
X {
X /* yes: format it as a memory value */
X p = strecpy(p, format_k(num));
X
X /* skip over the K, since it was included by format_k */
X p = strecpy(p, thisname+1);
X }
X else
X {
X p = strecpy(p, itoa(num));
X p = strecpy(p, thisname);
X }
X }
X
X /* ignore negative numbers, but display corresponding string */
X else if (num < 0)
X {
X p = strecpy(p, thisname);
X }
X }
X
X /* if the last two characters in the string are ", ", delete them */
X p -= 2;
X if (p >= str && p[0] == ',' && p[1] == ' ')
X {
X *p = '\0';
X }
X}
X
Xstatic void line_update(old, new, start, line)
X
Xregister char *old;
Xregister char *new;
Xint start;
Xint line;
X
X{
X register int ch;
X register int diff;
X register int newcol = start + 1;
X register int lastcol = start;
X char cursor_on_line = No;
X char *current;
X
X /* compare the two strings and only rewrite what has changed */
X current = old;
X#ifdef DEBUG
X fprintf(debug, "line_update, starting at %d\n", start);
X fputs(old, debug);
X fputc('\n', debug);
X fputs(new, debug);
X fputs("\n-\n", debug);
X#endif
X
X /* start things off on the right foot */
X /* this is to make sure the invariants get set up right */
X if ((ch = *new++) != *old)
X {
X if (line - lastline == 1 && start == 0)


X {
X putchar('\n');
X }

X else
X {
X Move_to(start, line);
X }
X cursor_on_line = Yes;
X putchar(ch);
X *old = ch;
X lastcol = 1;
X }
X old++;
X
X /*
X * main loop -- check each character. If the old and new aren't the
X * same, then update the display. When the distance from the
X * current cursor position to the new change is small enough,
X * the characters that belong there are written to move the
X * cursor over.
X *
X * Invariants:
X * lastcol is the column where the cursor currently is sitting
X * (always one beyond the end of the last mismatch).
X */
X do /* yes, a do...while */
X {
X if ((ch = *new++) != *old)
X {
X /* new character is different from old */
X /* make sure the cursor is on top of this character */
X diff = newcol - lastcol;
X if (diff > 0)
X {
X /* some motion is required--figure out which is shorter */
X if (diff < 6 && cursor_on_line)
X {
X /* overwrite old stuff--get it out of the old buffer */
X printf("%.*s", diff, &current[lastcol-start]);
X }
X else
X {
X /* use cursor addressing */
X Move_to(newcol, line);
X cursor_on_line = Yes;
X }
X /* remember where the cursor is */
X lastcol = newcol + 1;
X }
X else
X {
X /* already there, update position */
X lastcol++;
X }
X
X /* write what we need to */
X if (ch == '\0')
X {
X /* at the end--terminate with a clear-to-end-of-line */
X (void) clear_eol(strlen(old));
X }
X else
X {
X /* write the new character */
X putchar(ch);
X }
X /* put the new character in the screen buffer */
X *old = ch;
X }
X
X /* update working column and screen buffer pointer */
X newcol++;
X old++;
X
X } while (ch != '\0');
X
X /* zero out the rest of the line buffer -- MUST BE DONE! */
X diff = display_width - newcol;
X if (diff > 0)
X {
X memzero(old, diff);
X }
X
X /* remember where the current line is */
X if (cursor_on_line)
X {
X lastline = line;
X }
X}
X
X/*
X * printable(str) - make the string pointed to by "str" into one that is
X * printable (i.e.: all ascii), by converting all non-printable
X * characters into '?'. Replacements are done in place and a pointer
X * to the original buffer is returned.
X */
X
Xchar *printable(str)
X
Xchar *str;


X
X{
X register char *ptr;

X register char ch;
X
X ptr = str;
X while ((ch = *ptr) != '\0')
X {
X if (!isprint(ch))
X {
X *ptr = '?';
X }
X ptr++;
X }
X return(str);
X}
END_OF_FILE
if test 22989 -ne `wc -c <'top-3.4/display.c'`; then
echo shar: \"'top-3.4/display.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/display.c'
fi
if test -f 'top-3.4/machine/m_sunos4.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_sunos4.c'\"
else
echo shar: Extracting \"'top-3.4/machine/m_sunos4.c'\" \(22923 characters\)
sed "s/^X//" >'top-3.4/machine/m_sunos4.c' <<'END_OF_FILE'


X/*
X * top - a top users display for Unix
X *

X * SYNOPSIS: any Sun running SunOS version 4.x


X *
X * DESCRIPTION:

X * This is the machine-dependent module for SunOS 4.x.


X * This makes top work on the following systems:

X * SunOS 4.0
X * SunOS 4.0.1
X * SunOS 4.0.2 (including 386i architecture)
X * SunOS 4.0.3
X * SunOS 4.1
X * SunOS 4.1.1
X * SunOS 4.1.2 (including MP architectures)
X * SunOS 4.1.3 (including MP architectures)
X * SunOS 4.1.4 (including MP architectures)
X * Solbourne OS/MP PRIOR to 4.1A


X *
X * LIBS: -lkvm

X *
X * CFLAGS: -DHAVE_GETOPT -DORDER
X *


X * AUTHOR: William LeFebvre <ph...@eecs.nwu.edu>

X * Solbourne support by David MacKenzie <d...@eng.umd.edu>
X */
X
X/*
X * #ifdef MULTIPROCESSOR means Sun MP.
X * #ifdef solbourne is for Solbourne.
X */


X
X#include <sys/types.h>
X#include <sys/signal.h>
X

X/* make sure param.h gets loaded with KERNEL defined to get PZERO & NZERO */
X#define KERNEL
X#include <sys/param.h>
X#undef KERNEL
X
X#include <stdio.h>
X#include <kvm.h>

X#include <nlist.h>
X#include <math.h>


X#include <sys/dir.h>
X#include <sys/user.h>
X#include <sys/proc.h>
X#include <sys/dk.h>
X#include <sys/vm.h>
X#include <sys/file.h>
X#include <sys/time.h>
X#include <vm/page.h>
X

X#ifdef solbourne
X#include <sys/syscall.h>
X#endif
X
X/* Older versions of SunOS don't have a typedef for pid_t.
X Hopefully this will catch all those cases without causing other problems.
X */
X#ifndef __sys_stdtypes_h
Xtypedef int pid_t;
X#endif


X
X#include "top.h"
X#include "machine.h"

X#include "utils.h"


X
X/* declarations for load_avg */
X#include "loadavg.h"
X

X/* get_process_info passes back a handle. This is what it looks like: */
X
Xstruct handle
X{

X struct proc **next_proc; /* points to next valid proc pointer */


X int remaining; /* number of pointers remaining */
X};
X

X/* define what weighted cpu is. */

X#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
X ((pct) / (1.0 - exp((pp)->p_time * logcpu))))


X
X/* what we consider to be process size: */

X#define PROCSIZE(pp) ((pp)->p_tsize + (pp)->p_dsize + (pp)->p_ssize)

X
X/* definitions for indices in the nlist array */

X#define X_AVENRUN 0
X#define X_CCPU 1

X#define X_MPID 2
X#define X_NPROC 3
X#define X_PROC 4
X#define X_TOTAL 5


X#define X_CP_TIME 6
X#define X_PAGES 7
X#define X_EPAGES 8

X
Xstatic struct nlist nlst[] = {

X#ifdef i386


X { "avenrun" }, /* 0 */

X { "ccpu" }, /* 1 */
X { "mpid" }, /* 2 */


X { "nproc" }, /* 3 */

X { "proc" }, /* 4 */


X { "total" }, /* 5 */

X { "cp_time" }, /* 6 */
X { "pages" }, /* 7 */
X { "epages" }, /* 8 */
X#else


X { "_avenrun" }, /* 0 */
X { "_ccpu" }, /* 1 */
X { "_mpid" }, /* 2 */
X { "_nproc" }, /* 3 */
X { "_proc" }, /* 4 */
X { "_total" }, /* 5 */
X { "_cp_time" }, /* 6 */
X { "_pages" }, /* 7 */
X { "_epages" }, /* 8 */

X#ifdef MULTIPROCESSOR
X { "_ncpu" },
X#define X_NCPU 9
X { "_xp_time" },
X#define X_XP_TIME 10
X#endif
X#endif
X { 0 }
X};
X
X/*


X * These definitions control the format of the per-process area
X */
X
Xstatic char header[] =
X " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";
X/* 0123456 -- field to fill in starts at header+6 */
X#define UNAME_START 6
X
X#define Proc_format \

X "%5d %-8.8s %3d %4d %5s %5s %-5s %-6s %5.2f%% %5.2f%% %s"


X
X
X/* process state names for the "STATE" column of the display */
X/* the extra nulls in the string "run" are for adding a slash and
X the processor number when needed */
X
Xchar *state_abbrev[] =
X{

X "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"
X};

X
X/* values that we stash away in _init and use in later routines */
X
Xstatic double logcpu;

Xkvm_t *kd;


X
X/* these are retrieved from the kernel in _init */
X

Xstatic unsigned long proc;
Xstatic int nproc;
Xstatic load_avg ccpu;
Xstatic unsigned long pages;
Xstatic unsigned long epages;

Xstatic int ncpu = 0;


X
X/* these are offsets obtained via nlist and used in the get_ functions */
X

Xstatic unsigned long mpid_offset;
Xstatic unsigned long avenrun_offset;


Xstatic unsigned long total_offset;
Xstatic unsigned long cp_time_offset;

X#ifdef MULTIPROCESSOR
Xstatic unsigned long xp_time_offset;
X#endif


X
X/* these are for calculating cpu state percentages */
X
Xstatic long cp_time[CPUSTATES];
Xstatic long cp_old[CPUSTATES];
Xstatic long cp_diff[CPUSTATES];

X#ifdef MULTIPROCESSOR
Xstatic long xp_time[NCPU][XPSTATES];
X/* for now we only accumulate spin time, but extending this to pick up
X other stuff in xp_time is trivial. */
Xstatic long xp_old[NCPU];
X#endif


X
X/* these are for detailing the process states */
X
Xint process_states[7];
Xchar *procstatenames[] = {

X "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",

X " zombie, ", " stopped, ",


X NULL
X};
X
X/* these are for detailing the cpu states */
X

Xint cpu_states[5];
Xchar *cpustatenames[] = {
X "user", "nice", "system", "idle",
X#ifdef MULTIPROCESSOR
X "spin",
X#define XCP_SPIN 4
X#endif
X NULL
X};
X


X/* these are for detailing the memory statistics */
X

Xint memory_stats[4];
Xchar *memorynames[] = {
X "K available, ", "K in use, ", "K free, ", "K locked", NULL
X};
X
X/* these are names given to allowed sorting orders -- first is default */
Xchar *ordernames[] =
X{"cpu", "size", "res", "time", NULL};
X
X/* forward definitions for comparison functions */
Xint compare_cpu();
Xint compare_size();
Xint compare_res();
Xint compare_time();


X
Xint (*proc_compares[])() = {
X compare_cpu,
X compare_size,
X compare_res,
X compare_time,

X NULL };
X
X


X/* these are for keeping track of the proc array */
X

Xstatic int bytes;
Xstatic int pref_len;
Xstatic struct proc *pbase;
Xstatic struct proc **pref;


X
X/* these are for getting the memory statistics */
X

Xstatic struct page *physpage;
Xstatic int bytesize;
Xstatic int count;

Xstatic int pageshift; /* log base 2 of the pagesize */
X
X/* define pagetok in terms of pageshift */
X
X#define pagetok(size) ((size) << pageshift)
X
X/* useful externals */

Xextern int errno;
Xextern char *sys_errlist[];

X
Xlong lseek();
Xlong time();
X

Xmachine_init(statics)
X
Xstruct statics *statics;
X
X{

X register int i;


X register int pagesize;
X

X /* initialize the kernel interface */
X if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "top")) == NULL)
X {

X perror("kvm_open");
X return(-1);
X }
X


X /* get the list of symbols we want to access in the kernel */

X if ((i = kvm_nlist(kd, nlst)) < 0)


X {
X fprintf(stderr, "top: nlist failed\n");
X return(-1);
X }
X

X#ifdef MULTIPROCESSOR
X /* were ncpu and xp_time not found in the nlist? */
X if (i > 0 && nlst[X_NCPU].n_type == 0 && nlst[X_XP_TIME].n_type == 0)
X {
X /* we were compiled on an MP system but we are not running on one */
X /* so we will pretend this didn't happen and set ncpu = 1 */
X i -= 2;
X ncpu = 1;
X }
X#endif
X
X#ifdef solbourne
X {
X unsigned int status, type;
X
X /* Get the number of CPUs on this system. */
X syscall(SYS_getcpustatus, &status, &ncpu, &type);
X }
X#endif
X


X /* make sure they were all found */
X if (i > 0 && check_nlist(nlst) > 0)
X {
X return(-1);
X }
X
X /* get the symbol values out of kmem */

X (void) getkval(nlst[X_PROC].n_value, (int *)(&proc), sizeof(proc),
X nlst[X_PROC].n_name);
X (void) getkval(nlst[X_NPROC].n_value, &nproc, sizeof(nproc),
X nlst[X_NPROC].n_name);

X (void) getkval(nlst[X_CCPU].n_value, (int *)(&ccpu), sizeof(ccpu),
X nlst[X_CCPU].n_name);

X (void) getkval(nlst[X_PAGES].n_value, (int *)(&pages), sizeof(pages),
X nlst[X_PAGES].n_name);
X (void) getkval(nlst[X_EPAGES].n_value, (int *)(&epages), sizeof(epages),
X nlst[X_EPAGES].n_name);

X#ifdef MULTIPROCESSOR
X if (ncpu == 0)
X {
X /* if ncpu > 0 then we are not really on an MP system */
X (void) getkval(nlst[X_NCPU].n_value, (int *)(&ncpu), sizeof(ncpu),
X nlst[X_NCPU].n_name);
X }
X#endif
X


X /* stash away certain offsets for later use */

X mpid_offset = nlst[X_MPID].n_value;


X avenrun_offset = nlst[X_AVENRUN].n_value;

X total_offset = nlst[X_TOTAL].n_value;

X cp_time_offset = nlst[X_CP_TIME].n_value;

X#ifdef MULTIPROCESSOR
X xp_time_offset = nlst[X_XP_TIME].n_value;


X#endif
X
X /* this is used in calculating WCPU -- calculate it ahead of time */
X logcpu = log(loaddouble(ccpu));
X

X /* allocate space for proc structure array and array of pointers */

X bytes = nproc * sizeof(struct proc);
X pbase = (struct proc *)malloc(bytes);

X pref = (struct proc **)malloc(nproc * sizeof(struct proc *));


X
X /* Just in case ... */

X if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
X {

X fprintf(stderr, "top: can't allocate sufficient memory\n");
X return(-1);
X }
X


X /* allocate a table to hold all the page structs */
X bytesize = epages - pages;
X count = bytesize / sizeof(struct page);
X physpage = (struct page *)malloc(epages - pages);
X if (physpage == NULL)
X {

X fprintf(stderr, "top: can't allocate sufficient memory\n");
X return(-1);
X }
X

X /* get the page size with "getpagesize" and calculate pageshift from it */
X pagesize = getpagesize();
X pageshift = 0;
X while (pagesize > 1)
X {
X pageshift++;
X pagesize >>= 1;
X }
X
X /* we only need the amount of log(2)1024 for our conversion */
X pageshift -= LOG1024;
X

X#if defined(MULTIPROCESSOR) || defined(solbourne)


X /* add a slash to the "run" state abbreviation */

X if (ncpu > 1)
X {


X state_abbrev[SRUN][3] = '/';

X }
X#endif
X


X /* fill in the statics information */
X statics->procstate_names = procstatenames;
X statics->cpustate_names = cpustatenames;
X statics->memory_names = memorynames;

X#ifdef ORDER


X statics->order_names = ordernames;

X#endif


X
X /* all done! */
X return(0);
X}
X
Xchar *format_header(uname_field)
X
Xregister char *uname_field;
X
X{
X register char *ptr;
X
X ptr = header + UNAME_START;
X while (*uname_field != '\0')
X {
X *ptr++ = *uname_field++;
X }
X
X return(header);
X}
X

Xget_system_info(si)
X
Xstruct system_info *si;
X
X{

X load_avg avenrun[3];
X long total;

X#ifdef MULTIPROCESSOR
X long half_total;
X#endif
X


X /* get the cp_time array */
X (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),

X "_cp_time");
X
X#ifdef MULTIPROCESSOR
X /* get the xp_time array as well */
X if (ncpu > 1)
X {
X (void) getkval(xp_time_offset, (int *)xp_time, sizeof(xp_time),
X "_xp_time");
X }
X#endif
X


X /* get load average array */

X (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),

X "_avenrun");
X


X /* get mpid -- process id of last process */

X (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
X "_mpid");

X


X /* get the array of physpage descriptors */

X (void) getkval(pages, (int *)physpage, bytesize, "array _page");
X


X /* convert load averages to doubles */
X {
X register int i;
X register double *infoloadp;

X register load_avg *sysloadp;


X
X infoloadp = si->load_avg;

X sysloadp = avenrun;


X for (i = 0; i < 3; i++)
X {

X *infoloadp++ = loaddouble(*sysloadp++);


X }
X }
X
X /* convert cp_time counts to percentages */
X total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
X

X#ifdef MULTIPROCESSOR
X /* calculate spin time from all processors */
X if (ncpu > 1)
X {
X register int c;
X register int i;
X register long sum;
X register long change;
X
X /* collect differences for each processor and add them */
X sum = 0;
X for (i = 0; i < ncpu; i++)
X {
X c = xp_time[i][XP_SPIN];
X change = c - xp_old[i];
X if (change < 0)
X {
X /* counter wrapped */
X change = (long)((unsigned long)c -
X (unsigned long)xp_old[i]);
X }
X sum += change;
X xp_old[i] = c;
X }
X
X /*
X * NOTE: I am assuming that the ticks found in xp_time are
X * already included in the ticks accumulated in cp_time. To
X * get an accurate reflection, therefore, we have to subtract
X * the spin time from the system time and recompute those two
X * percentages.
X */
X half_total = total / 2l;
X cp_diff[CP_SYS] -= sum;
X cpu_states[CP_SYS] = (int)((cp_diff[CP_SYS] * 1000 + half_total) /
X total);
X cpu_states[XCP_SPIN] = (int)((sum * 1000 + half_total) / total);
X }
X#endif
X


X /* sum memory statistics */
X {

X register struct page *pp;
X register int cnt;


X register int inuse;
X register int free;
X register int locked;
X
X /* bop thru the array counting page types */
X pp = physpage;
X inuse = free = locked = 0;
X for (cnt = count; --cnt >= 0; pp++)
X {
X if (pp->p_free)
X free++;
X else if (pp->p_lock || pp->p_keepcnt > 0)
X locked++;
X else
X inuse++;

X }
X


X /* convert memory stats to Kbytes */

X memory_stats[0] = pagetok(inuse + free);
X memory_stats[1] = pagetok(inuse);
X memory_stats[2] = pagetok(free);
X memory_stats[3] = pagetok(locked);

X }
X


X /* set arrays and strings */
X si->cpustates = cpu_states;
X si->memory = memory_stats;

X}
X
Xstatic struct handle handle;
X
Xcaddr_t get_process_info(si, sel, compare)
X
Xstruct system_info *si;
Xstruct process_select *sel;
Xint (*compare)();
X
X{
X register int i;
X register int total_procs;
X register int active_procs;

X register struct proc **prefp;

X register struct proc *pp;


X
X /* these are copied out of sel for speed */
X int show_idle;
X int show_system;
X int show_uid;
X int show_command;
X

X /* read all the proc structures in one fell swoop */
X (void) getkval(proc, (int *)pbase, bytes, "proc array");

X
X /* get a pointer to the states summary array */
X si->procstates = process_states;
X
X /* set up flags which define what we are going to select */
X show_idle = sel->idle;
X show_system = sel->system;
X show_uid = sel->uid != -1;
X show_command = sel->command != NULL;
X
X /* count up process states and get pointers to interesting procs */
X total_procs = 0;
X active_procs = 0;

X bzero((char *)process_states, sizeof(process_states));


X prefp = pref;
X for (pp = pbase, i = 0; i < nproc; pp++, i++)
X {
X /*
X * Place pointers to each valid proc structure in pref[].
X * Process slots that are actually in use have a non-zero

X * status field. Processes with SSYS set are system


X * processes---these get ignored unless show_sysprocs is set.
X */

X if (pp->p_stat != 0 &&
X (show_system || ((pp->p_flag & SSYS) == 0)))
X {
X total_procs++;


X process_states[pp->p_stat]++;
X if ((pp->p_stat != SZOMB) &&

X (show_idle || (pp->p_pctcpu != 0) || (pp->p_stat == SRUN)) &&
X (!show_uid || pp->p_uid == (uid_t)sel->uid))


X {
X *prefp++ = pp;
X active_procs++;
X }
X }
X }
X
X /* if requested, sort the "interesting" processes */
X if (compare != NULL)
X {

X qsort((char *)pref, active_procs, sizeof(struct proc *), compare);


X }
X
X /* remember active and total counts */
X si->p_total = total_procs;
X si->p_active = pref_len = active_procs;
X
X /* pass back a handle */
X handle.next_proc = pref;
X handle.remaining = active_procs;
X return((caddr_t)&handle);
X}
X

Xchar fmt[MAX_COLS]; /* static area where result is built */


X
Xchar *format_next_process(handle, get_userid)
X
Xcaddr_t handle;
Xchar *(*get_userid)();
X
X{

X register struct proc *pp;


X register long cputime;
X register double pct;

X struct user u;


X struct handle *hp;
X
X /* find and remember the next proc structure */
X hp = (struct handle *)handle;
X pp = *(hp->next_proc++);
X hp->remaining--;
X
X /* get the process's user struct and set cputime */

X if (getu(pp, &u) == -1)
X {
X (void) strcpy(u.u_comm, "<swapped>");

X cputime = 0;
X }
X else
X {
X /* set u_comm for system processes */
X if (u.u_comm[0] == '\0')
X {


X if (pp->p_pid == 0)
X {
X (void) strcpy(u.u_comm, "Swapper");
X }
X else if (pp->p_pid == 2)
X {

X (void) strcpy(u.u_comm, "Pager");
X }
X }
X


X cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
X }

X
X /* calculate the base for cpu percentages */

X pct = pctdouble(pp->p_pctcpu);
X
X#ifdef MULTIPROCESSOR
X /*
X * If there is more than one cpu then add the processor number to
X * the "run/" string. Note that this will only show up if the
X * process is in the run state. Also note: when they
X * start making Suns with more than 9 processors this will break
X * since the string will then be more than 5 characters.
X */
X if (ncpu > 1)
X {
X state_abbrev[SRUN][4] = (pp->p_cpuid & 0xf) + '0';
X }
X#endif
X#ifdef solbourne
X if (ncpu > 1)
X {
X state_abbrev[SRUN][4] = (pp->p_lastcpu) + '0';
X }
X#endif
X


X /* format this entry */
X sprintf(fmt,
X Proc_format,

X pp->p_pid,
X (*get_userid)(pp->p_uid),
X pp->p_pri - PZERO,

X pp->p_nice - NZERO,
X format_k(pagetok(PROCSIZE(pp))),


X format_k(pagetok(pp->p_rssize)),
X state_abbrev[pp->p_stat],
X format_time(cputime),
X 100.0 * weighted_cpu(pct, pp),
X 100.0 * pct,
X printable(u.u_comm));

X
X /* return the result */
X return(fmt);

X}
X
X/*


X * getu(p, u) - get the user structure for the process whose proc structure
X * is pointed to by p. The user structure is put in the buffer pointed
X * to by u. Return 0 if successful, -1 on failure (such as the process
X * being swapped out).
X */
X
Xgetu(p, u)
X
Xregister struct proc *p;
Xstruct user *u;

X
X{


X register struct user *lu;
X
X lu = kvm_getu(kd, p);
X if (lu == NULL)

X {
X return(-1);
X }


X else
X {
X *u = *lu;
X return(0);
X }

X}
X
X/*


X * check_nlist(nlst) - checks the nlist to see if any symbols were not
X * found. For every symbol that was not found, a one-line
X * message is printed to stderr. The routine returns the
X * number of symbols NOT found.
X */
X

Xint check_nlist(nlst)


X
Xregister struct nlist *nlst;
X
X{
X register int i;
X
X /* check to see if we got ALL the symbols we requested */
X /* this will write one line to stderr for every symbol not found */
X
X i = 0;
X while (nlst->n_name != NULL)
X {

X#ifdef i386
X if (nlst->n_value == 0)
X#else


X if (nlst->n_type == 0)

X#endif
X {


X /* this one wasn't found */

X fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);


X i = 1;
X }
X nlst++;
X }
X
X return(i);
X}

X
X
X/*


X * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
X * "offset" is the byte offset into the kernel for the desired value,
X * "ptr" points to a buffer into which the value is retrieved,
X * "size" is the size of the buffer (and the object to retrieve),
X * "refstr" is a reference string used when printing error meessages,
X * if "refstr" starts with a '!', then a failure on read will not
X * be fatal (this may seem like a silly way to do things, but I
X * really didn't want the overhead of another argument).

X *
X */
X

Xgetkval(offset, ptr, size, refstr)


X
Xunsigned long offset;
Xint *ptr;
Xint size;
Xchar *refstr;
X
X{

X if (kvm_read(kd, offset, ptr, size) != size)


X {
X if (*refstr == '!')
X {
X return(0);
X }
X else
X {
X fprintf(stderr, "top: kvm_read for %s: %s\n",

X refstr, sys_errlist[errno]);
X quit(23);
X /*NOTREACHED*/

X }
X }
X return(1);
X}
X
X/* comparison routine for qsort */
X

X/* comparison routines for qsort */
X
X/*
X * There are currently four possible comparison routines. main selects
X * one of these by indexing in to the array proc_compares.
X *
X * Possible keys are defined as macros below. Currently these keys are
X * defined: percent cpu, cpu ticks, process state, resident set size,
X * total virtual memory usage. The process states are ordered as follows
X * (from least to most important): WAIT, zombie, sleep, stop, start, run.
X * The array declaration below maps a process state index into a number


X * that reflects this ordering.
X */
X

X/* First, the possible comparison keys. These are defined in such a way
X that they can be merely listed in the source code to define the actual
X desired ordering.
X */
X
X#define ORDERKEY_PCTCPU if (lresult = p2->p_pctcpu - p1->p_pctcpu,\


X (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)

X#define ORDERKEY_CPTICKS if ((result = p2->p_cpticks - p1->p_cpticks) == 0)
X#define ORDERKEY_STATE if ((result = sorted_state[p2->p_stat] - \


X sorted_state[p1->p_stat]) == 0)

X#define ORDERKEY_PRIO if ((result = p2->p_pri - p1->p_pri) == 0)
X#define ORDERKEY_RSSIZE if ((result = p2->p_rssize - p1->p_rssize) == 0)
X#define ORDERKEY_MEM if ((result = PROCSIZE(p2) - PROCSIZE(p1)) == 0)
X
X/* Now the array that maps process state to a weight */


X
Xstatic unsigned char sorted_state[] =
X{
X 0, /* not used */
X 3, /* sleep */
X 1, /* ABANDONED (WAIT) */
X 6, /* run */
X 5, /* start */
X 2, /* zombie */
X 4 /* stop */
X};
X

X/* compare_cpu - the comparison function for sorting by cpu percentage */
X

Xcompare_cpu(pp1, pp2)


X
Xstruct proc **pp1;
Xstruct proc **pp2;
X
X{

X register struct proc *p1;

X register struct proc *p2;


X register int result;
X register pctcpu lresult;
X
X /* remove one level of indirection */

X p1 = *pp1;
X p2 = *pp2;
X

X ORDERKEY_PCTCPU
X ORDERKEY_CPTICKS
X ORDERKEY_STATE
X ORDERKEY_PRIO
X ORDERKEY_RSSIZE
X ORDERKEY_MEM

X ;
X
X return(result);
X}
X

X/* compare_size - the comparison function for sorting by total memory usage */
X

Xcompare_size(pp1, pp2)


X
Xstruct proc **pp1;
Xstruct proc **pp2;
X
X{

X register struct proc *p1;

X register struct proc *p2;


X register int result;
X register pctcpu lresult;
X
X /* remove one level of indirection */

X p1 = *pp1;
X p2 = *pp2;
X

X ORDERKEY_MEM
X ORDERKEY_RSSIZE
X ORDERKEY_PCTCPU
X ORDERKEY_CPTICKS
X ORDERKEY_STATE
X ORDERKEY_PRIO

X ;
X
X return(result);
X}
X

X/* compare_res - the comparison function for sorting by resident set size */
X

Xcompare_res(pp1, pp2)


X
Xstruct proc **pp1;
Xstruct proc **pp2;
X
X{

X register struct proc *p1;

X register struct proc *p2;


X register int result;
X register pctcpu lresult;
X
X /* remove one level of indirection */

X p1 = *pp1;
X p2 = *pp2;
X

X ORDERKEY_RSSIZE
X ORDERKEY_MEM
X ORDERKEY_PCTCPU
X ORDERKEY_CPTICKS
X ORDERKEY_STATE
X ORDERKEY_PRIO

X ;
X
X return(result);
X}
X

X/* compare_time - the comparison function for sorting by total cpu time */
X

Xcompare_time(pp1, pp2)


X
Xstruct proc **pp1;
Xstruct proc **pp2;
X
X{

X register struct proc *p1;

X register struct proc *p2;


X register int result;
X register pctcpu lresult;
X
X /* remove one level of indirection */

X p1 = *pp1;
X p2 = *pp2;
X

X ORDERKEY_CPTICKS
X ORDERKEY_PCTCPU
X ORDERKEY_STATE
X ORDERKEY_PRIO

X ORDERKEY_RSSIZE
X ORDERKEY_MEM


X ;
X
X return(result);
X}

X
X
X/*


X * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
X * the process does not exist.
X * It is EXTREMLY IMPORTANT that this function work correctly.
X * If top runs setuid root (as in SVR4), then this function
X * is the only thing that stands in the way of a serious
X * security problem. It validates requests for the "kill"
X * and "renice" commands.
X */
X
Xint proc_owner(pid)
X
Xint pid;
X
X{
X register int cnt;

X register struct proc **prefp;

X register struct proc *pp;


X
X prefp = pref;
X cnt = pref_len;
X while (--cnt >= 0)
X {

X if ((pp = *prefp++)->p_pid == (pid_t)pid)
X {
X return((int)pp->p_uid);

X }
X }
X return(-1);
X}

END_OF_FILE
if test 22923 -ne `wc -c <'top-3.4/machine/m_sunos4.c'`; then
echo shar: \"'top-3.4/machine/m_sunos4.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_sunos4.c'
fi
echo shar: End of archive 18 \(of 22\).
cp /dev/null ark18isdone

William Lefebvre

unread,
Sep 1, 1996, 3:00:00 AM9/1/96
to

Submitted-By: w...@groupsys.com (William Lefebvre)
Posting-Number: Volume 29, Issue 120
Archive-Name: top-3.4/part19

#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:

# "End of archive 19 (of 22)."
# Contents: top-3.4/machine/m_decosf1.c top-3.4/machine/m_netbsd10.c
# Wrapped by lefebvre@acapulco on Fri Aug 30 12:35:52 1996


PATH=/bin:/usr/bin:/usr/ucb ; export PATH

if test -f 'top-3.4/machine/m_decosf1.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_decosf1.c'\"
else
echo shar: Extracting \"'top-3.4/machine/m_decosf1.c'\" \(23295 characters\)
sed "s/^X//" >'top-3.4/machine/m_decosf1.c' <<'END_OF_FILE'


X/*
X * top - a top users display for Unix
X *

X * SYNOPSIS: DEC Alpha AXP running OSF/1 or Digital Unix 4.0.


X *
X * DESCRIPTION:

X * This is the machine-dependent module for DEC OSF/1
X * It is known to work on OSF/1 1.2, 1.3, 2.0-T3, 3.0, and Digital Unix V4.0
X * WARNING: if you use optimization with the standard "cc" compiler that
X * . comes with V3.0 the resulting executable may core dump. If
X * . this happens, recompile without optimization.
X *
X * LIBS: -lmld -lmach
X *
X * CFLAGS: -DHAVE_GETOPT
X *
X * AUTHOR: Anthony Baxter, <ant...@aaii.oz.au>
X * Derived originally from m_ultrix, by David S. Comay <d...@seismo.css.gov>,
X * although by now there is hardly any of the code from m_ultrix left.
X * Helped a lot by having the source for syd(1), by Claus Kalle, and
X * from several people at DEC who helped with providing information on
X * some of the less-documented bits of the kernel interface.
X *
X * Modified: 31-Oct-94, Pat Welch, t...@physics.orst.edu
X * changed _mpid to pidtab for compatibility with OSF/1 version 3.0
X *
X * Modified: 13-Dec-94, William LeFebvre, lefe...@dis.anl.gov
X * removed used of pidtab (that was bogus) and changed things to
X * automatically detect the absence of _mpid in the nlist and
X * recover gracefully---this appears to be the only difference
X * with 3.0.
X */
X/*
X * $Id: m_decosf1.c,v 1.14 1994/01/18 07:34:42 anthony Exp $
X * Theres some real icky bits in this code - you have been warned :)
X * Extremely icky bits are marked with FIXME:
X *
X * Theory of operation:
X *
X * Use Mach calls to build up a structure that contains all the sorts
X * of stuff normally found in a struct proc in a BSD system. Then
X * everything else uses this structure. This has major performance wins,
X * and also should work for future versions of the O/S.


X */
X
X#include <sys/types.h>
X#include <sys/signal.h>

X#include <sys/param.h>
X
X#include <string.h>
X#include <sys/user.h>
X#include <stdio.h>


X#include <nlist.h>
X#include <math.h>
X#include <sys/dir.h>
X#include <sys/user.h>
X#include <sys/proc.h>
X#include <sys/dk.h>
X#include <sys/vm.h>
X#include <sys/file.h>
X#include <sys/time.h>

X/* #include <machine/pte.h> */
X#include <sys/table.h>
X#include <mach.h>
X#include <mach/mach_types.h>
X#include <mach/vm_statistics.h>
X#include <sys/syscall.h> /* for SYS_setpriority, in setpriority(), below */
X


X
X#include "top.h"
X#include "machine.h"

X
Xextern int errno, sys_nerr;
Xextern char *sys_errlist[];
X#define strerror(e) (((e) >= 0 && (e) < sys_nerr) ? sys_errlist[(e)] : "Unknown error")
X
X#define VMUNIX "/vmunix"
X#define KMEM "/dev/kmem"
X#define MEM "/dev/mem"

X
X/* get_process_info passes back a handle. This is what it looks like: */
X
Xstruct handle
X{

X struct osf1_top_proc **next_proc; /* points to next valid proc pointer */


X int remaining; /* number of pointers remaining */
X};
X

X/* declarations for load_avg */
X#include "loadavg.h"
X

X/* definitions for indices in the nlist array */

X#define X_MPID 0


X
Xstatic struct nlist nlst[] = {

X { "_mpid" }, /* 0 */
X { 0 }
X};
X
X/* Some versions of OSF/1 don't support reporting of the last PID.
X This flag indicates whether or not we are reporting the last PID. */
Xstatic int do_last_pid = 1;


X
X/*
X * These definitions control the format of the per-process area
X */
X
Xstatic char header[] =

X " PID X PRI NICE SIZE RES STATE TIME CPU COMMAND";


X/* 0123456 -- field to fill in starts at header+6 */
X#define UNAME_START 6
X
X#define Proc_format \

X "%5d %-8.8s %3d %4d %5s %5s %-5s %-6s %5.2f%% %.14s"


X
X
X/* process state names for the "STATE" column of the display */
X/* the extra nulls in the string "run" are for adding a slash and

X * the processor number when needed. Although OSF/1 doesnt support
X * multiple processors yet, (and this module _certainly_ doesnt
X * support it, either, we may as well plan for the future. :-)
X */


X
Xchar *state_abbrev[] =
X{

X "", "run\0\0\0", "WAIT", "sleep", "sleep", "stop", "halt", "???", "zomb"


X};
X
X
Xstatic int kmem, mem;

X
X/* values that we stash away in _init and use in later routines */
X
Xstatic double logcpu;

X
X/* these are retrieved from the kernel in _init */
X
Xstatic unsigned long proc;
Xstatic int nproc;
Xstatic load_avg ccpu;
X

Xtypedef long mtime_t;


X
X/* these are offsets obtained via nlist and used in the get_ functions */
X
Xstatic unsigned long mpid_offset;

X
X/* these are for detailing the process states */
X

Xint process_states[9];
Xchar *procstatenames[] = {
X "", " running, ", " waiting, ", " sleeping, ", " idle, ",
X " stopped, ", " halted, ", "", " zombie",


X NULL
X};
X
X/* these are for detailing the cpu states */
X

Xint cpu_states[4];
Xchar *cpustatenames[] = {
X "user", "nice", "system", "idle", NULL
X};
X
Xlong old_cpu_ticks[4];


X
X/* these are for detailing the memory statistics */
X

Xint memory_stats[8];
Xchar *memorynames[] = {
X "Real: ", "K/", "K act/tot ", "Virtual: ", "M/",
X "M use/tot ", "Free: ", "K", NULL
X};


X
X/* these are for getting the memory statistics */
X

Xstatic int pageshift; /* log base 2 of the pagesize */
X
X/* define pagetok in terms of pageshift */
X
X#define pagetok(size) ((size) << pageshift)
X

X/* take a process, make it a mach task, and grab all the info out */
Xvoid do_threads_calculations();
X
X/*
X * Because I dont feel like repeatedly grunging through the kernel with
X * Mach calls, and I also dont want the horrid performance hit this
X * would give, I read the stuff I need out, and put in into my own
X * structure, for later use.
X */
X
Xstruct osf1_top_proc {
X size_t p_mach_virt_size;
X char p_mach_state;
X fixpt_t p_mach_pct_cpu; /* aka p_pctcpu */
X int used_ticks;
X size_t process_size;
X pid_t p_pid;
X uid_t p_ruid;
X char p_pri;
X char p_nice;
X size_t p_rssize;
X char u_comm[PI_COMLEN + 1];


X} ;
X
X/* these are for keeping track of the proc array */
X
Xstatic int bytes;
Xstatic int pref_len;

Xstatic struct osf1_top_proc *pbase;
Xstatic struct osf1_top_proc **pref;


X
X/* useful externals */
Xextern int errno;
Xextern char *sys_errlist[];
X

Xlong percentages();
X
Xmachine_init(statics)
Xstruct statics *statics;
X{


X register int i = 0;

X register int pagesize;
X struct tbl_sysinfo sibuf;


X
X if ((kmem = open(KMEM, O_RDONLY)) == -1) {
X perror(KMEM);
X return(-1);
X }

X if ((mem = open(MEM, O_RDONLY)) == -1) {
X perror(MEM);

X return(-1);
X }
X
X /* get the list of symbols we want to access in the kernel */

X if (nlist(VMUNIX, nlst) == -1)
X {
X perror("TOP(nlist)");


X return (-1);
X }
X

X if (nlst[X_MPID].n_type == 0)
X {
X /* this kernel has no _mpid, so go without */
X do_last_pid = 0;
X }
X else
X {
X /* stash away mpid pointer for later use */


X mpid_offset = nlst[X_MPID].n_value;
X }

X
X /* get the symbol values out of kmem */

X nproc = table(TBL_PROCINFO, 0, (struct tbl_procinfo *)NULL, INT_MAX, 0);


X
X /* allocate space for proc structure array and array of pointers */

X bytes = nproc * sizeof(struct osf1_top_proc);
X pbase = (struct osf1_top_proc *)malloc(bytes);
X pref = (struct osf1_top_proc **)malloc(nproc *
X sizeof(struct osf1_top_proc *));


X
X /* Just in case ... */

X if (pbase == (struct osf1_top_proc *)NULL ||
X pref == (struct osf1_top_proc **)NULL)
X {
X fprintf(stderr, "top: cannot allocate sufficient memory\n");


X return(-1);
X }
X
X /* get the page size with "getpagesize" and calculate pageshift from it */
X pagesize = getpagesize();
X pageshift = 0;
X while (pagesize > 1)
X {
X pageshift++;
X pagesize >>= 1;
X }
X
X /* we only need the amount of log(2)1024 for our conversion */
X pageshift -= LOG1024;
X

X /* fill in the statics information */
X statics->procstate_names = procstatenames;
X statics->cpustate_names = cpustatenames;
X statics->memory_names = memorynames;
X

X /* initialise this, for calculating cpu time */
X if (table(TBL_SYSINFO,0,&sibuf,1,sizeof(struct tbl_sysinfo))<0) {
X perror("TBL_SYSINFO");
X return(-1);
X }
X old_cpu_ticks[0] = sibuf.si_user;
X old_cpu_ticks[1] = sibuf.si_nice;
X old_cpu_ticks[2] = sibuf.si_sys;
X old_cpu_ticks[3] = sibuf.si_idle;


X
X /* all done! */
X return(0);
X}
X
Xchar *format_header(uname_field)

Xregister char *uname_field;
X{


X register char *ptr;
X
X ptr = header + UNAME_START;
X while (*uname_field != '\0')
X {
X *ptr++ = *uname_field++;
X }
X
X return(header);
X}
X
Xget_system_info(si)

Xstruct system_info *si;
X{
X struct tbl_loadavg labuf;
X struct tbl_sysinfo sibuf;
X struct tbl_swapinfo swbuf;
X vm_statistics_data_t vmstats;
X int swap_pages=0,swap_free=0,i;
X long new_ticks[4],diff_ticks[4];
X long delta_ticks;
X
X if (do_last_pid)
X {
X /* last pid assigned */


X (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
X "_mpid");
X }

X else
X {
X si->last_pid = -1;
X }
X
X /* get load averages */
X if (table(TBL_LOADAVG,0,&labuf,1,sizeof(struct tbl_loadavg))<0) {
X perror("TBL_LOADAVG");
X return(-1);
X }
X if (labuf.tl_lscale) /* scaled */
X for(i=0;i<3;i++)
X si->load_avg[i] = ((double)labuf.tl_avenrun.l[i] /
X (double)labuf.tl_lscale );
X else /* not scaled */
X for(i=0;i<3;i++)
X si->load_avg[i] = labuf.tl_avenrun.d[i];
X
X /* array of cpu state counters */
X if (table(TBL_SYSINFO,0,&sibuf,1,sizeof(struct tbl_sysinfo))<0) {
X perror("TBL_SYSINFO");
X return(-1);
X }
X new_ticks[0] = sibuf.si_user ; new_ticks[1] = sibuf.si_nice;
X new_ticks[2] = sibuf.si_sys ; new_ticks[3] = sibuf.si_idle;
X delta_ticks=0;
X for(i=0;i<4;i++) {
X diff_ticks[i] = new_ticks[i] - old_cpu_ticks[i];
X delta_ticks += diff_ticks[i];
X old_cpu_ticks[i] = new_ticks[i];
X }


X si->cpustates = cpu_states;

X if(delta_ticks)
X for(i=0;i<4;i++)
X si->cpustates[i] = (int)( ( (double)diff_ticks[i] /
X (double)delta_ticks ) * 1000 );
X
X /* memory information */
X /* this is possibly bogus - we work out total # pages by */
X /* adding up the free, active, inactive, wired down, and */
X /* zero filled. Anyone who knows a better way, TELL ME! */
X /* Change: dont use zero filled. */
X (void) vm_statistics(task_self(),&vmstats);
X
X /* thanks DEC for the table() command. No thanks at all for */
X /* omitting the man page for it from OSF/1 1.2, and failing */
X /* to document SWAPINFO in the 1.3 man page. Lets hear it for */
X /* include files. */
X i=0;
X while(table(TBL_SWAPINFO,i,&swbuf,1,sizeof(struct tbl_swapinfo))>0) {
X swap_pages += swbuf.size;
X swap_free += swbuf.free;
X i++;
X }


X memory_stats[0] = -1;

X memory_stats[1] = pagetok(vmstats.active_count);
X memory_stats[2] = pagetok((vmstats.free_count + vmstats.active_count +
X vmstats.inactive_count + vmstats.wire_count));


X memory_stats[3] = -1;

X memory_stats[4] = pagetok((swap_pages - swap_free))/1024;
X memory_stats[5] = pagetok(swap_pages)/1024;


X memory_stats[6] = -1;

X memory_stats[7] = pagetok(vmstats.free_count);


X si->memory = memory_stats;
X}
X
Xstatic struct handle handle;
X
Xcaddr_t get_process_info(si, sel, compare)

Xstruct system_info *si;
Xstruct process_select *sel;
Xint (*compare)();
X{

X register int i;
X register int total_procs;
X register int active_procs;

X register struct osf1_top_proc **prefp;
X register struct osf1_top_proc *pp;
X struct tbl_procinfo p_i[8];
X int j,k,r;


X
X /* these are copied out of sel for speed */
X int show_idle;
X int show_system;
X int show_uid;
X int show_command;
X

X /* get a pointer to the states summary array */
X si->procstates = process_states;
X
X /* set up flags which define what we are going to select */
X show_idle = sel->idle;
X show_system = sel->system;
X show_uid = sel->uid != -1;
X show_command = sel->command != NULL;
X
X /* count up process states and get pointers to interesting procs */
X total_procs = 0;
X active_procs = 0;

X memset((char *)process_states, 0, sizeof(process_states));

X process_states[0]=0;
X process_states[1]=0;
X process_states[2]=0;
X process_states[3]=0;
X process_states[4]=0;
X process_states[5]=0;
X process_states[6]=0;
X prefp = pref;
X pp=pbase;
X for (j=0; j<nproc; j += 8)
X {
X r = table(TBL_PROCINFO, j, (struct tbl_procinfo *)p_i, 8,
X sizeof(struct tbl_procinfo));
X for (k=0; k < r; k++ , pp++)
X {
X if(p_i[k].pi_pid == 0)
X {
X pp->p_pid = 0;
X }
X else
X {
X pp->p_pid = p_i[k].pi_pid;
X pp->p_ruid = p_i[k].pi_ruid;
X pp->p_nice = getpriority(PRIO_PROCESS,p_i[k].pi_pid);
X /* Load useful values into the proc structure */
X do_threads_calculations(pp);


X /*
X * Place pointers to each valid proc structure in pref[].
X * Process slots that are actually in use have a non-zero
X * status field. Processes with SSYS set are system
X * processes---these get ignored unless show_sysprocs is set.
X */

X if (pp->p_mach_state != 0)
X {
X total_procs++;
X process_states[pp->p_mach_state]++;
X if ((pp->p_mach_state != SZOMB) &&
X (pp->p_mach_state != SIDL) &&
X (show_idle || (pp->p_mach_pct_cpu != 0) ||
X (pp->p_mach_state == SRUN)) &&
X (!show_uid || pp->p_ruid == (uid_t)sel->uid)) {


X *prefp++ = pp;
X active_procs++;
X }
X }
X }
X }
X }
X
X /* if requested, sort the "interesting" processes */
X if (compare != NULL)
X {

X qsort((char *)pref, active_procs, sizeof(struct osf1_top_proc *),
X compare);


X }
X
X /* remember active and total counts */
X si->p_total = total_procs;
X si->p_active = pref_len = active_procs;
X
X /* pass back a handle */
X handle.next_proc = pref;
X handle.remaining = active_procs;
X return((caddr_t)&handle);
X}
X

Xchar fmt[128]; /* static area where result is built */
X
Xchar *format_next_process(handle, get_userid)


Xcaddr_t handle;
Xchar *(*get_userid)();
X{

X register struct osf1_top_proc *pp;


X register long cputime;
X register double pct;

X int where;


X struct user u;
X struct handle *hp;
X
X /* find and remember the next proc structure */
X hp = (struct handle *)handle;
X pp = *(hp->next_proc++);
X hp->remaining--;
X
X /* get the process's user struct and set cputime */
X

X if (table(TBL_UAREA,pp->p_pid,&u,1,sizeof(struct user))<0) {
X /* whoops, it must have died between the read of the proc area
X * and now. Oh well, lets just dump some meaningless thing out
X * to keep the rest of the program happy
X */


X sprintf(fmt,
X Proc_format,
X pp->p_pid,

X (*get_userid)(pp->p_ruid),
X 0,
X 0,
X "",
X "",
X "dead",
X "",
X 0.0,
X "<dead>");
X return(fmt);
X }
X


X /* set u_comm for system processes */
X if (u.u_comm[0] == '\0')
X {
X if (pp->p_pid == 0)
X {

X (void) strcpy(u.u_comm, "[idle]");


X }
X else if (pp->p_pid == 2)
X {

X (void) strcpy(u.u_comm, "[execpt.hndlr]");
X }
X }
X if (where == 1) {


X /*
X * Print swapped processes as <pname>
X */

X char buf[sizeof(u.u_comm)];
X (void) strncpy(buf, u.u_comm, sizeof(u.u_comm));
X u.u_comm[0] = '<';
X (void) strncpy(&u.u_comm[1], buf, sizeof(u.u_comm) - 2);
X u.u_comm[sizeof(u.u_comm) - 2] = '\0';
X (void) strncat(u.u_comm, ">", sizeof(u.u_comm) - 1);

X u.u_comm[sizeof(u.u_comm) - 1] = '\0';
X }
X


X cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
X
X /* calculate the base for cpu percentages */

X pct = pctdouble(pp->p_mach_pct_cpu);


X
X /* format this entry */
X sprintf(fmt,
X Proc_format,
X pp->p_pid,

X (*get_userid)(pp->p_ruid),
X pp->p_pri,
X pp->p_nice,
X format_k(pp->p_mach_virt_size/1024),
X format_k(pp->p_rssize/1000),
X state_abbrev[pp->p_mach_state],
X format_time(cputime),
X 100.0 * ((double)pp->p_mach_pct_cpu / 10000.0),


X printable(u.u_comm));
X
X /* return the result */
X return(fmt);

X}
X
X/*


X * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
X * "offset" is the byte offset into the kernel for the desired value,
X * "ptr" points to a buffer into which the value is retrieved,
X * "size" is the size of the buffer (and the object to retrieve),
X * "refstr" is a reference string used when printing error meessages,
X * if "refstr" starts with a '!', then a failure on read will not
X * be fatal (this may seem like a silly way to do things, but I
X * really didn't want the overhead of another argument).

X *
X */
X

Xgetkval(offset, ptr, size, refstr)
X
Xunsigned long offset;
Xint *ptr;
Xint size;
Xchar *refstr;
X
X{

X if (lseek(kmem, (long)offset, L_SET) == -1) {

X if (*refstr == '!')

X refstr++;
X (void) fprintf(stderr, "%s: lseek to %s: %s\n", KMEM,

X refstr, strerror(errno));
X quit(23);
X }

X if (read(kmem, (char *) ptr, size) == -1) {

X if (*refstr == '!')

X return(0);
X else {
X (void) fprintf(stderr, "%s: reading %s: %s\n", KMEM,

X refstr, strerror(errno));
X quit(23);

X }
X }
X return(1);
X}
X

X/* comparison routine for qsort */
X
X/*


X * proc_compare - comparison function for "qsort"
X * Compares the resource consumption of two processes using five
X * distinct keys. The keys (in descending order of importance) are:
X * percent cpu, cpu ticks, state, resident set size, total virtual

X * memory usage. The process states are ordered as follows (from least
X * to most important): WAIT, zombie, sleep, stop, start, run. The array
X * declaration below maps a process state index into a number that
X * reflects this ordering.
X */
X


Xstatic unsigned char sorted_state[] =
X{

X 0, /*""*/
X 8, /*"run"*/
X 1, /*"WAIT"*/
X 6, /*"sleep"*/


X 5, /*"idle"*/

X 7, /*"stop"*/
X 4, /*"halt"*/
X 3, /*"???"*/
X 2, /*"zomb"*/


X};
X
Xproc_compare(pp1, pp2)
X

Xstruct osf1_top_proc **pp1;
Xstruct osf1_top_proc **pp2;
X
X{
X register struct osf1_top_proc *p1;
X register struct osf1_top_proc *p2;
X register int result;
X register pctcpu lresult=0.0;
X struct user u1, u2;


X
X /* remove one level of indirection */
X p1 = *pp1;
X p2 = *pp2;
X

X /* compare percent cpu (pctcpu) */

X if ((lresult = p2->p_mach_pct_cpu - p1->p_mach_pct_cpu) == 0)
X {


X /* use process state to break the tie */

X if ((result = sorted_state[p2->p_mach_state] -
X sorted_state[p1->p_mach_state]) == 0)
X {
X /* use elapsed time to break the tie */
X if ((result = p2->used_ticks - p1->used_ticks) == 0)
X {


X /* use priority to break the tie */

X if ((result = p2->p_pri - p1->p_pri) == 0)


X {
X /* use resident set size (rssize) to break the tie */

X if ((result = p2->p_rssize - p1->p_rssize) == 0)


X {
X /* use total memory to break the tie */

X result = p2->process_size - p1->process_size;


X }
X }
X }
X }
X }

X
X if(lresult)


X result = lresult < 0 ? -1 : 1;

X return(result);
X}
X
X/*


X * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
X * the process does not exist.
X * It is EXTREMLY IMPORTANT that this function work correctly.
X * If top runs setuid root (as in SVR4), then this function
X * is the only thing that stands in the way of a serious
X * security problem. It validates requests for the "kill"
X * and "renice" commands.
X */
X
Xint proc_owner(pid)
X
Xint pid;
X
X{
X register int cnt;

X register struct osf1_top_proc **prefp;
X register struct osf1_top_proc *pp;


X
X prefp = pref;
X cnt = pref_len;
X while (--cnt >= 0)
X {
X if ((pp = *prefp++)->p_pid == (pid_t)pid)
X {

X return((int)pp->p_ruid);


X }
X }
X return(-1);
X}

X
X
X/*
X * We use the Mach interface, as well as the table(UAREA,,,) call to
X * get some more information, then put it into unused fields in our
X * copy of the proc structure, to make it faster and easier to get at
X * later.
X */
Xvoid do_threads_calculations(thisproc)
Xstruct osf1_top_proc *thisproc;
X{
X int j;
X task_t thistask;
X task_basic_info_data_t taskinfo;
X unsigned int taskinfo_l;
X thread_array_t threadarr;
X unsigned int threadarr_l;
X thread_basic_info_t threadinfo;
X thread_basic_info_data_t threadinfodata;
X unsigned int threadinfo_l;
X int task_tot_cpu=0; /* total cpu usage of threads in a task */


X struct user u;
X

X thisproc->p_pri=0;
X thisproc->p_rssize=0;
X thisproc->p_mach_virt_size=0;
X thisproc->p_mach_state=0;
X thisproc->p_mach_pct_cpu=0;
X
X if(task_by_unix_pid(task_self(), thisproc->p_pid, &thistask)
X != KERN_SUCCESS){
X thisproc->p_mach_state=8; /* (zombie) */
X } else {
X taskinfo_l=TASK_BASIC_INFO_COUNT;
X if(task_info(thistask, TASK_BASIC_INFO, (task_info_t) &taskinfo,
X &taskinfo_l)
X != KERN_SUCCESS) {
X thisproc->p_mach_state=8; /* (zombie) */
X } else {
X int minim_state=99,mcurp=1000,mbasp=1000,mslpt=999;
X
X thisproc->p_rssize=taskinfo.resident_size;
X thisproc->p_mach_virt_size=taskinfo.virtual_size;
X
X (void) task_threads(thistask, &threadarr, &threadarr_l);
X threadinfo= &threadinfodata;
X for(j=0; j < threadarr_l; j++) {
X threadinfo_l=THREAD_BASIC_INFO_COUNT;
X if(thread_info(threadarr[j],THREAD_BASIC_INFO,
X (thread_info_t) threadinfo, &threadinfo_l) == KERN_SUCCESS) {
X
X task_tot_cpu += threadinfo->cpu_usage;
X if(minim_state>threadinfo->run_state)
X minim_state=threadinfo->run_state;
X if(mcurp>threadinfo->cur_priority)
X mcurp=threadinfo->cur_priority;
X if(mbasp>threadinfo->base_priority)
X mbasp=threadinfo->base_priority;
X if(mslpt>threadinfo->sleep_time)
X mslpt=threadinfo->sleep_time;
X }
X }
X switch (minim_state) {
X case TH_STATE_RUNNING:
X thisproc->p_mach_state=1; break;
X case TH_STATE_UNINTERRUPTIBLE:
X thisproc->p_mach_state=2; break;
X case TH_STATE_WAITING:
X thisproc->p_mach_state=(threadinfo->sleep_time > 20) ? 4 : 3; break;
X case TH_STATE_STOPPED:
X thisproc->p_mach_state=5; break;
X case TH_STATE_HALTED:
X thisproc->p_mach_state=6; break;
X default:
X thisproc->p_mach_state=7; break;
X }
X
X thisproc->p_pri=mcurp;
X thisproc->p_mach_pct_cpu=(fixpt_t)(task_tot_cpu*10);
X vm_deallocate(task_self(),(vm_address_t)threadarr,threadarr_l);
X }
X }
X if (table(TBL_UAREA,thisproc->p_pid,&u,1,sizeof(struct user))>=0) {
X thisproc->used_ticks=(u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec);
X thisproc->process_size=u.u_tsize + u.u_dsize + u.u_ssize;
X }
X}
X
X/* The reason for this function is that the system call will let
X * someone lower their own processes priority (because top is setuid :-(
X * Yes, using syscall() is a hack, if you can come up with something
X * better, then I'd be thrilled to hear it. I'm not holding my breath,
X * though.
X * Anthony.
X */
Xint setpriority(int dummy, int procnum, int niceval)
X{
X
X int uid, curprio;
X
X uid=getuid();
X if ( (curprio=getpriority(PRIO_PROCESS,procnum) ) == -1)
X {
X return(-1); /* errno goes back to renice_process() */
X }
X /* check for not-root - if so, dont allow users to decrease priority */
X else if ( uid && (niceval<curprio) )
X {
X errno=EACCES;
X return(-1);
X }
X return(syscall(SYS_setpriority,PRIO_PROCESS,procnum,niceval));
X}
END_OF_FILE
if test 23295 -ne `wc -c <'top-3.4/machine/m_decosf1.c'`; then
echo shar: \"'top-3.4/machine/m_decosf1.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_decosf1.c'
fi
if test -f 'top-3.4/machine/m_netbsd10.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_netbsd10.c'\"
else
echo shar: Extracting \"'top-3.4/machine/m_netbsd10.c'\" \(23192 characters\)
sed "s/^X//" >'top-3.4/machine/m_netbsd10.c' <<'END_OF_FILE'


X/*
X * top - a top users display for Unix
X *

X * SYNOPSIS: For a NetBSD-1.0 (4.4BSD) system


X * Note process resident sizes could be wrong, but ps shows
X * zero for them too..

X *
X * DESCRIPTION:

X * Originally written for BSD4.4 system by Christos Zoulas.

X * Based on the FreeBSD 2.0 version by Steven Wallace && Wolfram Schneider
X * NetBSD-1.0 port by Arne Helme
X * .
X * This is the machine-dependent module for NetBSD-1.0
X * Works for:
X * NetBSD-1.0


X *
X * LIBS: -lkvm

X *
X * CFLAGS: -DHAVE_GETOPT
X *


X * AUTHOR: Christos Zoulas <chri...@ee.cornell.edu>
X * Steven Wallace <swal...@freebsd.org>
X * Wolfram Schneider <wo...@cs.tu-berlin.de>

X * Arne Helme <ar...@acm.org>


X *
X * $Id: machine.c,v 1.5 1995/01/06 02:04:39 swallace Exp $
X */
X
X
X
X#define LASTPID /**/ /* use last pid, compiler depended */
X/* #define LASTPID_FIXED /**/
X#define VM_REAL /**/ /* use the same values as vmstat -s */
X#define USE_SWAP /**/ /* use swap usage (pstat -s),
X need to much cpu time */
X/* #define DEBUG 1 /**/

X
X#include <sys/types.h>
X#include <sys/signal.h>

X#include <sys/param.h>
X
X#include "os.h"
X#include <stdio.h>

X#include <nlist.h>
X#include <math.h>


X#include <kvm.h>
X#include <sys/errno.h>
X#include <sys/sysctl.h>
X#include <sys/dir.h>
X#include <sys/dkstat.h>
X#include <sys/file.h>
X#include <sys/time.h>
X
X#ifdef USE_SWAP
X#include <stdlib.h>

X#include <sys/map.h>


X#include <sys/conf.h>
X#endif
X
Xstatic int check_nlist __P((struct nlist *));
Xstatic int getkval __P((unsigned long, int *, int, char *));
Xextern char* printable __P((char *));

X
X#include "top.h"
X#include "machine.h"
X

X
X/* get_process_info passes back a handle. This is what it looks like: */
X
Xstruct handle
X{

X struct kinfo_proc **next_proc; /* points to next valid proc pointer */


X int remaining; /* number of pointers remaining */
X};
X

X/* declarations for load_avg */
X#include "loadavg.h"
X

X#define PP(pp, field) ((pp)->kp_proc . field)
X#define EP(pp, field) ((pp)->kp_eproc . field)
X#define VP(pp, field) ((pp)->kp_eproc.e_vm . field)

X
X/* define what weighted cpu is. */

X#define weighted_cpu(pct, pp) (PP((pp), p_swtime) == 0 ? 0.0 : \
X ((pct) / (1.0 - exp(PP((pp), p_swtime) * logcpu))))


X
X/* what we consider to be process size: */

X#define PROCSIZE(pp) (VP((pp), vm_tsize) + VP((pp), vm_dsize) + VP((pp), vm_ssize))

X
X/* definitions for indices in the nlist array */
X

X
Xstatic struct nlist nlst[] = {

X#define X_CCPU 0
X { "_ccpu" }, /* 0 */
X#define X_CP_TIME 1
X { "_cp_time" }, /* 1 */
X#define X_HZ 2
X { "_hz" }, /* 2 */
X#define X_STATHZ 3
X { "_stathz" }, /* 3 */
X#define X_AVENRUN 4

X { "_averunnable" }, /* 4 */
X
X#ifdef USE_SWAP
X#define VM_SWAPMAP 5
X { "_swapmap" }, /* list of free swap areas */
X#define VM_NSWAPMAP 6
X { "_nswapmap" },/* size of the swap map */
X#define VM_SWDEVT 7


X { "_swdevt" }, /* list of swap devices and sizes */

X#define VM_NSWAP 8


X { "_nswap" }, /* size of largest swap device */

X#define VM_NSWDEV 9


X { "_nswdev" }, /* number of swap devices */

X#define VM_DMMAX 10


X { "_dmmax" }, /* maximum size of a swap block */

X#define VM_NISWAP 11
X { "_niswap" },
X#define VM_NISWDEV 12
X { "_niswdev" },
X#endif /* USE_SWAP */
X
X#ifdef VM_REAL
X#ifdef USE_SWAP
X#define X_CNT 13


X#else
X#define X_CNT 5
X#endif
X { "_cnt" }, /* struct vmmeter cnt */
X#endif
X
X#ifdef LASTPID
X#if (defined USE_SWAP && defined VM_REAL)

X#define X_LASTPID 14


X#elif (defined VM_REAL)
X#define X_LASTPID 6
X#else
X#define X_LASTPID 5
X#endif
X#ifdef LASTPID_FIXED
X { "_nextpid" },
X#else
X { "_nextpid.178" }, /* lastpid, compiler depended
X * should be changed
X * in /sys/kern/kern_fork.c */
X#endif
X#endif
X
X { 0 }

X};
X
X/*


X * These definitions control the format of the per-process area
X */
X
Xstatic char header[] =
X " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";
X/* 0123456 -- field to fill in starts at header+6 */
X#define UNAME_START 6
X
X#define Proc_format \

X "%5d %-8.8s %3d %4d%7s %5s %-5s%7s %5.2f%% %5.2f%% %.14s"

X
X
X/* process state names for the "STATE" column of the display */
X/* the extra nulls in the string "run" are for adding a slash and
X the processor number when needed */
X
Xchar *state_abbrev[] =
X{

X "", "start", "run\0\0\0", "sleep", "stop", "zomb", "WAIT"
X};
X
X
Xstatic kvm_t *kd;

X
X/* values that we stash away in _init and use in later routines */
X
Xstatic double logcpu;

X
X/* these are retrieved from the kernel in _init */
X

Xstatic long hz;
Xstatic load_avg ccpu;

X
X/* these are offsets obtained via nlist and used in the get_ functions */
X

Xstatic unsigned long cp_time_offset;
Xstatic unsigned long avenrun_offset;
X#ifdef LASTPID
Xstatic unsigned long lastpid_offset;
Xstatic long lastpid;
X#endif
X#ifdef VM_REAL
Xstatic unsigned long cnt_offset;
Xstatic long cnt;
X#endif

X/* these are for calculating cpu state percentages */
X
Xstatic long cp_time[CPUSTATES];
Xstatic long cp_old[CPUSTATES];
Xstatic long cp_diff[CPUSTATES];

X
X/* these are for detailing the process states */
X
Xint process_states[7];
Xchar *procstatenames[] = {

X "", " starting, ", " running, ", " sleeping, ", " stopped, ",

X " zombie, ", " ABANDONED, ",


X NULL
X};
X
X/* these are for detailing the cpu states */
X

Xint cpu_states[CPUSTATES];
Xchar *cpustatenames[] = {
X "user", "nice", "system", "interrupt", "idle", NULL
X};
X


X/* these are for detailing the memory statistics */
X

Xint memory_stats[8];
Xchar *memorynames[] = {
X#ifndef VM_REAL
X "Real: ", "K/", "K ", "Virt: ", "K/",
X "K ", "Free: ", "K", NULL
X#else
X#if 0
X "K Act ", "K Inact ", "K Wired ", "K Free ", "% Swap, ",
X "K/", "K SWIO",
X#else
X "K Act ", "K Inact ", "K Wired ", "K Free ", "% Swap, ",
X "Kin ", "Kout",
X#endif
X NULL
X#endif

X};
X
X/* these are for keeping track of the proc array */
X

Xstatic int nproc;
Xstatic int onproc = -1;

Xstatic int pref_len;
Xstatic struct kinfo_proc *pbase;
Xstatic struct kinfo_proc **pref;


X
X/* these are for getting the memory statistics */
X

Xstatic int pageshift; /* log base 2 of the pagesize */
X
X/* define pagetok in terms of pageshift */
X
X#define pagetok(size) ((size) << pageshift)
X
X/* useful externals */

Xlong percentages();
X
Xint


Xmachine_init(statics)
X
Xstruct statics *statics;
X
X{

X register int i = 0;

X register int pagesize;
X
X if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL)
X return -1;

X
X
X /* get the list of symbols we want to access in the kernel */

X (void) kvm_nlist(kd, nlst);
X if (nlst[0].n_type == 0)
X {


X fprintf(stderr, "top: nlist failed\n");
X return(-1);
X }
X

X /* make sure they were all found */
X if (i > 0 && check_nlist(nlst) > 0)
X {
X return(-1);
X }
X
X /* get the symbol values out of kmem */

X (void) getkval(nlst[X_STATHZ].n_value, (int *)(&hz), sizeof(hz), "!");
X if (!hz) {
X (void) getkval(nlst[X_HZ].n_value, (int *)(&hz), sizeof(hz),
X nlst[X_HZ].n_name);
X }
X
X
X#if (defined DEBUG)
X fprintf(stderr, "Hertz: %d\n", hz);
X#endif
X

X (void) getkval(nlst[X_CCPU].n_value, (int *)(&ccpu), sizeof(ccpu),
X nlst[X_CCPU].n_name);
X

X /* stash away certain offsets for later use */

X cp_time_offset = nlst[X_CP_TIME].n_value;

X avenrun_offset = nlst[X_AVENRUN].n_value;

X#ifdef LASTPID
X lastpid_offset = nlst[X_LASTPID].n_value;
X#endif
X#ifdef VM_REAL

X cnt_offset = nlst[X_CNT].n_value;


X#endif
X
X /* this is used in calculating WCPU -- calculate it ahead of time */
X logcpu = log(loaddouble(ccpu));
X

X pbase = NULL;
X pref = NULL;
X nproc = 0;
X onproc = -1;

X /* get the page size with "getpagesize" and calculate pageshift from it */
X pagesize = getpagesize();
X pageshift = 0;
X while (pagesize > 1)
X {
X pageshift++;
X pagesize >>= 1;
X }
X
X /* we only need the amount of log(2)1024 for our conversion */
X pageshift -= LOG1024;
X

X /* fill in the statics information */
X statics->procstate_names = procstatenames;
X statics->cpustate_names = cpustatenames;
X statics->memory_names = memorynames;

X
X /* all done! */
X return(0);
X}
X
Xchar *format_header(uname_field)
X
Xregister char *uname_field;
X
X{
X register char *ptr;
X
X ptr = header + UNAME_START;
X while (*uname_field != '\0')
X {
X *ptr++ = *uname_field++;
X }
X
X return(header);
X}
X

Xstatic int swappgsin = -1;
Xstatic int swappgsout = -1;
Xextern struct timeval timeout;
X
Xvoid

Xget_system_info(si)
X
Xstruct system_info *si;
X
X{

X long total;


X load_avg avenrun[3];
X

X /* get the cp_time array */
X (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),

X nlst[X_CP_TIME].n_name);


X (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),

X nlst[X_AVENRUN].n_name);
X
X#ifdef LASTPID
X (void) getkval(lastpid_offset, (int *)(&lastpid), sizeof(lastpid),
X "!");
X#endif

X
X /* convert load averages to doubles */
X {
X register int i;
X register double *infoloadp;

X load_avg *avenrunp;
X
X#ifdef notyet
X struct loadavg sysload;
X int size;
X getkerninfo(KINFO_LOADAVG, &sysload, &size, 0);
X#endif

X
X infoloadp = si->load_avg;

X avenrunp = avenrun;


X for (i = 0; i < 3; i++)
X {

X#ifdef notyet
X *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
X#endif
X *infoloadp++ = loaddouble(*avenrunp++);

X }
X }
X
X /* convert cp_time counts to percentages */
X total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
X

X /* sum memory statistics */
X {
X

X#ifndef VM_REAL
X struct vmtotal total;
X int size = sizeof(total);
X static int mib[] = { CTL_VM, VM_METER };
X
X /* get total -- systemwide main memory usage structure */
X if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) {
X (void) fprintf(stderr, "top: sysctl failed: %s\n", strerror(errno));
X bzero(&total, sizeof(total));

X }
X /* convert memory stats to Kbytes */

X memory_stats[0] = -1;
X memory_stats[1] = pagetok(total.t_arm);
X memory_stats[2] = pagetok(total.t_rm);
X memory_stats[3] = -1;
X memory_stats[4] = pagetok(total.t_avm);
X memory_stats[5] = pagetok(total.t_vm);
X memory_stats[6] = -1;
X memory_stats[7] = pagetok(total.t_free);
X }
X#else
X struct vmmeter sum;
X static unsigned int swap_delay = 0;
X
X (void) getkval(cnt_offset, (int *)(&sum), sizeof(sum),

X "_cnt");
X


X /* convert memory stats to Kbytes */

X memory_stats[0] = pagetok(sum.v_active_count);
X memory_stats[1] = pagetok(sum.v_inactive_count);
X memory_stats[2] = pagetok(sum.v_wire_count);
X memory_stats[3] = pagetok(sum.v_free_count);
X
X if (swappgsin < 0) {
X memory_stats[5] = 0;
X memory_stats[6] = 0;
X } else {

X memory_stats[5] = pagetok(((sum.v_pswpin - swappgsin)));
X memory_stats[6] = pagetok(((sum.v_pswpout - swappgsout)));
X }
X swappgsin = sum.v_pswpin;
X swappgsout = sum.v_pswpout;


X
X#ifdef USE_SWAP
X if ((memory_stats[5] > 0 || memory_stats[6]) > 0 || swap_delay == 0) {
X memory_stats[4] = swapmode();
X }

X /* swap_delay++; XXX Arne */


X#else
X memory_stats[4] = 0;
X#endif
X
X
X memory_stats[7] = -1;
X }
X#endif

X /* set arrays and strings */
X si->cpustates = cpu_states;
X si->memory = memory_stats;

X#ifdef LASTPID
X if(lastpid > 0) {
X si->last_pid = lastpid;
X } else {
X si->last_pid = -1;
X }
X#else
X si->last_pid = -1;
X#endif
X

X}
X
Xstatic struct handle handle;
X
Xcaddr_t get_process_info(si, sel, compare)
X
Xstruct system_info *si;
Xstruct process_select *sel;
Xint (*compare)();
X
X{
X register int i;
X register int total_procs;
X register int active_procs;

X register struct kinfo_proc **prefp;

X register struct kinfo_proc *pp;


X
X /* these are copied out of sel for speed */
X int show_idle;
X int show_system;
X int show_uid;
X int show_command;
X
X

X pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc);
X if (nproc > onproc)
X pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *)
X * (onproc = nproc));
X if (pref == NULL || pbase == NULL) {
X (void) fprintf(stderr, "top: Out of memory.\n");
X quit(23);

X }
X /* get a pointer to the states summary array */
X si->procstates = process_states;
X
X /* set up flags which define what we are going to select */
X show_idle = sel->idle;
X show_system = sel->system;
X show_uid = sel->uid != -1;
X show_command = sel->command != NULL;
X
X /* count up process states and get pointers to interesting procs */
X total_procs = 0;
X active_procs = 0;

X memset((char *)process_states, 0, sizeof(process_states));


X prefp = pref;
X for (pp = pbase, i = 0; i < nproc; pp++, i++)
X {
X /*
X * Place pointers to each valid proc structure in pref[].
X * Process slots that are actually in use have a non-zero

X * status field. Processes with P_SYSTEM set are system


X * processes---these get ignored unless show_sysprocs is set.
X */

X if (PP(pp, p_stat) != 0 &&
X (show_system || ((PP(pp, p_flag) & P_SYSTEM) == 0)))
X {
X total_procs++;


X process_states[(unsigned char) PP(pp, p_stat)]++;
X if ((PP(pp, p_stat) != SZOMB) &&
X (show_idle || (PP(pp, p_pctcpu) != 0) ||

X (PP(pp, p_stat) == SRUN)) &&
X (!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t)sel->uid))


X {
X *prefp++ = pp;
X active_procs++;
X }
X }
X }
X
X /* if requested, sort the "interesting" processes */
X if (compare != NULL)
X {

X qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare);


X }
X
X /* remember active and total counts */
X si->p_total = total_procs;
X si->p_active = pref_len = active_procs;
X
X /* pass back a handle */
X handle.next_proc = pref;
X handle.remaining = active_procs;
X return((caddr_t)&handle);
X}
X

Xchar fmt[128]; /* static area where result is built */


X
Xchar *format_next_process(handle, get_userid)
X
Xcaddr_t handle;
Xchar *(*get_userid)();
X
X{

X register struct kinfo_proc *pp;


X register long cputime;
X register double pct;

X struct handle *hp;
X
X /* find and remember the next proc structure */
X hp = (struct handle *)handle;
X pp = *(hp->next_proc++);
X hp->remaining--;
X
X
X /* get the process's user struct and set cputime */

X if ((PP(pp, p_flag) & P_INMEM) == 0) {
X /*
X * Print swapped processes as <pname>
X */
X char *comm = PP(pp, p_comm);
X#define COMSIZ sizeof(PP(pp, p_comm))
X char buf[COMSIZ];
X (void) strncpy(buf, comm, COMSIZ);
X comm[0] = '<';
X (void) strncpy(&comm[1], buf, COMSIZ - 2);
X comm[COMSIZ - 2] = '\0';
X (void) strncat(comm, ">", COMSIZ - 1);
X comm[COMSIZ - 1] = '\0';
X }
X
X#if 0
X /* This does not produce the correct results */
X cputime = PP(pp, p_uticks) + PP(pp, p_sticks) + PP(pp, p_iticks);
X#endif
X cputime = PP(pp, p_rtime).tv_sec; /* This does not count interrupts */

X
X /* calculate the base for cpu percentages */

X pct = pctdouble(PP(pp, p_pctcpu));


X
X /* format this entry */
X sprintf(fmt,
X Proc_format,

X PP(pp, p_pid),
X (*get_userid)(EP(pp, e_pcred.p_ruid)),
X PP(pp, p_priority) - PZERO,

X PP(pp, p_nice) - NZERO,
X format_k(pagetok(PROCSIZE(pp))),


X format_k(pagetok(VP(pp, vm_rssize))),
X state_abbrev[(unsigned char) PP(pp, p_stat)],
X format_time(cputime),
X 10000.0 * weighted_cpu(pct, pp) / hz,
X 10000.0 * pct / hz,
X printable(PP(pp, p_comm)));

X
X /* return the result */
X return(fmt);
X}

X
X
X/*


X * check_nlist(nlst) - checks the nlist to see if any symbols were not
X * found. For every symbol that was not found, a one-line
X * message is printed to stderr. The routine returns the
X * number of symbols NOT found.
X */
X

Xstatic int check_nlist(nlst)


X
Xregister struct nlist *nlst;
X
X{
X register int i;
X
X /* check to see if we got ALL the symbols we requested */
X /* this will write one line to stderr for every symbol not found */
X
X i = 0;
X while (nlst->n_name != NULL)
X {

X if (nlst->n_type == 0)

X {
X /* this one wasn't found */

X (void) fprintf(stderr, "kernel: no symbol named `%s'\n",
X nlst->n_name);


X i = 1;
X }
X nlst++;
X }
X
X return(i);
X}

X
X
X/*


X * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
X * "offset" is the byte offset into the kernel for the desired value,
X * "ptr" points to a buffer into which the value is retrieved,
X * "size" is the size of the buffer (and the object to retrieve),
X * "refstr" is a reference string used when printing error meessages,
X * if "refstr" starts with a '!', then a failure on read will not
X * be fatal (this may seem like a silly way to do things, but I
X * really didn't want the overhead of another argument).

X *
X */
X

Xstatic int getkval(offset, ptr, size, refstr)


X
Xunsigned long offset;
Xint *ptr;
Xint size;
Xchar *refstr;
X
X{

X if (kvm_read(kd, offset, (char *) ptr, size) != size)


X {
X if (*refstr == '!')
X {
X return(0);
X }
X else
X {
X fprintf(stderr, "top: kvm_read for %s: %s\n",

X refstr, strerror(errno));
X quit(23);


X }
X }
X return(1);
X}
X

X/* comparison routine for qsort */
X
X/*


X * proc_compare - comparison function for "qsort"
X * Compares the resource consumption of two processes using five
X * distinct keys. The keys (in descending order of importance) are:
X * percent cpu, cpu ticks, state, resident set size, total virtual

X * memory usage. The process states are ordered as follows (from least
X * to most important): WAIT, zombie, sleep, stop, start, run. The
X * array declaration below maps a process state index into a number


X * that reflects this ordering.
X */
X

Xstatic unsigned char sorted_state[] =
X{
X 0, /* not used */
X 3, /* sleep */
X 1, /* ABANDONED (WAIT) */
X 6, /* run */
X 5, /* start */
X 2, /* zombie */
X 4 /* stop */
X};
X

Xint
Xproc_compare(pp1, pp2)


X
Xstruct proc **pp1;
Xstruct proc **pp2;
X
X{

X register struct kinfo_proc *p1;

X register struct kinfo_proc *p2;


X register int result;
X register pctcpu lresult;
X
X /* remove one level of indirection */

X p1 = *(struct kinfo_proc **) pp1;
X p2 = *(struct kinfo_proc **) pp2;
X
X /* compare percent cpu (pctcpu) */

X if ((lresult = PP(p2, p_pctcpu) - PP(p1, p_pctcpu)) == 0)
X {


X /* use cpticks to break the tie */

X if ((result = PP(p2, p_cpticks) - PP(p1, p_cpticks)) == 0)
X {


X /* use process state to break the tie */
X if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] -

X sorted_state[(unsigned char) PP(p1, p_stat)]) == 0)
X {


X /* use priority to break the tie */

X if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0)
X {


X /* use resident set size (rssize) to break the tie */

X if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0)
X {


X /* use total memory to break the tie */
X result = PROCSIZE(p2) - PROCSIZE(p1);

X }
X }
X }
X }
X }

X else
X {
X result = lresult < 0 ? -1 : 1;

X }
X
X return(result);
X}

X
X
X/*


X * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
X * the process does not exist.
X * It is EXTREMLY IMPORTANT that this function work correctly.
X * If top runs setuid root (as in SVR4), then this function
X * is the only thing that stands in the way of a serious
X * security problem. It validates requests for the "kill"
X * and "renice" commands.
X */
X
Xint proc_owner(pid)
X
Xint pid;
X
X{
X register int cnt;

X register struct kinfo_proc **prefp;

X register struct kinfo_proc *pp;


X
X prefp = pref;
X cnt = pref_len;
X while (--cnt >= 0)
X {

X pp = *prefp++;
X if (PP(pp, p_pid) == (pid_t)pid)
X {
X return((int)EP(pp, e_pcred.p_ruid));

X }
X }
X return(-1);
X}

X
X
X#ifdef USE_SWAP
X/*
X * swapmode is based on a program called swapinfo written
X * by Kevin Lahey <k...@rokkaku.atl.ga.us>.
X */
X
X#define SVAR(var) __STRING(var) /* to force expansion */
X#define KGET(idx, var) \
X KGET1(idx, &var, sizeof(var), SVAR(var))
X#define KGET1(idx, p, s, msg) \
X KGET2(nlst[idx].n_value, p, s, msg)
X#define KGET2(addr, p, s, msg) \
X if (kvm_read(kd, (u_long)(addr), p, s) != s) \
X warnx("cannot read %s: %s", msg, kvm_geterr(kd))
X#define KGETRET(addr, p, s, msg) \
X if (kvm_read(kd, (u_long)(addr), p, s) != s) { \
X warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \
X return (0); \
X }
X

Xint
Xswapmode()
X{
X char *header;
X int hlen, nswap, nswdev, dmmax, nswapmap, niswap, niswdev;
X int s, e, div, i, l, avail, nfree, npfree, used;


X struct swdevt *sw;
X long blocksize, *perdev;

X struct map *swapmap, *kswapmap;
X struct mapent *mp, *freemp;


X
X KGET(VM_NSWAP, nswap);
X KGET(VM_NSWDEV, nswdev);
X KGET(VM_DMMAX, dmmax);

X KGET(VM_NSWAPMAP, nswapmap);
X KGET(VM_SWAPMAP, kswapmap); /* kernel `swapmap' is a pointer */
X if ((sw = malloc(nswdev * sizeof(*sw))) == NULL ||
X (perdev = malloc(nswdev * sizeof(*perdev))) == NULL ||
X (freemp = mp = malloc(nswapmap * sizeof(*mp))) == NULL)


X err(1, "malloc");
X KGET1(VM_SWDEVT, sw, nswdev * sizeof(*sw), "swdevt");

X KGET2((long)kswapmap, mp, nswapmap * sizeof(*mp), "swapmap");
X
X /* Supports sequential swap */
X if (nlst[VM_NISWAP].n_value != 0) {
X KGET(VM_NISWAP, niswap);
X KGET(VM_NISWDEV, niswdev);
X } else {
X niswap = nswap;
X niswdev = nswdev;
X }
X
X /* First entry in map is `struct map'; rest are mapent's. */
X swapmap = (struct map *)mp;
X if (nswapmap != swapmap->m_limit - (struct mapent *)kswapmap)
X errx(1, "panic: nswapmap goof");


X
X /* Count up swap space. */
X nfree = 0;
X memset(perdev, 0, nswdev * sizeof(*perdev));

X for (mp++; mp->m_addr != 0; mp++) {
X s = mp->m_addr; /* start of swap region */
X e = mp->m_addr + mp->m_size; /* end of region */
X nfree += mp->m_size;
X
X /*


X * Swap space is split up among the configured disks.
X *
X * For interleaved swap devices, the first dmmax blocks
X * of swap space some from the first disk, the next dmmax

X * blocks from the next, and so on up to niswap blocks.
X *
X * Sequential swap devices follow the interleaved devices
X * (i.e. blocks starting at niswap) in the order in which
X * they appear in the swdev table. The size of each device
X * will be a multiple of dmmax.
X *


X * The list of free space joins adjacent free blocks,
X * ignoring device boundries. If we want to keep track
X * of this information per device, we'll just have to

X * extract it ourselves. We know that dmmax-sized chunks
X * cannot span device boundaries (interleaved or sequential)
X * so we loop over such chunks assigning them to devices.
X */
X i = -1;
X while (s < e) { /* XXX this is inefficient */
X int bound = roundup(s+1, dmmax);
X
X if (bound > e)
X bound = e;
X if (bound <= niswap) {
X /* Interleaved swap chunk. */
X if (i == -1)
X i = (s / dmmax) % niswdev;
X perdev[i] += bound - s;
X if (++i >= niswdev)
X i = 0;
X } else {
X /* Sequential swap chunk. */
X if (i < niswdev) {
X i = niswdev;
X l = niswap + sw[i].sw_nblks;
X }
X while (s >= l) {
X /* XXX don't die on bogus blocks */
X if (i == nswdev-1)
X break;
X l += sw[++i].sw_nblks;
X }
X perdev[i] += bound - s;
X }
X s = bound;
X }


X }
X
X header = getbsize(&hlen, &blocksize);
X div = blocksize / 512;
X avail = npfree = 0;
X for (i = 0; i < nswdev; i++) {
X int xsize, xfree;
X

X xsize = sw[i].sw_nblks;
X xfree = perdev[i];
X used = xsize - xfree;
X npfree++;
X avail += xsize;

X }
X
X /*

X * If only one partition has been set up via swapon(8), we don't
X * need to bother with totals.
X */
X used = avail - nfree;

X free (sw); free (freemp); free (perdev);


X return (int)(((double)used / (double)avail * 100.0) + 0.5);
X}
X
X
X#endif
X
END_OF_FILE

if test 23192 -ne `wc -c <'top-3.4/machine/m_netbsd10.c'`; then
echo shar: \"'top-3.4/machine/m_netbsd10.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_netbsd10.c'
fi
echo shar: End of archive 19 \(of 22\).
cp /dev/null ark19isdone

William Lefebvre

unread,
Sep 1, 1996, 3:00:00 AM9/1/96
to

Submitted-By: w...@groupsys.com (William Lefebvre)
Posting-Number: Volume 29, Issue 115
Archive-Name: top-3.4/part14

#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:

# "End of archive 15 (of 22)."
# Contents: top-3.4/machine/m_hpux7.c top-3.4/machine/m_ultrix4.c
# Wrapped by lefebvre@acapulco on Fri Aug 30 12:35:51 1996


PATH=/bin:/usr/bin:/usr/ucb ; export PATH

if test -f 'top-3.4/machine/m_hpux7.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_hpux7.c'\"
else
echo shar: Extracting \"'top-3.4/machine/m_hpux7.c'\" \(19787 characters\)
sed "s/^X//" >'top-3.4/machine/m_hpux7.c' <<'END_OF_FILE'


X/*
X * top - a top users display for Unix
X *

X * SYNOPSIS: any hp9000 running hpux version 7 or earlier


X *
X * DESCRIPTION:

X * This is the machine-dependent module for Hpux 6.5 and 7.0.


X * This makes top work on the following systems:

X * hp9000s300
X * hp9000s700
X * hp9000s800


X *
X * LIBS:
X *

X * AUTHOR: Christos Zoulas <chri...@ee.cornell.edu>

X */
X
X#include <sys/types.h>
X#include <sys/signal.h>
X#include <sys/param.h>
X

X#include <stdio.h>
X#include <nlist.h>
X#include <math.h>
X#include <sys/dir.h>
X#include <sys/user.h>
X#include <sys/proc.h>
X#include <sys/dk.h>
X#include <sys/vm.h>
X#include <sys/file.h>
X#include <sys/time.h>

X
X#include "top.h"
X#include "machine.h"

X#include "utils.h"
X
X#define VMUNIX "/hp-ux"


X#define KMEM "/dev/kmem"
X#define MEM "/dev/mem"

X#ifdef DOSWAP
X#define SWAP "/dev/swap"
X#endif


X
X/* get_process_info passes back a handle. This is what it looks like: */
X
Xstruct handle
X{

X struct proc **next_proc; /* points to next valid proc pointer */


X int remaining; /* number of pointers remaining */
X};
X
X/* declarations for load_avg */
X#include "loadavg.h"
X

X/* define what weighted cpu is. */

X#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
X ((pct) / (1.0 - exp((pp)->p_time * logcpu))))


X
X/* what we consider to be process size: */

X#define PROCSIZE(pp) ((pp)->p_tsize + (pp)->p_dsize + (pp)->p_ssize)

X
X/* definitions for indices in the nlist array */

X#define X_AVENRUN 0
X#define X_CCPU 1

X#define X_NPROC 2
X#define X_PROC 3
X#define X_TOTAL 4
X#define X_CP_TIME 5

X#ifdef hp9000s300
X# define X_USRPTMAP 6
X# define X_USRPT 7
X#else
X# define X_MPID 6
X# define X_HZ 7
X#endif
X#ifdef hp9000s800
X# define X_NPIDS 8
X# define X_UBASE 9
X#endif


X
Xstatic struct nlist nlst[] = {

X { "_avenrun" }, /* 0 */
X { "_ccpu" }, /* 1 */

X { "_nproc" }, /* 2 */
X { "_proc" }, /* 3 */
X { "_total" }, /* 4 */
X { "_cp_time" }, /* 5 */

X#ifdef hp9000s300
X { "_Usrptmap" }, /* 6 */
X { "_usrpt" }, /* 7 */
X#else


X { "_mpid" }, /* 6 */
X { "_hz" }, /* 7 */

X#endif
X#ifdef hp9000s800
X { "_npids" }, /* 8 */
X { "_ubase" }, /* 9 */
X#endif
X { 0 }
X};
X
X/*


X * These definitions control the format of the per-process area
X */
X
Xstatic char header[] =
X " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";

X/* 0123456 -- field to fill in starts at header+6 */
X#define UNAME_START 6
X
X#define Proc_format \

X "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %s"


X
X
X/* process state names for the "STATE" column of the display */
X/* the extra nulls in the string "run" are for adding a slash and
X the processor number when needed */
X
Xchar *state_abbrev[] =
X{

X "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"

X};
X
X
Xstatic int kmem, mem;

X#ifdef DOSWAP
Xstatic int swap;
X#endif

X
X/* values that we stash away in _init and use in later routines */
X
Xstatic double logcpu;
X
X/* these are retrieved from the kernel in _init */
X
Xstatic unsigned long proc;
Xstatic int nproc;

Xstatic long hz;
Xstatic load_avg ccpu;

Xstatic int ncpu = 0;

X
X/* these are offsets obtained via nlist and used in the get_ functions */
X

X#ifndef hp9000s300
Xstatic unsigned long mpid_offset;
X#endif
X#ifdef hp9000s300
Xstatic struct pte *Usrptmap, *usrpt;
X#endif
X#ifdef hp9000s800
Xstatic int npids;
Xchar *ubase;
X#endif


Xstatic unsigned long avenrun_offset;
Xstatic unsigned long total_offset;
Xstatic unsigned long cp_time_offset;

X


X/* these are for calculating cpu state percentages */
X
Xstatic long cp_time[CPUSTATES];
Xstatic long cp_old[CPUSTATES];
Xstatic long cp_diff[CPUSTATES];
X
X/* these are for detailing the process states */
X
Xint process_states[7];
Xchar *procstatenames[] = {

X "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",

X " zombie, ", " stopped, ",


X NULL
X};
X
X/* these are for detailing the cpu states */
X

X#ifdef hp9000s300
Xint cpu_states[9];
X#endif
X#ifdef hp9000s800
Xint cpu_states[5];
X#endif
Xchar *cpustatenames[] = {
X#ifdef hp9000s300
X "usr", "nice", "sys", "idle", "", "", "", "intr", "ker",
X#endif
X#ifdef hp9000s800
X "user", "nice", "system", "idle", "wait",
X#endif
X NULL
X};
X


X/* these are for detailing the memory statistics */
X
Xint memory_stats[8];
Xchar *memorynames[] = {

X "Real: ", "K/", "K act/tot ", "Virtual: ", "K/",

X "K act/tot ", "Free: ", "K", NULL
X};
X


X/* these are for keeping track of the proc array */
X
Xstatic int bytes;
Xstatic int pref_len;

Xstatic struct proc *pbase;
Xstatic struct proc **pref;


X
X/* these are for getting the memory statistics */
X
Xstatic int pageshift; /* log base 2 of the pagesize */
X
X/* define pagetok in terms of pageshift */
X
X#define pagetok(size) ((size) << pageshift)
X
X/* useful externals */

Xextern int errno;
Xextern char *sys_errlist[];
X

Xlong lseek();
Xlong time();
X


Xmachine_init(statics)
X
Xstruct statics *statics;
X
X{
X register int i = 0;
X register int pagesize;
X

X if ((kmem = open(KMEM, O_RDONLY)) == -1) {
X perror(KMEM);
X return(-1);
X }
X if ((mem = open(MEM, O_RDONLY)) == -1) {
X perror(MEM);
X return(-1);
X }
X

X#ifdef DOSWAP
X if ((swap = open(SWAP, O_RDONLY)) == -1) {
X perror(SWAP);
X return(-1);
X }
X#endif
X

X#ifdef hp9000s800
X /* 800 names don't have leading underscores */
X for (i = 0; nlst[i].n_name; nlst[i++].n_name++)
X continue;
X#endif


X
X /* get the list of symbols we want to access in the kernel */

X (void) nlist(VMUNIX, nlst);


X if (nlst[0].n_type == 0)
X {
X fprintf(stderr, "top: nlist failed\n");
X return(-1);
X }
X
X /* make sure they were all found */
X if (i > 0 && check_nlist(nlst) > 0)
X {
X return(-1);
X }
X
X /* get the symbol values out of kmem */

X (void) getkval(nlst[X_PROC].n_value, (int *)(&proc), sizeof(proc),
X nlst[X_PROC].n_name);
X (void) getkval(nlst[X_NPROC].n_value, &nproc, sizeof(nproc),
X nlst[X_NPROC].n_name);

X#ifndef hp9000s300


X (void) getkval(nlst[X_HZ].n_value, (int *)(&hz), sizeof(hz),
X nlst[X_HZ].n_name);

X#else
X hz = HZ;
X#endif


X (void) getkval(nlst[X_CCPU].n_value, (int *)(&ccpu), sizeof(ccpu),
X nlst[X_CCPU].n_name);

X#ifdef hp9000s800
X (void) getkval(nlst[X_NPIDS].n_value, (int *)(&npids), sizeof(npids),
X nlst[X_NPIDS].n_name);
X#endif


X
X /* stash away certain offsets for later use */

X#ifdef hp9000s800
X# ifndef UAREA
X ubase = nlst[X_UBASE].n_value;
X# else
X ubase = UAREA;
X# endif
X#endif
X#ifdef hp9000s300
X Usrptmap = (struct pte *) nlst[X_USRPTMAP].n_value;
X usrpt = (struct pte *) nlst[X_USRPT].n_value;
X#endif
X#ifndef hp9000s300


X mpid_offset = nlst[X_MPID].n_value;

X#endif


X avenrun_offset = nlst[X_AVENRUN].n_value;

X total_offset = nlst[X_TOTAL].n_value;

X cp_time_offset = nlst[X_CP_TIME].n_value;
X

X /* this is used in calculating WCPU -- calculate it ahead of time */
X logcpu = log(loaddouble(ccpu));
X

X /* allocate space for proc structure array and array of pointers */

X bytes = nproc * sizeof(struct proc);
X pbase = (struct proc *)malloc(bytes);

X pref = (struct proc **)malloc(nproc * sizeof(struct proc *));


X
X /* Just in case ... */

X if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
X {
X fprintf(stderr, "top: can't allocate sufficient memory\n");


X return(-1);
X }
X
X /* get the page size with "getpagesize" and calculate pageshift from it */
X pagesize = getpagesize();
X pageshift = 0;
X while (pagesize > 1)
X {
X pageshift++;
X pagesize >>= 1;
X }
X
X /* we only need the amount of log(2)1024 for our conversion */
X pageshift -= LOG1024;
X
X /* fill in the statics information */
X statics->procstate_names = procstatenames;
X statics->cpustate_names = cpustatenames;
X statics->memory_names = memorynames;
X

X /* all done! */
X return(0);
X}
X
Xchar *format_header(uname_field)
X
Xregister char *uname_field;
X
X{
X register char *ptr;
X
X ptr = header + UNAME_START;
X while (*uname_field != '\0')
X {
X *ptr++ = *uname_field++;
X }
X
X return(header);
X}
X

Xget_system_info(si)
X
Xstruct system_info *si;
X
X{

X load_avg avenrun[3];
X long total;

X
X /* get the cp_time array */
X (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),

X "_cp_time");
X
X /* get load average array */


X (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),

X "_avenrun");
X
X#ifndef hp9000s300
X /* get mpid -- process id of last process */


X (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
X "_mpid");

X#else
X si->last_pid = -1;
X#endif
X

X /* convert load averages to doubles */
X {
X register int i;
X register double *infoloadp;

X register load_avg *sysloadp;


X
X infoloadp = si->load_avg;

X sysloadp = avenrun;


X for (i = 0; i < 3; i++)
X {

X *infoloadp++ = loaddouble(*sysloadp++);


X }
X }
X
X /* convert cp_time counts to percentages */
X total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
X
X /* sum memory statistics */
X {

X struct vmtotal total;


X
X /* get total -- systemwide main memory usage structure */

X (void) getkval(total_offset, (int *)(&total), sizeof(total),
X "_total");

X /* convert memory stats to Kbytes */
X memory_stats[0] = -1;
X memory_stats[1] = pagetok(total.t_arm);
X memory_stats[2] = pagetok(total.t_rm);
X memory_stats[3] = -1;
X memory_stats[4] = pagetok(total.t_avm);
X memory_stats[5] = pagetok(total.t_vm);
X memory_stats[6] = -1;
X memory_stats[7] = pagetok(total.t_free);
X }
X

X /* set arrays and strings */
X si->cpustates = cpu_states;
X si->memory = memory_stats;

X}
X
Xstatic struct handle handle;
X
Xcaddr_t get_process_info(si, sel, compare)
X
Xstruct system_info *si;
Xstruct process_select *sel;
Xint (*compare)();
X
X{
X register int i;
X register int total_procs;
X register int active_procs;

X register struct proc **prefp;

X register struct proc *pp;


X
X /* these are copied out of sel for speed */
X int show_idle;
X int show_system;
X int show_uid;
X int show_command;
X

X /* read all the proc structures in one fell swoop */
X (void) getkval(proc, (int *)pbase, bytes, "proc array");

X
X /* get a pointer to the states summary array */
X si->procstates = process_states;
X

X /* set up flags which define what we are going to select */
X show_idle = sel->idle;
X show_system = sel->system;
X show_uid = sel->uid != -1;
X show_command = sel->command != NULL;
X
X /* count up process states and get pointers to interesting procs */
X total_procs = 0;
X active_procs = 0;
X memset((char *)process_states, 0, sizeof(process_states));
X prefp = pref;
X for (pp = pbase, i = 0; i < nproc; pp++, i++)
X {
X /*
X * Place pointers to each valid proc structure in pref[].
X * Process slots that are actually in use have a non-zero

X * status field. Processes with SSYS set are system
X * processes---these get ignored unless show_sysprocs is set.
X */

X if (pp->p_stat != 0 &&
X (show_system || ((pp->p_flag & SSYS) == 0)))
X {
X total_procs++;


X process_states[pp->p_stat]++;
X if ((pp->p_stat != SZOMB) &&

X (show_idle || (pp->p_pctcpu != 0) || (pp->p_stat == SRUN)) &&
X (!show_uid || pp->p_uid == (uid_t)sel->uid))


X {
X *prefp++ = pp;
X active_procs++;
X }
X }
X }
X
X /* if requested, sort the "interesting" processes */
X if (compare != NULL)
X {

X qsort((char *)pref, active_procs, sizeof(struct proc *), compare);


X }
X
X /* remember active and total counts */
X si->p_total = total_procs;
X si->p_active = pref_len = active_procs;
X
X /* pass back a handle */
X handle.next_proc = pref;
X handle.remaining = active_procs;
X return((caddr_t)&handle);
X}
X

Xchar fmt[MAX_COLS]; /* static area where result is built */


X
Xchar *format_next_process(handle, get_userid)
X
Xcaddr_t handle;
Xchar *(*get_userid)();
X
X{

X register struct proc *pp;


X register long cputime;
X register double pct;
X int where;
X struct user u;
X struct handle *hp;
X
X /* find and remember the next proc structure */
X hp = (struct handle *)handle;
X pp = *(hp->next_proc++);
X hp->remaining--;
X
X
X /* get the process's user struct and set cputime */

X where = getu(pp, &u);

X if (where == -1)


X {
X (void) strcpy(u.u_comm, "<swapped>");

X cputime = 0;


X }
X else
X {
X

X
X /* set u_comm for system processes */
X if (u.u_comm[0] == '\0')
X {
X if (pp->p_pid == 0)
X {

X (void) strcpy(u.u_comm, "Swapper");


X }
X else if (pp->p_pid == 2)
X {

X (void) strcpy(u.u_comm, "Pager");


X }
X }
X if (where == 1) {
X /*
X * Print swapped processes as <pname>
X */
X char buf[sizeof(u.u_comm)];
X (void) strncpy(buf, u.u_comm, sizeof(u.u_comm));
X u.u_comm[0] = '<';
X (void) strncpy(&u.u_comm[1], buf, sizeof(u.u_comm) - 2);
X u.u_comm[sizeof(u.u_comm) - 2] = '\0';
X (void) strncat(u.u_comm, ">", sizeof(u.u_comm) - 1);
X u.u_comm[sizeof(u.u_comm) - 1] = '\0';
X }
X
X cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
X }
X
X /* calculate the base for cpu percentages */

X pct = pctdouble(pp->p_pctcpu);


X
X /* format this entry */
X sprintf(fmt,
X Proc_format,
X pp->p_pid,

X (*get_userid)(pp->p_uid),
X pp->p_pri - PZERO,

X pp->p_nice - NZERO,
X format_k(pagetok(PROCSIZE(pp))),
X format_k(pagetok(pp->p_rssize)),
X state_abbrev[pp->p_stat],
X format_time(cputime),


X 100.0 * weighted_cpu(pct, pp),
X 100.0 * pct,

X printable(u.u_comm));
X
X /* return the result */
X return(fmt);

X}
X
X/*


X * getu(p, u) - get the user structure for the process whose proc structure
X * is pointed to by p. The user structure is put in the buffer pointed
X * to by u. Return 0 if successful, -1 on failure (such as the process
X * being swapped out).
X */
X

X#define USERSIZE sizeof(struct user)


X
Xgetu(p, u)
X
Xregister struct proc *p;
Xstruct user *u;
X
X{

X struct pte uptes[UPAGES];
X register caddr_t upage;
X register struct pte *pte;
X register nbytes, n;

X
X /*


X * Check if the process is currently loaded or swapped out. The way we
X * get the u area is totally different for the two cases. For this
X * application, we just don't bother if the process is swapped out.
X */
X if ((p->p_flag & SLOAD) == 0) {
X#ifdef DOSWAP
X if (lseek(swap, (long)dtob(p->p_swaddr), 0) == -1) {

X perror("lseek(swap)");
X return(-1);
X }
X if (read(swap, (char *) u, USERSIZE) != USERSIZE) {
X perror("read(swap)");
X return(-1);
X }


X return (1);
X#else
X return(-1);
X#endif

X }
X
X /*


X * Process is currently in memory, we hope!
X */
X if (!getkval((unsigned long)p->p_addr, (int *)uptes, sizeof(uptes),
X "!p->p_addr"))
X {
X#ifdef DEBUG
X perror("getkval(uptes)");
X#endif

X /* we can't seem to get to it, so pretend it's swapped out */
X return(-1);
X }
X upage = (caddr_t) u;


X pte = uptes;
X for (nbytes = USERSIZE; nbytes > 0; nbytes -= NBPG) {
X (void) lseek(mem, (long)(pte++->pg_pfnum * NBPG), 0);
X#ifdef DEBUG
X perror("lseek(mem)");
X#endif
X n = MIN(nbytes, NBPG);
X if (read(mem, upage, n) != n) {
X#ifdef DEBUG
X perror("read(mem)");
X#endif

X /* we can't seem to get to it, so pretend it's swapped out */
X return(-1);
X }


X upage += n;
X }

X return(0);
X}
X
X/*


X * check_nlist(nlst) - checks the nlist to see if any symbols were not
X * found. For every symbol that was not found, a one-line
X * message is printed to stderr. The routine returns the
X * number of symbols NOT found.
X */
X

Xint check_nlist(nlst)


X
Xregister struct nlist *nlst;
X
X{
X register int i;
X
X /* check to see if we got ALL the symbols we requested */
X /* this will write one line to stderr for every symbol not found */
X
X i = 0;
X while (nlst->n_name != NULL)
X {
X if (nlst->n_type == 0)
X {
X /* this one wasn't found */

X fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);


X i = 1;
X }
X nlst++;
X }
X
X return(i);
X}

X
X
X/*


X * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
X * "offset" is the byte offset into the kernel for the desired value,
X * "ptr" points to a buffer into which the value is retrieved,
X * "size" is the size of the buffer (and the object to retrieve),
X * "refstr" is a reference string used when printing error meessages,
X * if "refstr" starts with a '!', then a failure on read will not
X * be fatal (this may seem like a silly way to do things, but I
X * really didn't want the overhead of another argument).

X *
X */
X

X/* comparison routine for qsort */
X
X/*


X * proc_compare - comparison function for "qsort"
X * Compares the resource consumption of two processes using five
X * distinct keys. The keys (in descending order of importance) are:
X * percent cpu, cpu ticks, state, resident set size, total virtual
X * memory usage. The process states are ordered as follows (from least
X * to most important): WAIT, zombie, sleep, stop, start, run. The
X * array declaration below maps a process state index into a number
X * that reflects this ordering.
X */
X
Xstatic unsigned char sorted_state[] =
X{
X 0, /* not used */
X 3, /* sleep */
X 1, /* ABANDONED (WAIT) */
X 6, /* run */
X 5, /* start */
X 2, /* zombie */
X 4 /* stop */
X};
X

Xproc_compare(pp1, pp2)
X
Xstruct proc **pp1;
Xstruct proc **pp2;
X
X{

X register struct proc *p1;

X register struct proc *p2;


X register int result;
X register pctcpu lresult;
X
X /* remove one level of indirection */

X p1 = *pp1;
X p2 = *pp2;
X
X /* compare percent cpu (pctcpu) */

X if ((lresult = p2->p_pctcpu - p1->p_pctcpu) == 0)


X {
X /* use cpticks to break the tie */

X if ((result = p2->p_cpticks - p1->p_cpticks) == 0)


X {
X /* use process state to break the tie */

X if ((result = sorted_state[p2->p_stat] -
X sorted_state[p1->p_stat]) == 0)


X {
X /* use priority to break the tie */

X if ((result = p2->p_pri - p1->p_pri) == 0)
X {
X /* use resident set size (rssize) to break the tie */
X if ((result = p2->p_rssize - p1->p_rssize) == 0)
X {
X /* use total memory to break the tie */

X result = PROCSIZE(p2) - PROCSIZE(p1);
X }
X }
X }
X }
X }
X else
X {
X result = lresult < 0 ? -1 : 1;
X }
X
X return(result);
X}
X
X

Xvoid (*signal(sig, func))()
X int sig;
X void (*func)();
X{
X struct sigvec osv, sv;
X
X /*
X * XXX: we should block the signal we are playing with,
X * in case we get interrupted in here.
X */
X if (sigvector(sig, NULL, &osv) == -1)
X return BADSIG;
X sv = osv;
X sv.sv_handler = func;
X#ifdef SV_BSDSIG
X sv.sv_flags |= SV_BSDSIG;
X#endif
X if (sigvector(sig, &sv, NULL) == -1)
X return BADSIG;
X return osv.sv_handler;
X}
X
Xint getpagesize() { return 1 << PGSHIFT; }
X
Xint setpriority(a, b, c) { errno = ENOSYS; return -1; }


X
X/*
X * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
X * the process does not exist.
X * It is EXTREMLY IMPORTANT that this function work correctly.
X * If top runs setuid root (as in SVR4), then this function
X * is the only thing that stands in the way of a serious
X * security problem. It validates requests for the "kill"
X * and "renice" commands.
X */
X
Xint proc_owner(pid)
X
Xint pid;
X
X{
X register int cnt;

X register struct proc **prefp;

X register struct proc *pp;


X
X prefp = pref;
X cnt = pref_len;
X while (--cnt >= 0)
X {
X if ((pp = *prefp++)->p_pid == (pid_t)pid)
X {

X return((int)pp->p_uid);


X }
X }
X return(-1);
X}

END_OF_FILE
if test 19787 -ne `wc -c <'top-3.4/machine/m_hpux7.c'`; then
echo shar: \"'top-3.4/machine/m_hpux7.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_hpux7.c'
fi
if test -f 'top-3.4/machine/m_ultrix4.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_ultrix4.c'\"
else
echo shar: Extracting \"'top-3.4/machine/m_ultrix4.c'\" \(19643 characters\)
sed "s/^X//" >'top-3.4/machine/m_ultrix4.c' <<'END_OF_FILE'


X/*
X * top - a top users display for Unix
X *

X * SYNOPSIS: any DEC running ULTRIX V4.2 or later


X *
X * DESCRIPTION:

X * This is the machine-dependent module for ULTRIX V4.x
X * It should work on any DEC (mips or VAX) running V4.0 or later.
X *


X * LIBS:
X *

X * AUTHOR: David S. Comay <d...@seismo.css.gov>
X * patches: Alex A. Sergejew <a...@swin.oz.au>
X * Jeff White <jwh...@isdpvbds1.isd.csc.com>


X */
X
X#include <sys/types.h>
X#include <sys/signal.h>
X#include <sys/param.h>
X

X#include <stdio.h>
X#include <nlist.h>
X#include <math.h>
X#include <sys/dir.h>
X#include <sys/user.h>
X#include <sys/proc.h>
X#include <sys/dk.h>
X#include <sys/vm.h>
X#include <sys/file.h>
X#include <sys/time.h>

X#include <machine/pte.h>
X#ifdef _SIZE_T_
X#include <sys/cpudata.h>
X#endif
X
X/* #define DOSWAP */
X
X#include "top.h"


X#include "machine.h"
X
Xextern int errno, sys_nerr;
Xextern char *sys_errlist[];
X#define strerror(e) (((e) >= 0 && (e) < sys_nerr) ? sys_errlist[(e)] : "Unknown error")
X
X#define VMUNIX "/vmunix"
X#define KMEM "/dev/kmem"
X#define MEM "/dev/mem"

X#ifdef DOSWAP
X#define SWAP "/dev/drum"
X#endif

X
X/* get_process_info passes back a handle. This is what it looks like: */
X
Xstruct handle
X{

X struct proc **next_proc; /* points to next valid proc pointer */


X int remaining; /* number of pointers remaining */
X};
X
X/* declarations for load_avg */
X#include "loadavg.h"
X

X/* define what weighted cpu is. */

X#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
X ((pct) / (1.0 - exp((pp)->p_time * logcpu))))


X
X/* what we consider to be process size: */

X#define PROCSIZE(pp) ((pp)->p_tsize + (pp)->p_dsize + (pp)->p_ssize)

X
X/* definitions for indices in the nlist array */

X#define X_AVENRUN 0
X#define X_CCPU 1

X#define X_NPROC 2
X#define X_PROC 3
X#define X_TOTAL 4

X#define X_CPUDATA 5


X#define X_MPID 6
X#define X_HZ 7

X#define X_LOWCPU 8
X#define X_HIGHCPU 9
X


Xstatic struct nlist nlst[] = {

X { "_avenrun" }, /* 0 */
X { "_ccpu" }, /* 1 */

X { "_nproc" }, /* 2 */
X { "_proc" }, /* 3 */
X { "_total" }, /* 4 */
X { "_cpudata" }, /* 5 */
X { "_mpid" }, /* 6 */
X { "_hz" }, /* 7 */
X { "_lowcpu" }, /* 8 */
X { "_highcpu" }, /* 9 */
X { 0 }
X};
X
X/*


X * These definitions control the format of the per-process area
X */
X
Xstatic char header[] =
X " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";

X/* 0123456 -- field to fill in starts at header+6 */
X#define UNAME_START 6
X
X#define Proc_format \

X "%5d %-8.8s %3d %4d %5s %5s %-5s%4d:%02d %5.2f%% %5.2f%% %.16s"


X
X
X/* process state names for the "STATE" column of the display */
X/* the extra nulls in the string "run" are for adding a slash and
X the processor number when needed */
X
Xchar *state_abbrev[] =
X{

X "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"

X};
X
X
Xstatic int kmem, mem;

X#ifdef DOSWAP
Xstatic int swap;
X#endif

X
X/* values that we stash away in _init and use in later routines */
X
Xstatic double logcpu;
X
X/* these are retrieved from the kernel in _init */
X
Xstatic unsigned long proc;
Xstatic int nproc;

Xstatic long hz;
Xstatic load_avg ccpu;

Xstatic int lowcpu = 0;
Xstatic int highcpu = 0;


X
X/* these are offsets obtained via nlist and used in the get_ functions */
X

Xstatic unsigned long avenrun_offset;
Xstatic unsigned long mpid_offset;
Xstatic unsigned long total_offset;
Xstatic unsigned long cpudata_offset;
X


X/* these are for calculating cpu state percentages */
X
Xstatic long cp_time[CPUSTATES];
Xstatic long cp_old[CPUSTATES];
Xstatic long cp_diff[CPUSTATES];

Xstatic struct cpudata *cpudata[MAXCPU];


X
X/* these are for detailing the process states */
X
Xint process_states[7];
Xchar *procstatenames[] = {

X "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",

X " zombie, ", " stopped, ",


X NULL
X};
X
X/* these are for detailing the cpu states */
X
Xint cpu_states[4];
Xchar *cpustatenames[] = {
X "user", "nice", "system", "idle", NULL
X};
X

X/* these are for detailing the memory statistics */
X
Xint memory_stats[8];
Xchar *memorynames[] = {

X "Real: ", "K/", "K act/tot ", "Virtual: ", "K/",

X "K act/tot ", "Free: ", "K", NULL
X};
X


X/* these are for keeping track of the proc array */
X
Xstatic int bytes;
Xstatic int pref_len;

Xstatic struct proc *pbase;
Xstatic struct proc **pref;


X
X/* these are for getting the memory statistics */
X
Xstatic int pageshift; /* log base 2 of the pagesize */
X
X/* define pagetok in terms of pageshift */
X
X#define pagetok(size) ((size) << pageshift)
X
X/* useful externals */

Xextern int errno;
Xextern char *sys_errlist[];
X

Xlong lseek();
Xlong percentages();
X


Xmachine_init(statics)
X
Xstruct statics *statics;
X
X{
X register int i = 0;
X register int pagesize;
X

X if ((kmem = open(KMEM, O_RDONLY)) == -1) {
X perror(KMEM);
X return(-1);
X }
X if ((mem = open(MEM, O_RDONLY)) == -1) {
X perror(MEM);
X return(-1);
X }
X

X#ifdef DOSWAP
X if ((swap = open(SWAP, O_RDONLY)) == -1) {
X perror(SWAP);
X return(-1);
X }
X#endif

X
X /* get the list of symbols we want to access in the kernel */

X (void) nlist(VMUNIX, nlst);


X if (nlst[0].n_type == 0)
X {
X fprintf(stderr, "top: nlist failed\n");
X return(-1);
X }
X
X /* make sure they were all found */
X if (i > 0 && check_nlist(nlst) > 0)
X {
X return(-1);
X }
X
X /* get the symbol values out of kmem */

X (void) getkval(nlst[X_PROC].n_value, (int *)(&proc), sizeof(proc),
X nlst[X_PROC].n_name);
X (void) getkval(nlst[X_NPROC].n_value, &nproc, sizeof(nproc),
X nlst[X_NPROC].n_name);

X (void) getkval(nlst[X_HZ].n_value, (int *)(&hz), sizeof(hz),
X nlst[X_HZ].n_name);

X (void) getkval(nlst[X_CCPU].n_value, (int *)(&ccpu), sizeof(ccpu),
X nlst[X_CCPU].n_name);

X (void) getkval(nlst[X_LOWCPU].n_value, (int *)(&lowcpu), sizeof(lowcpu),
X nlst[X_LOWCPU].n_name);
X (void) getkval(nlst[X_HIGHCPU].n_value, (int *)(&highcpu), sizeof(highcpu),
X nlst[X_HIGHCPU].n_name);


X
X /* stash away certain offsets for later use */

X mpid_offset = nlst[X_MPID].n_value;

X avenrun_offset = nlst[X_AVENRUN].n_value;

X total_offset = nlst[X_TOTAL].n_value;

X cpudata_offset = nlst[X_CPUDATA].n_value;


X
X /* this is used in calculating WCPU -- calculate it ahead of time */
X logcpu = log(loaddouble(ccpu));
X

X /* allocate space for proc structure array and array of pointers */

X bytes = nproc * sizeof(struct proc);
X pbase = (struct proc *)malloc(bytes);

X pref = (struct proc **)malloc(nproc * sizeof(struct proc *));


X
X /* Just in case ... */

X if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
X {
X fprintf(stderr, "top: can't allocate sufficient memory\n");


X return(-1);
X }
X
X /* get the page size with "getpagesize" and calculate pageshift from it */
X pagesize = getpagesize();
X pageshift = 0;
X while (pagesize > 1)
X {
X pageshift++;
X pagesize >>= 1;
X }
X
X /* we only need the amount of log(2)1024 for our conversion */
X pageshift -= LOG1024;
X
X /* fill in the statics information */
X statics->procstate_names = procstatenames;
X statics->cpustate_names = cpustatenames;
X statics->memory_names = memorynames;
X

X /* all done! */
X return(0);
X}
X
Xchar *format_header(uname_field)
X
Xregister char *uname_field;
X
X{
X register char *ptr;
X
X ptr = header + UNAME_START;
X while (*uname_field != '\0')
X {
X *ptr++ = *uname_field++;
X }
X
X return(header);
X}
X

Xget_system_info(si)
X
Xstruct system_info *si;
X
X{

X load_avg avenrun[3];
X long total;

X register int i;
X register int ncpu;
X struct cpudata cpu;
X
X for (i = 0; i < CPUSTATES; ++i)
X {
X cp_time[i] = 0;
X }
X (void) getkval(cpudata_offset, cpudata, sizeof(cpudata), "_cpudata");
X for (ncpu = lowcpu; ncpu <= highcpu; ++ncpu)
X {
X if (cpudata[ncpu] != NULL) {
X (void) getkval(cpudata[ncpu], &cpu, sizeof(cpu), "???");
X if (cpu.cpu_state & CPU_RUN)
X {
X for (i = 0; i < CPUSTATES; ++i)
X {
X cp_time[i] += cpu.cpu_cptime[i];


X }
X }
X }
X }
X

X /* get load average array */

X (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),

X "_avenrun");
X
X /* get mpid -- process id of last process */


X (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
X "_mpid");
X

X /* convert load averages to doubles */
X {
X register int i;
X register double *infoloadp;

X register load_avg *sysloadp;


X
X infoloadp = si->load_avg;

X sysloadp = avenrun;


X for (i = 0; i < 3; i++)
X {

X *infoloadp++ = loaddouble(*sysloadp++);


X }
X }
X
X /* convert cp_time counts to percentages */
X total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
X
X /* sum memory statistics */
X {

X struct vmtotal total;


X
X /* get total -- systemwide main memory usage structure */

X (void) getkval(total_offset, (int *)(&total), sizeof(total),
X "_total");

X /* convert memory stats to Kbytes */
X memory_stats[0] = -1;
X memory_stats[1] = pagetok(total.t_arm);
X memory_stats[2] = pagetok(total.t_rm);
X memory_stats[3] = -1;
X memory_stats[4] = pagetok(total.t_avm);
X memory_stats[5] = pagetok(total.t_vm);
X memory_stats[6] = -1;
X memory_stats[7] = pagetok(total.t_free);
X }
X

X /* set arrays and strings */
X si->cpustates = cpu_states;
X si->memory = memory_stats;

X}
X
Xstatic struct handle handle;
X
Xcaddr_t get_process_info(si, sel, compare)
X
Xstruct system_info *si;
Xstruct process_select *sel;
Xint (*compare)();
X
X{
X register int i;
X register int total_procs;
X register int active_procs;

X register struct proc **prefp;

X register struct proc *pp;


X
X /* these are copied out of sel for speed */
X int show_idle;
X int show_system;
X int show_uid;
X int show_command;
X

X /* read all the proc structures in one fell swoop */
X (void) getkval(proc, (int *)pbase, bytes, "proc array");

X
X /* get a pointer to the states summary array */
X si->procstates = process_states;
X

X /* set up flags which define what we are going to select */
X show_idle = sel->idle;
X show_system = sel->system;
X show_uid = sel->uid != -1;
X show_command = sel->command != NULL;
X
X /* count up process states and get pointers to interesting procs */
X total_procs = 0;
X active_procs = 0;
X memset((char *)process_states, 0, sizeof(process_states));
X prefp = pref;
X for (pp = pbase, i = 0; i < nproc; pp++, i++)
X {
X /*
X * Place pointers to each valid proc structure in pref[].
X * Process slots that are actually in use have a non-zero

X * status field. Processes with SSYS set are system
X * processes---these get ignored unless show_sysprocs is set.
X */

X if (pp->p_stat != 0 && pp->p_stat != SIDL &&
X (show_system || ((pp->p_type & SSYS) == 0)))
X {
X total_procs++;


X process_states[pp->p_stat]++;

X if ((pp->p_stat != SZOMB) &&
X (pp->p_stat != SIDL) &&
X#ifdef vax
X (show_idle || (pp->p_pctcpu != 0.0) || (pp->p_stat == SRUN)) &&
X (!show_uid || pp->p_uid == (uid_t)sel->uid))
X#else
X (show_idle || (pp->p_pctcpu != 0) || (pp->p_stat == SRUN)) &&
X (!show_uid || pp->p_uid == (uid_t)sel->uid))
X#endif


X {
X *prefp++ = pp;
X active_procs++;
X }
X }
X }
X
X /* if requested, sort the "interesting" processes */
X if (compare != NULL)
X {

X qsort((char *)pref, active_procs, sizeof(struct proc *), compare);


X }
X
X /* remember active and total counts */
X si->p_total = total_procs;
X si->p_active = pref_len = active_procs;
X
X /* pass back a handle */
X handle.next_proc = pref;
X handle.remaining = active_procs;
X return((caddr_t)&handle);
X}
X

Xchar fmt[MAX_COLS]; /* static area where result is built */


X
Xchar *format_next_process(handle, get_userid)
X
Xcaddr_t handle;
Xchar *(*get_userid)();
X
X{

X register struct proc *pp;


X register long cputime;
X register double pct;
X int where;
X struct user u;
X struct handle *hp;
X
X /* find and remember the next proc structure */
X hp = (struct handle *)handle;
X pp = *(hp->next_proc++);
X hp->remaining--;
X
X
X /* get the process's user struct and set cputime */

X where = getu(pp, &u);

X if (where == -1)


X {
X (void) strcpy(u.u_comm, "<swapped>");

X cputime = 0;


X }
X else
X {
X

X
X /* set u_comm for system processes */
X if (u.u_comm[0] == '\0')
X {
X if (pp->p_pid == 0)
X {

X (void) strcpy(u.u_comm, "Swapper");


X }
X else if (pp->p_pid == 2)
X {

X (void) strcpy(u.u_comm, "Pager");


X }
X }
X if (where == 1) {
X /*
X * Print swapped processes as <pname>
X */
X char buf[sizeof(u.u_comm)];
X (void) strncpy(buf, u.u_comm, sizeof(u.u_comm));
X u.u_comm[0] = '<';
X (void) strncpy(&u.u_comm[1], buf, sizeof(u.u_comm) - 2);
X u.u_comm[sizeof(u.u_comm) - 2] = '\0';
X (void) strncat(u.u_comm, ">", sizeof(u.u_comm) - 1);
X u.u_comm[sizeof(u.u_comm) - 1] = '\0';
X }
X
X cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
X }
X
X /* calculate the base for cpu percentages */

X pct = pctdouble(pp->p_pctcpu);


X
X /* format this entry */
X sprintf(fmt,
X Proc_format,
X pp->p_pid,

X (*get_userid)(pp->p_uid),
X pp->p_pri - PZERO,

X pp->p_nice - NZERO,
X format_k(pagetok(PROCSIZE(pp))),


X format_k(pagetok(pp->p_rssize)),
X state_abbrev[pp->p_stat],

X cputime / 60l,
X cputime % 60l,


X 100.0 * weighted_cpu(pct, pp),
X 100.0 * pct,

X printable(u.u_comm));
X
X /* return the result */
X return(fmt);

X}
X
X/*


X * getu(p, u) - get the user structure for the process whose proc structure
X * is pointed to by p. The user structure is put in the buffer pointed
X * to by u. Return 0 if successful, -1 on failure (such as the process
X * being swapped out).
X */
X

X#ifdef ibm032
Xstatic struct alignuser {
X char userfill[UPAGES*NBPG-sizeof (struct user)];
X struct user user;
X} au;
X# define USERSIZE sizeof(struct alignuser)
X# define GETUSER(b) (&au)
X# define SETUSER(b) *(b) = au.user
X#else
X# define USERSIZE sizeof(struct user)
X# define GETUSER(b) (b)
X# define SETUSER(b) /* Nothing */
X#endif

X
Xgetu(p, u)
X
Xregister struct proc *p;
Xstruct user *u;
X
X{

X struct pte uptes[UPAGES];
X register caddr_t upage;
X register struct pte *pte;
X register nbytes, n;

X
X /*


X * Check if the process is currently loaded or swapped out. The way we
X * get the u area is totally different for the two cases. For this
X * application, we just don't bother if the process is swapped out.
X */

X if ((p->p_sched & SLOAD) == 0) {


X#ifdef DOSWAP
X if (lseek(swap, (long)dtob(p->p_swaddr), 0) == -1) {

X perror("lseek(swap)");
X return(-1);
X }


X if (read(swap, (char *) GETUSER(u), USERSIZE) != USERSIZE) {

X perror("read(swap)");
X return(-1);
X }


X SETUSER(u);
X return (1);
X#else
X return(-1);
X#endif

X }
X
X /*


X * Process is currently in memory, we hope!
X */
X if (!getkval((unsigned long)p->p_addr, (int *)uptes, sizeof(uptes),
X "!p->p_addr"))
X {
X#ifdef DEBUG
X perror("getkval(uptes)");
X#endif

X /* we can't seem to get to it, so pretend it's swapped out */
X return(-1);
X }

X upage = (caddr_t) GETUSER(u);
X pte = uptes;
X for (nbytes = USERSIZE; nbytes > 0; nbytes -= NBPG) {
X (void) lseek(mem, (long)(pte++->pg_pfnum * NBPG), 0);
X#ifdef DEBUG
X perror("lseek(mem)");
X#endif
X n = MIN(nbytes, NBPG);
X if (read(mem, upage, n) != n) {
X#ifdef DEBUG
X perror("read(mem)");
X#endif

X /* we can't seem to get to it, so pretend it's swapped out */
X return(-1);
X }


X upage += n;
X }
X SETUSER(u);
X return(0);

X}
X
X/*


X * check_nlist(nlst) - checks the nlist to see if any symbols were not
X * found. For every symbol that was not found, a one-line
X * message is printed to stderr. The routine returns the
X * number of symbols NOT found.
X */
X

Xint check_nlist(nlst)


X
Xregister struct nlist *nlst;
X
X{
X register int i;
X
X /* check to see if we got ALL the symbols we requested */
X /* this will write one line to stderr for every symbol not found */
X
X i = 0;
X while (nlst->n_name != NULL)
X {
X if (nlst->n_type == 0)
X {
X /* this one wasn't found */

X fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);


X i = 1;
X }
X nlst++;
X }
X
X return(i);
X}

X
X
X/*


X * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
X * "offset" is the byte offset into the kernel for the desired value,
X * "ptr" points to a buffer into which the value is retrieved,
X * "size" is the size of the buffer (and the object to retrieve),
X * "refstr" is a reference string used when printing error meessages,
X * if "refstr" starts with a '!', then a failure on read will not
X * be fatal (this may seem like a silly way to do things, but I
X * really didn't want the overhead of another argument).

X *
X */
X

X/* comparison routine for qsort */
X
X/*


X * proc_compare - comparison function for "qsort"
X * Compares the resource consumption of two processes using five
X * distinct keys. The keys (in descending order of importance) are:
X * percent cpu, cpu ticks, state, resident set size, total virtual
X * memory usage. The process states are ordered as follows (from least
X * to most important): WAIT, zombie, sleep, stop, start, run. The
X * array declaration below maps a process state index into a number
X * that reflects this ordering.
X */
X
Xstatic unsigned char sorted_state[] =
X{
X 0, /* not used */
X 3, /* sleep */
X 1, /* ABANDONED (WAIT) */
X 6, /* run */
X 5, /* start */
X 2, /* zombie */
X 4 /* stop */
X};
X

Xproc_compare(pp1, pp2)
X
Xstruct proc **pp1;
Xstruct proc **pp2;
X
X{

X register struct proc *p1;

X register struct proc *p2;


X register int result;
X register pctcpu lresult;
X
X /* remove one level of indirection */

X p1 = *pp1;
X p2 = *pp2;
X
X /* compare percent cpu (pctcpu) */

X#ifdef vax
X if ((lresult = p2->p_pctcpu - p1->p_pctcpu) == 0.0)
X#else


X if ((lresult = p2->p_pctcpu - p1->p_pctcpu) == 0)

X#endif


X {
X /* use cpticks to break the tie */

X if ((result = p2->p_cpticks - p1->p_cpticks) == 0)


X {
X /* use process state to break the tie */

X if ((result = sorted_state[p2->p_stat] -
X sorted_state[p1->p_stat]) == 0)


X {
X /* use priority to break the tie */

X if ((result = p2->p_pri - p1->p_pri) == 0)
X {
X /* use resident set size (rssize) to break the tie */
X if ((result = p2->p_rssize - p1->p_rssize) == 0)
X {
X /* use total memory to break the tie */

X result = PROCSIZE(p2) - PROCSIZE(p1);
X }
X }
X }
X }
X }
X else
X {
X result = lresult < 0 ? -1 : 1;
X }
X
X return(result);

X}
X
X/*


X * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
X * the process does not exist.
X * It is EXTREMLY IMPORTANT that this function work correctly.
X * If top runs setuid root (as in SVR4), then this function
X * is the only thing that stands in the way of a serious
X * security problem. It validates requests for the "kill"
X * and "renice" commands.
X */
X
Xint proc_owner(pid)
X
Xint pid;
X
X{
X register int cnt;

X register struct proc **prefp;

X register struct proc *pp;


X
X prefp = pref;
X cnt = pref_len;
X while (--cnt >= 0)
X {
X if ((pp = *prefp++)->p_pid == (pid_t)pid)
X {

X return((int)pp->p_uid);


X }
X }
X return(-1);
X}

END_OF_FILE
if test 19643 -ne `wc -c <'top-3.4/machine/m_ultrix4.c'`; then
echo shar: \"'top-3.4/machine/m_ultrix4.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_ultrix4.c'
fi
echo shar: End of archive 15 \(of 22\).
cp /dev/null ark15isdone

William Lefebvre

unread,
Sep 1, 1996, 3:00:00 AM9/1/96
to

Submitted-By: w...@groupsys.com (William Lefebvre)
Posting-Number: Volume 29, Issue 116
Archive-Name: top-3.4/part15

#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:

# "End of archive 16 (of 22)."
# Contents: top-3.4/machine/m_ftx.c top-3.4/machine/m_sunos4mp.c
# Wrapped by lefebvre@acapulco on Fri Aug 30 12:35:51 1996


PATH=/bin:/usr/bin:/usr/ucb ; export PATH

if test -f 'top-3.4/machine/m_ftx.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_ftx.c'\"
else
echo shar: Extracting \"'top-3.4/machine/m_ftx.c'\" \(21257 characters\)
sed "s/^X//" >'top-3.4/machine/m_ftx.c' <<'END_OF_FILE'


X/*
X * top - a top users display for Unix
X *

X * SYNOPSIS: For FTX based System V Release 4


X *
X * DESCRIPTION:

X * System V release 4.0.x for FTX (FTX 2.3 and greater)
X *
X * LIBS: -lelf
X *
X * AUTHORS: Andrew Herbert <and...@werple.apana.org.au>


X * Robert Boucher <bou...@sofkin.ca>

X * Steve Scherf <sch...@swdc.stratus.com>
X */
X


X#include <stdio.h>
X#include <fcntl.h>
X#include <unistd.h>
X#include <stdlib.h>
X#include <errno.h>
X#include <dirent.h>
X#include <nlist.h>
X#include <string.h>
X#include <sys/types.h>

X#include <sys/param.h>
X#include <sys/procfs.h>
X#include <sys/sysmacros.h>
X#include <sys/sysinfo.h>


X#include <sys/vmmeter.h>
X#include <vm/anon.h>
X#include <sys/priocntl.h>
X#include <sys/rtpriocntl.h>
X#include <sys/tspriocntl.h>
X#include <sys/procset.h>
X#include <sys/var.h>

X#include <sys/tuneable.h>
X#include <sys/fs/rf_acct.h>
X#include <sys/sar.h>
X#include <sys/ftx/dcm.h>


X
X#include "top.h"
X#include "machine.h"
X

X#define UNIX "/unix"
X#define KMEM "/dev/kmem"

X#define PROCFS "/proc"
X#define SAR "/dev/sar"


X#define CPUSTATES 5
X
X#ifndef PRIO_MAX
X#define PRIO_MAX 20
X#endif
X#ifndef PRIO_MIN
X#define PRIO_MIN -20
X#endif
X
X#ifndef FSCALE
X#define FSHIFT 8 /* bits to right of fixed binary point */
X#define FSCALE (1<<FSHIFT)
X#endif
X
X#define loaddouble(x) ((double)(x) / FSCALE)

X#define pagetok(size) ctob(size) >> LOG1024
X#define PRTOMS(pp) \
X ((pp)->pr_time.tv_sec * 1000) + ((pp)->pr_time.tv_nsec / 1000000)
X
X/* definitions for the index in the nlist array */
X#define X_AVENRUN 0
X#define X_MPID 1
X#define X_V 2
X#define X_NPROC 3


X#define X_ANONINFO 4
X#define X_TOTAL 5

X
Xstatic struct nlist nlst[] =
X{

X {"avenrun"}, /* 0 */
X {"mpid"}, /* 1 */
X {"v"}, /* 2 */
X {"nproc"}, /* 3 */
X {"anoninfo"}, /* 4 */
X {"total"}, /* 5 */
X {NULL}
X};


X
Xstatic unsigned long avenrun_offset;
Xstatic unsigned long mpid_offset;

Xstatic unsigned long nproc_offset;
Xstatic unsigned long anoninfo_offset;
Xstatic unsigned long total_offset;

X
X/* get_process_info passes back a handle. This is what it looks like: */
X
Xstruct handle
X {

X struct prpsinfo **next_proc;/* points to next valid proc pointer */


X int remaining; /* number of pointers remaining */
X };
X

X#define MAXTIMEHIST 12
X#define HASHSZ 512 /* This must be a power of 2. */
X#define HASHMASK (HASHSZ - 1)
X#define TF_USED 0x01
X#define TF_NEWPROC 0x02
X
X#define TD_HASH(pid) \
X (timedata_t *)(&hash[(pid) & HASHMASK])
X
Xtypedef struct hash {
X struct timedata *hnext;
X struct timedata *hlast;
X} hash_t;
X
X/* data for CPU and WCPU fields */
Xtypedef struct timedata {
X struct timedata *hnext;
X struct timedata *hlast;
X struct timedata *lnext;
X struct timedata *llast;
X pid_t pid;
X char index;
X char cnt;
X char flags;
X long hist[MAXTIMEHIST];
X long time;
X long ltime;
X} timedata_t;
X
X
X/*


X * These definitions control the format of the per-process area
X */
X
Xstatic char header[] =
X" PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";
X/* 0123456 -- field to fill in starts at header+6 */
X#define UNAME_START 6

X#define Proc_format \
X "%5d %-8.8s %3d %4d%6dK %4dK %-5s%4d:%02d %5.2f%% %5.2f%% %.16s"
X


Xchar *state_abbrev[] =
X{"", "sleep", "run", "zombie", "stop", "start", "cpu", "swap"};
X
Xint process_states[8];
Xchar *procstatenames[] =
X{
X "", " sleeping, ", " running, ", " zombie, ", " stopped, ",

X " starting, ", " on cpu, ", " swapped, ",
X NULL
X};
X


Xint cpu_states[CPUSTATES];
Xchar *cpustatenames[] =

X{"idle", "user", "kernel", "wait", "swap", NULL};

X
X/* these are for detailing the memory statistics */
X

Xint memory_stats[5];
Xchar *memorynames[] =


X{"K real, ", "K active, ", "K free, ", "K swap, ", "K free swap", NULL};
X

Xstatic int kmem;
Xstatic int sar;
Xstatic int initted;
Xstatic int nproc;


Xstatic int bytes;
Xstatic struct prpsinfo *pbase;
Xstatic struct prpsinfo **pref;
Xstatic DIR *procdir;

Xstatic char cpu_state[MAX_LOG_CPU];
Xstatic struct sysinfo cpu_sysinfo[MAX_LOG_CPU];
Xstatic sar_percpu_args_t spa;
Xstatic timedata_t timedata;
Xstatic long total_time;
Xstatic double total_cpu;
Xstatic hash_t hash[HASHSZ];


X
X/* useful externals */
Xextern int errno;
Xextern char *sys_errlist[];

Xextern char *myname;
Xextern long percentages ();


Xextern int check_nlist ();
Xextern int getkval ();
Xextern void perror ();
Xextern void getptable ();
Xextern void quit ();
Xextern int nlist ();
X

X/* Prototypes. */
Xvoid getsysinfo(struct sysinfo *);
Xvoid add_time(struct prpsinfo *);
Xvoid get_cpu(struct prpsinfo *, double *, double *);
Xvoid clean_timedata(void);
Xtimedata_t *get_timedata(struct prpsinfo *);
X


X
Xint
Xmachine_init (struct statics *statics)
X {

X int i;


X static struct var v;

X
X /* fill in the statics information */
X statics->procstate_names = procstatenames;
X statics->cpustate_names = cpustatenames;
X statics->memory_names = memorynames;
X

X /* get the list of symbols we want to access in the kernel */

X if (nlist (UNIX, nlst))
X {
X (void) fprintf (stderr, "Unable to nlist %s\n", UNIX);
X return (-1);

X }
X
X /* make sure they were all found */

X if (check_nlist (nlst) > 0)
X return (-1);
X


X /* open kernel memory */
X if ((kmem = open (KMEM, O_RDONLY)) == -1)
X {
X perror (KMEM);

X return (-1);
X }
X

X /* Open the sar driver device node. */
X if ((sar = open(SAR, O_RDONLY)) == -1)
X {
X perror (SAR);
X return (-1);
X }
X
X


X /* get the symbol values out of kmem */

X /* NPROC Tuning parameter for max number of processes */

X (void) getkval (nlst[X_V].n_value, &v, sizeof (struct var), nlst[X_V].n_name);
X nproc = v.v_proc;


X
X /* stash away certain offsets for later use */
X mpid_offset = nlst[X_MPID].n_value;

X nproc_offset = nlst[X_NPROC].n_value;


X avenrun_offset = nlst[X_AVENRUN].n_value;

X anoninfo_offset = nlst[X_ANONINFO].n_value;


X total_offset = nlst[X_TOTAL].n_value;
X

X /* allocate space for proc structure array and array of pointers */

X bytes = nproc * sizeof (struct prpsinfo);
X pbase = (struct prpsinfo *) malloc (bytes);

X pref = (struct prpsinfo **) malloc (nproc * sizeof (struct prpsinfo *));


X
X /* Just in case ... */

X if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL)
X {

X (void) fprintf (stderr, "%s: can't allocate sufficient memory\n", myname);


X return (-1);
X }
X

X if (!(procdir = opendir (PROCFS)))
X {
X (void) fprintf (stderr, "Unable to open %s\n", PROCFS);

X return (-1);
X }
X

X if (chdir (PROCFS))
X { /* handy for later on when we're reading it */
X (void) fprintf (stderr, "Unable to chdir to %s\n", PROCFS);

X return (-1);
X }
X

X /* Set up the pointers to the sysinfo data area. */
X spa.uvcp = (caddr_t) &cpu_state[0];
X spa.uvsp = (caddr_t) &cpu_sysinfo[0];
X
X timedata.lnext = &timedata;
X timedata.llast = &timedata;
X
X for (i = 0; i < HASHSZ; i++) {
X hash[i].hnext = (timedata_t *)&hash[i];
X hash[i].hlast = (timedata_t *)&hash[i];
X }


X
X /* all done! */

X return (0);
X }
X
Xchar *
Xformat_header (char *uname_field)

X{
X register char *ptr;
X
X ptr = header + UNAME_START;
X while (*uname_field != '\0')

X *ptr++ = *uname_field++;
X

X return (header);
X}
X
Xvoid
Xget_system_info (struct system_info *si)
X{
X long avenrun[3];
X struct sysinfo sysinfo;

X struct vmtotal total;


X struct anoninfo anoninfo;
X static time_t cp_old[CPUSTATES];

X static time_t cp_diff[CPUSTATES]; /* for cpu state percentages */


X register int i;
X

X getsysinfo(&sysinfo);


X
X /* convert cp_time counts to percentages */

X (void) percentages (CPUSTATES, cpu_states, sysinfo.cpu, cp_old, cp_diff);
X
X /* Find total CPU utilization, as a fraction of 1. */
X total_cpu = (cpu_states[CPU_USER] + cpu_states[CPU_KERNEL]) / 1000.0;


X
X /* get mpid -- process id of last process */

X (void) getkval (mpid_offset, &(si->last_pid), sizeof (si->last_pid),

X "mpid");


X
X /* get load average array */

X (void) getkval (avenrun_offset, (int *) avenrun, sizeof (avenrun), "avenrun");


X
X /* convert load averages to doubles */

X for (i = 0; i < 3; i++)

X si->load_avg[i] = loaddouble (avenrun[i]);
X


X /* get total -- systemwide main memory usage structure */

X (void) getkval (total_offset, (int *) (&total), sizeof (total), "total");


X /* convert memory stats to Kbytes */

X memory_stats[0] = pagetok (total.t_rm);
X memory_stats[1] = pagetok (total.t_arm);
X memory_stats[2] = pagetok (total.t_free);
X (void) getkval (anoninfo_offset, (int *) (&anoninfo), sizeof (anoninfo),
X "anoninfo");
X memory_stats[3] = pagetok (anoninfo.ani_max - anoninfo.ani_free);
X memory_stats[4] = pagetok (anoninfo.ani_max - anoninfo.ani_resv);

X
X /* set arrays and strings */
X si->cpustates = cpu_states;
X si->memory = memory_stats;
X}
X
Xstatic struct handle handle;
X
Xcaddr_t

Xget_process_info (
X struct system_info *si,
X struct process_select *sel,
X int (*compare) ())

X{
X register int i;
X register int total_procs;
X register int active_procs;

X register struct prpsinfo **prefp;

X register struct prpsinfo *pp;


X
X /* these are copied out of sel for speed */
X int show_idle;
X int show_system;
X int show_uid;
X

X /* Get current number of processes */
X (void) getkval (nproc_offset, (int *) (&nproc), sizeof (nproc), "nproc");

X
X /* read all the proc structures */
X getptable (pbase);


X
X /* get a pointer to the states summary array */
X si->procstates = process_states;
X
X /* set up flags which define what we are going to select */
X show_idle = sel->idle;
X show_system = sel->system;
X show_uid = sel->uid != -1;
X

X /* count up process states and get pointers to interesting procs */
X total_procs = 0;
X active_procs = 0;

X total_time = 0;


X (void) memset (process_states, 0, sizeof (process_states));

X prefp = pref;
X

X clean_timedata();
X


X for (pp = pbase, i = 0; i < nproc; pp++, i++)
X {
X /*
X * Place pointers to each valid proc structure in pref[].
X * Process slots that are actually in use have a non-zero
X * status field. Processes with SSYS set are system
X * processes---these get ignored unless show_sysprocs is set.
X */

X if (pp->pr_state != 0 &&
X (show_system || ((pp->pr_flag & SSYS) == 0)))
X {
X total_procs++;


X process_states[pp->pr_state]++;
X if ((!pp->pr_zomb) &&
X (show_idle || (pp->pr_state == SRUN) || (pp->pr_state == SONPROC)) &&

X (!show_uid || pp->pr_uid == (uid_t) sel->uid))


X {
X *prefp++ = pp;
X active_procs++;
X }
X }
X

X if (pp->pr_state != 0)
X add_time(pp);
X }
X
X /* Note that we've run this at least once. */
X initted++;


X
X /* if requested, sort the "interesting" processes */
X if (compare != NULL)

X qsort ((char *) pref, active_procs, sizeof (struct prpsinfo *), compare);

X
X /* remember active and total counts */
X si->p_total = total_procs;

X si->p_active = active_procs;


X
X /* pass back a handle */
X handle.next_proc = pref;
X handle.remaining = active_procs;
X return ((caddr_t) & handle);

X}
X
Xchar fmt[128]; /* static area where result is built */
X


Xchar *
Xformat_next_process (
X caddr_t handle,
X char *(*get_userid) ())
X{
X register struct prpsinfo *pp;

X struct handle *hp;
X register long cputime;
X double pctcpu;
X double pctwcpu;


X
X /* find and remember the next proc structure */
X hp = (struct handle *) handle;
X pp = *(hp->next_proc++);
X hp->remaining--;
X

X /* get the cpu usage and calculate the cpu percentages */
X cputime = pp->pr_time.tv_sec;

X get_cpu(pp, &pctcpu, &pctwcpu);


X
X /* format this entry */

X (void) sprintf (fmt,
X Proc_format,
X pp->pr_pid,
X (*get_userid) (pp->pr_uid),
X pp->pr_pri - PZERO,
X pp->pr_nice - NZERO,

X pagetok (pp->pr_size),
X pagetok (pp->pr_rssize),
X state_abbrev[pp->pr_state],


X cputime / 60l,
X cputime % 60l,

X pctwcpu,


X pctcpu,
X pp->pr_fname);

X
X /* return the result */
X return (fmt);

X}
X
X/*


X * check_nlist(nlst) - checks the nlist to see if any symbols were not
X * found. For every symbol that was not found, a one-line
X * message is printed to stderr. The routine returns the
X * number of symbols NOT found.
X */

Xint
Xcheck_nlist (register struct nlist *nlst)

X{
X register int i;
X
X /* check to see if we got ALL the symbols we requested */
X /* this will write one line to stderr for every symbol not found */
X
X i = 0;
X while (nlst->n_name != NULL)
X {
X if (nlst->n_type == 0)
X {
X /* this one wasn't found */

X (void) fprintf (stderr, "kernel: no symbol named `%s'\n", nlst->n_name);


X i = 1;
X }
X nlst++;
X }

X return (i);
X}
X
X
X/*


X * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
X * "offset" is the byte offset into the kernel for the desired value,
X * "ptr" points to a buffer into which the value is retrieved,
X * "size" is the size of the buffer (and the object to retrieve),
X * "refstr" is a reference string used when printing error meessages,
X * if "refstr" starts with a '!', then a failure on read will not
X * be fatal (this may seem like a silly way to do things, but I
X * really didn't want the overhead of another argument).
X *
X */

Xint
Xgetkval (
X unsigned long offset,
X int *ptr,
X int size,
X char *refstr)
X{
X if (lseek (kmem, (long) offset, 0) == -1)
X {

X if (*refstr == '!')
X refstr++;

X (void) fprintf (stderr, "%s: lseek to %s: %s\n",
X myname, refstr, sys_errlist[errno]);
X quit (22);
X }

X if (read (kmem, (char *) ptr, size) == -1)


X if (*refstr == '!')

X /* we lost the race with the kernel, process isn't in memory */
X return (0);
X else
X {
X (void) fprintf (stderr, "%s: reading %s: %s\n",
X myname, refstr, sys_errlist[errno]);
X quit (23);
X }
X return (1);

X}
X
X/* comparison routine for qsort */
X
X/*


X * proc_compare - comparison function for "qsort"
X * Compares the resource consumption of two processes using five
X * distinct keys. The keys (in descending order of importance) are:
X * percent cpu, cpu ticks, state, resident set size, total virtual
X * memory usage. The process states are ordered as follows (from least
X * to most important): WAIT, zombie, sleep, stop, start, run. The
X * array declaration below maps a process state index into a number
X * that reflects this ordering.
X */
X
X

Xunsigned char sorted_state[] =


X{
X 0, /* not used */
X 3, /* sleep */

X 6, /* run */

X 2, /* zombie */

X 4, /* stop */


X 5, /* start */

X 7, /* run on a processor */
X 1 /* being swapped (WAIT) */
X};
X
Xint
Xproc_compare (
X struct prpsinfo **pp1,
X struct prpsinfo **pp2)
X {
X register struct prpsinfo *p1;
X register struct prpsinfo *p2;
X register long result;

X register long d1;
X register long d2;
X register timedata_t *td;


X
X /* remove one level of indirection */
X p1 = *pp1;
X p2 = *pp2;
X

X td = get_timedata(p1);
X if (td->ltime == -1)
X d1 = 0;
X else
X d1 = td->time - td->ltime;
X
X td = get_timedata(p2);
X if (td->ltime == -1)
X d2 = 0;
X else
X d2 = td->time - td->ltime;
X
X /* compare cpu usage */
X if ((result = d2 - d1) == 0)


X {
X /* use cpticks to break the tie */

X if ((result = (PRTOMS(p2) - PRTOMS(p1))) == 0)


X {
X /* use process state to break the tie */

X if ((result = (long) (sorted_state[p2->pr_state] -

X sorted_state[p1->pr_state])) == 0)


X {
X /* use priority to break the tie */

X if ((result = p2->pr_oldpri - p1->pr_oldpri) == 0)


X {
X /* use resident set size (rssize) to break the tie */

X if ((result = p2->pr_rssize - p1->pr_rssize) == 0)


X {
X /* use total memory to break the tie */

X result = (p2->pr_size - p1->pr_size);
X }
X }

X return (-1);
X}
X

Xint
Xsetpriority (int dummy, int who, int niceval)
X{
X int scale;
X int prio;
X pcinfo_t pcinfo;
X pcparms_t pcparms;
X tsparms_t *tsparms;
X
X strcpy (pcinfo.pc_clname, "TS");
X if (priocntl (0, 0, PC_GETCID, (caddr_t) & pcinfo) == -1)

X return (-1);
X


X prio = niceval;
X if (prio > PRIO_MAX)
X prio = PRIO_MAX;
X else if (prio < PRIO_MIN)
X prio = PRIO_MIN;
X
X tsparms = (tsparms_t *) pcparms.pc_clparms;
X scale = ((tsinfo_t *) pcinfo.pc_clinfo)->ts_maxupri;
X tsparms->ts_uprilim = tsparms->ts_upri = -(scale * prio) / 20;
X pcparms.pc_cid = pcinfo.pc_cid;
X
X if (priocntl (P_PID, who, PC_SETPARMS, (caddr_t) & pcparms) == -1)

X return (-1);
X
X return (0);
X}
X
X
X/*
X * Per-process CPU calculation:
X *
X * We emulate actual % CPU usage calculation, since the statistics
X * kept by FTX are not valid for this purpose. We fake this calculation
X * by totalling the amount of CPU time used by all processes since the
X * last update, and dividing this into the CPU time used by the process
X * in question. For the WCPU value, we average the CPU calculations for the
X * process over the last td->cnt updates. This means that the first update
X * when starting top will always be 0% CPU (no big deal), and that WCPU will
X * be averaged over a varying amount of time (also no big deal). This is
X * probably the best we can do, since the kernel doesn't keep any of these
X * statistics itself.
X *
X * This method seems to yield good results. The only problems seem to be the
X * fact that the first update always shows 0%, and that the
X * sysinfo CPU data isn't always in sync with the per-process CPU usage
X * when a CPU-intensive process quits. This latter problem causes funny
X * results, because the remaining processes get credited with the residual
X * CPU time.
X *
X * This algorithm may seem CPU intensive, but it's actually very
X * inexpensive. The expensive part is the ioctl call to the sar driver.
X * No amount of optimization in this program will reduce the sar overhead.
X */
X
Xvoid
Xgetsysinfo (struct sysinfo *sysinfo)


X{
X register int i;

X register int j;
X register int cpus;
X
X /* Get the per-CPU sysinfo data from sar. */
X if(ioctl(sar, SAR_SYSINFO, &spa)) {
X perror("ioctl(sar, SAR_SYSINFO)");
X quit(24);
X }
X
X (void)memset((char *)sysinfo, 0, sizeof(struct sysinfo));
X
X /* Average the state times to get systemwide values. */
X for(i = 0, cpus = 0; i < MAX_LOG_CPU; i++) {
X if(cpu_state[i] != SAR_CPU_RUNNING)
X continue;
X
X cpus++;
X
X for(j = 0; j < 5; j++)
X sysinfo->cpu[j] += cpu_sysinfo[i].cpu[j];
X }
X
X for(i = 0; i < 5; i++)
X sysinfo->cpu[i] /= cpus;
X}
X
X
Xvoid
Xadd_time (struct prpsinfo *pp)
X{
X register timedata_t *td;
X
X td = get_timedata(pp);
X
X td->flags |= TF_USED;
X
X if(td->time == -1) {
X td->time = PRTOMS(pp);
X
X if(!(td->flags & TF_NEWPROC))
X return;
X
X td->flags &= ~TF_NEWPROC;
X td->ltime = 0;
X }
X else {
X td->ltime = td->time;
X td->time = PRTOMS(pp);
X }
X
X /* Keep track of the time spent by all processes. */
X total_time += td->time - td->ltime;
X}
X
X
Xvoid
Xget_cpu(struct prpsinfo *pp, double *cpu, double *wcpu)


X{
X register int i;

X register int j;
X register long t;
X register timedata_t *td;
X
X td = get_timedata(pp);
X
X /* No history, so return 0%. */
X if(td->ltime == -1) {
X *cpu = 0;
X *wcpu = 0;
X return;
X }
X
X i = td->index;
X td->index = (i + 1) % MAXTIMEHIST;
X td->cnt = MIN((td->cnt + 1), MAXTIMEHIST);
X
X /* Compute CPU usage (time diff from last update / total cpu time). */
X /* We don't want to div by 0. */
X if(total_time == 0) {
X td->hist[i] = 0;
X *cpu = 0.0;
X }
X else {
X t = (td->time - td->ltime) * 10000 / total_time * total_cpu;
X td->hist[i] = t;
X *cpu = t / 100.0;
X }
X
X /* Compute WCPU usage (average CPU % since oldest update). */
X for(j = 0, t = 0; j < td->cnt; j++) {
X t += td->hist[i];
X
X i--;
X if(i < 0)
X i = MAXTIMEHIST - 1;
X }
X *wcpu = t / j / 100.0;
X}
X
X
Xtimedata_t *
Xget_timedata(struct prpsinfo *pp)
X{
X register timedata_t *t;
X register timedata_t *l;
X
X l = TD_HASH(pp->pr_pid);
X
X for(t = l->hnext; t != l; t = t->hnext)
X if(t->pid == pp->pr_pid)
X return t;
X
X t = (timedata_t *)malloc(sizeof(timedata_t));
X if(t == 0) {
X perror("malloc");
X quit(25);
X }
X
X t->pid = pp->pr_pid;
X t->index = 0;
X t->cnt = 0;
X t->time = -1;
X t->ltime = -1;
X
X if(initted)
X t->flags = TF_USED | TF_NEWPROC;
X else
X t->flags = TF_USED;
X
X /* Put struct on hash list. */
X t->hnext = l->hnext;
X t->hlast = l;
X l->hnext->hlast = t;
X l->hnext = t;
X
X /* Put struct on timedata list. */
X t->lnext = timedata.lnext;
X t->llast = &timedata;
X timedata.lnext->llast = t;
X timedata.lnext = t;
X
X return t;
X}
X
X
Xvoid
Xclean_timedata(void)
X{
X register timedata_t *t;
X
X for(t = timedata.lnext; t != &timedata; t = t->lnext) {
X if(!(t->flags & TF_USED)) {
X t->hnext->hlast = t->hlast;
X t->hlast->hnext = t->hnext;
X t->lnext->llast = t->llast;
X t->llast->lnext = t->lnext;
X free(t);
X }
X else {
X t->flags &= ~TF_USED;
X }
X }
X}
END_OF_FILE
if test 21257 -ne `wc -c <'top-3.4/machine/m_ftx.c'`; then
echo shar: \"'top-3.4/machine/m_ftx.c'\" unpacked with wrong size!
fi
# end of 'top-3.4/machine/m_ftx.c'
fi
if test -f 'top-3.4/machine/m_sunos4mp.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'top-3.4/machine/m_sunos4mp.c'\"
else
echo shar: Extracting \"'top-3.4/machine/m_sunos4mp.c'\" \(19966 characters\)
sed "s/^X//" >'top-3.4/machine/m_sunos4mp.c' <<'END_OF_FILE'


X/*
X * top - a top users display for Unix
X *

X * SYNOPSIS: any multi-processor Sun running SunOS versions 4.1.2 or 4.1.3


X *
X * DESCRIPTION:

X * This is the machine-dependent module for SunOS 4.x with multi-processor
X * support. This module always compiles code for multiprocessors and
X * assumes that it is being compiled on a multiprocessor architecture
X * such as sun4m). This makes top work on the following systems:
X * SunOS 4.1.2 (MP architectures only)
X * SunOS 4.1.3 (MP architectures only)
X * Solbourne running os/mp 4.1b or later only


X *
X * LIBS: -lkvm

X *
X * CFLAGS: -DHAVE_GETOPT
X *


X * AUTHOR: William LeFebvre <ph...@eecs.nwu.edu>
X * Solbourne support by David MacKenzie <d...@eng.umd.edu>

X */
X
X/*
X * #ifdef MULTIPROCESSOR means Sun MP or newer Solbourne


X */
X
X#include <sys/types.h>
X#include <sys/signal.h>
X

X/*
X * When including files, we need to have MULTIPROCESSOR on so that a version
X * compiled on a non-MP system will work on an MP system. We must take
X * great care, then in pur interpretation of certain preprocessor constants,
X * such as NCPU, XPSTATES, XP_*.
X */
X#ifndef MULTIPROCESSOR
X#define MULTIPROCESSOR
X#endif


X
X/* make sure param.h gets loaded with KERNEL defined to get PZERO & NZERO */
X#define KERNEL
X#include <sys/param.h>
X#undef KERNEL
X
X#include <stdio.h>
X#include <kvm.h>

X#include <nlist.h>
X#include <math.h>
X#include <sys/dir.h>
X#include <sys/user.h>
X#include <sys/proc.h>
X#include <sys/dk.h>
X#include <sys/vm.h>
X#include <sys/file.h>
X#include <sys/time.h>

X#include <vm/page.h>


X
X#include "top.h"
X#include "machine.h"
X

X/* declarations for load_avg */
X#include "loadavg.h"
X
X/* get_process_info passes back a handle. This is what it looks like: */
X
Xstruct handle
X{
X struct proc **next_proc; /* points to next valid proc pointer */
X int remaining; /* number of pointers remaining */
X};
X
X/* define what weighted cpu is. */
X#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
X ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
X
X/* what we consider to be process size: */
X#define PROCSIZE(pp) ((pp)->p_tsize + (pp)->p_dsize + (pp)->p_ssize)
X
X/* definitions for indices in the nlist array */
X#define X_AVENRUN 0
X#define X_CCPU 1

X#define X_MPID 2
X#define X_NPROC 3
X#define X_PROC 4
X#define X_TOTAL 5
X#define X_CP_TIME 6
X#define X_PAGES 7
X#define X_EPAGES 8

X
Xstatic struct nlist nlst[] = {

X#ifdef i386
X { "avenrun" }, /* 0 */
X { "ccpu" }, /* 1 */
X { "mpid" }, /* 2 */
X { "nproc" }, /* 3 */
X { "proc" }, /* 4 */
X { "total" }, /* 5 */
X { "cp_time" }, /* 6 */
X { "pages" }, /* 7 */
X { "epages" }, /* 8 */
X#else

X { "_avenrun" }, /* 0 */
X { "_ccpu" }, /* 1 */

X { "_mpid" }, /* 2 */
X { "_nproc" }, /* 3 */
X { "_proc" }, /* 4 */
X { "_total" }, /* 5 */
X { "_cp_time" }, /* 6 */
X { "_pages" }, /* 7 */
X { "_epages" }, /* 8 */

X#define NLST_REQUIRED 9


X { "_ncpu" },
X#define X_NCPU 9
X { "_xp_time" },
X#define X_XP_TIME 10
X#endif

X { 0 }
X};
X
X/*


X * These definitions control the format of the per-process area
X */
X
Xstatic char header[] =
X " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";
X/* 0123456 -- field to fill in starts at header+6 */
X#define UNAME_START 6
X
X#define Proc_format \
X "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %s"
X
X
X/* process state names for the "STATE" column of the display */
X/* the extra nulls in the string "run" are for adding a slash and
X the processor number when needed */
X
Xchar *state_abbrev[] =
X{
X "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"
X};
X

X/* values that we stash away in _init and use in later routines */
X
Xstatic double logcpu;

Xkvm_t *kd;


X
X/* these are retrieved from the kernel in _init */
X
Xstatic unsigned long proc;
Xstatic int nproc;

Xstatic load_avg ccpu;
Xstatic unsigned long pages;
Xstatic unsigned long epages;

Xstatic int ncpu = 0;

X#define IS_MP (ncpu > 1)


X
X/* these are offsets obtained via nlist and used in the get_ functions */
X

Xstatic unsigned long mpid_offset;


Xstatic unsigned long avenrun_offset;
Xstatic unsigned long total_offset;
Xstatic unsigned long cp_time_offset;

Xstatic unsigned long xp_time_offset;


X
X/* these are for calculating cpu state percentages */
X
Xstatic long cp_time[CPUSTATES];
Xstatic long cp_old[CPUSTATES];
Xstatic long cp_diff[CPUSTATES];

Xstatic long xp_time[NCPU][XPSTATES];
X/* for now we only accumulate spin time, but extending this to pick up
X other stuff in xp_time is trivial. */
Xstatic long xp_old[NCPU];

X
X/* these are for detailing the process states */
X
Xint process_states[7];
Xchar *procstatenames[] = {
X "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",
X " zombie, ", " stopped, ",
X NULL
X};
X
X/* these are for detailing the cpu states */
X

Xint cpu_states[5];


Xchar *cpustatenames[] = {
X "user", "nice", "system", "idle",

X NULL, /* set to "spin" on MP machines */
X NULL
X};
X#define XCP_SPIN 4


X
X/* these are for detailing the memory statistics */
X

Xint memory_stats[4];
Xchar *memorynames[] = {

X "K available, ", "K in use, ", "K free, ", "K locked", NULL


X};
X
X/* these are for keeping track of the proc array */
X
Xstatic int bytes;
Xstatic int pref_len;
Xstatic struct proc *pbase;
Xstatic struct proc **pref;
X
X/* these are for getting the memory statistics */
X

Xstatic struct page *physpage;
Xstatic int bytesize;
Xstatic int count;

Xstatic int pageshift; /* log base 2 of the pagesize */
X
X/* define pagetok in terms of pageshift */
X
X#define pagetok(size) ((size) << pageshift)
X
X/* useful externals */
Xextern int errno;
Xextern char *sys_errlist[];
X
Xlong lseek();
Xlong time();

Xlong percentages();
X
Xmachine_init(statics)
X
Xstruct statics *statics;
X
X{

X register int i;


X register int pagesize;
X

X /* initialize the kernel interface */
X if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "top")) == NULL)
X {

X perror("kvm_open");
X return(-1);
X }
X


X /* get the list of symbols we want to access in the kernel */

X if ((i = kvm_nlist(kd, nlst)) < 0)


X {
X fprintf(stderr, "top: nlist failed\n");
X return(-1);
X }
X

X /* were ncpu and xp_time not found in the nlist? */

X if (i > 0 && nlst[X_NCPU].n_type == 0 && nlst[X_XP_TIME].n_type == 0)
X {
X /* we are only running with one cpu */


X /* so we will pretend this didn't happen and set ncpu = 1 */
X i -= 2;

X ncpu = 1;
X }
X


X /* make sure they were all found */
X if (i > 0 && check_nlist(nlst) > 0)
X {
X return(-1);
X }
X
X /* get the symbol values out of kmem */
X (void) getkval(nlst[X_PROC].n_value, (int *)(&proc), sizeof(proc),
X nlst[X_PROC].n_name);
X (void) getkval(nlst[X_NPROC].n_value, &nproc, sizeof(nproc),
X nlst[X_NPROC].n_name);

X (void) getkval(nlst[X_CCPU].n_value, (int *)(&ccpu), sizeof(ccpu),
X nlst[X_CCPU].n_name);

X (void) getkval(nlst[X_PAGES].n_value, (int *)(&pages), sizeof(pages),
X nlst[X_PAGES].n_name);
X (void) getkval(nlst[X_EPAGES].n_value, (int *)(&epages), sizeof(epages),
X nlst[X_EPAGES].n_name);

X if (ncpu == 0)
X {
X /* we have not yet determined the number of processors, so
X do that now */
X /* assert: nlst[X_NCPU].n_type != 0 => nlst[X_NCPU].n_value != 0 */


X (void) getkval(nlst[X_NCPU].n_value, (int *)(&ncpu), sizeof(ncpu),
X nlst[X_NCPU].n_name);
X }

X
X /* stash away certain offsets for later use */
X mpid_offset = nlst[X_MPID].n_value;
X avenrun_offset = nlst[X_AVENRUN].n_value;
X total_offset = nlst[X_TOTAL].n_value;

X cp_time_offset = nlst[X_CP_TIME].n_value;

X xp_time_offset = nlst[X_XP_TIME].n_value;


X
X /* this is used in calculating WCPU -- calculate it ahead of time */
X logcpu = log(loaddouble(ccpu));
X
X /* allocate space for proc structure array and array of pointers */
X bytes = nproc * sizeof(struct proc);
X pbase = (struct proc *)malloc(bytes);
X pref = (struct proc **)malloc(nproc * sizeof(struct proc *));
X
X /* Just in case ... */
X if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
X {
X fprintf(stderr, "top: can't allocate sufficient memory\n");
X return(-1);
X }
X

X /* allocate a table to hold all the page structs */
X bytesize = epages - pages;
X count = bytesize / sizeof(struct page);
X physpage = (struct page *)malloc(epages - pages);
X if (physpage == NULL)

X {
X fprintf(stderr, "top: can't allocate sufficient memory\n");
X return(-1);
X }
X
X /* get the page size with "getpagesize" and calculate pageshift from it */
X pagesize = getpagesize();
X pageshift = 0;
X while (pagesize > 1)
X {
X pageshift++;
X pagesize >>= 1;
X }
X
X /* we only need the amount of log(2)1024 for our conversion */
X pageshift -= LOG1024;
X