xref: /plan9/sys/src/9/port/sysproc.c (revision fac6300f1f1b25611e114fc0bdda9cf428c13da4)
13e12c5d1SDavid du Colombier #include	"u.h"
2e288d156SDavid du Colombier #include	"tos.h"
33e12c5d1SDavid du Colombier #include	"../port/lib.h"
43e12c5d1SDavid du Colombier #include	"mem.h"
53e12c5d1SDavid du Colombier #include	"dat.h"
63e12c5d1SDavid du Colombier #include	"fns.h"
73e12c5d1SDavid du Colombier #include	"../port/error.h"
8696c1e60SDavid du Colombier #include	"../port/edf.h"
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier #include	<a.out.h>
113e12c5d1SDavid du Colombier 
123e12c5d1SDavid du Colombier int	shargs(char*, int, char**);
133e12c5d1SDavid du Colombier 
14d717568cSDavid du Colombier extern void checkpages(void);
15ea15f0ccSDavid du Colombier extern void checkpagerefs(void);
169a747e4fSDavid du Colombier 
173e12c5d1SDavid du Colombier long
sysr1(ulong *)18964da602SDavid du Colombier sysr1(ulong*)
193e12c5d1SDavid du Colombier {
20ea15f0ccSDavid du Colombier 	checkpagerefs();
213e12c5d1SDavid du Colombier 	return 0;
223e12c5d1SDavid du Colombier }
233e12c5d1SDavid du Colombier 
243e12c5d1SDavid du Colombier long
sysrfork(ulong * arg)253e12c5d1SDavid du Colombier sysrfork(ulong *arg)
263e12c5d1SDavid du Colombier {
277dd7cddfSDavid du Colombier 	Proc *p;
283e12c5d1SDavid du Colombier 	int n, i;
297dd7cddfSDavid du Colombier 	Fgrp *ofg;
307dd7cddfSDavid du Colombier 	Pgrp *opg;
317dd7cddfSDavid du Colombier 	Rgrp *org;
327dd7cddfSDavid du Colombier 	Egrp *oeg;
337dd7cddfSDavid du Colombier 	ulong pid, flag;
347dd7cddfSDavid du Colombier 	Mach *wm;
353e12c5d1SDavid du Colombier 
363e12c5d1SDavid du Colombier 	flag = arg[0];
373e12c5d1SDavid du Colombier 	/* Check flags before we commit */
383e12c5d1SDavid du Colombier 	if((flag & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG))
393e12c5d1SDavid du Colombier 		error(Ebadarg);
403e12c5d1SDavid du Colombier 	if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG))
413e12c5d1SDavid du Colombier 		error(Ebadarg);
423e12c5d1SDavid du Colombier 	if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG))
433e12c5d1SDavid du Colombier 		error(Ebadarg);
443e12c5d1SDavid du Colombier 
457dd7cddfSDavid du Colombier 	if((flag&RFPROC) == 0) {
467dd7cddfSDavid du Colombier 		if(flag & (RFMEM|RFNOWAIT))
477dd7cddfSDavid du Colombier 			error(Ebadarg);
487dd7cddfSDavid du Colombier 		if(flag & (RFFDG|RFCFDG)) {
497dd7cddfSDavid du Colombier 			ofg = up->fgrp;
507dd7cddfSDavid du Colombier 			if(flag & RFFDG)
517dd7cddfSDavid du Colombier 				up->fgrp = dupfgrp(ofg);
527dd7cddfSDavid du Colombier 			else
537dd7cddfSDavid du Colombier 				up->fgrp = dupfgrp(nil);
547dd7cddfSDavid du Colombier 			closefgrp(ofg);
557dd7cddfSDavid du Colombier 		}
567dd7cddfSDavid du Colombier 		if(flag & (RFNAMEG|RFCNAMEG)) {
577dd7cddfSDavid du Colombier 			opg = up->pgrp;
587dd7cddfSDavid du Colombier 			up->pgrp = newpgrp();
597dd7cddfSDavid du Colombier 			if(flag & RFNAMEG)
607dd7cddfSDavid du Colombier 				pgrpcpy(up->pgrp, opg);
617dd7cddfSDavid du Colombier 			/* inherit noattach */
627dd7cddfSDavid du Colombier 			up->pgrp->noattach = opg->noattach;
637dd7cddfSDavid du Colombier 			closepgrp(opg);
647dd7cddfSDavid du Colombier 		}
657dd7cddfSDavid du Colombier 		if(flag & RFNOMNT)
667dd7cddfSDavid du Colombier 			up->pgrp->noattach = 1;
677dd7cddfSDavid du Colombier 		if(flag & RFREND) {
687dd7cddfSDavid du Colombier 			org = up->rgrp;
697dd7cddfSDavid du Colombier 			up->rgrp = newrgrp();
707dd7cddfSDavid du Colombier 			closergrp(org);
717dd7cddfSDavid du Colombier 		}
727dd7cddfSDavid du Colombier 		if(flag & (RFENVG|RFCENVG)) {
737dd7cddfSDavid du Colombier 			oeg = up->egrp;
747dd7cddfSDavid du Colombier 			up->egrp = smalloc(sizeof(Egrp));
757dd7cddfSDavid du Colombier 			up->egrp->ref = 1;
767dd7cddfSDavid du Colombier 			if(flag & RFENVG)
777dd7cddfSDavid du Colombier 				envcpy(up->egrp, oeg);
787dd7cddfSDavid du Colombier 			closeegrp(oeg);
797dd7cddfSDavid du Colombier 		}
807dd7cddfSDavid du Colombier 		if(flag & RFNOTEG)
817dd7cddfSDavid du Colombier 			up->noteid = incref(&noteidalloc);
827dd7cddfSDavid du Colombier 		return 0;
837dd7cddfSDavid du Colombier 	}
847dd7cddfSDavid du Colombier 
853e12c5d1SDavid du Colombier 	p = newproc();
863e12c5d1SDavid du Colombier 
877dd7cddfSDavid du Colombier 	p->fpsave = up->fpsave;
887dd7cddfSDavid du Colombier 	p->scallnr = up->scallnr;
897dd7cddfSDavid du Colombier 	p->s = up->s;
907dd7cddfSDavid du Colombier 	p->nerrlab = 0;
917dd7cddfSDavid du Colombier 	p->slash = up->slash;
927dd7cddfSDavid du Colombier 	p->dot = up->dot;
937dd7cddfSDavid du Colombier 	incref(p->dot);
943e12c5d1SDavid du Colombier 
957dd7cddfSDavid du Colombier 	memmove(p->note, up->note, sizeof(p->note));
969a747e4fSDavid du Colombier 	p->privatemem = up->privatemem;
97b7b24591SDavid du Colombier 	p->noswap = up->noswap;
987dd7cddfSDavid du Colombier 	p->nnote = up->nnote;
997dd7cddfSDavid du Colombier 	p->notified = 0;
1007dd7cddfSDavid du Colombier 	p->lastnote = up->lastnote;
1017dd7cddfSDavid du Colombier 	p->notify = up->notify;
1027dd7cddfSDavid du Colombier 	p->ureg = up->ureg;
1037dd7cddfSDavid du Colombier 	p->dbgreg = 0;
1043e12c5d1SDavid du Colombier 
1053e12c5d1SDavid du Colombier 	/* Make a new set of memory segments */
1063e12c5d1SDavid du Colombier 	n = flag & RFMEM;
1077dd7cddfSDavid du Colombier 	qlock(&p->seglock);
1087dd7cddfSDavid du Colombier 	if(waserror()){
1097dd7cddfSDavid du Colombier 		qunlock(&p->seglock);
1107dd7cddfSDavid du Colombier 		nexterror();
1117dd7cddfSDavid du Colombier 	}
1123e12c5d1SDavid du Colombier 	for(i = 0; i < NSEG; i++)
1137dd7cddfSDavid du Colombier 		if(up->seg[i])
1147dd7cddfSDavid du Colombier 			p->seg[i] = dupseg(up->seg, i, n);
1157dd7cddfSDavid du Colombier 	qunlock(&p->seglock);
1167dd7cddfSDavid du Colombier 	poperror();
1173e12c5d1SDavid du Colombier 
1183e12c5d1SDavid du Colombier 	/* File descriptors */
1193e12c5d1SDavid du Colombier 	if(flag & (RFFDG|RFCFDG)) {
1203e12c5d1SDavid du Colombier 		if(flag & RFFDG)
1217dd7cddfSDavid du Colombier 			p->fgrp = dupfgrp(up->fgrp);
1227dd7cddfSDavid du Colombier 		else
1237dd7cddfSDavid du Colombier 			p->fgrp = dupfgrp(nil);
1243e12c5d1SDavid du Colombier 	}
1253e12c5d1SDavid du Colombier 	else {
1267dd7cddfSDavid du Colombier 		p->fgrp = up->fgrp;
1273e12c5d1SDavid du Colombier 		incref(p->fgrp);
1283e12c5d1SDavid du Colombier 	}
1293e12c5d1SDavid du Colombier 
1303e12c5d1SDavid du Colombier 	/* Process groups */
1313e12c5d1SDavid du Colombier 	if(flag & (RFNAMEG|RFCNAMEG)) {
1323e12c5d1SDavid du Colombier 		p->pgrp = newpgrp();
133bd389b36SDavid du Colombier 		if(flag & RFNAMEG)
1347dd7cddfSDavid du Colombier 			pgrpcpy(p->pgrp, up->pgrp);
1357dd7cddfSDavid du Colombier 		/* inherit noattach */
1367dd7cddfSDavid du Colombier 		p->pgrp->noattach = up->pgrp->noattach;
1373e12c5d1SDavid du Colombier 	}
1383e12c5d1SDavid du Colombier 	else {
1397dd7cddfSDavid du Colombier 		p->pgrp = up->pgrp;
1403e12c5d1SDavid du Colombier 		incref(p->pgrp);
1413e12c5d1SDavid du Colombier 	}
1427dd7cddfSDavid du Colombier 	if(flag & RFNOMNT)
143b94bb474SDavid du Colombier 		p->pgrp->noattach = 1;
1447dd7cddfSDavid du Colombier 
1457dd7cddfSDavid du Colombier 	if(flag & RFREND)
1467dd7cddfSDavid du Colombier 		p->rgrp = newrgrp();
1477dd7cddfSDavid du Colombier 	else {
1487dd7cddfSDavid du Colombier 		incref(up->rgrp);
1497dd7cddfSDavid du Colombier 		p->rgrp = up->rgrp;
1507dd7cddfSDavid du Colombier 	}
1513e12c5d1SDavid du Colombier 
1523e12c5d1SDavid du Colombier 	/* Environment group */
1533e12c5d1SDavid du Colombier 	if(flag & (RFENVG|RFCENVG)) {
1543e12c5d1SDavid du Colombier 		p->egrp = smalloc(sizeof(Egrp));
1553e12c5d1SDavid du Colombier 		p->egrp->ref = 1;
1563e12c5d1SDavid du Colombier 		if(flag & RFENVG)
1577dd7cddfSDavid du Colombier 			envcpy(p->egrp, up->egrp);
1583e12c5d1SDavid du Colombier 	}
1593e12c5d1SDavid du Colombier 	else {
1607dd7cddfSDavid du Colombier 		p->egrp = up->egrp;
1613e12c5d1SDavid du Colombier 		incref(p->egrp);
1623e12c5d1SDavid du Colombier 	}
1637dd7cddfSDavid du Colombier 	p->hang = up->hang;
1647dd7cddfSDavid du Colombier 	p->procmode = up->procmode;
1653e12c5d1SDavid du Colombier 
1667dd7cddfSDavid du Colombier 	/* Craft a return frame which will cause the child to pop out of
1677dd7cddfSDavid du Colombier 	 * the scheduler in user mode with the return register zero
1683e12c5d1SDavid du Colombier 	 */
1697dd7cddfSDavid du Colombier 	forkchild(p, up->dbgreg);
1703e12c5d1SDavid du Colombier 
1717dd7cddfSDavid du Colombier 	p->parent = up;
1727dd7cddfSDavid du Colombier 	p->parentpid = up->pid;
1733e12c5d1SDavid du Colombier 	if(flag&RFNOWAIT)
1749a747e4fSDavid du Colombier 		p->parentpid = 0;
1753e12c5d1SDavid du Colombier 	else {
1767dd7cddfSDavid du Colombier 		lock(&up->exl);
1777dd7cddfSDavid du Colombier 		up->nchild++;
1787dd7cddfSDavid du Colombier 		unlock(&up->exl);
1793e12c5d1SDavid du Colombier 	}
1803e12c5d1SDavid du Colombier 	if((flag&RFNOTEG) == 0)
1817dd7cddfSDavid du Colombier 		p->noteid = up->noteid;
1823e12c5d1SDavid du Colombier 
1833b58d1fcSDavid du Colombier 	/* don't penalize the child, it hasn't done FP in a note handler. */
1843b58d1fcSDavid du Colombier 	p->fpstate = up->fpstate & ~FPillegal;
1853e12c5d1SDavid du Colombier 	pid = p->pid;
1863e12c5d1SDavid du Colombier 	memset(p->time, 0, sizeof(p->time));
1873e12c5d1SDavid du Colombier 	p->time[TReal] = MACHP(0)->ticks;
1889a747e4fSDavid du Colombier 
1899a747e4fSDavid du Colombier 	kstrdup(&p->text, up->text);
1909a747e4fSDavid du Colombier 	kstrdup(&p->user, up->user);
1913e12c5d1SDavid du Colombier 	/*
1923e12c5d1SDavid du Colombier 	 *  since the bss/data segments are now shareable,
1933e12c5d1SDavid du Colombier 	 *  any mmu info about this process is now stale
1943e12c5d1SDavid du Colombier 	 *  (i.e. has bad properties) and has to be discarded.
1953e12c5d1SDavid du Colombier 	 */
1963e12c5d1SDavid du Colombier 	flushmmu();
1977dd7cddfSDavid du Colombier 	p->basepri = up->basepri;
1989a747e4fSDavid du Colombier 	p->priority = up->basepri;
19980ee5cbfSDavid du Colombier 	p->fixedpri = up->fixedpri;
2007dd7cddfSDavid du Colombier 	p->mp = up->mp;
2017dd7cddfSDavid du Colombier 	wm = up->wired;
2027dd7cddfSDavid du Colombier 	if(wm)
2037dd7cddfSDavid du Colombier 		procwired(p, wm->machno);
2043e12c5d1SDavid du Colombier 	ready(p);
205219b2ee8SDavid du Colombier 	sched();
2063e12c5d1SDavid du Colombier 	return pid;
2073e12c5d1SDavid du Colombier }
2083e12c5d1SDavid du Colombier 
2095482313dSDavid du Colombier ulong
l2be(long l)2103e12c5d1SDavid du Colombier l2be(long l)
2113e12c5d1SDavid du Colombier {
2123e12c5d1SDavid du Colombier 	uchar *cp;
2133e12c5d1SDavid du Colombier 
2143e12c5d1SDavid du Colombier 	cp = (uchar*)&l;
2153e12c5d1SDavid du Colombier 	return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3];
2163e12c5d1SDavid du Colombier }
2173e12c5d1SDavid du Colombier 
2183e12c5d1SDavid du Colombier long
sysexec(ulong * arg)2193e12c5d1SDavid du Colombier sysexec(ulong *arg)
2203e12c5d1SDavid du Colombier {
2213e12c5d1SDavid du Colombier 	Segment *s, *ts;
2223e12c5d1SDavid du Colombier 	ulong t, d, b;
2233e12c5d1SDavid du Colombier 	int i;
2243e12c5d1SDavid du Colombier 	Chan *tc;
2253e12c5d1SDavid du Colombier 	char **argv, **argp;
226d1be6b08SDavid du Colombier 	char *a, *charp, *args, *file, *file0;
2279a747e4fSDavid du Colombier 	char *progarg[sizeof(Exec)/2+1], *elem, progelem[64];
2283e12c5d1SDavid du Colombier 	ulong ssize, spage, nargs, nbytes, n, bssend;
2293e12c5d1SDavid du Colombier 	int indir;
2303e12c5d1SDavid du Colombier 	Exec exec;
2313e12c5d1SDavid du Colombier 	char line[sizeof(Exec)];
2323e12c5d1SDavid du Colombier 	Fgrp *f;
2333e12c5d1SDavid du Colombier 	Image *img;
2343e12c5d1SDavid du Colombier 	ulong magic, text, entry, data, bss;
235e288d156SDavid du Colombier 	Tos *tos;
2363e12c5d1SDavid du Colombier 
2373e12c5d1SDavid du Colombier 	indir = 0;
2389a747e4fSDavid du Colombier 	elem = nil;
239d1be6b08SDavid du Colombier 	validaddr(arg[0], 1, 0);
240d1be6b08SDavid du Colombier 	file0 = validnamedup((char*)arg[0], 1);
2419a747e4fSDavid du Colombier 	if(waserror()){
242d1be6b08SDavid du Colombier 		free(file0);
2439a747e4fSDavid du Colombier 		free(elem);
2449a747e4fSDavid du Colombier 		nexterror();
2459a747e4fSDavid du Colombier 	}
246d1be6b08SDavid du Colombier 	file = file0;
2477dd7cddfSDavid du Colombier 	for(;;){
2483e12c5d1SDavid du Colombier 		tc = namec(file, Aopen, OEXEC, 0);
2493e12c5d1SDavid du Colombier 		if(waserror()){
2507dd7cddfSDavid du Colombier 			cclose(tc);
2513e12c5d1SDavid du Colombier 			nexterror();
2523e12c5d1SDavid du Colombier 		}
2533e12c5d1SDavid du Colombier 		if(!indir)
2549a747e4fSDavid du Colombier 			kstrdup(&elem, up->genbuf);
2553e12c5d1SDavid du Colombier 
2567dd7cddfSDavid du Colombier 		n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0);
2573e12c5d1SDavid du Colombier 		if(n < 2)
2583e12c5d1SDavid du Colombier 			error(Ebadexec);
2593e12c5d1SDavid du Colombier 		magic = l2be(exec.magic);
2603e12c5d1SDavid du Colombier 		text = l2be(exec.text);
2613e12c5d1SDavid du Colombier 		entry = l2be(exec.entry);
2627dd7cddfSDavid du Colombier 		if(n==sizeof(Exec) && (magic == AOUT_MAGIC)){
2634de34a7eSDavid du Colombier 			if(text >= USTKTOP-UTZERO
2643e12c5d1SDavid du Colombier 			|| entry < UTZERO+sizeof(Exec)
2653e12c5d1SDavid du Colombier 			|| entry >= UTZERO+sizeof(Exec)+text)
2667dd7cddfSDavid du Colombier 				error(Ebadexec);
2677dd7cddfSDavid du Colombier 			break; /* for binary */
2683e12c5d1SDavid du Colombier 		}
2693e12c5d1SDavid du Colombier 
2703e12c5d1SDavid du Colombier 		/*
2713e12c5d1SDavid du Colombier 		 * Process #! /bin/sh args ...
2723e12c5d1SDavid du Colombier 		 */
2733e12c5d1SDavid du Colombier 		memmove(line, &exec, sizeof(Exec));
2743e12c5d1SDavid du Colombier 		if(indir || line[0]!='#' || line[1]!='!')
2757dd7cddfSDavid du Colombier 			error(Ebadexec);
2763e12c5d1SDavid du Colombier 		n = shargs(line, n, progarg);
2773e12c5d1SDavid du Colombier 		if(n == 0)
2787dd7cddfSDavid du Colombier 			error(Ebadexec);
2793e12c5d1SDavid du Colombier 		indir = 1;
2803e12c5d1SDavid du Colombier 		/*
2813e12c5d1SDavid du Colombier 		 * First arg becomes complete file name
2823e12c5d1SDavid du Colombier 		 */
2833e12c5d1SDavid du Colombier 		progarg[n++] = file;
2843e12c5d1SDavid du Colombier 		progarg[n] = 0;
2853e12c5d1SDavid du Colombier 		validaddr(arg[1], BY2WD, 1);
2863e12c5d1SDavid du Colombier 		arg[1] += BY2WD;
2873e12c5d1SDavid du Colombier 		file = progarg[0];
2889a747e4fSDavid du Colombier 		if(strlen(elem) >= sizeof progelem)
2899a747e4fSDavid du Colombier 			error(Ebadexec);
2909a747e4fSDavid du Colombier 		strcpy(progelem, elem);
2919a747e4fSDavid du Colombier 		progarg[0] = progelem;
2923e12c5d1SDavid du Colombier 		poperror();
2937dd7cddfSDavid du Colombier 		cclose(tc);
2947dd7cddfSDavid du Colombier 	}
2953e12c5d1SDavid du Colombier 
2963e12c5d1SDavid du Colombier 	data = l2be(exec.data);
2973e12c5d1SDavid du Colombier 	bss = l2be(exec.bss);
29812009bffSDavid du Colombier 	t = UTROUND(UTZERO+sizeof(Exec)+text);
2993e12c5d1SDavid du Colombier 	d = (t + data + (BY2PG-1)) & ~(BY2PG-1);
3003e12c5d1SDavid du Colombier 	bssend = t + data + bss;
3013e12c5d1SDavid du Colombier 	b = (bssend + (BY2PG-1)) & ~(BY2PG-1);
3024de34a7eSDavid du Colombier 	if(t >= KZERO || d >= KZERO || b >= KZERO)
3033e12c5d1SDavid du Colombier 		error(Ebadexec);
3043e12c5d1SDavid du Colombier 
3053e12c5d1SDavid du Colombier 	/*
3063e12c5d1SDavid du Colombier 	 * Args: pass 1: count
3073e12c5d1SDavid du Colombier 	 */
308e288d156SDavid du Colombier 	nbytes = sizeof(Tos);		/* hole for profiling clock at top of stack (and more) */
3093e12c5d1SDavid du Colombier 	nargs = 0;
3103e12c5d1SDavid du Colombier 	if(indir){
3113e12c5d1SDavid du Colombier 		argp = progarg;
3123e12c5d1SDavid du Colombier 		while(*argp){
3133e12c5d1SDavid du Colombier 			a = *argp++;
3143e12c5d1SDavid du Colombier 			nbytes += strlen(a) + 1;
3153e12c5d1SDavid du Colombier 			nargs++;
3163e12c5d1SDavid du Colombier 		}
3173e12c5d1SDavid du Colombier 	}
318*fac6300fSDavid du Colombier 	validalign(arg[1], sizeof(char**));
3193e12c5d1SDavid du Colombier 	argp = (char**)arg[1];
3203e12c5d1SDavid du Colombier 	validaddr((ulong)argp, BY2WD, 0);
3213e12c5d1SDavid du Colombier 	while(*argp){
3223e12c5d1SDavid du Colombier 		a = *argp++;
3233e12c5d1SDavid du Colombier 		if(((ulong)argp&(BY2PG-1)) < BY2WD)
3243e12c5d1SDavid du Colombier 			validaddr((ulong)argp, BY2WD, 0);
3253e12c5d1SDavid du Colombier 		validaddr((ulong)a, 1, 0);
3262282df4eSDavid du Colombier 		nbytes += ((char*)vmemchr(a, 0, 0x7FFFFFFF) - a) + 1;
3273e12c5d1SDavid du Colombier 		nargs++;
3283e12c5d1SDavid du Colombier 	}
3293e12c5d1SDavid du Colombier 	ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1));
330bd389b36SDavid du Colombier 
3313e12c5d1SDavid du Colombier 	/*
3323e12c5d1SDavid du Colombier 	 * 8-byte align SP for those (e.g. sparc) that need it.
3333e12c5d1SDavid du Colombier 	 * execregs() will subtract another 4 bytes for argc.
3343e12c5d1SDavid du Colombier 	 */
3353e12c5d1SDavid du Colombier 	if((ssize+4) & 7)
3363e12c5d1SDavid du Colombier 		ssize += 4;
3373e12c5d1SDavid du Colombier 	spage = (ssize+(BY2PG-1)) >> PGSHIFT;
3387dd7cddfSDavid du Colombier 
3393e12c5d1SDavid du Colombier 	/*
3403e12c5d1SDavid du Colombier 	 * Build the stack segment, putting it in kernel virtual for the moment
3413e12c5d1SDavid du Colombier 	 */
3423e12c5d1SDavid du Colombier 	if(spage > TSTKSIZ)
3433e12c5d1SDavid du Colombier 		error(Enovmem);
3443e12c5d1SDavid du Colombier 
3457dd7cddfSDavid du Colombier 	qlock(&up->seglock);
3467dd7cddfSDavid du Colombier 	if(waserror()){
3477dd7cddfSDavid du Colombier 		qunlock(&up->seglock);
3487dd7cddfSDavid du Colombier 		nexterror();
3497dd7cddfSDavid du Colombier 	}
3507dd7cddfSDavid du Colombier 	up->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG);
3513e12c5d1SDavid du Colombier 
3523e12c5d1SDavid du Colombier 	/*
3533e12c5d1SDavid du Colombier 	 * Args: pass 2: assemble; the pages will be faulted in
3543e12c5d1SDavid du Colombier 	 */
355e288d156SDavid du Colombier 	tos = (Tos*)(TSTKTOP - sizeof(Tos));
356e288d156SDavid du Colombier 	tos->cyclefreq = m->cyclefreq;
357e288d156SDavid du Colombier 	cycles((uvlong*)&tos->pcycles);
358e288d156SDavid du Colombier 	tos->pcycles = -tos->pcycles;
359e288d156SDavid du Colombier 	tos->kcycles = tos->pcycles;
360e288d156SDavid du Colombier 	tos->clock = 0;
3613e12c5d1SDavid du Colombier 	argv = (char**)(TSTKTOP - ssize);
3623e12c5d1SDavid du Colombier 	charp = (char*)(TSTKTOP - nbytes);
3639a747e4fSDavid du Colombier 	args = charp;
3643e12c5d1SDavid du Colombier 	if(indir)
3653e12c5d1SDavid du Colombier 		argp = progarg;
3663e12c5d1SDavid du Colombier 	else
3673e12c5d1SDavid du Colombier 		argp = (char**)arg[1];
3683e12c5d1SDavid du Colombier 
3693e12c5d1SDavid du Colombier 	for(i=0; i<nargs; i++){
3703e12c5d1SDavid du Colombier 		if(indir && *argp==0) {
3713e12c5d1SDavid du Colombier 			indir = 0;
3723e12c5d1SDavid du Colombier 			argp = (char**)arg[1];
3733e12c5d1SDavid du Colombier 		}
3743e12c5d1SDavid du Colombier 		*argv++ = charp + (USTKTOP-TSTKTOP);
3753e12c5d1SDavid du Colombier 		n = strlen(*argp) + 1;
3763e12c5d1SDavid du Colombier 		memmove(charp, *argp++, n);
3773e12c5d1SDavid du Colombier 		charp += n;
3783e12c5d1SDavid du Colombier 	}
379d1be6b08SDavid du Colombier 	free(file0);
3803e12c5d1SDavid du Colombier 
3819a747e4fSDavid du Colombier 	free(up->text);
3829a747e4fSDavid du Colombier 	up->text = elem;
3839a747e4fSDavid du Colombier 	elem = nil;	/* so waserror() won't free elem */
3849a747e4fSDavid du Colombier 	USED(elem);
3859a747e4fSDavid du Colombier 
3869a747e4fSDavid du Colombier 	/* copy args; easiest from new process's stack */
3879a747e4fSDavid du Colombier 	n = charp - args;
3889a747e4fSDavid du Colombier 	if(n > 128)	/* don't waste too much space on huge arg lists */
3899a747e4fSDavid du Colombier 		n = 128;
3909a747e4fSDavid du Colombier 	a = up->args;
3919a747e4fSDavid du Colombier 	up->args = nil;
3929a747e4fSDavid du Colombier 	free(a);
3939a747e4fSDavid du Colombier 	up->args = smalloc(n);
3949a747e4fSDavid du Colombier 	memmove(up->args, args, n);
3959a747e4fSDavid du Colombier 	if(n>0 && up->args[n-1]!='\0'){
3969a747e4fSDavid du Colombier 		/* make sure last arg is NUL-terminated */
3979a747e4fSDavid du Colombier 		/* put NUL at UTF-8 character boundary */
3989a747e4fSDavid du Colombier 		for(i=n-1; i>0; --i)
3999a747e4fSDavid du Colombier 			if(fullrune(up->args+i, n-i))
4009a747e4fSDavid du Colombier 				break;
4019a747e4fSDavid du Colombier 		up->args[i] = 0;
4029a747e4fSDavid du Colombier 		n = i+1;
4039a747e4fSDavid du Colombier 	}
4049a747e4fSDavid du Colombier 	up->nargs = n;
4053e12c5d1SDavid du Colombier 
4063e12c5d1SDavid du Colombier 	/*
407bd389b36SDavid du Colombier 	 * Committed.
408bd389b36SDavid du Colombier 	 * Free old memory.
4097dd7cddfSDavid du Colombier 	 * Special segments are maintained across exec
4103e12c5d1SDavid du Colombier 	 */
4113e12c5d1SDavid du Colombier 	for(i = SSEG; i <= BSEG; i++) {
4127dd7cddfSDavid du Colombier 		putseg(up->seg[i]);
413219b2ee8SDavid du Colombier 		/* prevent a second free if we have an error */
4147dd7cddfSDavid du Colombier 		up->seg[i] = 0;
415219b2ee8SDavid du Colombier 	}
416219b2ee8SDavid du Colombier 	for(i = BSEG+1; i < NSEG; i++) {
4177dd7cddfSDavid du Colombier 		s = up->seg[i];
418219b2ee8SDavid du Colombier 		if(s != 0 && (s->type&SG_CEXEC)) {
419219b2ee8SDavid du Colombier 			putseg(s);
4207dd7cddfSDavid du Colombier 			up->seg[i] = 0;
421219b2ee8SDavid du Colombier 		}
4223e12c5d1SDavid du Colombier 	}
4233e12c5d1SDavid du Colombier 
4243e12c5d1SDavid du Colombier 	/*
4253e12c5d1SDavid du Colombier 	 * Close on exec
4263e12c5d1SDavid du Colombier 	 */
4277dd7cddfSDavid du Colombier 	f = up->fgrp;
4283e12c5d1SDavid du Colombier 	for(i=0; i<=f->maxfd; i++)
4293e12c5d1SDavid du Colombier 		fdclose(i, CCEXEC);
4303e12c5d1SDavid du Colombier 
4313e12c5d1SDavid du Colombier 	/* Text.  Shared. Attaches to cache image if possible */
4323e12c5d1SDavid du Colombier 	/* attachimage returns a locked cache image */
4333e12c5d1SDavid du Colombier 	img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (t-UTZERO)>>PGSHIFT);
4343e12c5d1SDavid du Colombier 	ts = img->s;
4357dd7cddfSDavid du Colombier 	up->seg[TSEG] = ts;
4363e12c5d1SDavid du Colombier 	ts->flushme = 1;
4373e12c5d1SDavid du Colombier 	ts->fstart = 0;
4383e12c5d1SDavid du Colombier 	ts->flen = sizeof(Exec)+text;
4393e12c5d1SDavid du Colombier 	unlock(img);
4403e12c5d1SDavid du Colombier 
4413e12c5d1SDavid du Colombier 	/* Data. Shared. */
4423e12c5d1SDavid du Colombier 	s = newseg(SG_DATA, t, (d-t)>>PGSHIFT);
4437dd7cddfSDavid du Colombier 	up->seg[DSEG] = s;
4443e12c5d1SDavid du Colombier 
4453e12c5d1SDavid du Colombier 	/* Attached by hand */
4463e12c5d1SDavid du Colombier 	incref(img);
4473e12c5d1SDavid du Colombier 	s->image = img;
4483e12c5d1SDavid du Colombier 	s->fstart = ts->fstart+ts->flen;
4493e12c5d1SDavid du Colombier 	s->flen = data;
4503e12c5d1SDavid du Colombier 
4513e12c5d1SDavid du Colombier 	/* BSS. Zero fill on demand */
4527dd7cddfSDavid du Colombier 	up->seg[BSEG] = newseg(SG_BSS, d, (b-d)>>PGSHIFT);
4533e12c5d1SDavid du Colombier 
4543e12c5d1SDavid du Colombier 	/*
4553e12c5d1SDavid du Colombier 	 * Move the stack
4563e12c5d1SDavid du Colombier 	 */
4577dd7cddfSDavid du Colombier 	s = up->seg[ESEG];
4587dd7cddfSDavid du Colombier 	up->seg[ESEG] = 0;
4597dd7cddfSDavid du Colombier 	up->seg[SSEG] = s;
4607dd7cddfSDavid du Colombier 	qunlock(&up->seglock);
4619a747e4fSDavid du Colombier 	poperror();	/* seglock */
4629a747e4fSDavid du Colombier 	poperror();	/* elem */
4633e12c5d1SDavid du Colombier 	s->base = USTKTOP-USTKSIZE;
4643e12c5d1SDavid du Colombier 	s->top = USTKTOP;
4657dd7cddfSDavid du Colombier 	relocateseg(s, USTKTOP-TSTKTOP);
4663e12c5d1SDavid du Colombier 
467219b2ee8SDavid du Colombier 	/*
468219b2ee8SDavid du Colombier 	 *  '/' processes are higher priority (hack to make /ip more responsive).
469219b2ee8SDavid du Colombier 	 */
4707dd7cddfSDavid du Colombier 	if(devtab[tc->type]->dc == L'/')
4717dd7cddfSDavid du Colombier 		up->basepri = PriRoot;
4727dd7cddfSDavid du Colombier 	up->priority = up->basepri;
4737dd7cddfSDavid du Colombier 	poperror();
4747dd7cddfSDavid du Colombier 	cclose(tc);
4753e12c5d1SDavid du Colombier 
4763e12c5d1SDavid du Colombier 	/*
4773e12c5d1SDavid du Colombier 	 *  At this point, the mmu contains info about the old address
4783e12c5d1SDavid du Colombier 	 *  space and needs to be flushed
4793e12c5d1SDavid du Colombier 	 */
4803e12c5d1SDavid du Colombier 	flushmmu();
4817dd7cddfSDavid du Colombier 	qlock(&up->debug);
4827dd7cddfSDavid du Colombier 	up->nnote = 0;
4837dd7cddfSDavid du Colombier 	up->notify = 0;
4847dd7cddfSDavid du Colombier 	up->notified = 0;
4859a747e4fSDavid du Colombier 	up->privatemem = 0;
4867dd7cddfSDavid du Colombier 	procsetup(up);
4877dd7cddfSDavid du Colombier 	qunlock(&up->debug);
4887dd7cddfSDavid du Colombier 	if(up->hang)
4897dd7cddfSDavid du Colombier 		up->procctl = Proc_stopme;
4903e12c5d1SDavid du Colombier 
4913e12c5d1SDavid du Colombier 	return execregs(entry, ssize, nargs);
4923e12c5d1SDavid du Colombier }
4933e12c5d1SDavid du Colombier 
4943e12c5d1SDavid du Colombier int
shargs(char * s,int n,char ** ap)4953e12c5d1SDavid du Colombier shargs(char *s, int n, char **ap)
4963e12c5d1SDavid du Colombier {
4973e12c5d1SDavid du Colombier 	int i;
4983e12c5d1SDavid du Colombier 
499bd389b36SDavid du Colombier 	s += 2;
500bd389b36SDavid du Colombier 	n -= 2;		/* skip #! */
5013e12c5d1SDavid du Colombier 	for(i=0; s[i]!='\n'; i++)
5023e12c5d1SDavid du Colombier 		if(i == n-1)
5033e12c5d1SDavid du Colombier 			return 0;
5043e12c5d1SDavid du Colombier 	s[i] = 0;
5053e12c5d1SDavid du Colombier 	*ap = 0;
5063e12c5d1SDavid du Colombier 	i = 0;
5073e12c5d1SDavid du Colombier 	for(;;) {
5083e12c5d1SDavid du Colombier 		while(*s==' ' || *s=='\t')
5093e12c5d1SDavid du Colombier 			s++;
5103e12c5d1SDavid du Colombier 		if(*s == 0)
5113e12c5d1SDavid du Colombier 			break;
5123e12c5d1SDavid du Colombier 		i++;
5133e12c5d1SDavid du Colombier 		*ap++ = s;
5143e12c5d1SDavid du Colombier 		*ap = 0;
5153e12c5d1SDavid du Colombier 		while(*s && *s!=' ' && *s!='\t')
5163e12c5d1SDavid du Colombier 			s++;
5173e12c5d1SDavid du Colombier 		if(*s == 0)
5183e12c5d1SDavid du Colombier 			break;
5193e12c5d1SDavid du Colombier 		else
5203e12c5d1SDavid du Colombier 			*s++ = 0;
5213e12c5d1SDavid du Colombier 	}
5223e12c5d1SDavid du Colombier 	return i;
5233e12c5d1SDavid du Colombier }
5243e12c5d1SDavid du Colombier 
5253e12c5d1SDavid du Colombier int
return0(void *)5267dd7cddfSDavid du Colombier return0(void*)
5273e12c5d1SDavid du Colombier {
5283e12c5d1SDavid du Colombier 	return 0;
5293e12c5d1SDavid du Colombier }
5303e12c5d1SDavid du Colombier 
5313e12c5d1SDavid du Colombier long
syssleep(ulong * arg)5323e12c5d1SDavid du Colombier syssleep(ulong *arg)
5333e12c5d1SDavid du Colombier {
5347dd7cddfSDavid du Colombier 
535219b2ee8SDavid du Colombier 	int n;
536219b2ee8SDavid du Colombier 
537219b2ee8SDavid du Colombier 	n = arg[0];
5387dd7cddfSDavid du Colombier 	if(n <= 0) {
539e288d156SDavid du Colombier 		if (up->edf && (up->edf->flags & Admitted))
540e288d156SDavid du Colombier 			edfyield();
541e288d156SDavid du Colombier 		else
542bd2ae673SDavid du Colombier 			yield();
543219b2ee8SDavid du Colombier 		return 0;
544219b2ee8SDavid du Colombier 	}
5457dd7cddfSDavid du Colombier 	if(n < TK2MS(1))
546219b2ee8SDavid du Colombier 		n = TK2MS(1);
5477dd7cddfSDavid du Colombier 	tsleep(&up->sleep, return0, 0, n);
5483e12c5d1SDavid du Colombier 	return 0;
5493e12c5d1SDavid du Colombier }
5503e12c5d1SDavid du Colombier 
5513e12c5d1SDavid du Colombier long
sysalarm(ulong * arg)5523e12c5d1SDavid du Colombier sysalarm(ulong *arg)
5533e12c5d1SDavid du Colombier {
5543e12c5d1SDavid du Colombier 	return procalarm(arg[0]);
5553e12c5d1SDavid du Colombier }
5563e12c5d1SDavid du Colombier 
5573e12c5d1SDavid du Colombier long
sysexits(ulong * arg)5583e12c5d1SDavid du Colombier sysexits(ulong *arg)
5593e12c5d1SDavid du Colombier {
5603e12c5d1SDavid du Colombier 	char *status;
5613e12c5d1SDavid du Colombier 	char *inval = "invalid exit string";
5629a747e4fSDavid du Colombier 	char buf[ERRMAX];
5633e12c5d1SDavid du Colombier 
5643e12c5d1SDavid du Colombier 	status = (char*)arg[0];
5653e12c5d1SDavid du Colombier 	if(status){
5663e12c5d1SDavid du Colombier 		if(waserror())
5673e12c5d1SDavid du Colombier 			status = inval;
5683e12c5d1SDavid du Colombier 		else{
5693e12c5d1SDavid du Colombier 			validaddr((ulong)status, 1, 0);
5709a747e4fSDavid du Colombier 			if(vmemchr(status, 0, ERRMAX) == 0){
5719a747e4fSDavid du Colombier 				memmove(buf, status, ERRMAX);
5729a747e4fSDavid du Colombier 				buf[ERRMAX-1] = 0;
573219b2ee8SDavid du Colombier 				status = buf;
574219b2ee8SDavid du Colombier 			}
5753e12c5d1SDavid du Colombier 			poperror();
5764b348146SDavid du Colombier 		}
5773e12c5d1SDavid du Colombier 
5783e12c5d1SDavid du Colombier 	}
5793e12c5d1SDavid du Colombier 	pexit(status, 1);
5803e12c5d1SDavid du Colombier 	return 0;		/* not reached */
5813e12c5d1SDavid du Colombier }
5823e12c5d1SDavid du Colombier 
5833e12c5d1SDavid du Colombier long
sys_wait(ulong * arg)5849a747e4fSDavid du Colombier sys_wait(ulong *arg)
5853e12c5d1SDavid du Colombier {
5869a747e4fSDavid du Colombier 	int pid;
5879a747e4fSDavid du Colombier 	Waitmsg w;
5889a747e4fSDavid du Colombier 	OWaitmsg *ow;
5899a747e4fSDavid du Colombier 
5909a747e4fSDavid du Colombier 	if(arg[0] == 0)
5919a747e4fSDavid du Colombier 		return pwait(nil);
5929a747e4fSDavid du Colombier 
5939a747e4fSDavid du Colombier 	validaddr(arg[0], sizeof(OWaitmsg), 1);
594*fac6300fSDavid du Colombier 	validalign(arg[0], BY2WD);			/* who cares? */
5959a747e4fSDavid du Colombier 	pid = pwait(&w);
5969a747e4fSDavid du Colombier 	if(pid >= 0){
5979a747e4fSDavid du Colombier 		ow = (OWaitmsg*)arg[0];
5989a747e4fSDavid du Colombier 		readnum(0, ow->pid, NUMSIZE, w.pid, NUMSIZE);
5999a747e4fSDavid du Colombier 		readnum(0, ow->time+TUser*NUMSIZE, NUMSIZE, w.time[TUser], NUMSIZE);
6009a747e4fSDavid du Colombier 		readnum(0, ow->time+TSys*NUMSIZE, NUMSIZE, w.time[TSys], NUMSIZE);
6019a747e4fSDavid du Colombier 		readnum(0, ow->time+TReal*NUMSIZE, NUMSIZE, w.time[TReal], NUMSIZE);
6029a747e4fSDavid du Colombier 		strncpy(ow->msg, w.msg, sizeof(ow->msg));
6039a747e4fSDavid du Colombier 		ow->msg[sizeof(ow->msg)-1] = '\0';
6043e12c5d1SDavid du Colombier 	}
6059a747e4fSDavid du Colombier 	return pid;
6069a747e4fSDavid du Colombier }
6079a747e4fSDavid du Colombier 
6089a747e4fSDavid du Colombier long
sysawait(ulong * arg)6099a747e4fSDavid du Colombier sysawait(ulong *arg)
6109a747e4fSDavid du Colombier {
6119a747e4fSDavid du Colombier 	int i;
6129a747e4fSDavid du Colombier 	int pid;
6139a747e4fSDavid du Colombier 	Waitmsg w;
6149a747e4fSDavid du Colombier 	ulong n;
6159a747e4fSDavid du Colombier 
6169a747e4fSDavid du Colombier 	n = arg[1];
6179a747e4fSDavid du Colombier 	validaddr(arg[0], n, 1);
6189a747e4fSDavid du Colombier 	pid = pwait(&w);
6199a747e4fSDavid du Colombier 	if(pid < 0)
6209a747e4fSDavid du Colombier 		return -1;
6219a747e4fSDavid du Colombier 	i = snprint((char*)arg[0], n, "%d %lud %lud %lud %q",
6229a747e4fSDavid du Colombier 		w.pid,
6239a747e4fSDavid du Colombier 		w.time[TUser], w.time[TSys], w.time[TReal],
6249a747e4fSDavid du Colombier 		w.msg);
6259a747e4fSDavid du Colombier 
6269a747e4fSDavid du Colombier 	return i;
6273e12c5d1SDavid du Colombier }
6283e12c5d1SDavid du Colombier 
6297dd7cddfSDavid du Colombier void
werrstr(char * fmt,...)6307dd7cddfSDavid du Colombier werrstr(char *fmt, ...)
6317dd7cddfSDavid du Colombier {
6327dd7cddfSDavid du Colombier 	va_list va;
6337dd7cddfSDavid du Colombier 
6347dd7cddfSDavid du Colombier 	if(up == nil)
6357dd7cddfSDavid du Colombier 		return;
6367dd7cddfSDavid du Colombier 
6377dd7cddfSDavid du Colombier 	va_start(va, fmt);
6389a747e4fSDavid du Colombier 	vseprint(up->syserrstr, up->syserrstr+ERRMAX, fmt, va);
6397dd7cddfSDavid du Colombier 	va_end(va);
6407dd7cddfSDavid du Colombier }
6417dd7cddfSDavid du Colombier 
6429a747e4fSDavid du Colombier static long
generrstr(char * buf,uint nbuf)6439a747e4fSDavid du Colombier generrstr(char *buf, uint nbuf)
6449a747e4fSDavid du Colombier {
6459a747e4fSDavid du Colombier 	char tmp[ERRMAX];
6469a747e4fSDavid du Colombier 
6479a747e4fSDavid du Colombier 	if(nbuf == 0)
6489a747e4fSDavid du Colombier 		error(Ebadarg);
6499a747e4fSDavid du Colombier 	validaddr((ulong)buf, nbuf, 1);
6509a747e4fSDavid du Colombier 	if(nbuf > sizeof tmp)
6519a747e4fSDavid du Colombier 		nbuf = sizeof tmp;
6529a747e4fSDavid du Colombier 	memmove(tmp, buf, nbuf);
653dc5a79c1SDavid du Colombier 
6549a747e4fSDavid du Colombier 	/* make sure it's NUL-terminated */
6559a747e4fSDavid du Colombier 	tmp[nbuf-1] = '\0';
6569a747e4fSDavid du Colombier 	memmove(buf, up->syserrstr, nbuf);
6579a747e4fSDavid du Colombier 	buf[nbuf-1] = '\0';
6589a747e4fSDavid du Colombier 	memmove(up->syserrstr, tmp, nbuf);
6599a747e4fSDavid du Colombier 	return 0;
6609a747e4fSDavid du Colombier }
6619a747e4fSDavid du Colombier 
6623e12c5d1SDavid du Colombier long
syserrstr(ulong * arg)6633e12c5d1SDavid du Colombier syserrstr(ulong *arg)
6643e12c5d1SDavid du Colombier {
6659a747e4fSDavid du Colombier 	return generrstr((char*)arg[0], arg[1]);
6669a747e4fSDavid du Colombier }
667219b2ee8SDavid du Colombier 
6689a747e4fSDavid du Colombier /* compatibility for old binaries */
6699a747e4fSDavid du Colombier long
sys_errstr(ulong * arg)6709a747e4fSDavid du Colombier sys_errstr(ulong *arg)
6719a747e4fSDavid du Colombier {
6729a747e4fSDavid du Colombier 	return generrstr((char*)arg[0], 64);
6733e12c5d1SDavid du Colombier }
6743e12c5d1SDavid du Colombier 
6753e12c5d1SDavid du Colombier long
sysnotify(ulong * arg)6763e12c5d1SDavid du Colombier sysnotify(ulong *arg)
6773e12c5d1SDavid du Colombier {
6783e12c5d1SDavid du Colombier 	if(arg[0] != 0)
6793e12c5d1SDavid du Colombier 		validaddr(arg[0], sizeof(ulong), 0);
6807dd7cddfSDavid du Colombier 	up->notify = (int(*)(void*, char*))(arg[0]);
6813e12c5d1SDavid du Colombier 	return 0;
6823e12c5d1SDavid du Colombier }
6833e12c5d1SDavid du Colombier 
6843e12c5d1SDavid du Colombier long
sysnoted(ulong * arg)6853e12c5d1SDavid du Colombier sysnoted(ulong *arg)
6863e12c5d1SDavid du Colombier {
6877dd7cddfSDavid du Colombier 	if(arg[0]!=NRSTR && !up->notified)
6883e12c5d1SDavid du Colombier 		error(Egreg);
6893e12c5d1SDavid du Colombier 	return 0;
6903e12c5d1SDavid du Colombier }
6913e12c5d1SDavid du Colombier 
6923e12c5d1SDavid du Colombier long
syssegbrk(ulong * arg)6933e12c5d1SDavid du Colombier syssegbrk(ulong *arg)
6943e12c5d1SDavid du Colombier {
6953e12c5d1SDavid du Colombier 	int i;
6967dd7cddfSDavid du Colombier 	ulong addr;
6977dd7cddfSDavid du Colombier 	Segment *s;
6983e12c5d1SDavid du Colombier 
6997dd7cddfSDavid du Colombier 	addr = arg[0];
700219b2ee8SDavid du Colombier 	for(i = 0; i < NSEG; i++) {
7017dd7cddfSDavid du Colombier 		s = up->seg[i];
7027dd7cddfSDavid du Colombier 		if(s == 0 || addr < s->base || addr >= s->top)
7037dd7cddfSDavid du Colombier 			continue;
7043e12c5d1SDavid du Colombier 		switch(s->type&SG_TYPE) {
7053e12c5d1SDavid du Colombier 		case SG_TEXT:
7063e12c5d1SDavid du Colombier 		case SG_DATA:
707219b2ee8SDavid du Colombier 		case SG_STACK:
7083e12c5d1SDavid du Colombier 			error(Ebadarg);
7093e12c5d1SDavid du Colombier 		default:
7103e12c5d1SDavid du Colombier 			return ibrk(arg[1], i);
7113e12c5d1SDavid du Colombier 		}
7123e12c5d1SDavid du Colombier 	}
7133e12c5d1SDavid du Colombier 
7143e12c5d1SDavid du Colombier 	error(Ebadarg);
7153e12c5d1SDavid du Colombier 	return 0;		/* not reached */
7163e12c5d1SDavid du Colombier }
7173e12c5d1SDavid du Colombier 
7183e12c5d1SDavid du Colombier long
syssegattach(ulong * arg)7193e12c5d1SDavid du Colombier syssegattach(ulong *arg)
7203e12c5d1SDavid du Colombier {
7217dd7cddfSDavid du Colombier 	return segattach(up, arg[0], (char*)arg[1], arg[2], arg[3]);
7223e12c5d1SDavid du Colombier }
7233e12c5d1SDavid du Colombier 
7243e12c5d1SDavid du Colombier long
syssegdetach(ulong * arg)7253e12c5d1SDavid du Colombier syssegdetach(ulong *arg)
7263e12c5d1SDavid du Colombier {
7273e12c5d1SDavid du Colombier 	int i;
7287dd7cddfSDavid du Colombier 	ulong addr;
7293e12c5d1SDavid du Colombier 	Segment *s;
7303e12c5d1SDavid du Colombier 
7317dd7cddfSDavid du Colombier 	qlock(&up->seglock);
7327dd7cddfSDavid du Colombier 	if(waserror()){
7337dd7cddfSDavid du Colombier 		qunlock(&up->seglock);
7347dd7cddfSDavid du Colombier 		nexterror();
7357dd7cddfSDavid du Colombier 	}
7367dd7cddfSDavid du Colombier 
7373e12c5d1SDavid du Colombier 	s = 0;
7387dd7cddfSDavid du Colombier 	addr = arg[0];
7393e12c5d1SDavid du Colombier 	for(i = 0; i < NSEG; i++)
7407dd7cddfSDavid du Colombier 		if(s = up->seg[i]) {
7413e12c5d1SDavid du Colombier 			qlock(&s->lk);
7427dd7cddfSDavid du Colombier 			if((addr >= s->base && addr < s->top) ||
7437dd7cddfSDavid du Colombier 			   (s->top == s->base && addr == s->base))
7443e12c5d1SDavid du Colombier 				goto found;
7453e12c5d1SDavid du Colombier 			qunlock(&s->lk);
7463e12c5d1SDavid du Colombier 		}
7473e12c5d1SDavid du Colombier 
7483e12c5d1SDavid du Colombier 	error(Ebadarg);
7493e12c5d1SDavid du Colombier 
7503e12c5d1SDavid du Colombier found:
7515e91980fSDavid du Colombier 	/*
7525e91980fSDavid du Colombier 	 * Check we are not detaching the initial stack segment.
7535e91980fSDavid du Colombier 	 */
7545e91980fSDavid du Colombier 	if(s == up->seg[SSEG]){
7553e12c5d1SDavid du Colombier 		qunlock(&s->lk);
7563e12c5d1SDavid du Colombier 		error(Ebadarg);
7573e12c5d1SDavid du Colombier 	}
7587dd7cddfSDavid du Colombier 	up->seg[i] = 0;
7593e12c5d1SDavid du Colombier 	qunlock(&s->lk);
7603e12c5d1SDavid du Colombier 	putseg(s);
7617dd7cddfSDavid du Colombier 	qunlock(&up->seglock);
7627dd7cddfSDavid du Colombier 	poperror();
7633e12c5d1SDavid du Colombier 
7643e12c5d1SDavid du Colombier 	/* Ensure we flush any entries from the lost segment */
7653e12c5d1SDavid du Colombier 	flushmmu();
7663e12c5d1SDavid du Colombier 	return 0;
7673e12c5d1SDavid du Colombier }
7683e12c5d1SDavid du Colombier 
7693e12c5d1SDavid du Colombier long
syssegfree(ulong * arg)7703e12c5d1SDavid du Colombier syssegfree(ulong *arg)
7713e12c5d1SDavid du Colombier {
7723e12c5d1SDavid du Colombier 	Segment *s;
7739a747e4fSDavid du Colombier 	ulong from, to;
7743e12c5d1SDavid du Colombier 
7759a747e4fSDavid du Colombier 	from = arg[0];
7767dd7cddfSDavid du Colombier 	s = seg(up, from, 1);
7779a747e4fSDavid du Colombier 	if(s == nil)
7783e12c5d1SDavid du Colombier 		error(Ebadarg);
7799a747e4fSDavid du Colombier 	to = (from + arg[1]) & ~(BY2PG-1);
7809a747e4fSDavid du Colombier 	from = PGROUND(from);
7813e12c5d1SDavid du Colombier 
7829a747e4fSDavid du Colombier 	if(to > s->top) {
7833e12c5d1SDavid du Colombier 		qunlock(&s->lk);
7843e12c5d1SDavid du Colombier 		error(Ebadarg);
7853e12c5d1SDavid du Colombier 	}
7863e12c5d1SDavid du Colombier 
7879a747e4fSDavid du Colombier 	mfreeseg(s, from, (to - from) / BY2PG);
7883e12c5d1SDavid du Colombier 	qunlock(&s->lk);
789bd389b36SDavid du Colombier 	flushmmu();
7903e12c5d1SDavid du Colombier 
7913e12c5d1SDavid du Colombier 	return 0;
7923e12c5d1SDavid du Colombier }
7933e12c5d1SDavid du Colombier 
7947dd7cddfSDavid du Colombier /* For binary compatibility */
7953e12c5d1SDavid du Colombier long
sysbrk_(ulong * arg)7963e12c5d1SDavid du Colombier sysbrk_(ulong *arg)
7973e12c5d1SDavid du Colombier {
7983e12c5d1SDavid du Colombier 	return ibrk(arg[0], BSEG);
7993e12c5d1SDavid du Colombier }
8003e12c5d1SDavid du Colombier 
8013e12c5d1SDavid du Colombier long
sysrendezvous(ulong * arg)8023e12c5d1SDavid du Colombier sysrendezvous(ulong *arg)
8033e12c5d1SDavid du Colombier {
8044de34a7eSDavid du Colombier 	uintptr tag, val;
8057dd7cddfSDavid du Colombier 	Proc *p, **l;
8063e12c5d1SDavid du Colombier 
8073e12c5d1SDavid du Colombier 	tag = arg[0];
8087dd7cddfSDavid du Colombier 	l = &REND(up->rgrp, tag);
8094de34a7eSDavid du Colombier 	up->rendval = ~(uintptr)0;
8103e12c5d1SDavid du Colombier 
8117dd7cddfSDavid du Colombier 	lock(up->rgrp);
8123e12c5d1SDavid du Colombier 	for(p = *l; p; p = p->rendhash) {
8133e12c5d1SDavid du Colombier 		if(p->rendtag == tag) {
8143e12c5d1SDavid du Colombier 			*l = p->rendhash;
8153e12c5d1SDavid du Colombier 			val = p->rendval;
8163e12c5d1SDavid du Colombier 			p->rendval = arg[1];
8177dd7cddfSDavid du Colombier 
818219b2ee8SDavid du Colombier 			while(p->mach != 0)
8193e12c5d1SDavid du Colombier 				;
8203e12c5d1SDavid du Colombier 			ready(p);
8217dd7cddfSDavid du Colombier 			unlock(up->rgrp);
8223e12c5d1SDavid du Colombier 			return val;
8233e12c5d1SDavid du Colombier 		}
8243e12c5d1SDavid du Colombier 		l = &p->rendhash;
8253e12c5d1SDavid du Colombier 	}
8263e12c5d1SDavid du Colombier 
8273e12c5d1SDavid du Colombier 	/* Going to sleep here */
8287dd7cddfSDavid du Colombier 	up->rendtag = tag;
8297dd7cddfSDavid du Colombier 	up->rendval = arg[1];
8307dd7cddfSDavid du Colombier 	up->rendhash = *l;
8317dd7cddfSDavid du Colombier 	*l = up;
8327dd7cddfSDavid du Colombier 	up->state = Rendezvous;
8337dd7cddfSDavid du Colombier 	unlock(up->rgrp);
834219b2ee8SDavid du Colombier 
8353e12c5d1SDavid du Colombier 	sched();
8363e12c5d1SDavid du Colombier 
8377dd7cddfSDavid du Colombier 	return up->rendval;
8383e12c5d1SDavid du Colombier }
8393c2ddefeSDavid du Colombier 
8403c2ddefeSDavid du Colombier /*
8413c2ddefeSDavid du Colombier  * The implementation of semaphores is complicated by needing
8423c2ddefeSDavid du Colombier  * to avoid rescheduling in syssemrelease, so that it is safe
8433c2ddefeSDavid du Colombier  * to call from real-time processes.  This means syssemrelease
8443c2ddefeSDavid du Colombier  * cannot acquire any qlocks, only spin locks.
8453c2ddefeSDavid du Colombier  *
8463c2ddefeSDavid du Colombier  * Semacquire and semrelease must both manipulate the semaphore
8473c2ddefeSDavid du Colombier  * wait list.  Lock-free linked lists only exist in theory, not
8483c2ddefeSDavid du Colombier  * in practice, so the wait list is protected by a spin lock.
8493c2ddefeSDavid du Colombier  *
8503c2ddefeSDavid du Colombier  * The semaphore value *addr is stored in user memory, so it
8513c2ddefeSDavid du Colombier  * cannot be read or written while holding spin locks.
8523c2ddefeSDavid du Colombier  *
8533c2ddefeSDavid du Colombier  * Thus, we can access the list only when holding the lock, and
8543c2ddefeSDavid du Colombier  * we can access the semaphore only when not holding the lock.
8553c2ddefeSDavid du Colombier  * This makes things interesting.  Note that sleep's condition function
8563c2ddefeSDavid du Colombier  * is called while holding two locks - r and up->rlock - so it cannot
8573c2ddefeSDavid du Colombier  * access the semaphore value either.
8583c2ddefeSDavid du Colombier  *
8593c2ddefeSDavid du Colombier  * An acquirer announces its intention to try for the semaphore
8603c2ddefeSDavid du Colombier  * by putting a Sema structure onto the wait list and then
8613c2ddefeSDavid du Colombier  * setting Sema.waiting.  After one last check of semaphore,
8623c2ddefeSDavid du Colombier  * the acquirer sleeps until Sema.waiting==0.  A releaser of n
8633c2ddefeSDavid du Colombier  * must wake up n acquirers who have Sema.waiting set.  It does
8643c2ddefeSDavid du Colombier  * this by clearing Sema.waiting and then calling wakeup.
8653c2ddefeSDavid du Colombier  *
8663c2ddefeSDavid du Colombier  * There are three interesting races here.
8673c2ddefeSDavid du Colombier 
8683c2ddefeSDavid du Colombier  * The first is that in this particular sleep/wakeup usage, a single
8693c2ddefeSDavid du Colombier  * wakeup can rouse a process from two consecutive sleeps!
8703c2ddefeSDavid du Colombier  * The ordering is:
8713c2ddefeSDavid du Colombier  *
8723c2ddefeSDavid du Colombier  * 	(a) set Sema.waiting = 1
8733c2ddefeSDavid du Colombier  * 	(a) call sleep
8743c2ddefeSDavid du Colombier  * 	(b) set Sema.waiting = 0
8753c2ddefeSDavid du Colombier  * 	(a) check Sema.waiting inside sleep, return w/o sleeping
8763c2ddefeSDavid du Colombier  * 	(a) try for semaphore, fail
8773c2ddefeSDavid du Colombier  * 	(a) set Sema.waiting = 1
8783c2ddefeSDavid du Colombier  * 	(a) call sleep
8793c2ddefeSDavid du Colombier  * 	(b) call wakeup(a)
8803c2ddefeSDavid du Colombier  * 	(a) wake up again
8813c2ddefeSDavid du Colombier  *
8823c2ddefeSDavid du Colombier  * This is okay - semacquire will just go around the loop
8833c2ddefeSDavid du Colombier  * again.  It does mean that at the top of the for(;;) loop in
8843c2ddefeSDavid du Colombier  * semacquire, phore.waiting might already be set to 1.
8853c2ddefeSDavid du Colombier  *
8863c2ddefeSDavid du Colombier  * The second is that a releaser might wake an acquirer who is
8873c2ddefeSDavid du Colombier  * interrupted before he can acquire the lock.  Since
8883c2ddefeSDavid du Colombier  * release(n) issues only n wakeup calls -- only n can be used
8893c2ddefeSDavid du Colombier  * anyway -- if the interrupted process is not going to use his
8903c2ddefeSDavid du Colombier  * wakeup call he must pass it on to another acquirer.
8913c2ddefeSDavid du Colombier  *
8923c2ddefeSDavid du Colombier  * The third race is similar to the second but more subtle.  An
8933c2ddefeSDavid du Colombier  * acquirer sets waiting=1 and then does a final canacquire()
8943c2ddefeSDavid du Colombier  * before going to sleep.  The opposite order would result in
8953c2ddefeSDavid du Colombier  * missing wakeups that happen between canacquire and
8963c2ddefeSDavid du Colombier  * waiting=1.  (In fact, the whole point of Sema.waiting is to
8973c2ddefeSDavid du Colombier  * avoid missing wakeups between canacquire() and sleep().) But
8983c2ddefeSDavid du Colombier  * there can be spurious wakeups between a successful
8993c2ddefeSDavid du Colombier  * canacquire() and the following semdequeue().  This wakeup is
9003c2ddefeSDavid du Colombier  * not useful to the acquirer, since he has already acquired
9013c2ddefeSDavid du Colombier  * the semaphore.  Like in the previous case, though, the
9023c2ddefeSDavid du Colombier  * acquirer must pass the wakeup call along.
9033c2ddefeSDavid du Colombier  *
9043c2ddefeSDavid du Colombier  * This is all rather subtle.  The code below has been verified
9053c2ddefeSDavid du Colombier  * with the spin model /sys/src/9/port/semaphore.p.  The
9063c2ddefeSDavid du Colombier  * original code anticipated the second race but not the first
9073c2ddefeSDavid du Colombier  * or third, which were caught only with spin.  The first race
9083c2ddefeSDavid du Colombier  * is mentioned in /sys/doc/sleep.ps, but I'd forgotten about it.
9093c2ddefeSDavid du Colombier  * It was lucky that my abstract model of sleep/wakeup still managed
9103c2ddefeSDavid du Colombier  * to preserve that behavior.
9113c2ddefeSDavid du Colombier  *
9123c2ddefeSDavid du Colombier  * I remain slightly concerned about memory coherence
9133c2ddefeSDavid du Colombier  * outside of locks.  The spin model does not take
9143c2ddefeSDavid du Colombier  * queued processor writes into account so we have to
9153c2ddefeSDavid du Colombier  * think hard.  The only variables accessed outside locks
9163c2ddefeSDavid du Colombier  * are the semaphore value itself and the boolean flag
9173c2ddefeSDavid du Colombier  * Sema.waiting.  The value is only accessed with cmpswap,
9183c2ddefeSDavid du Colombier  * whose job description includes doing the right thing as
9193c2ddefeSDavid du Colombier  * far as memory coherence across processors.  That leaves
9203c2ddefeSDavid du Colombier  * Sema.waiting.  To handle it, we call coherence() before each
9213c2ddefeSDavid du Colombier  * read and after each write.		- rsc
9223c2ddefeSDavid du Colombier  */
9233c2ddefeSDavid du Colombier 
9243c2ddefeSDavid du Colombier /* Add semaphore p with addr a to list in seg. */
9253c2ddefeSDavid du Colombier static void
semqueue(Segment * s,long * a,Sema * p)9263c2ddefeSDavid du Colombier semqueue(Segment *s, long *a, Sema *p)
9273c2ddefeSDavid du Colombier {
9283c2ddefeSDavid du Colombier 	memset(p, 0, sizeof *p);
9293c2ddefeSDavid du Colombier 	p->addr = a;
9303c2ddefeSDavid du Colombier 	lock(&s->sema);	/* uses s->sema.Rendez.Lock, but no one else is */
9313c2ddefeSDavid du Colombier 	p->next = &s->sema;
9323c2ddefeSDavid du Colombier 	p->prev = s->sema.prev;
9333c2ddefeSDavid du Colombier 	p->next->prev = p;
9343c2ddefeSDavid du Colombier 	p->prev->next = p;
9353c2ddefeSDavid du Colombier 	unlock(&s->sema);
9363c2ddefeSDavid du Colombier }
9373c2ddefeSDavid du Colombier 
9383c2ddefeSDavid du Colombier /* Remove semaphore p from list in seg. */
9393c2ddefeSDavid du Colombier static void
semdequeue(Segment * s,Sema * p)9403c2ddefeSDavid du Colombier semdequeue(Segment *s, Sema *p)
9413c2ddefeSDavid du Colombier {
9423c2ddefeSDavid du Colombier 	lock(&s->sema);
9433c2ddefeSDavid du Colombier 	p->next->prev = p->prev;
9443c2ddefeSDavid du Colombier 	p->prev->next = p->next;
9453c2ddefeSDavid du Colombier 	unlock(&s->sema);
9463c2ddefeSDavid du Colombier }
9473c2ddefeSDavid du Colombier 
9483c2ddefeSDavid du Colombier /* Wake up n waiters with addr a on list in seg. */
9493c2ddefeSDavid du Colombier static void
semwakeup(Segment * s,long * a,long n)9503c2ddefeSDavid du Colombier semwakeup(Segment *s, long *a, long n)
9513c2ddefeSDavid du Colombier {
9523c2ddefeSDavid du Colombier 	Sema *p;
9533c2ddefeSDavid du Colombier 
9543c2ddefeSDavid du Colombier 	lock(&s->sema);
9553c2ddefeSDavid du Colombier 	for(p=s->sema.next; p!=&s->sema && n>0; p=p->next){
9563c2ddefeSDavid du Colombier 		if(p->addr == a && p->waiting){
9573c2ddefeSDavid du Colombier 			p->waiting = 0;
9583c2ddefeSDavid du Colombier 			coherence();
9593c2ddefeSDavid du Colombier 			wakeup(p);
9603c2ddefeSDavid du Colombier 			n--;
9613c2ddefeSDavid du Colombier 		}
9623c2ddefeSDavid du Colombier 	}
9633c2ddefeSDavid du Colombier 	unlock(&s->sema);
9643c2ddefeSDavid du Colombier }
9653c2ddefeSDavid du Colombier 
9663c2ddefeSDavid du Colombier /* Add delta to semaphore and wake up waiters as appropriate. */
9673c2ddefeSDavid du Colombier static long
semrelease(Segment * s,long * addr,long delta)9683c2ddefeSDavid du Colombier semrelease(Segment *s, long *addr, long delta)
9693c2ddefeSDavid du Colombier {
9703c2ddefeSDavid du Colombier 	long value;
9713c2ddefeSDavid du Colombier 
9723c2ddefeSDavid du Colombier 	do
9733c2ddefeSDavid du Colombier 		value = *addr;
9743c2ddefeSDavid du Colombier 	while(!cmpswap(addr, value, value+delta));
9753c2ddefeSDavid du Colombier 	semwakeup(s, addr, delta);
9763c2ddefeSDavid du Colombier 	return value+delta;
9773c2ddefeSDavid du Colombier }
9783c2ddefeSDavid du Colombier 
9793c2ddefeSDavid du Colombier /* Try to acquire semaphore using compare-and-swap */
9803c2ddefeSDavid du Colombier static int
canacquire(long * addr)9813c2ddefeSDavid du Colombier canacquire(long *addr)
9823c2ddefeSDavid du Colombier {
9833c2ddefeSDavid du Colombier 	long value;
9843c2ddefeSDavid du Colombier 
9853c2ddefeSDavid du Colombier 	while((value=*addr) > 0)
9863c2ddefeSDavid du Colombier 		if(cmpswap(addr, value, value-1))
9873c2ddefeSDavid du Colombier 			return 1;
9883c2ddefeSDavid du Colombier 	return 0;
9893c2ddefeSDavid du Colombier }
9903c2ddefeSDavid du Colombier 
9913c2ddefeSDavid du Colombier /* Should we wake up? */
9923c2ddefeSDavid du Colombier static int
semawoke(void * p)9933c2ddefeSDavid du Colombier semawoke(void *p)
9943c2ddefeSDavid du Colombier {
9953c2ddefeSDavid du Colombier 	coherence();
9963c2ddefeSDavid du Colombier 	return !((Sema*)p)->waiting;
9973c2ddefeSDavid du Colombier }
9983c2ddefeSDavid du Colombier 
9993c2ddefeSDavid du Colombier /* Acquire semaphore (subtract 1). */
10003c2ddefeSDavid du Colombier static int
semacquire(Segment * s,long * addr,int block)10013c2ddefeSDavid du Colombier semacquire(Segment *s, long *addr, int block)
10023c2ddefeSDavid du Colombier {
10033c2ddefeSDavid du Colombier 	int acquired;
10043c2ddefeSDavid du Colombier 	Sema phore;
10053c2ddefeSDavid du Colombier 
10063c2ddefeSDavid du Colombier 	if(canacquire(addr))
10073c2ddefeSDavid du Colombier 		return 1;
10083c2ddefeSDavid du Colombier 	if(!block)
10093c2ddefeSDavid du Colombier 		return 0;
10103c2ddefeSDavid du Colombier 
10113c2ddefeSDavid du Colombier 	acquired = 0;
10123c2ddefeSDavid du Colombier 	semqueue(s, addr, &phore);
10133c2ddefeSDavid du Colombier 	for(;;){
10143c2ddefeSDavid du Colombier 		phore.waiting = 1;
10153c2ddefeSDavid du Colombier 		coherence();
10163c2ddefeSDavid du Colombier 		if(canacquire(addr)){
10173c2ddefeSDavid du Colombier 			acquired = 1;
10183c2ddefeSDavid du Colombier 			break;
10193c2ddefeSDavid du Colombier 		}
10203c2ddefeSDavid du Colombier 		if(waserror())
10213c2ddefeSDavid du Colombier 			break;
10223c2ddefeSDavid du Colombier 		sleep(&phore, semawoke, &phore);
10233c2ddefeSDavid du Colombier 		poperror();
10243c2ddefeSDavid du Colombier 	}
10253c2ddefeSDavid du Colombier 	semdequeue(s, &phore);
10263c2ddefeSDavid du Colombier 	coherence();	/* not strictly necessary due to lock in semdequeue */
10273c2ddefeSDavid du Colombier 	if(!phore.waiting)
10283c2ddefeSDavid du Colombier 		semwakeup(s, addr, 1);
10293c2ddefeSDavid du Colombier 	if(!acquired)
10303c2ddefeSDavid du Colombier 		nexterror();
10313c2ddefeSDavid du Colombier 	return 1;
10323c2ddefeSDavid du Colombier }
10333c2ddefeSDavid du Colombier 
103409525e75SDavid du Colombier /* Acquire semaphore or time-out */
103509525e75SDavid du Colombier static int
tsemacquire(Segment * s,long * addr,ulong ms)103609525e75SDavid du Colombier tsemacquire(Segment *s, long *addr, ulong ms)
103709525e75SDavid du Colombier {
103809525e75SDavid du Colombier 	int acquired, timedout;
10393128c8a0SDavid du Colombier 	ulong t, elms;
104009525e75SDavid du Colombier 	Sema phore;
104109525e75SDavid du Colombier 
104209525e75SDavid du Colombier 	if(canacquire(addr))
104309525e75SDavid du Colombier 		return 1;
104409525e75SDavid du Colombier 	if(ms == 0)
104509525e75SDavid du Colombier 		return 0;
104609525e75SDavid du Colombier 	acquired = timedout = 0;
104709525e75SDavid du Colombier 	semqueue(s, addr, &phore);
104809525e75SDavid du Colombier 	for(;;){
104909525e75SDavid du Colombier 		phore.waiting = 1;
105009525e75SDavid du Colombier 		coherence();
105109525e75SDavid du Colombier 		if(canacquire(addr)){
105209525e75SDavid du Colombier 			acquired = 1;
105309525e75SDavid du Colombier 			break;
105409525e75SDavid du Colombier 		}
105509525e75SDavid du Colombier 		if(waserror())
105609525e75SDavid du Colombier 			break;
105709525e75SDavid du Colombier 		t = m->ticks;
105809525e75SDavid du Colombier 		tsleep(&phore, semawoke, &phore, ms);
10593128c8a0SDavid du Colombier 		elms = TK2MS(m->ticks - t);
106009525e75SDavid du Colombier 		poperror();
10613128c8a0SDavid du Colombier 		if(elms >= ms){
10623128c8a0SDavid du Colombier 			timedout = 1;
106309525e75SDavid du Colombier 			break;
106409525e75SDavid du Colombier 		}
10653128c8a0SDavid du Colombier 		ms -= elms;
106609525e75SDavid du Colombier 	}
106709525e75SDavid du Colombier 	semdequeue(s, &phore);
106809525e75SDavid du Colombier 	coherence();	/* not strictly necessary due to lock in semdequeue */
106909525e75SDavid du Colombier 	if(!phore.waiting)
107009525e75SDavid du Colombier 		semwakeup(s, addr, 1);
107109525e75SDavid du Colombier 	if(timedout)
107209525e75SDavid du Colombier 		return 0;
107309525e75SDavid du Colombier 	if(!acquired)
107409525e75SDavid du Colombier 		nexterror();
107509525e75SDavid du Colombier 	return 1;
107609525e75SDavid du Colombier }
107709525e75SDavid du Colombier 
10783c2ddefeSDavid du Colombier long
syssemacquire(ulong * arg)10793c2ddefeSDavid du Colombier syssemacquire(ulong *arg)
10803c2ddefeSDavid du Colombier {
10813c2ddefeSDavid du Colombier 	int block;
10823c2ddefeSDavid du Colombier 	long *addr;
10833c2ddefeSDavid du Colombier 	Segment *s;
10843c2ddefeSDavid du Colombier 
10853c2ddefeSDavid du Colombier 	validaddr(arg[0], sizeof(long), 1);
1086*fac6300fSDavid du Colombier 	validalign(arg[0], sizeof(long));
10873c2ddefeSDavid du Colombier 	addr = (long*)arg[0];
10883c2ddefeSDavid du Colombier 	block = arg[1];
10893c2ddefeSDavid du Colombier 
10903c2ddefeSDavid du Colombier 	if((s = seg(up, (ulong)addr, 0)) == nil)
10913c2ddefeSDavid du Colombier 		error(Ebadarg);
10923c2ddefeSDavid du Colombier 	if(*addr < 0)
10933c2ddefeSDavid du Colombier 		error(Ebadarg);
10943c2ddefeSDavid du Colombier 	return semacquire(s, addr, block);
10953c2ddefeSDavid du Colombier }
10963c2ddefeSDavid du Colombier 
10973c2ddefeSDavid du Colombier long
systsemacquire(ulong * arg)109809525e75SDavid du Colombier systsemacquire(ulong *arg)
109909525e75SDavid du Colombier {
110009525e75SDavid du Colombier 	long *addr;
110109525e75SDavid du Colombier 	ulong ms;
110209525e75SDavid du Colombier 	Segment *s;
110309525e75SDavid du Colombier 
110409525e75SDavid du Colombier 	validaddr(arg[0], sizeof(long), 1);
1105*fac6300fSDavid du Colombier 	validalign(arg[0], sizeof(long));
110609525e75SDavid du Colombier 	addr = (long*)arg[0];
110709525e75SDavid du Colombier 	ms = arg[1];
110809525e75SDavid du Colombier 
110909525e75SDavid du Colombier 	if((s = seg(up, (ulong)addr, 0)) == nil)
111009525e75SDavid du Colombier 		error(Ebadarg);
111109525e75SDavid du Colombier 	if(*addr < 0)
111209525e75SDavid du Colombier 		error(Ebadarg);
111309525e75SDavid du Colombier 	return tsemacquire(s, addr, ms);
111409525e75SDavid du Colombier }
111509525e75SDavid du Colombier 
111609525e75SDavid du Colombier long
syssemrelease(ulong * arg)11173c2ddefeSDavid du Colombier syssemrelease(ulong *arg)
11183c2ddefeSDavid du Colombier {
11193c2ddefeSDavid du Colombier 	long *addr, delta;
11203c2ddefeSDavid du Colombier 	Segment *s;
11213c2ddefeSDavid du Colombier 
11223c2ddefeSDavid du Colombier 	validaddr(arg[0], sizeof(long), 1);
1123*fac6300fSDavid du Colombier 	validalign(arg[0], sizeof(long));
11243c2ddefeSDavid du Colombier 	addr = (long*)arg[0];
11253c2ddefeSDavid du Colombier 	delta = arg[1];
11263c2ddefeSDavid du Colombier 
11273c2ddefeSDavid du Colombier 	if((s = seg(up, (ulong)addr, 0)) == nil)
11283c2ddefeSDavid du Colombier 		error(Ebadarg);
11293128c8a0SDavid du Colombier 	/* delta == 0 is a no-op, not a release */
11303c2ddefeSDavid du Colombier 	if(delta < 0 || *addr < 0)
11313c2ddefeSDavid du Colombier 		error(Ebadarg);
11323128c8a0SDavid du Colombier 	return semrelease(s, addr, delta);
11333c2ddefeSDavid du Colombier }
1134*fac6300fSDavid du Colombier 
1135*fac6300fSDavid du Colombier long
sysnsec(ulong * arg)1136*fac6300fSDavid du Colombier sysnsec(ulong *arg)
1137*fac6300fSDavid du Colombier {
1138*fac6300fSDavid du Colombier 	validaddr(arg[0], sizeof(vlong), 1);
1139*fac6300fSDavid du Colombier 	validalign(arg[0], sizeof(vlong));
1140*fac6300fSDavid du Colombier 
1141*fac6300fSDavid du Colombier 	*(vlong*)arg[0] = todget(nil);
1142*fac6300fSDavid du Colombier 
1143*fac6300fSDavid du Colombier 	return 0;
1144*fac6300fSDavid du Colombier }
1145