xref: /plan9-contrib/sys/src/9k/port/sysproc.c (revision 094d68186d4cdde21fdab9786d6c843a03693e4e)
19ef1f84bSDavid du Colombier #include	"u.h"
29ef1f84bSDavid du Colombier #include	"tos.h"
39ef1f84bSDavid du Colombier #include	"../port/lib.h"
49ef1f84bSDavid du Colombier #include	"mem.h"
59ef1f84bSDavid du Colombier #include	"dat.h"
69ef1f84bSDavid du Colombier #include	"fns.h"
79ef1f84bSDavid du Colombier #include	"../port/error.h"
89ef1f84bSDavid du Colombier 
99ef1f84bSDavid du Colombier #include	"../port/edf.h"
109ef1f84bSDavid du Colombier #include	<a.out.h>
11d46407a3SDavid du Colombier #include	<ptrace.h>
129ef1f84bSDavid du Colombier 
139ef1f84bSDavid du Colombier void
sysr1(Ar0 * ar0,va_list list)149ef1f84bSDavid du Colombier sysr1(Ar0* ar0, va_list list)
159ef1f84bSDavid du Colombier {
169ef1f84bSDavid du Colombier 	USED(list);
179ef1f84bSDavid du Colombier 
189ef1f84bSDavid du Colombier 	ar0->i = 0;
199ef1f84bSDavid du Colombier }
209ef1f84bSDavid du Colombier 
219ef1f84bSDavid du Colombier void
sysrfork(Ar0 * ar0,va_list list)229ef1f84bSDavid du Colombier sysrfork(Ar0* ar0, va_list list)
239ef1f84bSDavid du Colombier {
249ef1f84bSDavid du Colombier 	Proc *p;
259ef1f84bSDavid du Colombier 	int flag, i, n, pid;
269ef1f84bSDavid du Colombier 	Fgrp *ofg;
279ef1f84bSDavid du Colombier 	Pgrp *opg;
289ef1f84bSDavid du Colombier 	Rgrp *org;
299ef1f84bSDavid du Colombier 	Egrp *oeg;
309ef1f84bSDavid du Colombier 	Mach *wm;
31d46407a3SDavid du Colombier 	void (*pt)(Proc*, int, vlong, vlong);
32d46407a3SDavid du Colombier 	u64int ptarg;
339ef1f84bSDavid du Colombier 
349ef1f84bSDavid du Colombier 	/*
359ef1f84bSDavid du Colombier 	 * int rfork(int);
369ef1f84bSDavid du Colombier 	 */
379ef1f84bSDavid du Colombier 	flag = va_arg(list, int);
389ef1f84bSDavid du Colombier 
399ef1f84bSDavid du Colombier 	/* Check flags before we commit */
409ef1f84bSDavid du Colombier 	if((flag & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG))
419ef1f84bSDavid du Colombier 		error(Ebadarg);
429ef1f84bSDavid du Colombier 	if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG))
439ef1f84bSDavid du Colombier 		error(Ebadarg);
449ef1f84bSDavid du Colombier 	if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG))
459ef1f84bSDavid du Colombier 		error(Ebadarg);
469ef1f84bSDavid du Colombier 
479ef1f84bSDavid du Colombier 	if((flag&RFPROC) == 0) {
489ef1f84bSDavid du Colombier 		if(flag & (RFMEM|RFNOWAIT))
499ef1f84bSDavid du Colombier 			error(Ebadarg);
509ef1f84bSDavid du Colombier 		if(flag & (RFFDG|RFCFDG)) {
519ef1f84bSDavid du Colombier 			ofg = up->fgrp;
529ef1f84bSDavid du Colombier 			if(flag & RFFDG)
539ef1f84bSDavid du Colombier 				up->fgrp = dupfgrp(ofg);
549ef1f84bSDavid du Colombier 			else
559ef1f84bSDavid du Colombier 				up->fgrp = dupfgrp(nil);
569ef1f84bSDavid du Colombier 			closefgrp(ofg);
579ef1f84bSDavid du Colombier 		}
589ef1f84bSDavid du Colombier 		if(flag & (RFNAMEG|RFCNAMEG)) {
599ef1f84bSDavid du Colombier 			opg = up->pgrp;
609ef1f84bSDavid du Colombier 			up->pgrp = newpgrp();
619ef1f84bSDavid du Colombier 			if(flag & RFNAMEG)
629ef1f84bSDavid du Colombier 				pgrpcpy(up->pgrp, opg);
639ef1f84bSDavid du Colombier 			/* inherit noattach */
649ef1f84bSDavid du Colombier 			up->pgrp->noattach = opg->noattach;
659ef1f84bSDavid du Colombier 			closepgrp(opg);
669ef1f84bSDavid du Colombier 		}
679ef1f84bSDavid du Colombier 		if(flag & RFNOMNT)
689ef1f84bSDavid du Colombier 			up->pgrp->noattach = 1;
699ef1f84bSDavid du Colombier 		if(flag & RFREND) {
709ef1f84bSDavid du Colombier 			org = up->rgrp;
719ef1f84bSDavid du Colombier 			up->rgrp = newrgrp();
729ef1f84bSDavid du Colombier 			closergrp(org);
739ef1f84bSDavid du Colombier 		}
749ef1f84bSDavid du Colombier 		if(flag & (RFENVG|RFCENVG)) {
759ef1f84bSDavid du Colombier 			oeg = up->egrp;
769ef1f84bSDavid du Colombier 			up->egrp = smalloc(sizeof(Egrp));
779ef1f84bSDavid du Colombier 			up->egrp->ref = 1;
789ef1f84bSDavid du Colombier 			if(flag & RFENVG)
799ef1f84bSDavid du Colombier 				envcpy(up->egrp, oeg);
809ef1f84bSDavid du Colombier 			closeegrp(oeg);
819ef1f84bSDavid du Colombier 		}
829ef1f84bSDavid du Colombier 		if(flag & RFNOTEG)
839ef1f84bSDavid du Colombier 			up->noteid = incref(&noteidalloc);
849ef1f84bSDavid du Colombier 
859ef1f84bSDavid du Colombier 		ar0->i = 0;
869ef1f84bSDavid du Colombier 		return;
879ef1f84bSDavid du Colombier 	}
889ef1f84bSDavid du Colombier 
899ef1f84bSDavid du Colombier 	p = newproc();
909ef1f84bSDavid du Colombier 
919ef1f84bSDavid du Colombier 	p->trace = up->trace;
929ef1f84bSDavid du Colombier 	p->scallnr = up->scallnr;
939ef1f84bSDavid du Colombier 	memmove(p->arg, up->arg, sizeof(up->arg));
949ef1f84bSDavid du Colombier 	p->nerrlab = 0;
959ef1f84bSDavid du Colombier 	p->slash = up->slash;
969ef1f84bSDavid du Colombier 	p->dot = up->dot;
979ef1f84bSDavid du Colombier 	incref(p->dot);
989ef1f84bSDavid du Colombier 
999ef1f84bSDavid du Colombier 	memmove(p->note, up->note, sizeof(p->note));
1009ef1f84bSDavid du Colombier 	p->privatemem = up->privatemem;
1019ef1f84bSDavid du Colombier 	p->nnote = up->nnote;
1029ef1f84bSDavid du Colombier 	p->notified = 0;
1039ef1f84bSDavid du Colombier 	p->lastnote = up->lastnote;
1049ef1f84bSDavid du Colombier 	p->notify = up->notify;
1059ef1f84bSDavid du Colombier 	p->ureg = up->ureg;
1069ef1f84bSDavid du Colombier 	p->dbgreg = 0;
1079ef1f84bSDavid du Colombier 
1089ef1f84bSDavid du Colombier 	/* Make a new set of memory segments */
1099ef1f84bSDavid du Colombier 	n = flag & RFMEM;
1109ef1f84bSDavid du Colombier 	qlock(&p->seglock);
1119ef1f84bSDavid du Colombier 	if(waserror()){
1129ef1f84bSDavid du Colombier 		qunlock(&p->seglock);
1139ef1f84bSDavid du Colombier 		nexterror();
1149ef1f84bSDavid du Colombier 	}
1159ef1f84bSDavid du Colombier 	for(i = 0; i < NSEG; i++)
1164498a243SDavid du Colombier 		if(up->seg[i] != nil)
1179ef1f84bSDavid du Colombier 			p->seg[i] = dupseg(up->seg, i, n);
1189ef1f84bSDavid du Colombier 	qunlock(&p->seglock);
1199ef1f84bSDavid du Colombier 	poperror();
1209ef1f84bSDavid du Colombier 
1219ef1f84bSDavid du Colombier 	/* File descriptors */
1229ef1f84bSDavid du Colombier 	if(flag & (RFFDG|RFCFDG)) {
1239ef1f84bSDavid du Colombier 		if(flag & RFFDG)
1249ef1f84bSDavid du Colombier 			p->fgrp = dupfgrp(up->fgrp);
1259ef1f84bSDavid du Colombier 		else
1269ef1f84bSDavid du Colombier 			p->fgrp = dupfgrp(nil);
1279ef1f84bSDavid du Colombier 	}
1289ef1f84bSDavid du Colombier 	else {
1299ef1f84bSDavid du Colombier 		p->fgrp = up->fgrp;
1309ef1f84bSDavid du Colombier 		incref(p->fgrp);
1319ef1f84bSDavid du Colombier 	}
1329ef1f84bSDavid du Colombier 
1339ef1f84bSDavid du Colombier 	/* Process groups */
1349ef1f84bSDavid du Colombier 	if(flag & (RFNAMEG|RFCNAMEG)) {
1359ef1f84bSDavid du Colombier 		p->pgrp = newpgrp();
1369ef1f84bSDavid du Colombier 		if(flag & RFNAMEG)
1379ef1f84bSDavid du Colombier 			pgrpcpy(p->pgrp, up->pgrp);
1389ef1f84bSDavid du Colombier 		/* inherit noattach */
1399ef1f84bSDavid du Colombier 		p->pgrp->noattach = up->pgrp->noattach;
1409ef1f84bSDavid du Colombier 	}
1419ef1f84bSDavid du Colombier 	else {
1429ef1f84bSDavid du Colombier 		p->pgrp = up->pgrp;
1439ef1f84bSDavid du Colombier 		incref(p->pgrp);
1449ef1f84bSDavid du Colombier 	}
1459ef1f84bSDavid du Colombier 	if(flag & RFNOMNT)
1469ef1f84bSDavid du Colombier 		p->pgrp->noattach = 1;
1479ef1f84bSDavid du Colombier 
1489ef1f84bSDavid du Colombier 	if(flag & RFREND)
1499ef1f84bSDavid du Colombier 		p->rgrp = newrgrp();
1509ef1f84bSDavid du Colombier 	else {
1519ef1f84bSDavid du Colombier 		incref(up->rgrp);
1529ef1f84bSDavid du Colombier 		p->rgrp = up->rgrp;
1539ef1f84bSDavid du Colombier 	}
1549ef1f84bSDavid du Colombier 
1559ef1f84bSDavid du Colombier 	/* Environment group */
1569ef1f84bSDavid du Colombier 	if(flag & (RFENVG|RFCENVG)) {
1579ef1f84bSDavid du Colombier 		p->egrp = smalloc(sizeof(Egrp));
1589ef1f84bSDavid du Colombier 		p->egrp->ref = 1;
1599ef1f84bSDavid du Colombier 		if(flag & RFENVG)
1609ef1f84bSDavid du Colombier 			envcpy(p->egrp, up->egrp);
1619ef1f84bSDavid du Colombier 	}
1629ef1f84bSDavid du Colombier 	else {
1639ef1f84bSDavid du Colombier 		p->egrp = up->egrp;
1649ef1f84bSDavid du Colombier 		incref(p->egrp);
1659ef1f84bSDavid du Colombier 	}
1669ef1f84bSDavid du Colombier 	p->hang = up->hang;
1679ef1f84bSDavid du Colombier 	p->procmode = up->procmode;
1689ef1f84bSDavid du Colombier 
1699ef1f84bSDavid du Colombier 	/* Craft a return frame which will cause the child to pop out of
1709ef1f84bSDavid du Colombier 	 * the scheduler in user mode with the return register zero
1719ef1f84bSDavid du Colombier 	 */
1729ef1f84bSDavid du Colombier 	sysrforkchild(p, up);
1739ef1f84bSDavid du Colombier 
1749ef1f84bSDavid du Colombier 	p->parent = up;
1759ef1f84bSDavid du Colombier 	p->parentpid = up->pid;
1769ef1f84bSDavid du Colombier 	if(flag&RFNOWAIT)
1779ef1f84bSDavid du Colombier 		p->parentpid = 0;
1789ef1f84bSDavid du Colombier 	else {
1799ef1f84bSDavid du Colombier 		lock(&up->exl);
1809ef1f84bSDavid du Colombier 		up->nchild++;
1819ef1f84bSDavid du Colombier 		unlock(&up->exl);
1829ef1f84bSDavid du Colombier 	}
1839ef1f84bSDavid du Colombier 	if((flag&RFNOTEG) == 0)
1849ef1f84bSDavid du Colombier 		p->noteid = up->noteid;
1859ef1f84bSDavid du Colombier 
1869ef1f84bSDavid du Colombier 	pid = p->pid;
1879ef1f84bSDavid du Colombier 	memset(p->time, 0, sizeof(p->time));
1889ef1f84bSDavid du Colombier 	p->time[TReal] = sys->ticks;
1899ef1f84bSDavid du Colombier 
1909ef1f84bSDavid du Colombier 	kstrdup(&p->text, up->text);
1919ef1f84bSDavid du Colombier 	kstrdup(&p->user, up->user);
1929ef1f84bSDavid du Colombier 	/*
1939ef1f84bSDavid du Colombier 	 *  since the bss/data segments are now shareable,
1949ef1f84bSDavid du Colombier 	 *  any mmu info about this process is now stale
1959ef1f84bSDavid du Colombier 	 *  (i.e. has bad properties) and has to be discarded.
1969ef1f84bSDavid du Colombier 	 */
1979ef1f84bSDavid du Colombier 	mmuflush();
1989ef1f84bSDavid du Colombier 	p->basepri = up->basepri;
1999ef1f84bSDavid du Colombier 	p->priority = up->basepri;
2009ef1f84bSDavid du Colombier 	p->fixedpri = up->fixedpri;
2019ef1f84bSDavid du Colombier 	p->mp = up->mp;
2029ef1f84bSDavid du Colombier 	wm = up->wired;
2034498a243SDavid du Colombier 	if(wm != nil)
2049ef1f84bSDavid du Colombier 		procwired(p, wm->machno);
205d46407a3SDavid du Colombier 	if(p->trace && (pt = proctrace) != nil){
206d46407a3SDavid du Colombier 		strncpy((char*)&ptarg, p->text, sizeof ptarg);
207d46407a3SDavid du Colombier 		pt(p, SName, 0, ptarg);
208d46407a3SDavid du Colombier 	}
209*094d6818SDavid du Colombier 	p->color = up->color;
2109ef1f84bSDavid du Colombier 	ready(p);
2119ef1f84bSDavid du Colombier 	sched();
2129ef1f84bSDavid du Colombier 
2139ef1f84bSDavid du Colombier 	ar0->i = pid;
2149ef1f84bSDavid du Colombier }
2159ef1f84bSDavid du Colombier 
2169ef1f84bSDavid du Colombier static uvlong
vl2be(uvlong v)2179ef1f84bSDavid du Colombier vl2be(uvlong v)
2189ef1f84bSDavid du Colombier {
2199ef1f84bSDavid du Colombier 	uchar *p;
2209ef1f84bSDavid du Colombier 
2219ef1f84bSDavid du Colombier 	p = (uchar*)&v;
2229ef1f84bSDavid du Colombier 	return ((uvlong)((p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3])<<32)
2239ef1f84bSDavid du Colombier 	      |((uvlong)(p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7]);
2249ef1f84bSDavid du Colombier }
2259ef1f84bSDavid du Colombier 
226406c76faSDavid du Colombier ulong
l2be(long l)2279ef1f84bSDavid du Colombier l2be(long l)
2289ef1f84bSDavid du Colombier {
2299ef1f84bSDavid du Colombier 	uchar *cp;
2309ef1f84bSDavid du Colombier 
2319ef1f84bSDavid du Colombier 	cp = (uchar*)&l;
2329ef1f84bSDavid du Colombier 	return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3];
2339ef1f84bSDavid du Colombier }
2349ef1f84bSDavid du Colombier 
2359ef1f84bSDavid du Colombier typedef struct {
2369ef1f84bSDavid du Colombier 	Exec;
2379ef1f84bSDavid du Colombier 	uvlong hdr[1];
2389ef1f84bSDavid du Colombier } Hdr;
2399ef1f84bSDavid du Colombier 
2409ef1f84bSDavid du Colombier void
sysexec(Ar0 * ar0,va_list list)2419ef1f84bSDavid du Colombier sysexec(Ar0* ar0, va_list list)
2429ef1f84bSDavid du Colombier {
2439ef1f84bSDavid du Colombier 	Hdr hdr;
2449ef1f84bSDavid du Colombier 	Fgrp *f;
2459ef1f84bSDavid du Colombier 	Tos *tos;
2469ef1f84bSDavid du Colombier 	Chan *chan;
2479ef1f84bSDavid du Colombier 	Image *img;
2489ef1f84bSDavid du Colombier 	Segment *s;
2499ef1f84bSDavid du Colombier 	int argc, i, n, nargs;
2509ef1f84bSDavid du Colombier 	char *a, *args, **argv, elem[sizeof(up->genbuf)], *file, *p;
2519ef1f84bSDavid du Colombier 	char line[sizeof(Exec)], *progarg[sizeof(Exec)/2+1];
2529ef1f84bSDavid du Colombier 	long hdrsz, magic, textsz, datasz, bsssz;
2539ef1f84bSDavid du Colombier 	uintptr textlim, textmin, datalim, bsslim, entry, stack;
254d46407a3SDavid du Colombier 	void (*pt)(Proc*, int, vlong, vlong);
255d46407a3SDavid du Colombier 	u64int ptarg;
2569ef1f84bSDavid du Colombier 
2579ef1f84bSDavid du Colombier 	/*
2589ef1f84bSDavid du Colombier 	 * void* exec(char* name, char* argv[]);
2599ef1f84bSDavid du Colombier 	 */
2609ef1f84bSDavid du Colombier 
2619ef1f84bSDavid du Colombier 	/*
2629ef1f84bSDavid du Colombier 	 * Remember the full name of the file,
2639ef1f84bSDavid du Colombier 	 * open it, and remember the final element of the
2649ef1f84bSDavid du Colombier 	 * name left in up->genbuf by namec.
2659ef1f84bSDavid du Colombier 	 */
2669ef1f84bSDavid du Colombier 	p = va_arg(list, char*);
2679ef1f84bSDavid du Colombier 	p = validaddr(p, 1, 0);
2689ef1f84bSDavid du Colombier 	file = validnamedup(p, 1);
2699ef1f84bSDavid du Colombier 	if(waserror()){
2709ef1f84bSDavid du Colombier 		free(file);
2719ef1f84bSDavid du Colombier 		nexterror();
2729ef1f84bSDavid du Colombier 	}
2739ef1f84bSDavid du Colombier 	chan = namec(file, Aopen, OEXEC, 0);
2749ef1f84bSDavid du Colombier 	if(waserror()){
2759ef1f84bSDavid du Colombier 		cclose(chan);
2769ef1f84bSDavid du Colombier 		nexterror();
2779ef1f84bSDavid du Colombier 	}
2789ef1f84bSDavid du Colombier 	strncpy(elem, up->genbuf, sizeof(elem));
2799ef1f84bSDavid du Colombier 
2809ef1f84bSDavid du Colombier 	/*
2819ef1f84bSDavid du Colombier 	 * Read the header.
2829ef1f84bSDavid du Colombier 	 * If it's a #!, fill in progarg[] with info then read a new header
2839ef1f84bSDavid du Colombier 	 * from the file indicated by the #!.
2849ef1f84bSDavid du Colombier 	 * The #! line must be less than sizeof(Exec) in size,
2859ef1f84bSDavid du Colombier 	 * including the terminating \n.
2869ef1f84bSDavid du Colombier 	 */
2879ef1f84bSDavid du Colombier 	hdrsz = chan->dev->read(chan, &hdr, sizeof(Hdr), 0);
2889ef1f84bSDavid du Colombier 	if(hdrsz < 2)
2899ef1f84bSDavid du Colombier 		error(Ebadexec);
2909ef1f84bSDavid du Colombier 	p = (char*)&hdr;
2919ef1f84bSDavid du Colombier 	argc = 0;
2929ef1f84bSDavid du Colombier 	if(p[0] == '#' && p[1] == '!'){
2939ef1f84bSDavid du Colombier 		p = memccpy(line, (char*)&hdr, '\n', MIN(sizeof(Exec), hdrsz));
2949ef1f84bSDavid du Colombier 		if(p == nil)
2959ef1f84bSDavid du Colombier 			error(Ebadexec);
2969ef1f84bSDavid du Colombier 		*(p-1) = '\0';
2979ef1f84bSDavid du Colombier 		argc = tokenize(line+2, progarg, nelem(progarg));
2989ef1f84bSDavid du Colombier 		if(argc == 0)
2999ef1f84bSDavid du Colombier 			error(Ebadexec);
3009ef1f84bSDavid du Colombier 
3019ef1f84bSDavid du Colombier 		/* The original file becomes an extra arg after #! line */
3029ef1f84bSDavid du Colombier 		progarg[argc++] = file;
3039ef1f84bSDavid du Colombier 
3049ef1f84bSDavid du Colombier 		/*
3059ef1f84bSDavid du Colombier 		 * Take the #! $0 as a file to open, and replace
3069ef1f84bSDavid du Colombier 		 * $0 with the original path's name.
3079ef1f84bSDavid du Colombier 		 */
3089ef1f84bSDavid du Colombier 		p = progarg[0];
3099ef1f84bSDavid du Colombier 		progarg[0] = elem;
3109ef1f84bSDavid du Colombier 		poperror();			/* chan */
3119ef1f84bSDavid du Colombier 		cclose(chan);
3129ef1f84bSDavid du Colombier 
3139ef1f84bSDavid du Colombier 		chan = namec(p, Aopen, OEXEC, 0);
3149ef1f84bSDavid du Colombier 		if(waserror()){
3159ef1f84bSDavid du Colombier 			cclose(chan);
3169ef1f84bSDavid du Colombier 			nexterror();
3179ef1f84bSDavid du Colombier 		}
3189ef1f84bSDavid du Colombier 		hdrsz = chan->dev->read(chan, &hdr, sizeof(Hdr), 0);
3199ef1f84bSDavid du Colombier 		if(hdrsz < 2)
3209ef1f84bSDavid du Colombier 			error(Ebadexec);
3219ef1f84bSDavid du Colombier 	}
3229ef1f84bSDavid du Colombier 
3239ef1f84bSDavid du Colombier 	/*
3249ef1f84bSDavid du Colombier 	 * #! has had its chance, now we need a real binary.
3259ef1f84bSDavid du Colombier 	 */
3269ef1f84bSDavid du Colombier 	magic = l2be(hdr.magic);
3279ef1f84bSDavid du Colombier 	if(hdrsz != sizeof(Hdr) || magic != AOUT_MAGIC)
3289ef1f84bSDavid du Colombier 		error(Ebadexec);
3299ef1f84bSDavid du Colombier 	if(magic & HDR_MAGIC){
3309ef1f84bSDavid du Colombier 		entry = vl2be(hdr.hdr[0]);
3319ef1f84bSDavid du Colombier 		hdrsz = sizeof(Hdr);
3329ef1f84bSDavid du Colombier 	}
3339ef1f84bSDavid du Colombier 	else{
3349ef1f84bSDavid du Colombier 		entry = l2be(hdr.entry);
3359ef1f84bSDavid du Colombier 		hdrsz = sizeof(Exec);
3369ef1f84bSDavid du Colombier 	}
3379ef1f84bSDavid du Colombier 
3389ef1f84bSDavid du Colombier 	textsz = l2be(hdr.text);
3399ef1f84bSDavid du Colombier 	datasz = l2be(hdr.data);
3409ef1f84bSDavid du Colombier 	bsssz = l2be(hdr.bss);
3419ef1f84bSDavid du Colombier 
3429ef1f84bSDavid du Colombier 	textmin = ROUNDUP(UTZERO+hdrsz+textsz, PGSZ);
3439ef1f84bSDavid du Colombier 	textlim = UTROUND(textmin);
3449ef1f84bSDavid du Colombier 	datalim = ROUNDUP(textlim+datasz, PGSZ);
3459ef1f84bSDavid du Colombier 	bsslim = ROUNDUP(textlim+datasz+bsssz, PGSZ);
3469ef1f84bSDavid du Colombier 
3479ef1f84bSDavid du Colombier 	/*
3489ef1f84bSDavid du Colombier 	 * Check the binary header for consistency,
3499ef1f84bSDavid du Colombier 	 * e.g. the entry point is within the text segment and
3509ef1f84bSDavid du Colombier 	 * the segments don't overlap each other.
3519ef1f84bSDavid du Colombier 	 */
3529ef1f84bSDavid du Colombier 	if(entry < UTZERO+hdrsz || entry >= UTZERO+hdrsz+textsz)
3539ef1f84bSDavid du Colombier 		error(Ebadexec);
3549ef1f84bSDavid du Colombier 
3559ef1f84bSDavid du Colombier 	if(textsz >= textlim || datasz > datalim || bsssz > bsslim
3569ef1f84bSDavid du Colombier 	|| textlim >= USTKTOP || datalim >= USTKTOP || bsslim >= USTKTOP
3579ef1f84bSDavid du Colombier 	|| datalim < textlim || bsslim < datalim)
3589ef1f84bSDavid du Colombier 		error(Ebadexec);
3599ef1f84bSDavid du Colombier 
360*094d6818SDavid du Colombier 	up->color = corecolor(m->machno);
361*094d6818SDavid du Colombier 
3629ef1f84bSDavid du Colombier 	/*
3639ef1f84bSDavid du Colombier 	 * The new stack is created in ESEG, temporarily mapped elsewhere.
3649ef1f84bSDavid du Colombier 	 * The stack contains, in descending address order:
3659ef1f84bSDavid du Colombier 	 *	a structure containing housekeeping and profiling data (Tos);
3669ef1f84bSDavid du Colombier 	 *	argument strings;
3679ef1f84bSDavid du Colombier 	 *	array of vectors to the argument strings with a terminating
3689ef1f84bSDavid du Colombier 	 *	nil (argv).
3699ef1f84bSDavid du Colombier 	 * When the exec is committed, this temporary stack in ESEG will
3709ef1f84bSDavid du Colombier 	 * become SSEG.
3719ef1f84bSDavid du Colombier 	 * The architecture-dependent code which jumps to the new image
3729ef1f84bSDavid du Colombier 	 * will also push a count of the argument array onto the stack (argc).
3739ef1f84bSDavid du Colombier 	 */
3749ef1f84bSDavid du Colombier 	qlock(&up->seglock);
3759ef1f84bSDavid du Colombier 	if(waserror()){
3769ef1f84bSDavid du Colombier 		if(up->seg[ESEG] != nil){
3779ef1f84bSDavid du Colombier 			putseg(up->seg[ESEG]);
3789ef1f84bSDavid du Colombier 			up->seg[ESEG] = nil;
3799ef1f84bSDavid du Colombier 		}
3809ef1f84bSDavid du Colombier 		qunlock(&up->seglock);
3819ef1f84bSDavid du Colombier 		nexterror();
3829ef1f84bSDavid du Colombier 	}
3839ef1f84bSDavid du Colombier 	up->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, TSTKTOP);
384*094d6818SDavid du Colombier 	up->seg[ESEG]->color = up->color;
3859ef1f84bSDavid du Colombier 
3869ef1f84bSDavid du Colombier 	/*
3879ef1f84bSDavid du Colombier 	 * Stack is a pointer into the temporary stack
3889ef1f84bSDavid du Colombier 	 * segment, and will move as items are pushed.
3899ef1f84bSDavid du Colombier 	 */
3909ef1f84bSDavid du Colombier 	stack = TSTKTOP-sizeof(Tos);
3919ef1f84bSDavid du Colombier 
3929ef1f84bSDavid du Colombier 	/*
3939ef1f84bSDavid du Colombier 	 * First, the top-of-stack structure.
3949ef1f84bSDavid du Colombier 	 */
3959ef1f84bSDavid du Colombier 	tos = (Tos*)stack;
3969ef1f84bSDavid du Colombier 	tos->cyclefreq = m->cyclefreq;
3979ef1f84bSDavid du Colombier 	cycles((uvlong*)&tos->pcycles);
3989ef1f84bSDavid du Colombier 	tos->pcycles = -tos->pcycles;
3999ef1f84bSDavid du Colombier 	tos->kcycles = tos->pcycles;
4009ef1f84bSDavid du Colombier 	tos->clock = 0;
4019ef1f84bSDavid du Colombier 
4029ef1f84bSDavid du Colombier 	/*
4039ef1f84bSDavid du Colombier 	 * As the pass is made over the arguments and they are pushed onto
4049ef1f84bSDavid du Colombier 	 * the temporary stack, make a good faith copy in args for up->args.
4059ef1f84bSDavid du Colombier 	 */
4069ef1f84bSDavid du Colombier 	args = smalloc(128);
4079ef1f84bSDavid du Colombier 	if(waserror()){
4089ef1f84bSDavid du Colombier 		free(args);
4099ef1f84bSDavid du Colombier 		nexterror();
4109ef1f84bSDavid du Colombier 	}
4119ef1f84bSDavid du Colombier 	nargs = 0;
4129ef1f84bSDavid du Colombier 
4139ef1f84bSDavid du Colombier 	/*
4149ef1f84bSDavid du Colombier 	 * Next push any arguments found from a #! header.
4159ef1f84bSDavid du Colombier 	 */
4169ef1f84bSDavid du Colombier 	for(i = 0; i < argc; i++){
4179ef1f84bSDavid du Colombier 		n = strlen(progarg[i])+1;
4189ef1f84bSDavid du Colombier 		stack -= n;
4199ef1f84bSDavid du Colombier 		memmove(UINT2PTR(stack), progarg[i], n);
4209ef1f84bSDavid du Colombier 
4219ef1f84bSDavid du Colombier 		if((n = MIN(n, 128-nargs)) <= 0)
4229ef1f84bSDavid du Colombier 			continue;
4239ef1f84bSDavid du Colombier 		memmove(&args[nargs], progarg[i], n);
4249ef1f84bSDavid du Colombier 		nargs += n;
4259ef1f84bSDavid du Colombier 	}
4269ef1f84bSDavid du Colombier 
4279ef1f84bSDavid du Colombier 	/*
4289ef1f84bSDavid du Colombier 	 * Copy the strings pointed to by the syscall argument argv into
4299ef1f84bSDavid du Colombier 	 * the temporary stack segment, being careful to check both argv and
4309ef1f84bSDavid du Colombier 	 * the strings it points to are valid.
4319ef1f84bSDavid du Colombier 	 */
4329ef1f84bSDavid du Colombier 	argv = va_arg(list, char**);
4339ef1f84bSDavid du Colombier 	evenaddr(PTR2UINT(argv));
4349ef1f84bSDavid du Colombier 	for(i = 0;; i++, argv++){
4359ef1f84bSDavid du Colombier 		a = *(char**)validaddr(argv, sizeof(char**), 0);
4369ef1f84bSDavid du Colombier 		if(a == nil)
4379ef1f84bSDavid du Colombier 			break;
4389ef1f84bSDavid du Colombier 		a = validaddr(a, 1, 0);
4399ef1f84bSDavid du Colombier 		n = ((char*)vmemchr(a, 0, 0x7fffffff) - a) + 1;
4409ef1f84bSDavid du Colombier 
4419ef1f84bSDavid du Colombier 		/*
4429ef1f84bSDavid du Colombier 		 * This futzing is so argv[0] gets validated even
4439ef1f84bSDavid du Colombier 		 * though it will be thrown away if this is a shell
4449ef1f84bSDavid du Colombier 		 * script.
4459ef1f84bSDavid du Colombier 		 */
4469ef1f84bSDavid du Colombier 		if(argc > 0 && i == 0)
4479ef1f84bSDavid du Colombier 			continue;
4489ef1f84bSDavid du Colombier 
4499ef1f84bSDavid du Colombier 		/*
4509ef1f84bSDavid du Colombier 		 * Before copying the string into the temporary stack,
4519ef1f84bSDavid du Colombier 		 * which might involve a demand-page, check the string
4529ef1f84bSDavid du Colombier 		 * will not overflow the bottom of the stack.
4539ef1f84bSDavid du Colombier 		 */
4549ef1f84bSDavid du Colombier 		stack -= n;
4559ef1f84bSDavid du Colombier 		if(stack < TSTKTOP-USTKSIZE)
4569ef1f84bSDavid du Colombier 			error(Enovmem);
4579ef1f84bSDavid du Colombier 		p = UINT2PTR(stack);
4589ef1f84bSDavid du Colombier 		memmove(p, a, n);
4599ef1f84bSDavid du Colombier 		p[n-1] = 0;
4609ef1f84bSDavid du Colombier 		argc++;
4619ef1f84bSDavid du Colombier 
4629ef1f84bSDavid du Colombier 		if((n = MIN(n, 128-nargs)) <= 0)
4639ef1f84bSDavid du Colombier 			continue;
4649ef1f84bSDavid du Colombier 		memmove(&args[nargs], p, n);
4659ef1f84bSDavid du Colombier 		nargs += n;
4669ef1f84bSDavid du Colombier 	}
4679ef1f84bSDavid du Colombier 	if(argc < 1)
4689ef1f84bSDavid du Colombier 		error(Ebadexec);
4699ef1f84bSDavid du Colombier 
4709ef1f84bSDavid du Colombier 	/*
4719ef1f84bSDavid du Colombier 	 * Before pushing the argument pointers onto the temporary stack,
4729ef1f84bSDavid du Colombier 	 * which might involve a demand-page, check there is room for the
4739ef1f84bSDavid du Colombier 	 * terminating nil pointer, plus pointers, plus some slop for however
4749ef1f84bSDavid du Colombier 	 * argc might be passed on the stack by sysexecregs (give a page
4759ef1f84bSDavid du Colombier 	 * of slop, it is an overestimate, but why not).
4769ef1f84bSDavid du Colombier 	 * Sysexecstack does any architecture-dependent stack alignment.
4779ef1f84bSDavid du Colombier 	 * Keep a copy of the start of the argument strings before alignment
4789ef1f84bSDavid du Colombier 	 * so up->args can be created later.
4799ef1f84bSDavid du Colombier 	 * Although the argument vectors are being pushed onto the stack in
4809ef1f84bSDavid du Colombier 	 * the temporary segment, the values must be adjusted to reflect
4819ef1f84bSDavid du Colombier 	 * the segment address after it replaces the current SSEG.
4829ef1f84bSDavid du Colombier 	 */
4839ef1f84bSDavid du Colombier 	p = UINT2PTR(stack);
4849ef1f84bSDavid du Colombier 	stack = sysexecstack(stack, argc);
485557885a5SDavid du Colombier 	if(stack-(argc+1)*sizeof(char**)-segpgsize(up->seg[ESEG]) < TSTKTOP-USTKSIZE)
4869ef1f84bSDavid du Colombier 		error(Ebadexec);
4879ef1f84bSDavid du Colombier 
4889ef1f84bSDavid du Colombier 	argv = (char**)stack;
4899ef1f84bSDavid du Colombier 	*--argv = nil;
4909ef1f84bSDavid du Colombier 	for(i = 0; i < argc; i++){
4919ef1f84bSDavid du Colombier 		*--argv = p + (USTKTOP-TSTKTOP);
4929ef1f84bSDavid du Colombier 		p += strlen(p) + 1;
4939ef1f84bSDavid du Colombier 	}
4949ef1f84bSDavid du Colombier 
4959ef1f84bSDavid du Colombier 	/*
4969ef1f84bSDavid du Colombier 	 * Fix up the up->args copy in args. The length must be > 0 as it
4979ef1f84bSDavid du Colombier 	 * includes the \0 on the last argument and argc was checked earlier
4989ef1f84bSDavid du Colombier 	 * to be > 0. Compensate for any UTF character boundary before
4999ef1f84bSDavid du Colombier 	 * placing the terminating \0.
5009ef1f84bSDavid du Colombier 	 */
5019ef1f84bSDavid du Colombier 	if(nargs <= 0)
5029ef1f84bSDavid du Colombier 		error(Egreg);
5039ef1f84bSDavid du Colombier 
5049ef1f84bSDavid du Colombier 	while(nargs > 0 && (args[nargs-1] & 0xc0) == 0x80)
5059ef1f84bSDavid du Colombier 		nargs--;
5069ef1f84bSDavid du Colombier 	args[nargs-1] = '\0';
5079ef1f84bSDavid du Colombier 
5089ef1f84bSDavid du Colombier 	/*
5099ef1f84bSDavid du Colombier 	 * All the argument processing is now done, ready to commit.
5109ef1f84bSDavid du Colombier 	 */
5119ef1f84bSDavid du Colombier 	kstrdup(&up->text, elem);
5129ef1f84bSDavid du Colombier 	free(up->args);
5139ef1f84bSDavid du Colombier 	up->args = args;
5149ef1f84bSDavid du Colombier 	up->nargs = nargs;
5159ef1f84bSDavid du Colombier 	poperror();				/* args */
5169ef1f84bSDavid du Colombier 
5179ef1f84bSDavid du Colombier 	/*
5189ef1f84bSDavid du Colombier 	 * Close on exec
5199ef1f84bSDavid du Colombier 	 */
5209ef1f84bSDavid du Colombier 	f = up->fgrp;
5219ef1f84bSDavid du Colombier 	for(i=0; i<=f->maxfd; i++)
5229ef1f84bSDavid du Colombier 		fdclose(i, CCEXEC);
5239ef1f84bSDavid du Colombier 
5249ef1f84bSDavid du Colombier 	/*
5259ef1f84bSDavid du Colombier 	 * Free old memory.
5269ef1f84bSDavid du Colombier 	 * Special segments maintained across exec.
5279ef1f84bSDavid du Colombier 	 */
5289ef1f84bSDavid du Colombier 	for(i = SSEG; i <= BSEG; i++) {
5299ef1f84bSDavid du Colombier 		putseg(up->seg[i]);
5309ef1f84bSDavid du Colombier 		up->seg[i] = nil;		/* in case of error */
5319ef1f84bSDavid du Colombier 	}
5329ef1f84bSDavid du Colombier 	for(i = BSEG+1; i< NSEG; i++) {
5339ef1f84bSDavid du Colombier 		s = up->seg[i];
5349ef1f84bSDavid du Colombier 		if(s && (s->type&SG_CEXEC)) {
5359ef1f84bSDavid du Colombier 			putseg(s);
5369ef1f84bSDavid du Colombier 			up->seg[i] = nil;
5379ef1f84bSDavid du Colombier 		}
5389ef1f84bSDavid du Colombier 	}
5399ef1f84bSDavid du Colombier 
540d46407a3SDavid du Colombier 	if(up->trace && (pt = proctrace) != nil){
541d46407a3SDavid du Colombier 		strncpy((char*)&ptarg, elem, sizeof ptarg);
542d46407a3SDavid du Colombier 		pt(up, SName, 0, ptarg);
543d46407a3SDavid du Colombier 	}
544d46407a3SDavid du Colombier 
5459ef1f84bSDavid du Colombier 	/* Text.  Shared. Attaches to cache image if possible */
5469ef1f84bSDavid du Colombier 	/* attachimage returns a locked cache image */
5479ef1f84bSDavid du Colombier 
548*094d6818SDavid du Colombier 	img = attachimage(SG_TEXT|SG_RONLY, chan, up->color, UTZERO, textmin);
5499ef1f84bSDavid du Colombier 	s = img->s;
5509ef1f84bSDavid du Colombier 	up->seg[TSEG] = s;
5519ef1f84bSDavid du Colombier 	s->flushme = 1;
5529ef1f84bSDavid du Colombier 	s->fstart = 0;
5539ef1f84bSDavid du Colombier 	s->flen = hdrsz+textsz;
554*094d6818SDavid du Colombier 	if(img->color != up->color){
555*094d6818SDavid du Colombier 		up->color = img->color;
556*094d6818SDavid du Colombier 	}
5579ef1f84bSDavid du Colombier 	unlock(img);
5589ef1f84bSDavid du Colombier 
5599ef1f84bSDavid du Colombier 	/* Data. Shared. */
5609ef1f84bSDavid du Colombier 	s = newseg(SG_DATA, textlim, datalim);
5619ef1f84bSDavid du Colombier 	up->seg[DSEG] = s;
562*094d6818SDavid du Colombier 	s->color = up->color;
5639ef1f84bSDavid du Colombier 
5649ef1f84bSDavid du Colombier 	/* Attached by hand */
5659ef1f84bSDavid du Colombier 	incref(img);
5669ef1f84bSDavid du Colombier 	s->image = img;
5679ef1f84bSDavid du Colombier 	s->fstart = hdrsz+textsz;
5689ef1f84bSDavid du Colombier 	s->flen = datasz;
5699ef1f84bSDavid du Colombier 
5709ef1f84bSDavid du Colombier 	/* BSS. Zero fill on demand */
5719ef1f84bSDavid du Colombier 	up->seg[BSEG] = newseg(SG_BSS, datalim, bsslim);
572*094d6818SDavid du Colombier 	up->seg[BSEG]->color= up->color;
5739ef1f84bSDavid du Colombier 
5749ef1f84bSDavid du Colombier 	/*
5759ef1f84bSDavid du Colombier 	 * Move the stack
5769ef1f84bSDavid du Colombier 	 */
5779ef1f84bSDavid du Colombier 	s = up->seg[ESEG];
5789ef1f84bSDavid du Colombier 	up->seg[ESEG] = nil;
5799ef1f84bSDavid du Colombier 	up->seg[SSEG] = s;
5809ef1f84bSDavid du Colombier 	qunlock(&up->seglock);
5819ef1f84bSDavid du Colombier 	poperror();				/* seglock */
5829ef1f84bSDavid du Colombier 
5839ef1f84bSDavid du Colombier 	s->base = USTKTOP-USTKSIZE;
5849ef1f84bSDavid du Colombier 	s->top = USTKTOP;
5859ef1f84bSDavid du Colombier 	relocateseg(s, USTKTOP-TSTKTOP);
5869ef1f84bSDavid du Colombier 
5879ef1f84bSDavid du Colombier 	/*
5889ef1f84bSDavid du Colombier 	 *  '/' processes are higher priority.
5899ef1f84bSDavid du Colombier 	 */
5909ef1f84bSDavid du Colombier 	if(chan->dev->dc == L'/')
5919ef1f84bSDavid du Colombier 		up->basepri = PriRoot;
5929ef1f84bSDavid du Colombier 	up->priority = up->basepri;
5939ef1f84bSDavid du Colombier 	poperror();				/* chan */
5949ef1f84bSDavid du Colombier 	cclose(chan);
5959ef1f84bSDavid du Colombier 	poperror();				/* file */
5969ef1f84bSDavid du Colombier 	free(file);
5979ef1f84bSDavid du Colombier 
5989ef1f84bSDavid du Colombier 	/*
5999ef1f84bSDavid du Colombier 	 *  At this point, the mmu contains info about the old address
6009ef1f84bSDavid du Colombier 	 *  space and needs to be flushed
6019ef1f84bSDavid du Colombier 	 */
6029ef1f84bSDavid du Colombier 	mmuflush();
6039ef1f84bSDavid du Colombier 	qlock(&up->debug);
6049ef1f84bSDavid du Colombier 	up->nnote = 0;
6059ef1f84bSDavid du Colombier 	up->notify = 0;
6069ef1f84bSDavid du Colombier 	up->notified = 0;
6079ef1f84bSDavid du Colombier 	up->privatemem = 0;
6089ef1f84bSDavid du Colombier 	sysprocsetup(up);
6099ef1f84bSDavid du Colombier 	qunlock(&up->debug);
6109ef1f84bSDavid du Colombier 	if(up->hang)
6119ef1f84bSDavid du Colombier 		up->procctl = Proc_stopme;
6129ef1f84bSDavid du Colombier 
6139ef1f84bSDavid du Colombier 	ar0->v = sysexecregs(entry, TSTKTOP - PTR2UINT(argv), argc);
6149ef1f84bSDavid du Colombier }
6159ef1f84bSDavid du Colombier 
6169ef1f84bSDavid du Colombier int
return0(void *)6179ef1f84bSDavid du Colombier return0(void*)
6189ef1f84bSDavid du Colombier {
6199ef1f84bSDavid du Colombier 	return 0;
6209ef1f84bSDavid du Colombier }
6219ef1f84bSDavid du Colombier 
6229ef1f84bSDavid du Colombier void
syssleep(Ar0 * ar0,va_list list)6239ef1f84bSDavid du Colombier syssleep(Ar0* ar0, va_list list)
6249ef1f84bSDavid du Colombier {
6259ef1f84bSDavid du Colombier 	long ms;
6269ef1f84bSDavid du Colombier 
6279ef1f84bSDavid du Colombier 	/*
6289ef1f84bSDavid du Colombier 	 * int sleep(long millisecs);
6299ef1f84bSDavid du Colombier 	 */
6309ef1f84bSDavid du Colombier 	ms = va_arg(list, long);
6319ef1f84bSDavid du Colombier 
6329ef1f84bSDavid du Colombier 	ar0->i = 0;
6339ef1f84bSDavid du Colombier 	if(ms <= 0) {
6349ef1f84bSDavid du Colombier 		if (up->edf && (up->edf->flags & Admitted))
6359ef1f84bSDavid du Colombier 			edfyield();
6369ef1f84bSDavid du Colombier 		else
6379ef1f84bSDavid du Colombier 			yield();
6389ef1f84bSDavid du Colombier 		return;
6399ef1f84bSDavid du Colombier 	}
6409ef1f84bSDavid du Colombier 	if(ms < TK2MS(1))
6419ef1f84bSDavid du Colombier 		ms = TK2MS(1);
6429ef1f84bSDavid du Colombier 	tsleep(&up->sleep, return0, 0, ms);
6439ef1f84bSDavid du Colombier }
6449ef1f84bSDavid du Colombier 
6459ef1f84bSDavid du Colombier void
sysalarm(Ar0 * ar0,va_list list)6469ef1f84bSDavid du Colombier sysalarm(Ar0* ar0, va_list list)
6479ef1f84bSDavid du Colombier {
6489ef1f84bSDavid du Colombier 	unsigned long ms;
6499ef1f84bSDavid du Colombier 
6509ef1f84bSDavid du Colombier 	/*
6519ef1f84bSDavid du Colombier 	 * long alarm(unsigned long millisecs);
6529ef1f84bSDavid du Colombier 	 * Odd argument type...
6539ef1f84bSDavid du Colombier 	 */
6549ef1f84bSDavid du Colombier 	ms = va_arg(list, unsigned long);
6559ef1f84bSDavid du Colombier 
6569ef1f84bSDavid du Colombier 	ar0->l = procalarm(ms);
6579ef1f84bSDavid du Colombier }
6589ef1f84bSDavid du Colombier 
6599ef1f84bSDavid du Colombier void
sysexits(Ar0 *,va_list list)6609ef1f84bSDavid du Colombier sysexits(Ar0*, va_list list)
6619ef1f84bSDavid du Colombier {
6629ef1f84bSDavid du Colombier 	char *status;
6639ef1f84bSDavid du Colombier 	char *inval = "invalid exit string";
6649ef1f84bSDavid du Colombier 	char buf[ERRMAX];
6659ef1f84bSDavid du Colombier 
6669ef1f84bSDavid du Colombier 	/*
6679ef1f84bSDavid du Colombier 	 * void exits(char *msg);
6689ef1f84bSDavid du Colombier 	 */
6699ef1f84bSDavid du Colombier 	status = va_arg(list, char*);
6709ef1f84bSDavid du Colombier 
6719ef1f84bSDavid du Colombier 	if(status){
6729ef1f84bSDavid du Colombier 		if(waserror())
6739ef1f84bSDavid du Colombier 			status = inval;
6749ef1f84bSDavid du Colombier 		else{
6759ef1f84bSDavid du Colombier 			status = validaddr(status, 1, 0);
6769ef1f84bSDavid du Colombier 			if(vmemchr(status, 0, ERRMAX) == 0){
6779ef1f84bSDavid du Colombier 				memmove(buf, status, ERRMAX);
6789ef1f84bSDavid du Colombier 				buf[ERRMAX-1] = 0;
6799ef1f84bSDavid du Colombier 				status = buf;
6809ef1f84bSDavid du Colombier 			}
6819ef1f84bSDavid du Colombier 			poperror();
6829ef1f84bSDavid du Colombier 		}
6839ef1f84bSDavid du Colombier 
6849ef1f84bSDavid du Colombier 	}
6859ef1f84bSDavid du Colombier 	pexit(status, 1);
6869ef1f84bSDavid du Colombier }
6879ef1f84bSDavid du Colombier 
6889ef1f84bSDavid du Colombier void
sys_wait(Ar0 * ar0,va_list list)6899ef1f84bSDavid du Colombier sys_wait(Ar0* ar0, va_list list)
6909ef1f84bSDavid du Colombier {
6919ef1f84bSDavid du Colombier 	int pid;
6929ef1f84bSDavid du Colombier 	Waitmsg w;
6939ef1f84bSDavid du Colombier 	OWaitmsg *ow;
6949ef1f84bSDavid du Colombier 
6959ef1f84bSDavid du Colombier 	/*
6969ef1f84bSDavid du Colombier 	 * int wait(Waitmsg* w);
6979ef1f84bSDavid du Colombier 	 *
6989ef1f84bSDavid du Colombier 	 * Deprecated; backwards compatibility only.
6999ef1f84bSDavid du Colombier 	 */
7009ef1f84bSDavid du Colombier 	ow = va_arg(list, OWaitmsg*);
7019ef1f84bSDavid du Colombier 	if(ow == nil){
7029ef1f84bSDavid du Colombier 		ar0->i = pwait(nil);
7039ef1f84bSDavid du Colombier 		return;
7049ef1f84bSDavid du Colombier 	}
7059ef1f84bSDavid du Colombier 
7069ef1f84bSDavid du Colombier 	ow = validaddr(ow, sizeof(OWaitmsg), 1);
7079ef1f84bSDavid du Colombier 	evenaddr(PTR2UINT(ow));
7089ef1f84bSDavid du Colombier 	pid = pwait(&w);
7099ef1f84bSDavid du Colombier 	if(pid >= 0){
7109ef1f84bSDavid du Colombier 		readnum(0, ow->pid, NUMSIZE, w.pid, NUMSIZE);
7119ef1f84bSDavid du Colombier 		readnum(0, ow->time+TUser*NUMSIZE, NUMSIZE, w.time[TUser], NUMSIZE);
7129ef1f84bSDavid du Colombier 		readnum(0, ow->time+TSys*NUMSIZE, NUMSIZE, w.time[TSys], NUMSIZE);
7139ef1f84bSDavid du Colombier 		readnum(0, ow->time+TReal*NUMSIZE, NUMSIZE, w.time[TReal], NUMSIZE);
7149ef1f84bSDavid du Colombier 		strncpy(ow->msg, w.msg, sizeof(ow->msg));
7159ef1f84bSDavid du Colombier 		ow->msg[sizeof(ow->msg)-1] = '\0';
7169ef1f84bSDavid du Colombier 	}
7179ef1f84bSDavid du Colombier 
7189ef1f84bSDavid du Colombier 	ar0->i = pid;
7199ef1f84bSDavid du Colombier }
7209ef1f84bSDavid du Colombier 
7219ef1f84bSDavid du Colombier void
sysawait(Ar0 * ar0,va_list list)7229ef1f84bSDavid du Colombier sysawait(Ar0* ar0, va_list list)
7239ef1f84bSDavid du Colombier {
7249ef1f84bSDavid du Colombier 	int i;
7259ef1f84bSDavid du Colombier 	int pid;
7269ef1f84bSDavid du Colombier 	Waitmsg w;
7279ef1f84bSDavid du Colombier 	usize n;
7289ef1f84bSDavid du Colombier 	char *p;
7299ef1f84bSDavid du Colombier 
7309ef1f84bSDavid du Colombier 	/*
7319ef1f84bSDavid du Colombier 	 * int await(char* s, int n);
7329ef1f84bSDavid du Colombier 	 * should really be
7339ef1f84bSDavid du Colombier 	 * usize await(char* s, usize n);
7349ef1f84bSDavid du Colombier 	 */
7359ef1f84bSDavid du Colombier 	p = va_arg(list, char*);
7369ef1f84bSDavid du Colombier 	n = va_arg(list, long);
7379ef1f84bSDavid du Colombier 	p = validaddr(p, n, 1);
7389ef1f84bSDavid du Colombier 
7399ef1f84bSDavid du Colombier 	pid = pwait(&w);
7409ef1f84bSDavid du Colombier 	if(pid < 0){
7419ef1f84bSDavid du Colombier 		ar0->i = -1;
7429ef1f84bSDavid du Colombier 		return;
7439ef1f84bSDavid du Colombier 	}
7449ef1f84bSDavid du Colombier 	i = snprint(p, n, "%d %lud %lud %lud %q",
7459ef1f84bSDavid du Colombier 		w.pid,
7469ef1f84bSDavid du Colombier 		w.time[TUser], w.time[TSys], w.time[TReal],
7479ef1f84bSDavid du Colombier 		w.msg);
7489ef1f84bSDavid du Colombier 
7499ef1f84bSDavid du Colombier 	ar0->i = i;
7509ef1f84bSDavid du Colombier }
7519ef1f84bSDavid du Colombier 
7529ef1f84bSDavid du Colombier void
werrstr(char * fmt,...)7539ef1f84bSDavid du Colombier werrstr(char *fmt, ...)
7549ef1f84bSDavid du Colombier {
7559ef1f84bSDavid du Colombier 	va_list va;
7569ef1f84bSDavid du Colombier 
7579ef1f84bSDavid du Colombier 	if(up == nil)
7589ef1f84bSDavid du Colombier 		return;
7599ef1f84bSDavid du Colombier 
7609ef1f84bSDavid du Colombier 	va_start(va, fmt);
7619ef1f84bSDavid du Colombier 	vseprint(up->syserrstr, up->syserrstr+ERRMAX, fmt, va);
7629ef1f84bSDavid du Colombier 	va_end(va);
7639ef1f84bSDavid du Colombier }
7649ef1f84bSDavid du Colombier 
7659ef1f84bSDavid du Colombier static void
generrstr(char * buf,long n)7669ef1f84bSDavid du Colombier generrstr(char *buf, long n)
7679ef1f84bSDavid du Colombier {
7689ef1f84bSDavid du Colombier 	char *p, tmp[ERRMAX];
7699ef1f84bSDavid du Colombier 
7709ef1f84bSDavid du Colombier 	if(n <= 0)
7719ef1f84bSDavid du Colombier 		error(Ebadarg);
7729ef1f84bSDavid du Colombier 	p = validaddr(buf, n, 1);
7739ef1f84bSDavid du Colombier 	if(n > sizeof tmp)
7749ef1f84bSDavid du Colombier 		n = sizeof tmp;
7759ef1f84bSDavid du Colombier 	memmove(tmp, p, n);
7769ef1f84bSDavid du Colombier 
7779ef1f84bSDavid du Colombier 	/* make sure it's NUL-terminated */
7789ef1f84bSDavid du Colombier 	tmp[n-1] = '\0';
7799ef1f84bSDavid du Colombier 	memmove(p, up->syserrstr, n);
7809ef1f84bSDavid du Colombier 	p[n-1] = '\0';
7819ef1f84bSDavid du Colombier 	memmove(up->syserrstr, tmp, n);
7829ef1f84bSDavid du Colombier }
7839ef1f84bSDavid du Colombier 
7849ef1f84bSDavid du Colombier void
syserrstr(Ar0 * ar0,va_list list)7859ef1f84bSDavid du Colombier syserrstr(Ar0* ar0, va_list list)
7869ef1f84bSDavid du Colombier {
7879ef1f84bSDavid du Colombier 	char *err;
7889ef1f84bSDavid du Colombier 	usize nerr;
7899ef1f84bSDavid du Colombier 
7909ef1f84bSDavid du Colombier 	/*
7919ef1f84bSDavid du Colombier 	 * int errstr(char* err, uint nerr);
7929ef1f84bSDavid du Colombier 	 * should really be
7939ef1f84bSDavid du Colombier 	 * usize errstr(char* err, usize nerr);
7949ef1f84bSDavid du Colombier 	 * but errstr always returns 0.
7959ef1f84bSDavid du Colombier 	 */
7969ef1f84bSDavid du Colombier 	err = va_arg(list, char*);
7979ef1f84bSDavid du Colombier 	nerr = va_arg(list, usize);
7989ef1f84bSDavid du Colombier 	generrstr(err, nerr);
7999ef1f84bSDavid du Colombier 
8009ef1f84bSDavid du Colombier 	ar0->i = 0;
8019ef1f84bSDavid du Colombier }
8029ef1f84bSDavid du Colombier 
8039ef1f84bSDavid du Colombier void
sys_errstr(Ar0 * ar0,va_list list)8049ef1f84bSDavid du Colombier sys_errstr(Ar0* ar0, va_list list)
8059ef1f84bSDavid du Colombier {
8069ef1f84bSDavid du Colombier 	char *p;
8079ef1f84bSDavid du Colombier 
8089ef1f84bSDavid du Colombier 	/*
8099ef1f84bSDavid du Colombier 	 * int errstr(char* err);
8109ef1f84bSDavid du Colombier 	 *
8119ef1f84bSDavid du Colombier 	 * Deprecated; backwards compatibility only.
8129ef1f84bSDavid du Colombier 	 */
8139ef1f84bSDavid du Colombier 	p = va_arg(list, char*);
8149ef1f84bSDavid du Colombier 	generrstr(p, 64);
8159ef1f84bSDavid du Colombier 
8169ef1f84bSDavid du Colombier 	ar0->i = 0;
8179ef1f84bSDavid du Colombier }
8189ef1f84bSDavid du Colombier 
8199ef1f84bSDavid du Colombier void
sysnotify(Ar0 * ar0,va_list list)8209ef1f84bSDavid du Colombier sysnotify(Ar0* ar0, va_list list)
8219ef1f84bSDavid du Colombier {
8229ef1f84bSDavid du Colombier 	void (*f)(void*, char*);
8239ef1f84bSDavid du Colombier 
8249ef1f84bSDavid du Colombier 	/*
8259ef1f84bSDavid du Colombier 	 * int notify(void (*f)(void*, char*));
8269ef1f84bSDavid du Colombier 	 */
8279ef1f84bSDavid du Colombier 	f = (void (*)(void*, char*))va_arg(list, void*);
8289ef1f84bSDavid du Colombier 
8299ef1f84bSDavid du Colombier 	if(f != nil)
8309ef1f84bSDavid du Colombier 		validaddr(f, sizeof(void (*)(void*, char*)), 0);
8319ef1f84bSDavid du Colombier 	up->notify = f;
8329ef1f84bSDavid du Colombier 
8339ef1f84bSDavid du Colombier 	ar0->i = 0;
8349ef1f84bSDavid du Colombier }
8359ef1f84bSDavid du Colombier 
8369ef1f84bSDavid du Colombier void
sysnoted(Ar0 * ar0,va_list list)8379ef1f84bSDavid du Colombier sysnoted(Ar0* ar0, va_list list)
8389ef1f84bSDavid du Colombier {
8399ef1f84bSDavid du Colombier 	int v;
8409ef1f84bSDavid du Colombier 
8419ef1f84bSDavid du Colombier 	/*
8429ef1f84bSDavid du Colombier 	 * int noted(int v);
8439ef1f84bSDavid du Colombier 	 */
8449ef1f84bSDavid du Colombier 	v = va_arg(list, int);
8459ef1f84bSDavid du Colombier 
8469ef1f84bSDavid du Colombier 	if(v != NRSTR && !up->notified)
8479ef1f84bSDavid du Colombier 		error(Egreg);
8489ef1f84bSDavid du Colombier 
8499ef1f84bSDavid du Colombier 	ar0->i = 0;
8509ef1f84bSDavid du Colombier }
8519ef1f84bSDavid du Colombier 
8529ef1f84bSDavid du Colombier void
sysrendezvous(Ar0 * ar0,va_list list)8539ef1f84bSDavid du Colombier sysrendezvous(Ar0* ar0, va_list list)
8549ef1f84bSDavid du Colombier {
8559ef1f84bSDavid du Colombier 	Proc *p, **l;
856d46407a3SDavid du Colombier 	uintptr tag, val, pc;
857d46407a3SDavid du Colombier 	void (*pt)(Proc*, int, vlong, vlong);
8589ef1f84bSDavid du Colombier 
8599ef1f84bSDavid du Colombier 	/*
8609ef1f84bSDavid du Colombier 	 * void* rendezvous(void*, void*);
8619ef1f84bSDavid du Colombier 	 */
8629ef1f84bSDavid du Colombier 	tag = PTR2UINT(va_arg(list, void*));
8639ef1f84bSDavid du Colombier 
8649ef1f84bSDavid du Colombier 	l = &REND(up->rgrp, tag);
8659ef1f84bSDavid du Colombier 	up->rendval = ~0;
8669ef1f84bSDavid du Colombier 
8679ef1f84bSDavid du Colombier 	lock(up->rgrp);
8689ef1f84bSDavid du Colombier 	for(p = *l; p; p = p->rendhash) {
8699ef1f84bSDavid du Colombier 		if(p->rendtag == tag) {
8709ef1f84bSDavid du Colombier 			*l = p->rendhash;
8719ef1f84bSDavid du Colombier 			val = p->rendval;
8729ef1f84bSDavid du Colombier 			p->rendval = PTR2UINT(va_arg(list, void*));
8739ef1f84bSDavid du Colombier 
8749ef1f84bSDavid du Colombier 			while(p->mach != 0)
8759ef1f84bSDavid du Colombier 				;
8769ef1f84bSDavid du Colombier 			ready(p);
8779ef1f84bSDavid du Colombier 			unlock(up->rgrp);
8789ef1f84bSDavid du Colombier 
8799ef1f84bSDavid du Colombier 			ar0->v = UINT2PTR(val);
8809ef1f84bSDavid du Colombier 			return;
8819ef1f84bSDavid du Colombier 		}
8829ef1f84bSDavid du Colombier 		l = &p->rendhash;
8839ef1f84bSDavid du Colombier 	}
8849ef1f84bSDavid du Colombier 
8859ef1f84bSDavid du Colombier 	/* Going to sleep here */
8869ef1f84bSDavid du Colombier 	up->rendtag = tag;
8879ef1f84bSDavid du Colombier 	up->rendval = PTR2UINT(va_arg(list, void*));
8889ef1f84bSDavid du Colombier 	up->rendhash = *l;
8899ef1f84bSDavid du Colombier 	*l = up;
8909ef1f84bSDavid du Colombier 	up->state = Rendezvous;
891d46407a3SDavid du Colombier 	if(up->trace && (pt = proctrace) != nil){
892d46407a3SDavid du Colombier 		pc = (uintptr)sysrendezvous;
893d46407a3SDavid du Colombier 		pt(up, SSleep, 0, Rendezvous|(pc<<8));
894d46407a3SDavid du Colombier 	}
8959ef1f84bSDavid du Colombier 	unlock(up->rgrp);
8969ef1f84bSDavid du Colombier 
8979ef1f84bSDavid du Colombier 	sched();
8989ef1f84bSDavid du Colombier 
8999ef1f84bSDavid du Colombier 	ar0->v = UINT2PTR(up->rendval);
9009ef1f84bSDavid du Colombier }
9019ef1f84bSDavid du Colombier 
9029ef1f84bSDavid du Colombier /*
9039ef1f84bSDavid du Colombier  * The implementation of semaphores is complicated by needing
9049ef1f84bSDavid du Colombier  * to avoid rescheduling in syssemrelease, so that it is safe
9059ef1f84bSDavid du Colombier  * to call from real-time processes.  This means syssemrelease
9069ef1f84bSDavid du Colombier  * cannot acquire any qlocks, only spin locks.
9079ef1f84bSDavid du Colombier  *
9089ef1f84bSDavid du Colombier  * Semacquire and semrelease must both manipulate the semaphore
9099ef1f84bSDavid du Colombier  * wait list.  Lock-free linked lists only exist in theory, not
9109ef1f84bSDavid du Colombier  * in practice, so the wait list is protected by a spin lock.
9119ef1f84bSDavid du Colombier  *
9129ef1f84bSDavid du Colombier  * The semaphore value *addr is stored in user memory, so it
9139ef1f84bSDavid du Colombier  * cannot be read or written while holding spin locks.
9149ef1f84bSDavid du Colombier  *
9159ef1f84bSDavid du Colombier  * Thus, we can access the list only when holding the lock, and
9169ef1f84bSDavid du Colombier  * we can access the semaphore only when not holding the lock.
9179ef1f84bSDavid du Colombier  * This makes things interesting.  Note that sleep's condition function
9189ef1f84bSDavid du Colombier  * is called while holding two locks - r and up->rlock - so it cannot
9199ef1f84bSDavid du Colombier  * access the semaphore value either.
9209ef1f84bSDavid du Colombier  *
9219ef1f84bSDavid du Colombier  * An acquirer announces its intention to try for the semaphore
9229ef1f84bSDavid du Colombier  * by putting a Sema structure onto the wait list and then
9239ef1f84bSDavid du Colombier  * setting Sema.waiting.  After one last check of semaphore,
9249ef1f84bSDavid du Colombier  * the acquirer sleeps until Sema.waiting==0.  A releaser of n
9259ef1f84bSDavid du Colombier  * must wake up n acquirers who have Sema.waiting set.  It does
9269ef1f84bSDavid du Colombier  * this by clearing Sema.waiting and then calling wakeup.
9279ef1f84bSDavid du Colombier  *
9289ef1f84bSDavid du Colombier  * There are three interesting races here.
9299ef1f84bSDavid du Colombier 
9309ef1f84bSDavid du Colombier  * The first is that in this particular sleep/wakeup usage, a single
9319ef1f84bSDavid du Colombier  * wakeup can rouse a process from two consecutive sleeps!
9329ef1f84bSDavid du Colombier  * The ordering is:
9339ef1f84bSDavid du Colombier  *
9349ef1f84bSDavid du Colombier  * 	(a) set Sema.waiting = 1
9359ef1f84bSDavid du Colombier  * 	(a) call sleep
9369ef1f84bSDavid du Colombier  * 	(b) set Sema.waiting = 0
9379ef1f84bSDavid du Colombier  * 	(a) check Sema.waiting inside sleep, return w/o sleeping
9389ef1f84bSDavid du Colombier  * 	(a) try for semaphore, fail
9399ef1f84bSDavid du Colombier  * 	(a) set Sema.waiting = 1
9409ef1f84bSDavid du Colombier  * 	(a) call sleep
9419ef1f84bSDavid du Colombier  * 	(b) call wakeup(a)
9429ef1f84bSDavid du Colombier  * 	(a) wake up again
9439ef1f84bSDavid du Colombier  *
9449ef1f84bSDavid du Colombier  * This is okay - semacquire will just go around the loop
9459ef1f84bSDavid du Colombier  * again.  It does mean that at the top of the for(;;) loop in
9469ef1f84bSDavid du Colombier  * semacquire, phore.waiting might already be set to 1.
9479ef1f84bSDavid du Colombier  *
9489ef1f84bSDavid du Colombier  * The second is that a releaser might wake an acquirer who is
9499ef1f84bSDavid du Colombier  * interrupted before he can acquire the lock.  Since
9509ef1f84bSDavid du Colombier  * release(n) issues only n wakeup calls -- only n can be used
9519ef1f84bSDavid du Colombier  * anyway -- if the interrupted process is not going to use his
9529ef1f84bSDavid du Colombier  * wakeup call he must pass it on to another acquirer.
9539ef1f84bSDavid du Colombier  *
9549ef1f84bSDavid du Colombier  * The third race is similar to the second but more subtle.  An
9559ef1f84bSDavid du Colombier  * acquirer sets waiting=1 and then does a final canacquire()
9569ef1f84bSDavid du Colombier  * before going to sleep.  The opposite order would result in
9579ef1f84bSDavid du Colombier  * missing wakeups that happen between canacquire and
9589ef1f84bSDavid du Colombier  * waiting=1.  (In fact, the whole point of Sema.waiting is to
9599ef1f84bSDavid du Colombier  * avoid missing wakeups between canacquire() and sleep().) But
9609ef1f84bSDavid du Colombier  * there can be spurious wakeups between a successful
9619ef1f84bSDavid du Colombier  * canacquire() and the following semdequeue().  This wakeup is
9629ef1f84bSDavid du Colombier  * not useful to the acquirer, since he has already acquired
9639ef1f84bSDavid du Colombier  * the semaphore.  Like in the previous case, though, the
9649ef1f84bSDavid du Colombier  * acquirer must pass the wakeup call along.
9659ef1f84bSDavid du Colombier  *
9669ef1f84bSDavid du Colombier  * This is all rather subtle.  The code below has been verified
9679ef1f84bSDavid du Colombier  * with the spin model /sys/src/9/port/semaphore.p.  The
9689ef1f84bSDavid du Colombier  * original code anticipated the second race but not the first
9699ef1f84bSDavid du Colombier  * or third, which were caught only with spin.  The first race
9709ef1f84bSDavid du Colombier  * is mentioned in /sys/doc/sleep.ps, but I'd forgotten about it.
9719ef1f84bSDavid du Colombier  * It was lucky that my abstract model of sleep/wakeup still managed
9729ef1f84bSDavid du Colombier  * to preserve that behavior.
9739ef1f84bSDavid du Colombier  *
9749ef1f84bSDavid du Colombier  * I remain slightly concerned about memory coherence
9759ef1f84bSDavid du Colombier  * outside of locks.  The spin model does not take
9769ef1f84bSDavid du Colombier  * queued processor writes into account so we have to
9779ef1f84bSDavid du Colombier  * think hard.  The only variables accessed outside locks
9789ef1f84bSDavid du Colombier  * are the semaphore value itself and the boolean flag
9799ef1f84bSDavid du Colombier  * Sema.waiting.  The value is only accessed with CAS,
9809ef1f84bSDavid du Colombier  * whose job description includes doing the right thing as
9819ef1f84bSDavid du Colombier  * far as memory coherence across processors.  That leaves
9829ef1f84bSDavid du Colombier  * Sema.waiting.  To handle it, we call coherence() before each
9839ef1f84bSDavid du Colombier  * read and after each write.		- rsc
9849ef1f84bSDavid du Colombier  */
9859ef1f84bSDavid du Colombier 
9869ef1f84bSDavid du Colombier /* Add semaphore p with addr a to list in seg. */
9879ef1f84bSDavid du Colombier static void
semqueue(Segment * s,int * addr,Sema * p)9889ef1f84bSDavid du Colombier semqueue(Segment* s, int* addr, Sema* p)
9899ef1f84bSDavid du Colombier {
9909ef1f84bSDavid du Colombier 	memset(p, 0, sizeof *p);
9919ef1f84bSDavid du Colombier 	p->addr = addr;
9929ef1f84bSDavid du Colombier 
9939ef1f84bSDavid du Colombier 	lock(&s->sema);	/* uses s->sema.Rendez.Lock, but no one else is */
9949ef1f84bSDavid du Colombier 	p->next = &s->sema;
9959ef1f84bSDavid du Colombier 	p->prev = s->sema.prev;
9969ef1f84bSDavid du Colombier 	p->next->prev = p;
9979ef1f84bSDavid du Colombier 	p->prev->next = p;
9989ef1f84bSDavid du Colombier 	unlock(&s->sema);
9999ef1f84bSDavid du Colombier }
10009ef1f84bSDavid du Colombier 
10019ef1f84bSDavid du Colombier /* Remove semaphore p from list in seg. */
10029ef1f84bSDavid du Colombier static void
semdequeue(Segment * s,Sema * p)10039ef1f84bSDavid du Colombier semdequeue(Segment* s, Sema* p)
10049ef1f84bSDavid du Colombier {
10059ef1f84bSDavid du Colombier 	lock(&s->sema);
10069ef1f84bSDavid du Colombier 	p->next->prev = p->prev;
10079ef1f84bSDavid du Colombier 	p->prev->next = p->next;
10089ef1f84bSDavid du Colombier 	unlock(&s->sema);
10099ef1f84bSDavid du Colombier }
10109ef1f84bSDavid du Colombier 
10119ef1f84bSDavid du Colombier /* Wake up n waiters with addr on list in seg. */
10129ef1f84bSDavid du Colombier static void
semwakeup(Segment * s,int * addr,int n)10139ef1f84bSDavid du Colombier semwakeup(Segment* s, int* addr, int n)
10149ef1f84bSDavid du Colombier {
10159ef1f84bSDavid du Colombier 	Sema *p;
10169ef1f84bSDavid du Colombier 
10179ef1f84bSDavid du Colombier 	lock(&s->sema);
10189ef1f84bSDavid du Colombier 	for(p = s->sema.next; p != &s->sema && n > 0; p = p->next){
10199ef1f84bSDavid du Colombier 		if(p->addr == addr && p->waiting){
10209ef1f84bSDavid du Colombier 			p->waiting = 0;
10219ef1f84bSDavid du Colombier 			coherence();
10229ef1f84bSDavid du Colombier 			wakeup(p);
10239ef1f84bSDavid du Colombier 			n--;
10249ef1f84bSDavid du Colombier 		}
10259ef1f84bSDavid du Colombier 	}
10269ef1f84bSDavid du Colombier 	unlock(&s->sema);
10279ef1f84bSDavid du Colombier }
10289ef1f84bSDavid du Colombier 
10299ef1f84bSDavid du Colombier /* Add delta to semaphore and wake up waiters as appropriate. */
10309ef1f84bSDavid du Colombier static int
semrelease(Segment * s,int * addr,int delta)10319ef1f84bSDavid du Colombier semrelease(Segment* s, int* addr, int delta)
10329ef1f84bSDavid du Colombier {
10339ef1f84bSDavid du Colombier 	int value;
10349ef1f84bSDavid du Colombier 
10359ef1f84bSDavid du Colombier 	do
10369ef1f84bSDavid du Colombier 		value = *addr;
10379ef1f84bSDavid du Colombier 	while(!CASW(addr, value, value+delta));
10389ef1f84bSDavid du Colombier 	semwakeup(s, addr, delta);
10399ef1f84bSDavid du Colombier 
10409ef1f84bSDavid du Colombier 	return value+delta;
10419ef1f84bSDavid du Colombier }
10429ef1f84bSDavid du Colombier 
10439ef1f84bSDavid du Colombier /* Try to acquire semaphore using compare-and-swap */
10449ef1f84bSDavid du Colombier static int
canacquire(int * addr)10459ef1f84bSDavid du Colombier canacquire(int* addr)
10469ef1f84bSDavid du Colombier {
10479ef1f84bSDavid du Colombier 	int value;
10489ef1f84bSDavid du Colombier 
10499ef1f84bSDavid du Colombier 	while((value = *addr) > 0){
10509ef1f84bSDavid du Colombier 		if(CASW(addr, value, value-1))
10519ef1f84bSDavid du Colombier 			return 1;
10529ef1f84bSDavid du Colombier 	}
10539ef1f84bSDavid du Colombier 
10549ef1f84bSDavid du Colombier 	return 0;
10559ef1f84bSDavid du Colombier }
10569ef1f84bSDavid du Colombier 
10579ef1f84bSDavid du Colombier /* Should we wake up? */
10589ef1f84bSDavid du Colombier static int
semawoke(void * p)10599ef1f84bSDavid du Colombier semawoke(void* p)
10609ef1f84bSDavid du Colombier {
10619ef1f84bSDavid du Colombier 	coherence();
10629ef1f84bSDavid du Colombier 	return !((Sema*)p)->waiting;
10639ef1f84bSDavid du Colombier }
10649ef1f84bSDavid du Colombier 
10659ef1f84bSDavid du Colombier /* Acquire semaphore (subtract 1). */
10669ef1f84bSDavid du Colombier static int
semacquire(Segment * s,int * addr,int block)10679ef1f84bSDavid du Colombier semacquire(Segment* s, int* addr, int block)
10689ef1f84bSDavid du Colombier {
10699ef1f84bSDavid du Colombier 	int acquired;
10709ef1f84bSDavid du Colombier 	Sema phore;
10719ef1f84bSDavid du Colombier 
10729ef1f84bSDavid du Colombier 	if(canacquire(addr))
10739ef1f84bSDavid du Colombier 		return 1;
10749ef1f84bSDavid du Colombier 	if(!block)
10759ef1f84bSDavid du Colombier 		return 0;
10769ef1f84bSDavid du Colombier 
10779ef1f84bSDavid du Colombier 	acquired = 0;
10789ef1f84bSDavid du Colombier 	semqueue(s, addr, &phore);
10799ef1f84bSDavid du Colombier 	for(;;){
10809ef1f84bSDavid du Colombier 		phore.waiting = 1;
10819ef1f84bSDavid du Colombier 		coherence();
10829ef1f84bSDavid du Colombier 		if(canacquire(addr)){
10839ef1f84bSDavid du Colombier 			acquired = 1;
10849ef1f84bSDavid du Colombier 			break;
10859ef1f84bSDavid du Colombier 		}
10869ef1f84bSDavid du Colombier 		if(waserror())
10879ef1f84bSDavid du Colombier 			break;
10889ef1f84bSDavid du Colombier 		sleep(&phore, semawoke, &phore);
10899ef1f84bSDavid du Colombier 		poperror();
10909ef1f84bSDavid du Colombier 	}
10919ef1f84bSDavid du Colombier 	semdequeue(s, &phore);
10929ef1f84bSDavid du Colombier 	coherence();	/* not strictly necessary due to lock in semdequeue */
10939ef1f84bSDavid du Colombier 	if(!phore.waiting)
10949ef1f84bSDavid du Colombier 		semwakeup(s, addr, 1);
10959ef1f84bSDavid du Colombier 	if(!acquired)
10969ef1f84bSDavid du Colombier 		nexterror();
10979ef1f84bSDavid du Colombier 
10989ef1f84bSDavid du Colombier 	return 1;
10999ef1f84bSDavid du Colombier }
11009ef1f84bSDavid du Colombier 
11019ef1f84bSDavid du Colombier /* Acquire semaphore or time-out */
11029ef1f84bSDavid du Colombier static int
tsemacquire(Segment * s,int * addr,long ms)11039ef1f84bSDavid du Colombier tsemacquire(Segment* s, int* addr, long ms)
11049ef1f84bSDavid du Colombier {
11059ef1f84bSDavid du Colombier 	int acquired;
11069ef1f84bSDavid du Colombier 	ulong t;
11079ef1f84bSDavid du Colombier 	Sema phore;
11089ef1f84bSDavid du Colombier 
11099ef1f84bSDavid du Colombier 	if(canacquire(addr))
11109ef1f84bSDavid du Colombier 		return 1;
11119ef1f84bSDavid du Colombier 	if(ms == 0)
11129ef1f84bSDavid du Colombier 		return 0;
11139ef1f84bSDavid du Colombier 
11149ef1f84bSDavid du Colombier 	acquired = 0;
11159ef1f84bSDavid du Colombier 	semqueue(s, addr, &phore);
11169ef1f84bSDavid du Colombier 	for(;;){
11179ef1f84bSDavid du Colombier 		phore.waiting = 1;
11189ef1f84bSDavid du Colombier 		coherence();
11199ef1f84bSDavid du Colombier 		if(canacquire(addr)){
11209ef1f84bSDavid du Colombier 			acquired = 1;
11219ef1f84bSDavid du Colombier 			break;
11229ef1f84bSDavid du Colombier 		}
11239ef1f84bSDavid du Colombier 		if(waserror())
11249ef1f84bSDavid du Colombier 			break;
11259ef1f84bSDavid du Colombier 		t = m->ticks;
11269ef1f84bSDavid du Colombier 		tsleep(&phore, semawoke, &phore, ms);
11279ef1f84bSDavid du Colombier 		ms -= TK2MS(m->ticks-t);
11289ef1f84bSDavid du Colombier 		poperror();
11299ef1f84bSDavid du Colombier 		if(ms <= 0)
11309ef1f84bSDavid du Colombier 			break;
11319ef1f84bSDavid du Colombier 	}
11329ef1f84bSDavid du Colombier 	semdequeue(s, &phore);
11339ef1f84bSDavid du Colombier 	coherence();	/* not strictly necessary due to lock in semdequeue */
11349ef1f84bSDavid du Colombier 	if(!phore.waiting)
11359ef1f84bSDavid du Colombier 		semwakeup(s, addr, 1);
11369ef1f84bSDavid du Colombier 	if(ms <= 0)
11379ef1f84bSDavid du Colombier 		return 0;
11389ef1f84bSDavid du Colombier 	if(!acquired)
11399ef1f84bSDavid du Colombier 		nexterror();
11409ef1f84bSDavid du Colombier 	return 1;
11419ef1f84bSDavid du Colombier }
11429ef1f84bSDavid du Colombier 
11439ef1f84bSDavid du Colombier void
syssemacquire(Ar0 * ar0,va_list list)11449ef1f84bSDavid du Colombier syssemacquire(Ar0* ar0, va_list list)
11459ef1f84bSDavid du Colombier {
11469ef1f84bSDavid du Colombier 	Segment *s;
11479ef1f84bSDavid du Colombier 	int *addr, block;
11489ef1f84bSDavid du Colombier 
11499ef1f84bSDavid du Colombier 	/*
11509ef1f84bSDavid du Colombier 	 * int semacquire(long* addr, int block);
11519ef1f84bSDavid du Colombier 	 * should be (and will be implemented below as) perhaps
11529ef1f84bSDavid du Colombier 	 * int semacquire(int* addr, int block);
11539ef1f84bSDavid du Colombier 	 */
11549ef1f84bSDavid du Colombier 	addr = va_arg(list, int*);
11559ef1f84bSDavid du Colombier 	addr = validaddr(addr, sizeof(int), 1);
11569ef1f84bSDavid du Colombier 	evenaddr(PTR2UINT(addr));
11579ef1f84bSDavid du Colombier 	block = va_arg(list, int);
11589ef1f84bSDavid du Colombier 
11599ef1f84bSDavid du Colombier 	if((s = seg(up, PTR2UINT(addr), 0)) == nil)
11609ef1f84bSDavid du Colombier 		error(Ebadarg);
11619ef1f84bSDavid du Colombier 	if(*addr < 0)
11629ef1f84bSDavid du Colombier 		error(Ebadarg);
11639ef1f84bSDavid du Colombier 
11649ef1f84bSDavid du Colombier 	ar0->i = semacquire(s, addr, block);
11659ef1f84bSDavid du Colombier }
11669ef1f84bSDavid du Colombier 
11679ef1f84bSDavid du Colombier void
systsemacquire(Ar0 * ar0,va_list list)11689ef1f84bSDavid du Colombier systsemacquire(Ar0* ar0, va_list list)
11699ef1f84bSDavid du Colombier {
11709ef1f84bSDavid du Colombier 	Segment *s;
11719ef1f84bSDavid du Colombier 	int *addr, ms;
11729ef1f84bSDavid du Colombier 
11739ef1f84bSDavid du Colombier 	/*
11749ef1f84bSDavid du Colombier 	 * int tsemacquire(long* addr, ulong ms);
11759ef1f84bSDavid du Colombier 	 * should be (and will be implemented below as) perhaps
11769ef1f84bSDavid du Colombier 	 * int tsemacquire(int* addr, ulong ms);
11779ef1f84bSDavid du Colombier 	 */
11789ef1f84bSDavid du Colombier 	addr = va_arg(list, int*);
11799ef1f84bSDavid du Colombier 	addr = validaddr(addr, sizeof(int), 1);
11809ef1f84bSDavid du Colombier 	evenaddr(PTR2UINT(addr));
11819ef1f84bSDavid du Colombier 	ms = va_arg(list, ulong);
11829ef1f84bSDavid du Colombier 
11839ef1f84bSDavid du Colombier 	if((s = seg(up, PTR2UINT(addr), 0)) == nil)
11849ef1f84bSDavid du Colombier 		error(Ebadarg);
11859ef1f84bSDavid du Colombier 	if(*addr < 0)
11869ef1f84bSDavid du Colombier 		error(Ebadarg);
11879ef1f84bSDavid du Colombier 
11889ef1f84bSDavid du Colombier 	ar0->i = tsemacquire(s, addr, ms);
11899ef1f84bSDavid du Colombier }
11909ef1f84bSDavid du Colombier 
11919ef1f84bSDavid du Colombier void
syssemrelease(Ar0 * ar0,va_list list)11929ef1f84bSDavid du Colombier syssemrelease(Ar0* ar0, va_list list)
11939ef1f84bSDavid du Colombier {
11949ef1f84bSDavid du Colombier 	Segment *s;
11959ef1f84bSDavid du Colombier 	int *addr, delta;
11969ef1f84bSDavid du Colombier 
11979ef1f84bSDavid du Colombier 	/*
11989ef1f84bSDavid du Colombier 	 * long semrelease(long* addr, long count);
11999ef1f84bSDavid du Colombier 	 * should be (and will be implemented below as) perhaps
12009ef1f84bSDavid du Colombier 	 * int semrelease(int* addr, int count);
12019ef1f84bSDavid du Colombier 	 */
12029ef1f84bSDavid du Colombier 	addr = va_arg(list, int*);
12039ef1f84bSDavid du Colombier 	addr = validaddr(addr, sizeof(int), 1);
12049ef1f84bSDavid du Colombier 	evenaddr(PTR2UINT(addr));
12059ef1f84bSDavid du Colombier 	delta = va_arg(list, int);
12069ef1f84bSDavid du Colombier 
12079ef1f84bSDavid du Colombier 	if((s = seg(up, PTR2UINT(addr), 0)) == nil)
12089ef1f84bSDavid du Colombier 		error(Ebadarg);
12099ef1f84bSDavid du Colombier 	if(delta < 0 || *addr < 0)
12109ef1f84bSDavid du Colombier 		error(Ebadarg);
12119ef1f84bSDavid du Colombier 
12129ef1f84bSDavid du Colombier 	ar0->i = semrelease(s, addr, delta);
12139ef1f84bSDavid du Colombier }
12145891e653SDavid du Colombier 
12155891e653SDavid du Colombier void
sysnsec(Ar0 * ar0,va_list)12165891e653SDavid du Colombier sysnsec(Ar0* ar0, va_list)
12175891e653SDavid du Colombier {
12185891e653SDavid du Colombier 	ar0->vl = todget(nil);
12195891e653SDavid du Colombier }
1220