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(¬eidalloc);
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