mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-15 11:20:03 +00:00
9aa1c92f74
syntax will change.
296 lines
5 KiB
C
296 lines
5 KiB
C
#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, j->r->shellt);
|
|
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, j->r->shellt, j->r->shellcmd);
|
|
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): %r\n", echildok);
|
|
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, j->r->shellt);
|
|
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]);
|
|
}
|