run.c (5103B)
1 #include "mk.h" 2 3 typedef struct Event 4 { 5 int pid; 6 Job *job; 7 } Event; 8 static Event *events; 9 static int nevents, nrunning, nproclimit; 10 11 typedef struct Process 12 { 13 int pid; 14 int status; 15 struct Process *b, *f; 16 } Process; 17 static Process *phead, *pfree; 18 static void sched(void); 19 static void pnew(int, int), pdelete(Process *); 20 21 int pidslot(int); 22 23 void 24 run(Job *j) 25 { 26 Job *jj; 27 28 if(jobs){ 29 for(jj = jobs; jj->next; jj = jj->next) 30 ; 31 jj->next = j; 32 } else 33 jobs = j; 34 j->next = 0; 35 /* this code also in waitup after parse redirect */ 36 if(nrunning < nproclimit) 37 sched(); 38 } 39 40 static void 41 sched(void) 42 { 43 char *flags; 44 Job *j; 45 Bufblock *buf; 46 int slot; 47 Node *n; 48 Envy *e; 49 50 if(jobs == 0){ 51 usage(); 52 return; 53 } 54 j = jobs; 55 jobs = j->next; 56 if(DEBUG(D_EXEC)) 57 fprint(1, "firing up job for target %s\n", wtos(j->t, ' ')); 58 slot = nextslot(); 59 events[slot].job = j; 60 buf = newbuf(); 61 e = buildenv(j, slot); 62 shprint(j->r->recipe, e, buf, j->r->shellt); 63 if(!tflag && (nflag || !(j->r->attr&QUIET))) 64 Bwrite(&bout, buf->start, (long)strlen(buf->start)); 65 freebuf(buf); 66 if(nflag||tflag){ 67 for(n = j->n; n; n = n->next){ 68 if(tflag){ 69 if(!(n->flags&VIRTUAL)) 70 touch(n->name); 71 else if(explain) 72 Bprint(&bout, "no touch of virtual '%s'\n", n->name); 73 } 74 n->time = time((long *)0); 75 MADESET(n, MADE); 76 } 77 } else { 78 if(DEBUG(D_EXEC)) 79 fprint(1, "recipe='%s'", j->r->recipe);/**/ 80 Bflush(&bout); 81 if(j->r->attr&NOMINUSE) 82 flags = 0; 83 else 84 flags = "-e"; 85 events[slot].pid = execsh(flags, j->r->recipe, 0, e, j->r->shellt, j->r->shellcmd); 86 usage(); 87 nrunning++; 88 if(DEBUG(D_EXEC)) 89 fprint(1, "pid for target %s = %d\n", wtos(j->t, ' '), events[slot].pid); 90 } 91 } 92 93 int 94 waitup(int echildok, int *retstatus) 95 { 96 Envy *e; 97 int pid; 98 int slot; 99 Symtab *s; 100 Word *w; 101 Job *j; 102 char buf[ERRMAX]; 103 Bufblock *bp; 104 int uarg = 0; 105 int done; 106 Node *n; 107 Process *p; 108 extern int runerrs; 109 110 /* first check against the proces slist */ 111 if(retstatus) 112 for(p = phead; p; p = p->f) 113 if(p->pid == *retstatus){ 114 *retstatus = p->status; 115 pdelete(p); 116 return(-1); 117 } 118 again: /* rogue processes */ 119 pid = waitfor(buf); 120 if(pid == -1){ 121 if(echildok > 0) 122 return(1); 123 else { 124 fprint(2, "mk: (waitup %d): %r\n", echildok); 125 Exit(); 126 } 127 } 128 if(DEBUG(D_EXEC)) 129 fprint(1, "waitup got pid=%d, status='%s'\n", pid, buf); 130 if(retstatus && pid == *retstatus){ 131 *retstatus = buf[0]? 1:0; 132 return(-1); 133 } 134 slot = pidslot(pid); 135 if(slot < 0){ 136 if(DEBUG(D_EXEC)) 137 fprint(2, "mk: wait returned unexpected process %d\n", pid); 138 pnew(pid, buf[0]? 1:0); 139 goto again; 140 } 141 j = events[slot].job; 142 usage(); 143 nrunning--; 144 events[slot].pid = -1; 145 if(buf[0]){ 146 e = buildenv(j, slot); 147 bp = newbuf(); 148 shprint(j->r->recipe, e, bp, j->r->shellt); 149 front(bp->start); 150 fprint(2, "mk: %s: exit status=%s", bp->start, buf); 151 freebuf(bp); 152 for(n = j->n, done = 0; n; n = n->next) 153 if(n->flags&DELETE){ 154 if(done++ == 0) 155 fprint(2, ", deleting"); 156 fprint(2, " '%s'", n->name); 157 delete(n->name); 158 } 159 fprint(2, "\n"); 160 if(kflag){ 161 runerrs++; 162 uarg = 1; 163 } else { 164 jobs = 0; 165 Exit(); 166 } 167 } 168 for(w = j->t; w; w = w->next){ 169 if((s = symlook(w->s, S_NODE, 0)) == 0) 170 continue; /* not interested in this node */ 171 update(uarg, s->u.ptr); 172 } 173 if(nrunning < nproclimit) 174 sched(); 175 return(0); 176 } 177 178 void 179 nproc(void) 180 { 181 Symtab *sym; 182 Word *w; 183 184 if(sym = symlook("NPROC", S_VAR, 0)) { 185 w = sym->u.ptr; 186 if (w && w->s && w->s[0]) 187 nproclimit = atoi(w->s); 188 } 189 if(nproclimit < 1) 190 nproclimit = 1; 191 if(DEBUG(D_EXEC)) 192 fprint(1, "nprocs = %d\n", nproclimit); 193 if(nproclimit > nevents){ 194 if(nevents) 195 events = (Event *)Realloc((char *)events, nproclimit*sizeof(Event)); 196 else 197 events = (Event *)Malloc(nproclimit*sizeof(Event)); 198 while(nevents < nproclimit) 199 events[nevents++].pid = 0; 200 } 201 } 202 203 int 204 nextslot(void) 205 { 206 int i; 207 208 for(i = 0; i < nproclimit; i++) 209 if(events[i].pid <= 0) return i; 210 assert("out of slots!!", 0); 211 return 0; /* cyntax */ 212 } 213 214 int 215 pidslot(int pid) 216 { 217 int i; 218 219 for(i = 0; i < nevents; i++) 220 if(events[i].pid == pid) return(i); 221 if(DEBUG(D_EXEC)) 222 fprint(2, "mk: wait returned unexpected process %d\n", pid); 223 return(-1); 224 } 225 226 227 static void 228 pnew(int pid, int status) 229 { 230 Process *p; 231 232 if(pfree){ 233 p = pfree; 234 pfree = p->f; 235 } else 236 p = (Process *)Malloc(sizeof(Process)); 237 p->pid = pid; 238 p->status = status; 239 p->f = phead; 240 phead = p; 241 if(p->f) 242 p->f->b = p; 243 p->b = 0; 244 } 245 246 static void 247 pdelete(Process *p) 248 { 249 if(p->f) 250 p->f->b = p->b; 251 if(p->b) 252 p->b->f = p->f; 253 else 254 phead = p->f; 255 p->f = pfree; 256 pfree = p; 257 } 258 259 void 260 killchildren(char *msg) 261 { 262 Process *p; 263 264 kflag = 1; /* to make sure waitup doesn't exit */ 265 jobs = 0; /* make sure no more get scheduled */ 266 for(p = phead; p; p = p->f) 267 expunge(p->pid, msg); 268 while(waitup(1, (int *)0) == 0) 269 ; 270 Bprint(&bout, "mk: %s\n", msg); 271 Exit(); 272 } 273 274 static long tslot[1000]; 275 static long tick; 276 277 void 278 usage(void) 279 { 280 long t; 281 282 time(&t); 283 if(tick) 284 tslot[nrunning] += (t-tick); 285 tick = t; 286 } 287 288 void 289 prusage(void) 290 { 291 int i; 292 293 usage(); 294 for(i = 0; i <= nevents; i++) 295 fprint(1, "%d: %ld\n", i, tslot[i]); 296 }