|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T p
Length: 17745 (0x4551)
Types: TextFile
Names: »process.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦f1ce22008⟧ »EurOpenD3/news/newsxd2.5.0.tar.Z«
└─⟦caa165e81⟧
└─⟦this⟧ »process.c«
/*
* #include <legal/bs.h>
>
> Copyright (c) 1989 Washington University in Saint Louis, Missouri and
> Chris Myers. All rights reserved.
>
> Permission is hereby granted to copy, reproduce, redistribute or
> otherwise use this software as long as: (1) there is no monetary
> profit gained specifically from the use or reproduction of this
> software, (2) it is not sold, rented, traded, or otherwise marketed,
> (3) the above copyright notice and this paragraph is included
> prominently in any copy made, and (4) that the name of the University
> is not used to endorse or promote products derived from this software
> without the specific prior written permission of the University.
> THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
> IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
> WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
>
*/
#include "defs.h"
extern int errno;
/*************************************************************************/
/* FUNCTION : kill_children */
/* PURPOSE : Kills all outstanding transmitters. Kill_children will */
/* wait ten seconds to allow all of the transmitters to exit */
/* gracefully. If invoked by a signal (SIGTERM?), exit else */
/* return to caller. */
/* ARGUMENTS : Signal number or 0 if to return to caller */
/*************************************************************************/
void
kill_children(sig)
int sig; /* sig will be nonzero if called by SIGTERM */
{
struct host *hostptr;
if ((hostlist == NULL) & (sig == 0)) return;
log(LOG_INFO, "newsxd: shutting down all transmitters\n");
foreach (hostptr, hostlist) {
if (hostptr->pid != 0) {
dprintf("newsxd: killing transmitter for %s\n", hostptr->hostname);
(void) kill (hostptr->pid, SIGTERM);
}
}
dprintf("(kill_children): sleeping 10 seconds\n");
(void) sleep(15); /* allow transmitters to quit gracefully */
if (sig == 0) return;
log(LOG_INFO, "shut down by signal %d\n", sig);
(void) exit(0); /* invoked by SIGTERM, time to quit */
}
/*************************************************************************/
/* FUNCTION : xmit_done */
/* PURPOSE : Catch the SIGCHLD from completed transmitters and do the */
/* necessary cleanup. Also wait synchronously for a xmitter */
/* to complete; also perform forced cleanup for an xmitter */
/* ARGUMENTS : sig, > 0 if xmit_done is called by SIGCHLD */
/* == 0 if called to check for a zombie w/NOHANG */
/* ==-1 if called to sync wait for a transmitter */
/* < -1 to perform a forced cleanup on a transmitter */
/*************************************************************************/
void
xmit_done(sig)
int sig; /* sig will be nonzero if called by SIGCHLD */
{
struct host *hostptr;
struct class *classptr;
union wait status;
struct rusage usage;
int options,
loop,
pid;
(void) sigsetmask(0);
/*
* Try and catch any completed transmitters first and process them.
* Then, if xmit_done() was called to synchronously wait on a transmitter
* or to perform forced cleanup on a transmitter, do it.
*/
while (1) {
Dprintf("(xmit_done) sig %d\n", sig);
if (sig != -1) options = WNOHANG;
pid = wait3(&status, options, &usage);
if (pid <= 0)
if (sig < -1) {
pid = -sig;
sig = 0;
} else
return;
Dprintf("(xmit_done) pid %d\n", pid);
for (loop = 0; loop < MAXXMITTERS; loop++) {
if (pidlist[loop] == pid) {
hostptr = pidmap[loop];
pidlist[loop] = 0;
pidmap[loop] = (struct host *) NULL;
foreach (classptr, classlist) {
if (strcmp(hostptr->class, classptr->classname) == 0) {
classptr->curxmits--;
hostptr->pid = 0;
freeclassslot(classptr, hostptr->classslot);
hostptr->whynot = WN_NOTMYTURN;
dprintf("%s: transmission completed\n",hostptr->hostname);
return;
}
}
/*
* The (sig < -1) check is here just in case a transmitter exitted
* normally just as run_queue tries to force a cleanup on it. If
* this isn't here, newsxd will abort with a corrupted data err.
*/
if (sig < -1) return;
/* Something is seriously wrong here -- quit somewhat gracefully */
logerr("newsxd: corrupted host/class structure!\n");
kill_children(1);
}
}
}
}
/*************************************************************************/
/* FUNCTION : run_queue */
/* PURPOSE : Go through the list of hosts to transmit to and start any */
/* transmitter that meets all of the necessary conditions */
/* ARGUMENTS : none */
/*************************************************************************/
void
run_queue()
{
struct host *hostptr;
struct class *classptr, *lastclass;
struct stat statbuf;
struct tm *curtime;
int clock,
pid,
hadtheirchance,
which,
which2,
loop,
loop2;
char fnbuf[MAXPATHLEN],
fnbuf2[MAXPATHLEN];
CONFIGCHANGED = 0;
hadtheirchance = 0;
lastclass = (struct class *) NULL;
foreach (hostptr, hostlist) {
/*
* If the configuration has been changed (possibly via SIGHUP), we
* need to assume that all of the current pointers and such are
* invalid since the current host MAY have been deleted...
*
* There is still a race condition, but this check lessens the chance
* of problems considerably.
*
*/
if (CONFIGCHANGED) {
dprintf("Reconfigured during queue run -- aborting queue run\n");
CONFIGCHANGED = 0;
return;
}
(void) time(&clock);
curtime = localtime(&clock);
classptr = getclass(hostptr->class);
if (classptr != lastclass) {
if (lastclass) {
dprintf("class %s: members %d, hadtheirchance %d\n",
lastclass->classname, lastclass->members, hadtheirchance);
if (lastclass->members == hadtheirchance) {
lastclass->xmitsernum++;
dprintf("class %s: add 1 to xmitsernum, now %d\n",
lastclass->classname, lastclass->xmitsernum);
}
}
hadtheirchance = 0;
lastclass = classptr;
}
/*
* Check and see if we somehow missed the SIGCHLD for a transmitter and
* it's really gone and we don't know it. If so, force a cleanup.
*/
if ((hostptr->pid) && (kill(hostptr->pid, 0) == -1) && (errno == ESRCH)) {
xmit_done(-hostptr->pid);
}
/*
* Check to see if the host has had a transmitter running for more
* than the ttl of its transmission class. If so, kill it.
*/
which = (hostptr->options.ttl) ?
hostptr->options.ttl : classptr->options.ttl;
which2 = (hostptr->options.ttlpenalty) ?
hostptr->options.ttlpenalty : classptr->options.ttlpenalty;
dprintf("%s: checking ttl (%d/%d)\n", hostptr->hostname, which, which2);
if ((hostptr->pid > 0) && (clock > (hostptr->lasttime + which))) {
dprintf("%s: exceeded ttl, killing\n");
hostptr->penaltytime = clock + which2;
if (kill(hostptr->pid, SIGTERM) != 0) xmit_done(-hostptr->pid);
hostptr->whynot = WN_TTL;
continue; /* skip this host to give others a chance */
}
/*
* If there is already a running transmitter for this host, skip it. We
* don't want more than one!
*/
dprintf("%s: checking for active daemon (%d)\n", hostptr->hostname,
hostptr->pid);
if (hostptr->pid > 0) {
hostptr->whynot = WN_RUNNING;
hadtheirchance++;
continue;
}
/*
* Check to see if this host has already had a chance to start
* a transmitter. If so, let someone else have a chance.
*/
dprintf("%s: xmitsernum is %d, class xmitsernum is %d\n",
hostptr->hostname, hostptr->xmitsernum, classptr->xmitsernum);
/*
if ((hostptr->xmitsernum == classptr->xmitsernum) &&
(classptr->maxxmits < classptr->members)) {
*/
if (hostptr->xmitsernum == classptr->xmitsernum) {
hadtheirchance++;
/* hostptr->whynot = WN_NOTMYTURN; */
continue;
}
/*
* Check the current time against the last time an xmit was started
* for this class to make sure we don't start too many daemons at
* one time.
*/
which = (hostptr->options.startint) ?
hostptr->options.startint : classptr->options.startint;
dprintf("%s: checking class startup interval (clock is %d, start %d)\n",
hostptr->hostname, clock, (classptr->laststart + which));
if (clock < (classptr->laststart + which)) {
hostptr->whynot = WN_CLASSSTARTINT;
continue;
}
/*
* Check the current load and compare against the maximum allowed
* load for starting new transmitters for this hosts's class.
*/
which = (hostptr->options.maxload) ?
hostptr->options.maxload : classptr->options.maxload;
dprintf("%s: checking maximum load (cur %d, max %d)\n",
hostptr->hostname, getla(), which);
if (getla() > which) {
hostptr->whynot = WN_LOAD;
continue;
}
/*
* Check the number of currently running transmitters for this host's
* transmission class. If we're already running at the limit, skip
* this host.
*/
dprintf("%s (%s): checking running xmit count (%d of %d)\n",
hostptr->hostname, classptr->classname, classptr->curxmits,
classptr->maxxmits);
if (classptr->curxmits >= classptr->maxxmits) {
hostptr->whynot = WN_MAXXMITS;
continue;
}
/*
* All tests after this point should be tests for some characteristic
* of the host that would cause it to avoid its turn to start its
* transmitter. Things like: the host startup interval hasn't passed
* yet, or it's a bad time to send to that host, or there's no work
* to send to that host.
*
* Tests before this point should be tests for some characteristic not
* related to the particular host that prevents it from being able to
* start its transmitter. Things like: load too high, too many xmits
* already running...
*/
/*
* This host had a chance to send news (and can possibly skip it).
*/
hostptr->xmitsernum = classptr->xmitsernum;
hadtheirchance++;
/*
* Check to see if the host had a transmitter killed because it ran
* longer than its class' ttl. If so, see if its penalty time is
* still unexpired.
*/
dprintf("%s: checking ttl penalty\n", hostptr->hostname);
if (hostptr->penaltytime > clock) {
hostptr->whynot = WN_PENALTYTIME;
continue;
}
/*
* Check the current time against the last time an xmit was started
* for this class to make sure we don't start a transmitter for this
* host too often...
*/
which = (hostptr->options.interval) ?
hostptr->options.interval : classptr->options.interval;
dprintf("%s: checking host startup interval (%d)\n", hostptr->hostname,
which);
if (clock < (hostptr->lasttime + which)) {
hostptr->whynot = WN_HOSTSTARTINT;
continue;
}
/*
* Check to see that the current time is within the permitted range
* of transmission times. If not, skip this host.
*/
dprintf("%s: checking valid transmission times (%s)\n",
hostptr->hostname, hostptr->times);
if (!validtime(hostptr->times)) {
hostptr->whynot = WN_BADTIME;
continue;
}
/*
* See if there is an outstanding work file for this host, if so we
* just need to run a transmitter, otherwise rename the batch file
* to the work file and run the transmitter.
*/
(void) sprintf(fnbuf, workfile, hostptr->hostname);
dprintf("%s: checking for workfile (%s)\n",
hostptr->hostname, fnbuf);
if (classptr->flags[C_NOWORK] || (stat(fnbuf, &statbuf) != 0)) {
(void) sprintf(fnbuf2, batchfile, hostptr->hostname);
dprintf("%s: checking for batchfile (%s)\n",
hostptr->hostname, fnbuf2);
if (!classptr->flags[C_NOBATCH]) {
if (stat(fnbuf2, &statbuf) != 0) {
hostptr->whynot = WN_NOWORK;
continue;
} else {
hostptr->whynot = WN_RENAMEFAILED;
if (!classptr->flags[C_NOWORK] && rename(fnbuf2, fnbuf) != 0) {
dprintf("%s: rename failed (%s to %s)\n",
hostptr->hostname, fnbuf2, fnbuf);
continue;
}
}
}
}
/*
* Fork off a transmitter for this host
*/
hostptr->whynot = WN_RUNNING;
if ((hostptr->classslot = getclassslot(classptr)) == -1) {
hostptr->whynot = WN_NOSLOT;
exit(1);
}
if ((pid = fork()) == 0) {
/* Child. */
Dprintf("(%s): classslot is %d\n", hostptr->hostname,
hostptr->classslot);
dprintf("%s: spawning transmitter\n", hostptr->hostname);
if (!newsxdebug) {
(void) sprintf(fnbuf2, xmitlogs, hostptr->hostname);
(void) freopen(fnbuf2, "a", stdout);
(void) freopen(fnbuf2, "a", stderr);
}
(void) fprintf(stderr, "%s: begin at %02d:%02d:%02d\n",
hostptr->hostname, curtime->tm_hour, curtime->tm_min,
curtime->tm_sec);
(void) fflush(stderr);
which = (hostptr->options.deltanice) ?
hostptr->options.deltanice : classptr->options.deltanice;
if (which != 0) {
Dprintf("Changing transmitter nice by %d for %s\n",
which, hostptr->hostname);
(void) nice(which);
}
if (classptr->xargc == 0) {
classptr = getclass("DEFAULT");
if (classptr->xargc == 0) {
logerr("host %s: No DEFAULT xmitter defined -- aborting\n",
hostptr->hostname);
exit(1);
}
}
Dprintf("classptr->xargc = %d\n", classptr->xargc);
Dprintf("%s: EXECing %s with parameters:\n",
hostptr->hostname, classptr->xpath);
classptr->xargv[classptr->xargc] = NULL;
for (loop = 0; loop < classptr->xargc; loop++)
if (strcmp(classptr->xargv[loop], "%f") == NULL) {
if (hostptr->xargc == 0) {
classptr->xargc--;
for (loop2 = loop; loop2 < MAXEXECARGS-1; loop2++)
classptr->xargv[loop2] = classptr->xargv[loop2+1];
} else {
classptr->xargc += hostptr->xargc - 1;
for (loop2=MAXEXECARGS-hostptr->xargc; loop2 > loop; loop2--)
classptr->xargv[loop2+hostptr->xargc-1] = classptr->xargv[loop2];
for (loop2 = loop; loop2 < loop + hostptr->xargc; loop2++)
classptr->xargv[loop2] = hostptr->xargv[loop2 - loop];
loop += hostptr->xargc - 1;
}
}
Dprintf("(after host flag insertion) classptr->xargc = %d\n",
classptr->xargc);
for (loop = 0; loop <= classptr->xargc; loop++) {
/* WARNING: we are mangling the xargv array here! */
processarg(loop, hostptr, classptr);
if (classptr->xargv[loop] == NULL) {
Dprintf("arg[%d] = NULL\n", loop);
} else {
Dprintf("arg[%d] = %s\n", loop, classptr->xargv[loop]);
}
}
(void) execvp(classptr->xpath, classptr->xargv);
logerr("%s: can't exec %s\n", hostptr->hostname, classptr->xpath);
(void) exit(1); /* could not exec the news transmitter! */
} else {
/* Parent. */
if (pid == -1) {
logerr("host %s: Can't fork child.\n", hostptr->hostname);
continue;
}
for (loop = 0; loop < MAXXMITTERS; loop++) {
if (pidlist[loop] == 0) {
pidlist[loop] = pid;
pidmap[loop] = hostptr;
Dprintf("%s: entered into pidmap/list at %d\n",
hostptr->hostname, loop);
break;
}
}
hostptr->pid = pid;
hostptr->lasttime = clock;
classptr->laststart = clock;
classptr->curxmits++;
if (newsxdebug) xmit_done(-1); /* wait for xmitter to complete */
}
}
if (classptr->members == hadtheirchance) {
dprintf("class %s: add 1 to sernum (members %d, hadchance %d)\n",
classptr->classname, classptr->members, hadtheirchance);
classptr->xmitsernum++;
}
}