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