#include "mk.h" typedef struct Event { int pid; Job *job; } Event; static Event *events; static int nevents, nrunning; typedef struct Process { int pid; int status; struct Process *b, *f; } Process; static Process *phead, *pfree; static void pnew(), pdelete(); static char *envy[1024]; static char **special; static pidslot(); run(j) Job *j; { register Job *jj; if(jobs){ for(jj = jobs; jj->next; jj = jj->next) ; jj->next = j; } else jobs = j; j->next = 0; /* this code also in waitup after parse redirect */ if(nrunning < nproclimit) sched(); } sched() { register Job *j; char buf[BIGBLOCK]; int slot, pip[2], pid; Node *n; if(jobs == 0){ account(); return; } j = jobs; jobs = j->next; if(DEBUG(D_EXEC)) fprint(1, "firing up job for target %s\n", wtos(j->t)); slot = nextslot(); events[slot].job = j; dovars(j, slot); shprint(j->r->recipe, envy, buf); if(!tflag && !mflag && (nflag || !(j->r->attr&QUIET))) Fwrite(1, buf, (long)strlen(buf)); if(mflag){ for(n = j->n; n; n = n->next) symlook(n->name, S_MAKEFILE, (char *)j); } if(nflag||tflag){ for(n = j->n; n; n = n->next){ if(tflag){ if(!(n->flags&VIRTUAL)) touch(n->name); else if(explain) Fprint(1, "no touch of virtual '%s'\n", n->name); } n->time = time((long *)0); MADESET(n, MADE); } } else { Fexit(0); if(j->r->attr&RED){ if(pipe(pip) < 0){ perror("pipe"); Exit(); } } if((pid = fork()) < 0){ perror("mk fork"); Exit(); } if(pid == 0){ if(j->r->attr&RED){ close(pip[0]); dup2(pip[1], 1); close(pip[1]); } if(pipe(pip) < 0){ perror("pipe-i"); Exit(); } if((pid = fork()) < 0){ perror("mk fork"); Exit(); } if(pid != 0){ close(pip[1]); dup2(pip[0], 0); close(pip[0]); execle(SHELL, "sh", "-e", (char *)0, envy); perror(SHELL); _exit(1); } else { int k; char *s, *send; close(pip[0]); s = j->r->recipe; send = s+strlen(s); while(s < send){ if((k = write(pip[1], s, send-s)) < 0) break; s += k; } _exit(0); } } account(); nrunning++; if(j->r->attr&RED) close(pip[1]), j->fd = pip[0]; else j->fd = -1; if(DEBUG(D_EXEC)) fprint(1, "pid for target %s = %d\n", wtos(j->t), pid); events[slot].pid = pid; } } waitup(echildok, retstatus) int *retstatus; { int status, pid; int slot; Symtab *s; Word *w; Job *j; char buf[64]; char buf1[BIGBLOCK]; int uarg = 0; int done; Node *n; Process *p; extern int errno, runerrs; /* first check against the proces slist */ if(retstatus) for(p = phead; p; p = p->f) if(p->pid == *retstatus){ *retstatus = p->status; pdelete(p); return(-1); } again: /* rogue processes */ if((pid = wait(&status)) < 0){ if(echildok > 0){ return(1); } else { fprint(2, "mk: (waitup %d) ", echildok); perror("mk wait"); Exit(); } } if(DEBUG(D_EXEC)) fprint(1, "waitup got pid=%d, status=0x%ux\n", pid, status); if(retstatus && (pid == *retstatus)){ *retstatus = status; return(-1); } slot = pidslot(pid); if(slot < 0){ if(DEBUG(D_EXEC)) fprint(2, "mk: wait returned unexpected process %d\n", pid); pnew(pid, status); goto again; } j = events[slot].job; account(); nrunning--; events[slot].pid = -1; if(status){ dovars(j, slot); shprint(j->r->recipe, envy, buf1); front(buf1); Fprint(2, "mk: %s: exit status=%d", buf1, 0xFF&(status>>8)); status &= 0xFF; if(status&0x7F) Fprint(2, " signal=%d", status&0x7F); if(status&0x80) Fprint(2, ", core dumped"); for(n = j->n, done = 0; n; n = n->next) if(n->flags&DELETE){ if(done++ == 0) Fprint(2, ", deleting"); Fprint(2, " '%s'", n->name); } Fputc(2, '\n'); for(n = j->n, done = 0; n; n = n->next) if(n->flags&DELETE){ if(done++ == 0) Fflush(2); delete(n->name); } if(kflag){ runerrs++; uarg = 1; Fflush(2); } else { jobs = 0; Exit(); } } if(j->fd >= 0){ sprint(buf, "process %d", pid); parse(buf, j->fd, 0, 0); execinit(); /* reread environ */ nproc(); while(jobs && (nrunning < nproclimit)) sched(); } for(w = j->t; w; w = w->next){ if((s = symlook(w->s, S_NODE, (char *)0)) == 0) continue; /* not interested in this node */ update(uarg, (Node *)s->value); } if(nrunning < nproclimit) sched(); return(0); } execinit() { extern char **environ; extern char **vardump(); register char *s, *ss, c; Symtab *st; environ = envy; special = vardump(envy); if(st = symlook("ENVIRON", S_VAR, (char *)0)) for(s = st->value; *s;){ for(ss = s; *ss && (*ss != 1); ss++); c = *ss; *ss = 0; *special++ = strdup(s); s = ss; if(*ss = c) s++; } *special = 0; } char *myenv[] = { "target", "stem", "prereq", "pid", "nproc", "newprereq", "alltarget", "stem1", "stem2", "stem3", "stem4", "stem5", "stem6", "stem7", "stem8", "stem9", "stem0", 0 }; dovars(j, slot) register Job *j; { char buf[BIGBLOCK]; char *s, *t; int i, n = 0; #define SPECIAL ((sizeof myenv)/(sizeof myenv[0])-1) #define VSET(name, exp) {strcpy(buf, "name="); strcpy(strchr(buf, 0), exp);} for(i = 0; i < SPECIAL; i++) if(special[i]) free(special[i]); VSET(target, s = wtos(j->t)); special[n++] = strdup(buf); free(s); /* WATCH OUT; stem set below if reg exp!! */ VSET(stem, j->stem); special[n++] = strdup(buf); VSET(prereq, s = wtos(j->p)); special[n++] = strdup(buf); free(s); sprint(buf, "pid=%d", getpid()); special[n++] = strdup(buf); sprint(buf, "nproc=%d", slot); special[n++] = strdup(buf); VSET(newprereq, s = wtos(j->np)); special[n++] = strdup(buf); free(s); VSET(alltarget, s = wtos(j->at)); special[n++] = strdup(buf); free(s); for(i = 0; i <= 9; i++){ sprint(buf, "stem%d=", i); if(j->r->attr®EXP){ for(s = buf; *s; s++); for(t = j->match[i].sp; t < j->match[i].ep; *s++ = *t++); *s = 0; } special[n+i] = strdup(buf); if((i == 1) && (j->r->attr®EXP)){ buf[1] = 's'; buf[2] = 't'; buf[3] = 'e'; buf[4] = 'm'; special[1] = strdup(buf+1); } } special[SPECIAL] = 0; } nproc() { register Symtab *sym; if(sym = symlook("NPROC", S_VAR, (char *)0)) nproclimit = atoi(sym->value); if(nproclimit < 1) nproclimit = 1; if(DEBUG(D_EXEC)) fprint(1, "nprocs = %d\n", nproclimit); if(nproclimit > nevents){ if(nevents) events = (Event *)realloc((char *)events, nproclimit*sizeof(Event)); else events = (Event *)malloc(nproclimit*sizeof(Event)); while(nevents < nproclimit) events[nevents++].pid = 0; } } nextslot() { register i; for(i = 0; i < nproclimit; i++) if(events[i].pid <= 0) return(i); assert("out of slots!!", 0); return(0); /* cyntax */ } static pidslot(pid) { register i; for(i = 0; i < nevents; i++) if(events[i].pid == pid) return(i); return(-1); } static void pnew(pid, status) { register Process *p; if(pfree){ p = pfree; pfree = p->f; } else p = (Process *)Malloc(sizeof(Process)); p->pid = pid; p->status = status; p->f = phead; phead = p; if(p->f) p->f->b = p; p->b = 0; } static void pdelete(p) Process *p; { if(p->f) p->f->b = p->b; if(p->b) p->b->f = p->f; else phead = p->f; p->f = pfree; pfree = p; } static long tslot[1000]; static long tick; account() { long t; time(&t); if(tick) tslot[nrunning] += (t-tick); tick = t; } praccount() { int i; account(); for(i = 0; i <= nevents; i++) Fprint(1, "%d: %ld\n", i, tslot[i]); }