aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/mk/run.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/mk/run.c')
-rw-r--r--src/cmd/mk/run.c296
1 files changed, 296 insertions, 0 deletions
diff --git a/src/cmd/mk/run.c b/src/cmd/mk/run.c
new file mode 100644
index 00000000..3c0c7f3e
--- /dev/null
+++ b/src/cmd/mk/run.c
@@ -0,0 +1,296 @@
+#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): %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);
+ 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]);
+}