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
run(Job * j)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
sched(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((long *)0);
75 MADESET(n, MADE);
76 }
77 } else {
78 if(DEBUG(D_EXEC))
79 fprint(1, "recipe='%s'\n", 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
waitup(int echildok,int * retstatus)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, s->u.ptr);
173 }
174 if(nrunning < nproclimit)
175 sched();
176 return(0);
177 }
178
179 void
nproc(void)180 nproc(void)
181 {
182 Symtab *sym;
183 Word *w;
184
185 if(sym = symlook("NPROC", S_VAR, 0)) {
186 w = sym->u.ptr;
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
nextslot(void)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
pidslot(int pid)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
pnew(int pid,int status)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
pdelete(Process * p)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
killchildren(char * msg)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 ulong tslot[1000];
276 static ulong tick;
277
278 void
usage(void)279 usage(void)
280 {
281 ulong t;
282
283 t = time(0);
284 if(tick)
285 tslot[nrunning] += t - tick;
286 tick = t;
287 }
288
289 void
prusage(void)290 prusage(void)
291 {
292 int i;
293
294 usage();
295 for(i = 0; i <= nevents; i++)
296 fprint(1, "%d: %lud\n", i, tslot[i]);
297 }
298