[comp.mail.sendmail] getloadavg

meggers@mothra.nts.uci.edu (Mark Eggers) (07/12/90)

Anyone have any hacks of getloadavg.c that will allow it to work on a Sun
Sparc running 4.03c?  I like the idea, and I was thinking about using the
code to build part of a distributed database - if the load is too great,
send a message back to the client, and the client goes to the next server
type of stuff.

thanks for any pointers - /mde/

Andy.Linton@comp.vuw.ac.nz (Andy Linton) (07/12/90)

I have posted a couple of bits and pieces on this and have eventually
come down to the following strategy - throw away all the system
dependent stuff inside conf.c for getting the load average and have a
routine that will get the load average for lots of different systems.

The X11 tool 'xload' has a routine which does this and I used this with
minor mods and a patch to make it work on the HP Series 800 to produce a
new getloadavg.c. I know this has slightly different semantics to the
one in ../support but this works on a lot more systems. It also tidies
up the code in conf.c by removing that horrible #if !defined(sun) section.

I don't have all the machines (:-) so I can't vouch for this totally but
it does run on:

	DEC 5400 (Mips) running Ultrix V3.1D (Rev. 54)
	HP Series 800 running HP-UX 7.0
	HP Series 300 running HP-UX 7.0
	HP Series 300 running Mt Xinu MORE/BSD
	Sun3 running 4.0.3_EXPORT


Patch to conf.c and new getloadavg.c follow:
--
*** /tmp/,RCSt1a17653	Thu Jul 12 13:31:51 1990
--- conf.c	Fri Jul  6 16:50:14 1990
***************
*** 422,487 ****
  **		none.
  */

- #if !defined(sun)
- 
  getla()
  {
! 	double avenrun[3];
  
! 	if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0)
  		return (0);
! 	return ((int) (avenrun[0] + 0.5));
! }
! 
! #else /* sun */
! 
! #include <nlist.h>
! 
! struct	nlist Nl[] =
! {
! 	{"_avenrun"},
! #define	X_AVENRUN	0
! 	{ 0 },
! };
! 
! getla()
! {
! # ifdef sequent
! 	return (1);
! # else /* !sequent */
! 	static int kmem = -1;
! 	long avenrun[3];
! 	extern off_t lseek();
! 
! 	if (kmem < 0)
! 	{
! 		kmem = open("/dev/kmem", 0, 0);
! 		if (kmem < 0)
! 			return (-1);
! 		(void) ioctl(kmem, (int) FIOCLEX, (char *) 0);
! 		(void) nlist ("/vmunix", Nl);
! 		if (Nl[0].n_type == 0)
! 		{
! 			/*
! 			 * if nlist() has failed we can't use Nl to grope 
! 			 * about in kmem on subsequent calls to getla()
! 			 */
! 		  	close (kmem);
! 			kmem = -1;
! 			return (-1);
! 		}
! 	}
! 	if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 ||
! 	    read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
! 	{
! 		/* thank you Ian */
! 		return (-1);
! 	}
! 	return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
! # endif /* sequent */
  }
  
