1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
|
/* $Id: activeCpu.c,v 1.10 2003/01/29 05:31:39 graziano Exp $ */
#include "config_nws.h"
#include <stdlib.h>
#include <sys/types.h> /* pid_t */
#include <sys/wait.h> /* wait() */
#include <setjmp.h> /* {long,set}jmp() */
#include <signal.h> /* signal() */
#include <unistd.h> /* nice() pipe() */
#include "diagnostic.h" /* FAIL() */
#include "osutil.h" /* SetRealTimer() */
#include "spinner.h" /* spin() */
#include "activeCpu.h"
#define READ_END 0
#define WRITE_END 1
#define SPIN_TIMED_OUT 1
/* The process state, saved before the spinner invocation. */
static sigjmp_buf preSpin;
/* A SIGALRM handler that aborts the spinner call when invoked. */
static void
SpinTimeOut(int sig) {
longjmp(preSpin, SPIN_TIMED_OUT);
}
int
ActiveCpuGetLoad(unsigned short niceValue,
unsigned int maxWait,
unsigned int testLength,
double *available) {
int connection[2];
pid_t childPid;
unsigned long cpuTime;
void (*oldHandler)(int);
unsigned long wallTime;
if (niceValue != 0) {
/*
** Since we can't ever reduce our nice value, we have to run any niced
** spinner in a forked process. We use a communication channel to report
** results from the forked process to the parent.
*/
if(pipe(connection) != 0) {
FAIL("ActiveCpuGetLoad: pipe() failed\n");
}
childPid = fork();
if(childPid < 0) {
FAIL("ActiveCpuGetLoad: fork() failed\n");
}
else if(childPid > 0) {
/* Parent process. */
close(connection[WRITE_END]);
read(connection[READ_END], available, sizeof(*available));
close(connection[READ_END]);
wait(NULL);
return(*available >= 0.0);
}
/* Child comes here. */
close(connection[READ_END]);
nice(niceValue);
}
/*
** Set an alarm and begin the spin process. If the alarm goes off before the
** spin completes, setjmp() will return (via SpinTimeOut()) SPIN_TIMED_OUT
** and we report that no cpu is availble. This is overly pessimistic; we
** should probably look at the rusage ourselves and report the actual amount
** of CPU we received. Also, if we really get *no* CPU time, then we'll
** never be able to execute any of this code anyway.
*/
oldHandler = signal(SIGALRM, SpinTimeOut);
SetRealTimer(maxWait);
*available = (setjmp(preSpin) == SPIN_TIMED_OUT) ? 0.0 :
(spin(testLength, &cpuTime, &wallTime) && (wallTime > 0.0)) ?
((float)cpuTime / (float)wallTime) : -1.0;
RESETREALTIMER;
(void)signal(SIGALRM, oldHandler);
if (niceValue != 0) {
write(connection[WRITE_END], available, sizeof(*available));
close(connection[WRITE_END]);
exit(0);
}
return(*available >= 0.0);
}
|