/* System dependent file for Solbourne workstations running OS/MP.	*/
/*
 * Copyright 1990 Solbourne Computer, Inc.
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Solbourne not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  Solbourne Computer, Inc. makes no representations 
 * about the suitability of this software for any purpose.  It is provided 
 * "as is" without express or implied warranty.
 *
 * SOLBOURNE COMPUTER, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 
 * IN NO EVENT SHALL SOLBOURNE COMPUTER, INC. BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * Author:  William Kucharski, Solbourne Computer, Inc.
 *          kucharsk@Solbourne.COM
 *	    ...!{boulder,sun,uunet}!stan!kucharsk
 */
/* LINTLIBRARY */

#include <sys/syscall.h>
#include <sys/param.h>
#include <sys/dk.h>
#include <nlist.h>

extern char *xmalloc(/* int nbytes */);

extern int open(), read();
extern long lseek();

extern char *kernelSymbols();

long	cp_time[MAXNCPUS][CPUSTATES];
long	cp_old[MAXNCPUS][CPUSTATES];
int	kmem;			/* file descriptor of /dev/kmem. */
struct nlist	nl[] = {
#define	X_CP_TIME	0
	{ "_cp_mp_time" },
	{ "" },
};

/* Called by -version */
void
version()
{
	printf("Solbourne OS/MP: maxcpus=%d, maxdisk=0\n", MAXNCPUS);
}

/* Called at the beginning to inquire how many bars are needed. */

int
num_bars()
{
	unsigned int	status;
	unsigned int	width;
	unsigned int	type;

	int	numcpus = 0;
	int	proc;

	if (syscall(SYS_getcpustatus, &status, &width, &type) < 0) {
		perror("getcpustatus");
		exit(1);
	}

	for (proc = 0; proc < width; proc++)
		if ((status >> proc) & 1)
			numcpus++;

	return(numcpus);
}

/*
 * Indicates how many levels each bar has.  For most machines, each bar will
 * have the same stuff.  But one can, for instance, display memory use on one
 * bar, processor levels on others, etc.
 */
void
bar_items(nbars, items)
int nbars;
int items[];    /* nbars items in this */
{
    int i;

    for(i = 0; i < nbars; i++)
        items[i] = CPUSTATES;
}

/* Called after num_bars to ask for the bar names */
/* ARGSUSED */
char **
label_bars(nbars)
{
    extern char *strcpy(/* char *, const char * */);

    char **names;
    int i;

    static char hname[MAXHOSTNAMELEN];

    if (gethostname(hname, MAXHOSTNAMELEN) < 0) {
        perror("gethostname");
        hname[0] = '\0';
    }

    names = (char **) xmalloc(nbars * sizeof(char *));
    if (nbars == 1) {
	    char buf[MAXHOSTNAMELEN + 3];
	    (void) sprintf(buf, "%s: ", hname);
	    names[0] = strcpy(xmalloc(strlen(buf) + 1), buf);
    } else {
    for(i = 0; i < nbars; i++) {
        char buf[MAXHOSTNAMELEN + 6];

		    /* 
		     * Use bar number % 10 in case someone someday can stuff
		     * more than 9 CPUs into a Solbourne box...
		     */

		    (void) sprintf(buf, "%s(%d): ", hname, (i % 10));
        names[i] = strcpy(xmalloc(strlen(buf) + 1), buf);
	    }
    }
    return names;
}

/* 
 *  Called after the bars are created to perform any machine dependent
 *  initializations.
 */
/* ARGSUSED */
void
init_bars(nbars)
int nbars;
{
    
    if ((kmem = open("/dev/kmem", 0)) < 0) {
	    perror("/dev/kmem");
	    exit(1);
    }
    (void)nlist(kernelSymbols?kernelSymbols:"/vmunix", nl);
    if (lseek(kmem, (long) nl[X_CP_TIME].n_value, 0) !=
	(long) nl[X_CP_TIME].n_value)
	    perror("lseek");
    if (read(kmem, (char *) cp_old, sizeof(cp_old)) !=
	sizeof(cp_old))
	    perror("read");
}

/* 
 *  This procedure gets called every interval to compute and display the
 *  bars. It should call draw_bar() with the bar number, the array of
 *  integer values to display in the bar, and the number of values in
 *  the array.
 */
/* ARGSUSED */
void
display_bars(nbars)
{
	int	nstates;
	int	states[CPUSTATES];
	int	i;
	int	proc;

	extern void draw_bar(/*int bar_num, int *states, int num_states*/);
	
	if (lseek(kmem, (long) nl[X_CP_TIME].n_value, 0) !=
	    (long) nl[X_CP_TIME].n_value)
		perror("lseek");
	if (read(kmem, (char *) cp_time, sizeof(cp_time)) !=
	    sizeof(cp_time))
		perror("read");
	
#define delta(cpu, cpustate) ((int) (cp_time[cpu][(cpustate)] - \
	cp_old[cpu][(cpustate)]))

	for (proc = 0; proc < nbars; proc++) {
		nstates = 0;
		states[nstates++] = delta(proc, CP_IDLE);
		states[nstates++] = delta(proc, CP_USER);
		states[nstates++] = delta(proc, CP_NICE);
		states[nstates++] = delta(proc, CP_SYS);
		draw_bar(proc, states, nstates);
		for (i = 0; i < CPUSTATES; i ++)
			cp_old[proc][i] = cp_time[proc][i];
	}
}


syntax highlighted by Code2HTML, v. 0.9.1