- #endif /* sun */
  /*
  **  SHOULDQUEUE -- should this message be queued or sent?
  **
--- 529,543 ----
  **		none.
  */
  
  getla()
  {
! 	double avenrun;
  
! 	if (getloadavg(&avenrun) < 0)
  		return (0);
! 	return ((int) (avenrun + 0.5));
  }
  
  /*
  **  SHOULDQUEUE -- should this message be queued or sent?
  **
--
#! /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 shell archive."
# Contents:  work/sendmail-5.64/src/getloadavg.c
# Wrapped by asjl@tinakori.comp.vuw.ac.nz on Thu Jul 12 13:46:11 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'work/sendmail-5.64/src/getloadavg.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file
\"'work/sendmail-5.64/src/getloadavg.c'\"
else
echo shar: Extracting \"'work/sendmail-5.64/src/getloadavg.c'\" \(9617
characters\)
sed "s/^X//" >'work/sendmail-5.64/src/getloadavg.c' <<'END_OF_FILE'
X/*
X * Copyright 1989 Massachusetts Institute of Technology
X *
X * Permission to use, copy, modify, distribute, and sell this software and its
X * documentation for any purpose is hereby granted without fee, provided that
X * the above copyright notice appear in all copies and that both that
X * copyright notice and this permission notice appear in supporting
X * documentation, and that the name of M.I.T. not be used in advertising or
X * publicity pertaining to distribution of the software without specific,
X * written prior permission.  M.I.T. makes no representations about the
X * suitability of this software for any purpose.  It is provided "as is"
X * without express or implied warranty.
X *
X * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
X * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
X * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION
X * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
X * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
X *
X * Authors:  Many and varied...
X */
X
X#include <stdio.h>
X
X/*
X * Get open(2) constants
X */
X#ifdef SYSV
X#ifndef macII
X#include <fcntl.h>
X#endif
X#endif /* SYSV */
X#include <sys/file.h>
X#ifdef USG
X#include <unistd.h>
X#endif
X
X#ifdef att
X#define LOADSTUB
X#endif
X
X#ifdef apollo
X#include <apollo/base.h>
X#include <apollo/time.h>
Xtypedef struct {
X	short		state;		/* ready, waiting, etc. */
X	pinteger	usr;		/* user sr */
X	linteger	upc;		/* user pc */
X	linteger	usp;		/* user stack pointer */
X	linteger	usb;		/* user sb ptr (A6) */
X	time_$clock_t	cpu_total;	/* cumulative cpu used by process */
X	unsigned short	priority;	/* process priority */
X    } proc1_$info_t;
X
Xvoid proc1_$get_cput(
X	time_$clock_t	*cput
X);
X
Xvoid proc1_$get_info(
X	short		&pid,
X	proc1_$info_t	*info,
X	status_$t	*sts
X);
X#endif /* apollo */
X
X#ifndef macII
X#ifndef apollo
X#ifndef LOADSTUB
X#include <nlist.h>
X#endif /* LOADSTUB */
X#endif /* apollo */
X#endif /* macII */
X
X#ifdef sun
X#    include <sys/param.h>
X#    ifdef i386
X#        include <kvm.h>
X#        define	KVM_ROUTINES
X#    endif /* i386 */
X#endif
X
X#ifdef mips
X#include <sys/fixpoint.h>
X#endif
X
X#ifdef	CRAY
X#include <sys/param.h>
X#include <sys/sysinfo.h>
X#undef n_type
X#define n_type n_value
X#endif	/* CRAY */
X
X#ifdef sequent
X#include <sys/vm.h>
X#endif /* sequent */
X
X#ifdef macII
X#include <a.out.h>
X#include <sys/var.h>
X#define X_AVENRUN 0
X#define fxtod(i) (vec[i].high+(vec[i].low/65536.0))
Xstruct lavnum {
X    unsigned short high;
X    unsigned short low;
X};
X#endif /* macII */
X
X#if defined(UTEK) || defined(alliant)
X#define FSCALE	100.0
X#endif
X
X#ifdef sequent
X#define FSCALE	1000.0
X#endif
X
X#ifdef hp9000
X#include <sys/param.h>
X#endif
X
Xextern long lseek();
Xextern void exit();
X
X#if apollo
X/* ARGSUSED */
Xint getloadavg( call_data )
X     caddr_t	call_data;	/* pointer to (double) return value */
X{
X     static Bool    firstTime = TRUE;
X     static int     lastNullCpu;
X     static int     lastClock;
X     time_$clock_t  timeNow;
X     double         temp;
X     proc1_$info_t  info;
X     status_$t      st;
X
X     proc1_$get_info( (short) 2, &info, &st );
X     time_$clock( &timeNow );
X
X     if (firstTime)
X     {
X     	*(double *)call_data = 1.0;
X         firstTime = FALSE;
X     }
X     else {
X         temp = info.cpu_total.low32 - lastNullCpu;
X     	*(double *)call_data = 1.0 - temp / (timeNow.low32 - lastClock);
X     }
X
X     lastClock = timeNow.low32;
X     lastNullCpu = info.cpu_total.low32;
X     return(0);
X}
X#else
X#ifdef KVM_ROUTINES
X/*
X *	Sun 386i Code - abstracted to see the wood for the trees
X */
X
X/* ARGSUSED */
Xvoid 
Xgetloadavg( call_data )
X     caddr_t	call_data;	/* pointer to (double) return value */
X{
X    double *loadavg = (double *)call_data;
X    long	temp;
X    static int init = 0;
X    static struct nlist nl[2];
X    static kvm_t *kd;
X    
X    if (!init) {
X	kd = kvm_open("/vmunix", NULL, NULL, O_RDONLY, NULL);
X	if (kd == (kvm_t *)0) {
X	    return (-1);
X	}
X	
X	nl[0].n_name = "avenrun";
X	nl[1].n_name = NULL;
X	
X	if (kvm_nlist(kd, nl) != 0) {
X	    return (-1);
X	}
X	init = 1;
X    }
X    
X    if (nl[0].n_value == 0) {
X	    return (-1);
X    }
X    if (kvm_read(kd, nl[0].n_value, (char *)&temp, sizeof (temp)) != 
X	sizeof (temp)) {
X	return (-1);
X    }
X    *loadavg = (double)temp/FSCALE;
X    return(0);
X}
X#else /* KVM_ROUTINES */
X#ifdef LOADSTUB
X
X/* ARGSUSED */
Xint getloadavg( call_data )
X     caddr_t	call_data;	/* pointer to (double) return value */
X{
X	*(double *)call_data = 1.0;
X}
X
X#else /* LOADSTUB */
X
X#ifndef KMEM_FILE
X#define KMEM_FILE "/dev/kmem"
X#endif
X
X#ifndef KERNEL_FILE
X
X#ifdef alliant
X#define KERNEL_FILE "/unix"
X#endif /* alliant */
X
X#ifdef CRAY
X#define KERNEL_FILE "/unicos"
X#endif /* CRAY */
X
X#ifdef hpux
X#define KERNEL_FILE "/hp-ux"
X#endif /* hpux */
X
X#ifdef macII
X#define KERNEL_FILE "/unix"
X#endif /* macII */
X
X#ifdef mips
X# ifdef SYSTYPE_SYSV
X# define KERNEL_FILE "/unix"
X# else
X# define KERNEL_FILE "/vmunix"
X# endif /* SYSTYPE_SYSV */
X#endif /* mips */
X
X#ifdef sequent
X#define KERNEL_FILE "/dynix"
X#endif /* sequent */
X
X/*
X * provide default for everyone else
X */
X#ifndef KERNEL_FILE
X#ifdef SYSV
X#define KERNEL_FILE "/unix"
X#else
X#define KERNEL_FILE "/vmunix"
X#endif /* SYSV */
X#endif /* KERNEL_FILE */
X#endif /* KERNEL_FILE */
X
X#ifndef KERNEL_LOAD_VARIABLE
X/*
X * provide default
X */
X#    ifdef USG
X#        define KERNEL_LOAD_VARIABLE "sysinfo"
X#        define SYSINFO
X#    else
X#        define KERNEL_LOAD_VARIABLE "_avenrun"
X#    endif
X
X#    ifdef alliant
X#        undef KERNEL_LOAD_VARIABLE
X#        define KERNEL_LOAD_VARIABLE "_Loadave"
X#    endif /* alliant */
X
X#    ifdef CRAY
X#        if defined(CRAY2) && OSMAJORVERSION == 4
X#            undef KERNEL_LOAD_VARIABLE
X#            define KERNEL_LOAD_VARIABLE "avenrun"
X#        else
X#            undef KERNEL_LOAD_VARIABLE
X#            define KERNEL_LOAD_VARIABLE "sysinfo"
X#            define SYSINFO
X#        endif /* defined(CRAY2) && OSMAJORVERSION == 4 */
X#    endif /* CRAY */
X
X#    ifdef hpux
X#        ifdef hp9000s800
X#            undef KERNEL_LOAD_VARIABLE
X#            define KERNEL_LOAD_VARIABLE "avenrun"
X#        endif /* hp9000s800 */
X#    endif /* hpux */
X
X#    ifdef mips
X#        ifdef SYSTYPE_SYSV
X#            undef KERNEL_LOAD_VARIABLE
X#            define KERNEL_LOAD_VARIABLE "avenrun"
X#        else
X#            undef KERNEL_LOAD_VARIABLE
X#            define KERNEL_LOAD_VARIABLE "_avenrun"
X#        endif /* SYSTYPE_SYSV */
X#    endif /* mips */
X
X#    ifdef sequent
X#        define KERNEL_FILE "/dynix"
X#    endif /* sequent */
X#endif /* KERNEL_LOAD_VARIABLE */
X
X#ifdef macII
Xstruct var v;
Xstatic int pad[2];	/* This padding is needed if getloadavg compiled on */
X			/* a/ux 1.1 is executed on a/ux 1.0, because */
X			/* the var structure had too much padding in 1.0, */
X			/* so the 1.0 kernel writes past the end of the 1.1 */
X			/* var structure in the uvar() call. */
Xstatic struct nlist nl[2];
Xstatic struct lavnum vec[3];
X#else /* not macII */
Xstatic struct nlist namelist[] = {	    /* namelist for vmunix grubbing */
X#define LOADAV 0
X    {KERNEL_LOAD_VARIABLE},
X    {0}
X};
X#endif /* macII */
X
X
X/* ARGSUSED */
Xint getloadavg( call_data )
X     caddr_t	call_data;	/* pointer to (double) return value */
X{
X  	double *loadavg = (double *)call_data;
X	static int init = 0;
X	static kmem;
X	static long loadavg_seek;
X#ifdef macII
X        extern nlist();
X
X        if(!init)   {
X            int i;
X
X            strcpy(nl[0].n_name, "avenrun");
X            nl[1].n_name[0] = '\0';
X
X            kmem = open(KMEM_FILE, O_RDONLY);
X            if (kmem < 0) {
X		return (-1);
X	    }
X
X            uvar(&v);
X
X            if (nlist( KERNEL_FILE, nl) != 0) {
X		return (-1);
X	    }
X            for (i = 0; i < 2; i++) {
X                nl[i].n_value = (int)nl[i].n_value - v.v_kvoffset;
X            }
X            init = 1;
X        }
X#else /* not macII */
X	extern void nlist();
X	
X	if(!init)   {
X	    nlist( KERNEL_FILE, namelist);
X/*
X * Some systems appear to set only one of these to Zero if the entry could
X * not be found, I hope no_one returns Zero as a good value, or bad things
X * will happen to you.  (I have a hard time believing the value will
X * ever really be zero anyway).   CDP 5/17/89.
X */
X	    if (namelist[LOADAV].n_type == 0 ||
X		namelist[LOADAV].n_value == 0) {
X		return (-1);
X	    }
X	    loadavg_seek = namelist[LOADAV].n_value;
X#if defined(mips) && defined(SYSTYPE_SYSV)
X	    loadavg_seek &= 0x7fffffff;
X#endif /* mips && SYSTYPE_SYSV */
X#if (defined(CRAY) && defined(SYSINFO))
X 	    loadavg_seek += ((char *) (((struct sysinfo *)NULL)->avenrun)) -
X	                    ((char *) NULL);
X#endif /* SYSINFO */
X  
X	    kmem = open(KMEM_FILE, O_RDONLY);
X	    if (kmem < 0)
X		return (-1);
X	    init = 1;
X	}
X	
X
X	(void) lseek(kmem, loadavg_seek, 0);
X#endif /* macII */
X#if defined(sun) || defined (UTEK) || defined(sequent) ||
defined(alliant) || defined(hp9000)
X	{
X		long temp;
X		(void) read(kmem, (char *)&temp, sizeof(long));
X		*loadavg = (double)temp/FSCALE;
X	}
X#else /* else not sun */
X# ifdef macII
X        {
X                lseek(kmem, (long)nl[X_AVENRUN].n_value, 0);
X                read(kmem, vec, 3*sizeof(struct lavnum));
X                *loadavg = fxtod(0);
X        }
X# else /* else not macII */
X#  ifdef mips
X	{
X		fix temp;
X		(void) read(kmem, (char *)&temp, sizeof(fix));
X		*loadavg = FIX_TO_DBL(temp);
X	}
X#  else /* not mips */
X	(void) read(kmem, (char *)loadavg, sizeof(double));
X#  endif /* mips */
X# endif /* macII */
X#endif /* sun */
X	return(0);
X}
X#endif /* LOADSTUB */
X#endif /* KVM_ROUTINES */
X#endif /* apollo */
X
END_OF_FILE
if test 9617 -ne `wc -c <'work/sendmail-5.64/src/getloadavg.c'`; then
    echo shar: \"'work/sendmail-5.64/src/getloadavg.c'\" unpacked with
wrong size!
fi
# end of 'work/sendmail-5.64/src/getloadavg.c'
fi
echo shar: End of shell archive.
exit 0