xref: /inferno-os/utils/mk/run.c (revision 9dc22068e29604f4b484e746112a9a4efe6fd57f)
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'", 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 	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 }
298