# # initially generated by c2l # Event: adt{ pid: int; job: ref Job; }; events: array of Event; nevents, nrunning, nproclimit: int; Process: adt{ pid: int; status: int; b: cyclic ref Process; f: cyclic ref Process; }; phead, pfree: ref Process; run(j: ref Job) { jj: ref Job; if(jobs != nil){ for(jj = jobs; jj.next != nil; jj = jj.next) ; jj.next = j; } else jobs = j; j.next = nil; # this code also in waitup after parse redirect if(nrunning < nproclimit) sched(); } sched() { flags: array of byte; j: ref Job; buf: ref Bufblock; slot: int; n: ref Node; e: array of Envy; if(jobs == nil){ usage(); return; } j = jobs; jobs = j.next; if(debug&D_EXEC) sys->fprint(sys->fildes(1), "firing up job for target %s\n", libc0->ab2s(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))) bout.write(buf.start, libc0->strlen(buf.start)); freebuf(buf); if(nflag || tflag){ bout.flush(); for(n = j.n; n != nil; n = n.next){ if(tflag){ if(!(n.flags&VIRTUAL)) touch(n.name); else if(explain != nil) bout.puts(sys->sprint("no touch of virtual '%s'\n", libc0->ab2s(n.name))); } n.time = daytime->now(); n.flags = n.flags&~(NOTMADE|BEINGMADE|MADE)|MADE; } } else{ if(debug&D_EXEC) sys->fprint(sys->fildes(1), "recipe='%s'", libc0->ab2s(j.r.recipe)); # bout.flush(); if(j.r.attr&NOMINUSE) flags = nil; else flags = libc0->s2ab("-e"); events[slot].pid = execsh(flags, j.r.recipe, nil, e); usage(); nrunning++; if(debug&D_EXEC) sys->fprint(sys->fildes(1), "pid for target %s = %d\n", libc0->ab2s(wtos(j.t, ' ')), events[slot].pid); } } waitup(echildok: int, retstatus: array of int): int { e: array of Envy; pid, slot: int; s: ref Symtab; w: ref Word; j: ref Job; buf := array[ERRLEN] of byte; bp: ref Bufblock; uarg: int = 0; done: int; n: ref Node; p: ref Process; runerrs: int; # first check against the proces slist if(retstatus != nil) for(p = phead; p != nil; p = p.f) if(p.pid == retstatus[0]){ retstatus[0] = p.status; pdelete(p); return -1; } # rogue processes for(;;){ pid = waitfor(buf); if(pid == -1){ if(echildok > 0) return 1; else{ sys->fprint(sys->fildes(2), "mk: (waitup %d) ", echildok); perrors("mk wait"); Exit(); } } if(debug&D_EXEC) sys->fprint(sys->fildes(1), "waitup got pid=%d, status='%s'\n", pid, libc0->ab2s(buf)); if(retstatus != nil && pid == retstatus[0]){ if(int buf[0]) retstatus[0] = 1; else retstatus[0] = 0; return -1; } slot = pidslot(pid); if(slot < 0){ if(debug&D_EXEC) sys->fprint(sys->fildes(2), "mk: wait returned unexpected process %d\n", pid); if(int buf[0]) pnew(pid, 1); else pnew(pid, 0); continue; } break; } j = events[slot].job; usage(); nrunning--; events[slot].pid = -1; if(int buf[0]){ e = buildenv(j, slot); bp = newbuf(); shprint(j.r.recipe, e, bp); front(bp.start); sys->fprint(sys->fildes(2), "mk: %s: exit status=%s", libc0->ab2s(bp.start), libc0->ab2s(buf)); freebuf(bp); for((n, done) = (j.n, 0); n != nil; n = n.next) if(n.flags&DELETE){ if(done++ == 0) sys->fprint(sys->fildes(2), ", deleting"); sys->fprint(sys->fildes(2), " '%s'", libc0->ab2s(n.name)); delete(n.name); } sys->fprint(sys->fildes(2), "\n"); if(kflag){ runerrs++; uarg = 1; } else{ jobs = nil; Exit(); } } for(w = j.t; w != nil; w = w.next){ if((s = symlooki(w.s, S_NODE, 0)) == nil) continue; # not interested in this node update(uarg, s.nvalue); } if(nrunning < nproclimit) sched(); return 0; } nproc() { sym: ref Symtab; w: ref Word; if((sym = symlooki(libc0->s2ab("NPROC"), S_VAR, 0)) != nil){ w = sym.wvalue; if(w != nil && w.s != nil && int w.s[0]) nproclimit = int string w.s; } if(nproclimit < 1) nproclimit = 1; if(debug&D_EXEC) sys->fprint(sys->fildes(1), "nprocs = %d\n", nproclimit); if(nproclimit > nevents){ if(nevents){ olen := len events; ne := array[nproclimit] of Event; if(olen) ne[0: ] = events[0: olen]; events = ne; } else events = array[nproclimit] of Event; while(nevents < nproclimit) events[nevents++].pid = 0; } } nextslot(): int { i: int; for(i = 0; i < nproclimit; i++) if(events[i].pid <= 0) return i; assert(libc0->s2ab("out of slots!!"), 0); return 0; # cyntax } pidslot(pid: int): int { i: int; for(i = 0; i < nevents; i++) if(events[i].pid == pid) return i; if(debug&D_EXEC) sys->fprint(sys->fildes(2), "mk: wait returned unexpected process %d\n", pid); return -1; } pnew(pid: int, status: int) { p: ref Process; if(pfree != nil){ p = pfree; pfree = p.f; } else p = ref Process; p.pid = pid; p.status = status; p.f = phead; phead = p; if(p.f != nil) p.f.b = p; p.b = nil; } pdelete(p: ref Process) { if(p.f != nil) p.f.b = p.b; if(p.b != nil) p.b.f = p.f; else phead = p.f; p.f = pfree; pfree = p; } killchildren(msg: array of byte) { p: ref Process; kflag = 1; # to make sure waitup doesn't exit jobs = nil; # make sure no more get scheduled for(p = phead; p != nil; p = p.f) expunge(p.pid, msg); while(waitup(1, nil) == 0) ; bout.puts(sys->sprint("mk: %s\n", libc0->ab2s(msg))); Exit(); } tslot := array[1000] of int; tick: int; usage() { t: int; t = daytime->now(); if(tick) tslot[nrunning] += t-tick; tick = t; } prusage() { i: int; usage(); for(i = 0; i <= nevents; i++) sys->fprint(sys->fildes(1), "%d: %d\n", i, tslot[i]); }