| #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, 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 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]); | 
 | } |