9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

run.c (5103B)


      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, 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 }
     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): %r\n", echildok);
    125 			Exit();
    126 		}
    127 	}
    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);
    133 	}
    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;
    140 	}
    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);
    158 			}
    159 		fprint(2, "\n");
    160 		if(kflag){
    161 			runerrs++;
    162 			uarg = 1;
    163 		} else {
    164 			jobs = 0;
    165 			Exit();
    166 		}
    167 	}
    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);
    172 	}
    173 	if(nrunning < nproclimit)
    174 		sched();
    175 	return(0);
    176 }
    177 
    178 void
    179 nproc(void)
    180 {
    181 	Symtab *sym;
    182 	Word *w;
    183 
    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);
    188 	}
    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;
    200 	}
    201 }
    202 
    203 int
    204 nextslot(void)
    205 {
    206 	int i;
    207 
    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 */
    212 }
    213 
    214 int
    215 pidslot(int pid)
    216 {
    217 	int i;
    218 
    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);
    224 }
    225 
    226 
    227 static void
    228 pnew(int pid, int status)
    229 {
    230 	Process *p;
    231 
    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;
    244 }
    245 
    246 static void
    247 pdelete(Process *p)
    248 {
    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;
    257 }
    258 
    259 void
    260 killchildren(char *msg)
    261 {
    262 	Process *p;
    263 
    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)
    269 		;
    270 	Bprint(&bout, "mk: %s\n", msg);
    271 	Exit();
    272 }
    273 
    274 static long tslot[1000];
    275 static long tick;
    276 
    277 void
    278 usage(void)
    279 {
    280 	long t;
    281 
    282 	time(&t);
    283 	if(tick)
    284 		tslot[nrunning] += (t-tick);
    285 	tick = t;
    286 }
    287 
    288 void
    289 prusage(void)
    290 {
    291 	int i;
    292 
    293 	usage();
    294 	for(i = 0; i <= nevents; i++)
    295 		fprint(1, "%d: %ld\n", i, tslot[i]);
    296 }