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); 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(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); 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) ", echildok); 125 perror("mk wait"); 126 Exit(); 127 } 128 } 129 if(DEBUG(D_EXEC)) 130 fprint(1, "waitup got pid=%d, status='%s'\n", pid, buf); 131 if(retstatus && pid == *retstatus){ 132 *retstatus = buf[0]? 1:0; 133 return(-1); 134 } 135 slot = pidslot(pid); 136 if(slot < 0){ 137 if(DEBUG(D_EXEC)) 138 fprint(2, "mk: wait returned unexpected process %d\n", pid); 139 pnew(pid, buf[0]? 1:0); 140 goto again; 141 } 142 j = events[slot].job; 143 usage(); 144 nrunning--; 145 events[slot].pid = -1; 146 if(buf[0]){ 147 e = buildenv(j, slot); 148 bp = newbuf(); 149 shprint(j->r->recipe, e, bp); 150 front(bp->start); 151 fprint(2, "mk: %s: exit status=%s", bp->start, buf); 152 freebuf(bp); 153 for(n = j->n, done = 0; n; n = n->next) 154 if(n->flags&DELETE){ 155 if(done++ == 0) 156 fprint(2, ", deleting"); 157 fprint(2, " '%s'", n->name); 158 delete(n->name); 159 } 160 fprint(2, "\n"); 161 if(kflag){ 162 runerrs++; 163 uarg = 1; 164 } else { 165 jobs = 0; 166 Exit(); 167 } 168 } 169 for(w = j->t; w; w = w->next){ 170 if((s = symlook(w->s, S_NODE, 0)) == 0) 171 continue; /* not interested in this node */ 172 update(uarg, (Node *)s->value); 173 } 174 if(nrunning < nproclimit) 175 sched(); 176 return(0); 177 } 178 179 void 180 nproc(void) 181 { 182 Symtab *sym; 183 Word *w; 184 185 if(sym = symlook("NPROC", S_VAR, 0)) { 186 w = (Word *) sym->value; 187 if (w && w->s && w->s[0]) 188 nproclimit = atoi(w->s); 189 } 190 if(nproclimit < 1) 191 nproclimit = 1; 192 if(DEBUG(D_EXEC)) 193 fprint(1, "nprocs = %d\n", nproclimit); 194 if(nproclimit > nevents){ 195 if(nevents) 196 events = (Event *)Realloc((char *)events, nproclimit*sizeof(Event)); 197 else 198 events = (Event *)Malloc(nproclimit*sizeof(Event)); 199 while(nevents < nproclimit) 200 events[nevents++].pid = 0; 201 } 202 } 203 204 int 205 nextslot(void) 206 { 207 int i; 208 209 for(i = 0; i < nproclimit; i++) 210 if(events[i].pid <= 0) return i; 211 assert("out of slots!!", 0); 212 return 0; /* cyntax */ 213 } 214 215 int 216 pidslot(int pid) 217 { 218 int i; 219 220 for(i = 0; i < nevents; i++) 221 if(events[i].pid == pid) return(i); 222 if(DEBUG(D_EXEC)) 223 fprint(2, "mk: wait returned unexpected process %d\n", pid); 224 return(-1); 225 } 226 227 228 static void 229 pnew(int pid, int status) 230 { 231 Process *p; 232 233 if(pfree){ 234 p = pfree; 235 pfree = p->f; 236 } else 237 p = (Process *)Malloc(sizeof(Process)); 238 p->pid = pid; 239 p->status = status; 240 p->f = phead; 241 phead = p; 242 if(p->f) 243 p->f->b = p; 244 p->b = 0; 245 } 246 247 static void 248 pdelete(Process *p) 249 { 250 if(p->f) 251 p->f->b = p->b; 252 if(p->b) 253 p->b->f = p->f; 254 else 255 phead = p->f; 256 p->f = pfree; 257 pfree = p; 258 } 259 260 void 261 killchildren(char *msg) 262 { 263 Process *p; 264 265 kflag = 1; /* to make sure waitup doesn't exit */ 266 jobs = 0; /* make sure no more get scheduled */ 267 for(p = phead; p; p = p->f) 268 expunge(p->pid, msg); 269 while(waitup(1, (int *)0) == 0) 270 ; 271 Bprint(&bout, "mk: %s\n", msg); 272 Exit(); 273 } 274 275 static long tslot[1000]; 276 static long tick; 277 278 void 279 usage(void) 280 { 281 long t; 282 283 t = time(0); 284 if(tick) 285 tslot[nrunning] += (t-tick); 286 tick = t; 287 } 288 289 void 290 prusage(void) 291 { 292 int i; 293 294 usage(); 295 for(i = 0; i <= nevents; i++) 296 fprint(1, "%d: %ld\n", i, tslot[i]); 297 } 298