|
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++; } }