home *** CD-ROM | disk | FTP | other *** search
- /*
- * dummy code for execl test [ old version of makework.c ]
- *
- * makework [ -r rate ] [ -c copyfile ] nusers
- *
- * job streams are specified on standard input with lines of the form
- * full_path_name_for_command [ options ] [ <standard_input_file ]
- *
- * "standard input" is send to all nuser instances of the commands in the
- * job streams at a rate not in excess of "rate" characters per second
- * per command
- *
- * $Header: big.c,v 1.2 87/06/22 14:22:40 kjmcdonell Beta $
- */
-
- #include <stdio.h>
- #include <signal.h>
-
- #define DEF_RATE 5.0
- #define GRANULE 5
- #define CHUNK 60
- #define MAXCHILD 12
- #define MAXWORK 10
-
- float thres;
- float est_rate = DEF_RATE;
- int nusers; /* number of concurrent users to be simulated by
- * this process */
- int firstuser; /* ordinal identification of first user for this
- * process */
- int nwork = 0; /* number of job streams */
- int exit_status = 0; /* returned to parent */
- int sigpipe; /* pipe write error flag */
-
- struct st_work {
- char *cmd; /* name of command to run */
- char **av; /* arguments to command */
- char *input; /* standard input buffer */
- int inpsize; /* size of standard input buffer */
- char *outf; /* standard output (filename) */
- } work[MAXWORK];
-
- struct {
- int xmit; /* # characters sent */
- char *bp; /* std input buffer pointer */
- int blen; /* std input buffer length */
- int fd; /* stdin to command */
- int pid; /* child PID */
- char *line; /* start of input line */
- int firstjob; /* inital piece of work */
- int thisjob; /* current piece of work */
- } child[MAXCHILD], *cp;
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int i;
- int l;
- int fcopy = 0; /* fd for copy output */
- int master = 1; /* the REAL master, == 0 for clones */
- int nchild; /* no. of children for a clone to run */
- int done; /* count of children finished */
- int output; /* aggregate output char count for all
- children */
- int c;
- int thiswork = 0; /* next job stream to allocate */
- int nch; /* # characters to write */
- int written; /* # characters actully written */
- char logname[15]; /* name of the log file(s) */
- int onalarm();
- int pipeerr();
- int wrapup();
- int grunt();
- int pvec[2]; /* for pipes */
- char *p;
- char *prog; /* my name */
-
- #if ! debug
- freopen("masterlog.00", "a", stderr);
- #endif
- fprintf(stderr, "*** New Run *** ");
- prog = argv[0];
- while (argc > 1 && argv[1][0] == '-') {
- p = &argv[1][1];
- argc--;
- argv++;
- while (*p) {
- switch (*p) {
- case 'r':
- est_rate = atoi(argv[1]);
- sscanf(argv[1], "%f", &est_rate);
- if (est_rate <= 0) {
- fprintf(stderr, "%s: bad rate, reset to %.2f chars/sec\n", prog, DEF_RATE);
- est_rate = DEF_RATE;
- }
- argc--;
- argv++;
- break;
-
- case 'c':
- fcopy = open(argv[1], 1);
- if (fcopy < 0)
- fcopy = creat(argv[1], 0600);
- if (fcopy < 0) {
- fprintf(stderr, "%s: cannot open copy file '%s'\n",
- prog, argv[1]);
- exit(2);
- }
- lseek(fcopy, 0L, 2); /* append at end of file */
- argc--;
- argv++;
- break;
-
- default:
- fprintf(stderr, "%s: bad flag '%c'\n", prog, *p);
- exit(4);
- }
- p++;
- }
- }
-
- if (argc < 2) {
- fprintf(stderr, "%s: missing nusers\n", prog);
- exit(4);
- }
-
- nusers = atoi(argv[1]);
- if (nusers < 1) {
- fprintf(stderr, "%s: impossible nusers (%d<-%s)\n", prog, nusers, argv[1]);
- exit(4);
- }
- fprintf(stderr, "%d Users\n", nusers);
- argc--;
- argv++;
-
- /* build job streams */
- getwork();
- #if debug
- dumpwork();
- #endif
-
- /* clone copies of myself to run up to MAXCHILD jobs each */
- firstuser = MAXCHILD;
- fprintf(stderr, "master pid %d\n", getpid());
- fflush(stderr);
- while (nusers > MAXCHILD) {
- fflush(stderr);
- if (nusers >= 2*MAXCHILD)
- /* the next clone must run MAXCHILD jobs */
- nchild = MAXCHILD;
- else
- /* the next clone must run the leftover jobs */
- nchild = nusers - MAXCHILD;
- if ((l = fork()) == -1) {
- /* fork failed */
- fatal("** clone fork failed **\n");
- goto bepatient;
- } else if (l > 0) {
- fprintf(stderr, "master clone pid %d\n", l);
- /* I am the master with nchild fewer jobs to run */
- nusers -= nchild;
- firstuser += MAXCHILD;
- continue;
- } else {
- /* I am a clone, run MAXCHILD jobs */
- #if ! debug
- sprintf(logname, "masterlog.%02d", firstuser/MAXCHILD);
- freopen(logname, "w", stderr);
- #endif
- master = 0;
- nusers = nchild;
- break;
- }
- }
- if (master)
- firstuser = 0;
-
- close(0);
- for (i = 0; i < nusers; i++ ) {
- fprintf(stderr, "user %d job %d ", firstuser+i, thiswork);
- if (pipe(pvec) == -1) {
- /* this is fatal */
- fatal("** pipe failed **\n");
- goto bepatient;
- }
- fflush(stderr);
- if ((child[i].pid = fork()) == 0) {
- int fd;
- /* the command */
- if (pvec[0] != 0) {
- close(0);
- dup(pvec[0]);
- }
- #if ! debug
- sprintf(logname, "userlog.%02d", firstuser+i);
- freopen(logname, "w", stderr);
- #endif
- for (fd = 3; fd < 24; fd++)
- close(fd);
- if (work[thiswork].outf[0] != '\0') {
- /* redirect std output */
- char *q;
- for (q = work[thiswork].outf; *q != '\n'; q++) ;
- *q = '\0';
- if (freopen(work[thiswork].outf, "w", stdout) == NULL) {
- fprintf(stderr, "makework: cannot open %s for std output\n",
- work[thiswork].outf);
- fflush(stderr);
- }
- *q = '\n';
- }
- execv(work[thiswork].cmd, work[thiswork].av);
- /* don't expect to get here! */
- fatal("** exec failed **\n");
- goto bepatient;
- }
- else if (child[i].pid == -1) {
- fatal("** fork failed **\n");
- goto bepatient;
- }
- else {
- close(pvec[0]);
- child[i].fd = pvec[1];
- child[i].line = child[i].bp = work[thiswork].input;
- child[i].blen = work[thiswork].inpsize;
- child[i].thisjob = thiswork;
- child[i].firstjob = thiswork;
- fprintf(stderr, "pid %d pipe fd %d", child[i].pid, child[i].fd);
- if (work[thiswork].outf[0] != '\0') {
- char *q;
- fprintf(stderr, " > ");
- for (q=work[thiswork].outf; *q != '\n'; q++)
- fputc(*q, stderr);
- }
- fputc('\n', stderr);
- thiswork++;
- if (thiswork >= nwork)
- thiswork = 0;
- }
- }
- fflush(stderr);
-
- srand(time(0));
- thres = 0;
- done = output = 0;
- for (i = 0; i < nusers; i++) {
- if (child[i].blen == 0)
- done++;
- else
- thres += est_rate * GRANULE;
- }
- est_rate = thres;
-
- signal(SIGALRM, onalarm);
- signal(SIGPIPE, pipeerr);
- alarm(GRANULE);
- while (done < nusers) {
- for (i = 0; i < nusers; i++) {
- cp = &child[i];
- if (cp->xmit >= cp->blen) continue;
- l = rand() % CHUNK + 1; /* 1-CHUNK chars */
- if (l == 0) continue;
- if (cp->xmit + l > cp->blen)
- l = cp->blen - cp->xmit;
- p = cp->bp;
- cp->bp += l;
- cp->xmit += l;
- #if debug
- fprintf(stderr, "child %d, %d processed, %d to go\n", i, cp->xmit, cp->blen - cp->xmit);
- #endif
- while (p < cp->bp) {
- if (*p == '\n' || (p == &cp->bp[-1] && cp->xmit >= cp->blen)) {
- /* write it out */
- nch = p - cp->line + 1;
- if ((written = write(cp->fd, cp->line, nch)) != nch) {
- /* argh! */
- cp->line[nch] = '\0';
- fprintf(stderr, "user %d job %d cmd %s ",
- firstuser+i, cp->thisjob, cp->line);
- fprintf(stderr, "write(,,%d) returns %d\n", nch, written);
- if (sigpipe)
- fatal("** SIGPIPE error **\n");
- else
- fatal("** write error **\n");
- goto bepatient;
-
- }
- if (fcopy)
- write(fcopy, cp->line, p - cp->line + 1);
- #if debug
- fprintf(stderr, "child %d gets \"", i);
- {
- char *q = cp->line;
- while (q <= p) {
- if (*q >= ' ' && *q <= '~')
- fputc(*q, stderr);
- else
- fprintf(stderr, "\\%03o", *q);
- q++;
- }
- }
- fputc('"', stderr);
- #endif
- cp->line = &p[1];
- }
- p++;
- }
- if (cp->xmit >= cp->blen) {
- done++;
- close(cp->fd);
- #if debug
- fprintf(stderr, "child %d, close std input\n", i);
- #endif
- }
- output += l;
- }
- while (output > thres) {
- pause();
- #if debug
- fprintf(stderr, "after pause: output, thres, done %d %.2f %d\n", output, thres, done);
- #endif
- }
- }
-
- bepatient:
- alarm(0);
- /****
- * If everything is going OK, we should simply be able to keep
- * looping unitil 'wait' fails, however some descendent process may
- * be in a state from which it can never exit, and so a timeout
- * is used.
- * 5 minutes should be ample, since the time to run all jobs is of
- * the order of 5-10 minutes, however some machines are painfully slow,
- * so the timeout has been set at 20 minutes (1200 seconds).
- ****/
- signal(SIGALRM, grunt);
- alarm(1200);
- while ((c = wait(&l)) != -1) {
- for (i = 0; i < nusers; i++) {
- if (c == child[i].pid) {
- fprintf(stderr, "user %d job %d pid %d done", firstuser+i, child[i].thisjob, c);
- if (l != 0) {
- if (l & 0x7f)
- fprintf(stderr, " status %d", l & 0x7f);
- if (l & 0xff00)
- fprintf(stderr, " exit code %d", (l>>8) & 0xff);
- exit_status = 4;
- }
- fputc('\n', stderr);
- c = child[i].pid = -1;
- break;
- }
- }
- if (c != -1) {
- fprintf(stderr, "master clone done, pid %d ", c);
- if (l != 0) {
- if (l & 0x7f)
- fprintf(stderr, " status %d", l & 0x7f);
- if (l & 0xff00)
- fprintf(stderr, " exit code %d", (l>>8) & 0xff);
- exit_status = 4;
- }
- fputc('\n', stderr);
- }
- }
- alarm(0);
- wrapup("Finished waiting ...");
-
-
- }
-
- onalarm()
- {
- thres += est_rate;
- signal(SIGALRM, onalarm);
- alarm(GRANULE);
- }
-
- grunt()
- {
- /* timeout after label "bepatient" in main */
- exit_status = 4;
- wrapup("Timed out waiting for jobs to finish ...");
- }
-
- pipeerr()
- {
- sigpipe++;
- }
-
- wrapup(reason)
- char *reason;
- {
- int i;
- int killed = 0;
- fflush(stderr);
- for (i = 0; i < nusers; i++) {
- if (child[i].pid > 0 && kill(child[i].pid, SIGKILL) != -1) {
- if (!killed) {
- killed++;
- fprintf(stderr, "%s\n", reason);
- fflush(stderr);
- }
- fprintf(stderr, "user %d job %d pid %d killed off\n", firstuser+i, child[i].thisjob, child[i].pid);
- fflush(stderr);
- }
- }
- exit(exit_status);
- }
-
- getwork()
- {
- int i;
- int f;
- int ac;
- char *lp;
- char *q;
- struct st_work *w;
- char line[512];
- char c;
- char *malloc(), *realloc();
-
- while (gets(line) != NULL) {
- if (nwork >= MAXWORK) {
- fprintf(stderr, stderr, "Too many jobs specified, .. increase MAXWORK\n");
- exit(4);
- }
- w = &work[nwork];
- lp = line;
- i = 1;
- while (*lp && *lp != ' ') {
- i++;
- lp++;
- }
- w->cmd = (char *)malloc(i);
- strncpy(w->cmd, line, i-1);
- w->cmd[i-1] = '\0';
- w->inpsize = 0;
- w->input = "";
- /* start to build arg list */
- ac = 2;
- w->av = (char **)malloc(2*sizeof(char *));
- q = w->cmd;
- while (*q) q++;
- q--;
- while (q >= w->cmd) {
- if (*q == '/') {
- q++;
- break;
- }
- q--;
- }
- w->av[0] = q;
- while (*lp) {
- if (*lp == ' ') {
- /* space */
- lp++;
- continue;
- }
- else if (*lp == '<') {
- /* standard input for this job */
- q = ++lp;
- while (*lp && *lp != ' ') lp++;
- c = *lp;
- *lp = '\0';
- if ((f = open(q, 0)) == -1) {
- fprintf(stderr, "cannot open input file (%s) for job %d\n",
- q, nwork);
- exit(4);
- }
- /* gobble input */
- w->input = (char *)malloc(512);
- while ((i = read(f, &w->input[w->inpsize], 512)) > 0) {
- w->inpsize += i;
- w->input = (char *)realloc(w->input, w->inpsize+512);
- }
- w->input = (char *)realloc(w->input, w->inpsize);
- close(f);
- /* extract stdout file name from line beginning "C=" */
- w->outf = "";
- for (q = w->input; q < &w->input[w->inpsize-10]; q++) {
- if (*q == '\n' && strncmp(&q[1], "C=", 2) == 0) {
- w->outf = &q[3];
- break;
- }
- }
- #if debug
- if (*w->outf) {
- fprintf(stderr, "stdout->");
- for (q=w->outf; *q != '\n'; q++)
- fputc(*q, stderr);
- fputc('\n', stderr);
- }
- #endif
- }
- else {
- /* a command option */
- ac++;
- w->av = (char **)realloc(w->av, ac*sizeof(char *));
- q = lp;
- i = 1;
- while (*lp && *lp != ' ') {
- lp++;
- i++;
- }
- w->av[ac-2] = (char *)malloc(i);
- strncpy(w->av[ac-2], q, i-1);
- w->av[ac-2][i-1] = '\0';
- }
- }
- w->av[ac-1] = (char *)0;
- nwork++;
- }
- }
-
- #if debug
- dumpwork()
- {
- int i;
- int j;
-
- for (i = 0; i < nwork; i++) {
- fprintf(stderr, "job %d: cmd: %s\n", i, work[i].cmd);
- j = 0;
- while (work[i].av[j]) {
- fprintf(stderr, "argv[%d]: %s\n", j, work[i].av[j]);
- j++;
- }
- fprintf(stderr, "input: %d chars text: ", work[i].inpsize);
- if (work[i].input == (char *)0)
- fprintf(stderr, "<NULL>\n");
- else {
- register char *pend;
- char *p;
- char c;
- p = work[i].input;
- while (*p) {
- pend = p;
- while (*pend && *pend != '\n')
- pend++;
- c = *pend;
- *pend = '\0';
- fprintf(stderr, "%s\n", p);
- *pend = c;
- p = &pend[1];
- }
- }
- }
- }
- #endif
-
- fatal(s)
- char *s;
- {
- int i;
- fprintf(stderr, s);
- fflush(stderr);
- perror("Reason?");
- fflush(stderr);
- for (i = 0; i < nusers; i++) {
- if (child[i].pid > 0 && kill(child[i].pid, SIGKILL) != -1) {
- fprintf(stderr, "pid %d killed off\n", child[i].pid);
- fflush(stderr);
- }
- }
- exit_status = 4;
- return;
- }
-