Blob


1 #include "mk.h"
3 typedef struct Event
4 {
5 int pid;
6 Job *job;
7 } Event;
8 static Event *events;
9 static int nevents, nrunning, nproclimit;
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 *);
21 int pidslot(int);
23 void
24 run(Job *j)
25 {
26 Job *jj;
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 }
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;
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 }
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;
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);
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();
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);
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;
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);
159 fprint(2, "\n");
160 if(kflag){
161 runerrs++;
162 uarg = 1;
163 } else {
164 jobs = 0;
165 Exit();
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);
173 if(nrunning < nproclimit)
174 sched();
175 return(0);
178 void
179 nproc(void)
181 Symtab *sym;
182 Word *w;
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);
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;
203 int
204 nextslot(void)
206 int i;
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 */
214 int
215 pidslot(int pid)
217 int i;
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);
227 static void
228 pnew(int pid, int status)
230 Process *p;
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;
246 static void
247 pdelete(Process *p)
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;
259 void
260 killchildren(char *msg)
262 Process *p;
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)
270 Bprint(&bout, "mk: %s\n", msg);
271 Exit();
274 static long tslot[1000];
275 static long tick;
277 void
278 usage(void)
280 long t;
282 time(&t);
283 if(tick)
284 tslot[nrunning] += (t-tick);
285 tick = t;
288 void
289 prusage(void)
291 int i;
293 usage();
294 for(i = 0; i <= nevents; i++)
295 fprint(1, "%d: %ld\n", i, tslot[i]);