#include "mk.h" typedef struct Event { int pid; Job *job; } Event; static Event *events; static int nevents, nrunning, nproclimit; typedef struct Process { int pid; int status; struct Process *b, *f; } Process; static Process *phead, *pfree; static void sched(void); static void pnew(int, int), pdelete(Process *); int pidslot(int); void run(Job *j) { 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(); } static void sched(void) { char *flags; Job *j; Bufblock *buf; int slot; Node *n; Envy *e; if(jobs == 0){ usage(); 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; buf = newbuf(); e = buildenv(j, slot); shprint(j->r->recipe, e, buf); if(!tflag && (nflag || !(j->r->attr&QUIET))) Bwrite(&bout, buf->start, (long)strlen(buf->start)); freebuf(buf); if(nflag||tflag){ for(n = j->n; n; n = n->next){ if(tflag){ if(!(n->flags&VIRTUAL)) touch(n->name); else if(explain) Bprint(&bout, "no touch of virtual '%s'\n", n->name); } n->time = time((long *)0); MADESET(n, MADE); } } else { if(DEBUG(D_EXEC)) fprint(1, "recipe='%s'\n", j->r->recipe); /**/ Bflush(&bout); if(j->r->attr&NOMINUSE) flags = 0; else flags = "-e"; events[slot].pid = execsh(flags, j->r->recipe, 0, e); usage(); nrunning++; if(DEBUG(D_EXEC)) fprint(1, "pid for target %s = %d\n", wtos(j->t, ' '), events[slot].pid); } } int waitup(int echildok, int *retstatus) { Envy *e; int pid; int slot; Symtab *s; Word *w; Job *j; char buf[ERRMAX]; Bufblock *bp; int uarg = 0; int done; Node *n; Process *p; extern int 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 */ pid = waitfor(buf); if(pid == -1){ 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='%s'\n", pid, buf); if(retstatus && pid == *retstatus){ *retstatus = buf[0]? 1:0; return(-1); } slot = pidslot(pid); if(slot < 0){ if(DEBUG(D_EXEC)) fprint(2, "mk: wait returned unexpected process %d\n", pid); pnew(pid, buf[0]? 1:0); goto again; } j = events[slot].job; usage(); nrunning--; events[slot].pid = -1; if(buf[0]){ e = buildenv(j, slot); bp = newbuf(); shprint(j->r->recipe, e, bp); front(bp->start); fprint(2, "mk: %s: exit status=%s", bp->start, buf); freebuf(bp); 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); delete(n->name); } fprint(2, "\n"); if(kflag){ runerrs++; uarg = 1; } else { jobs = 0; Exit(); } } for(w = j->t; w; w = w->next){ if((s = symlook(w->s, S_NODE, 0)) == 0) continue; /* not interested in this node */ update(uarg, s->u.ptr); } if(nrunning < nproclimit) sched(); return(0); } void nproc(void) { Symtab *sym; Word *w; if(sym = symlook("NPROC", S_VAR, 0)) { w = sym->u.ptr; if (w && w->s && w->s[0]) nproclimit = atoi(w->s); } 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; } } int nextslot(void) { int i; for(i = 0; i < nproclimit; i++) if(events[i].pid <= 0) return i; assert(/*out of slots!!*/ 0); return 0; /* cyntax */ } int pidslot(int pid) { int i; for(i = 0; i < nevents; i++) if(events[i].pid == pid) return(i); if(DEBUG(D_EXEC)) fprint(2, "mk: wait returned unexpected process %d\n", pid); return(-1); } static void pnew(int pid, int status) { 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(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; } void killchildren(char *msg) { Process *p; kflag = 1; /* to make sure waitup doesn't exit */ jobs = 0; /* make sure no more get scheduled */ for(p = phead; p; p = p->f) expunge(p->pid, msg); while(waitup(1, (int *)0) == 0) ; Bprint(&bout, "mk: %s\n", msg); Exit(); } static ulong tslot[1000]; static ulong tick; void usage(void) { ulong t; t = time(0); if(tick) tslot[nrunning] += t - tick; tick = t; } void prusage(void) { int i; usage(); for(i = 0; i <= nevents; i++) fprint(1, "%d: %lud\n", i, tslot[i]); }