]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/mk/run.c
ecee9819a174574190a2dc86ef6d3263bdb0064a
[plan9front.git] / sys / src / cmd / mk / run.c
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((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
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                         sysfatal("%s", buf);
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
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
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         time(&t);
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 }