#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); voidrun(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 voidsched(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'", 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); }} intwaitup(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, (Node *)s->value); } if(nrunning < nproclimit) sched(); return(0);} voidnproc(void){ Symtab *sym; Word *w; if(sym = symlook("NPROC", S_VAR, 0)) { w = (Word *) sym->value; 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; }} intnextslot(void){ int i; for(i = 0; i < nproclimit; i++) if(events[i].pid <= 0) return i; assert("out of slots!!", 0); return 0; /* cyntax */} intpidslot(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 voidpnew(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 voidpdelete(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;} voidkillchildren(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 long tslot[1000];static long tick; voidusage(void){ long t; time(&t); if(tick) tslot[nrunning] += (t-tick); tick = t;} voidprusage(void){ int i; usage(); for(i = 0; i <= nevents; i++) fprint(1, "%d: %ld\n", i, tslot[i]);}
#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'", 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, (Node *)s->value);
}
if(nrunning < nproclimit)
sched();
return(0);
}
void
nproc(void)
{
Symtab *sym;
Word *w;
if(sym = symlook("NPROC", S_VAR, 0)) {
w = (Word *) sym->value;
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 long tslot[1000];
static long tick;
void
usage(void)
{
long t;
time(&t);
if(tick)
tslot[nrunning] += (t-tick);
tick = t;
}
void
prusage(void)
{
int i;
usage();
for(i = 0; i <= nevents; i++)
fprint(1, "%d: %ld\n", i, tslot[i]);
}