]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/sysproc.c
merge
[plan9front.git] / sys / src / 9 / port / sysproc.c
1 #include        "u.h"
2 #include        "tos.h"
3 #include        "../port/lib.h"
4 #include        "mem.h"
5 #include        "dat.h"
6 #include        "fns.h"
7 #include        "../port/error.h"
8 #include        "edf.h"
9
10 #include        <a.out.h>
11
12 int     shargs(char*, int, char**);
13
14 extern void checkpages(void);
15 extern void checkpagerefs(void);
16
17 long
18 sysr1(ulong*)
19 {
20         checkpagerefs();
21         return 0;
22 }
23
24 long
25 sysrfork(ulong *arg)
26 {
27         Proc *p;
28         int n, i;
29         Fgrp *ofg;
30         Pgrp *opg;
31         Rgrp *org;
32         Egrp *oeg;
33         ulong pid, flag;
34         Mach *wm;
35
36         flag = arg[0];
37         /* Check flags before we commit */
38         if((flag & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG))
39                 error(Ebadarg);
40         if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG))
41                 error(Ebadarg);
42         if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG))
43                 error(Ebadarg);
44
45         if((flag&RFPROC) == 0) {
46                 if(flag & (RFMEM|RFNOWAIT))
47                         error(Ebadarg);
48                 if(flag & (RFFDG|RFCFDG)) {
49                         ofg = up->fgrp;
50                         if(flag & RFFDG)
51                                 up->fgrp = dupfgrp(ofg);
52                         else
53                                 up->fgrp = dupfgrp(nil);
54                         closefgrp(ofg);
55                 }
56                 if(flag & (RFNAMEG|RFCNAMEG)) {
57                         opg = up->pgrp;
58                         up->pgrp = newpgrp();
59                         if(flag & RFNAMEG)
60                                 pgrpcpy(up->pgrp, opg);
61                         /* inherit noattach */
62                         up->pgrp->noattach = opg->noattach;
63                         closepgrp(opg);
64                 }
65                 if(flag & RFNOMNT)
66                         up->pgrp->noattach = 1;
67                 if(flag & RFREND) {
68                         org = up->rgrp;
69                         up->rgrp = newrgrp();
70                         closergrp(org);
71                 }
72                 if(flag & (RFENVG|RFCENVG)) {
73                         oeg = up->egrp;
74                         up->egrp = smalloc(sizeof(Egrp));
75                         up->egrp->ref = 1;
76                         if(flag & RFENVG)
77                                 envcpy(up->egrp, oeg);
78                         closeegrp(oeg);
79                 }
80                 if(flag & RFNOTEG)
81                         up->noteid = pidalloc(0);
82                 return 0;
83         }
84
85         p = newproc();
86
87         p->scallnr = up->scallnr;
88         p->s = up->s;
89         p->nerrlab = 0;
90         p->slash = up->slash;
91         p->dot = up->dot;
92         incref(p->dot);
93
94         memmove(p->note, up->note, sizeof(p->note));
95         p->privatemem = up->privatemem;
96         p->noswap = up->noswap;
97         p->nnote = up->nnote;
98         p->notified = 0;
99         p->lastnote = up->lastnote;
100         p->notify = up->notify;
101         p->ureg = up->ureg;
102         p->dbgreg = 0;
103
104         /* Make a new set of memory segments */
105         n = flag & RFMEM;
106         qlock(&p->seglock);
107         if(waserror()){
108                 qunlock(&p->seglock);
109                 nexterror();
110         }
111         for(i = 0; i < NSEG; i++)
112                 if(up->seg[i])
113                         p->seg[i] = dupseg(up->seg, i, n);
114         qunlock(&p->seglock);
115         poperror();
116
117         /* File descriptors */
118         if(flag & (RFFDG|RFCFDG)) {
119                 if(flag & RFFDG)
120                         p->fgrp = dupfgrp(up->fgrp);
121                 else
122                         p->fgrp = dupfgrp(nil);
123         }
124         else {
125                 p->fgrp = up->fgrp;
126                 incref(p->fgrp);
127         }
128
129         /* Process groups */
130         if(flag & (RFNAMEG|RFCNAMEG)) {
131                 p->pgrp = newpgrp();
132                 if(flag & RFNAMEG)
133                         pgrpcpy(p->pgrp, up->pgrp);
134                 /* inherit noattach */
135                 p->pgrp->noattach = up->pgrp->noattach;
136         }
137         else {
138                 p->pgrp = up->pgrp;
139                 incref(p->pgrp);
140         }
141         if(flag & RFNOMNT)
142                 p->pgrp->noattach = 1;
143
144         if(flag & RFREND)
145                 p->rgrp = newrgrp();
146         else {
147                 incref(up->rgrp);
148                 p->rgrp = up->rgrp;
149         }
150
151         /* Environment group */
152         if(flag & (RFENVG|RFCENVG)) {
153                 p->egrp = smalloc(sizeof(Egrp));
154                 p->egrp->ref = 1;
155                 if(flag & RFENVG)
156                         envcpy(p->egrp, up->egrp);
157         }
158         else {
159                 p->egrp = up->egrp;
160                 incref(p->egrp);
161         }
162         p->hang = up->hang;
163         p->procmode = up->procmode;
164         if(up->procctl == Proc_tracesyscall)
165                 p->procctl = Proc_tracesyscall;
166
167         /* Craft a return frame which will cause the child to pop out of
168          * the scheduler in user mode with the return register zero
169          */
170         forkchild(p, up->dbgreg);
171
172         p->parent = up;
173         if((flag&RFNOWAIT) == 0){
174                 p->parentpid = up->pid;
175                 lock(&up->exl);
176                 up->nchild++;
177                 unlock(&up->exl);
178         }
179         if((flag&RFNOTEG) == 0)
180                 p->noteid = up->noteid;
181
182         pid = p->pid;
183         memset(p->time, 0, sizeof(p->time));
184         p->time[TReal] = MACHP(0)->ticks;
185
186         kstrdup(&p->text, up->text);
187         kstrdup(&p->user, up->user);
188
189         procfork(p);
190
191         /*
192          *  since the bss/data segments are now shareable,
193          *  any mmu info about this process is now stale
194          *  (i.e. has bad properties) and has to be discarded.
195          */
196         flushmmu();
197         p->basepri = up->basepri;
198         p->priority = up->basepri;
199         p->fixedpri = up->fixedpri;
200         p->mp = up->mp;
201         wm = up->wired;
202         if(wm)
203                 procwired(p, wm->machno);
204         ready(p);
205         sched();
206         return pid;
207 }
208
209 static ulong
210 l2be(long l)
211 {
212         uchar *cp;
213
214         cp = (uchar*)&l;
215         return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3];
216 }
217
218 long
219 sysexec(ulong *arg)
220 {
221         Segment *s, *ts;
222         ulong t, d, b;
223         int i;
224         Chan *tc;
225         char **argv, **argp;
226         char *a, *charp, *args, *file, *file0;
227         char *progarg[sizeof(Exec)/2+1], *elem, progelem[64];
228         ulong ssize, tstk, nargs, nbytes, n, bssend;
229         int indir;
230         Exec exec;
231         char line[sizeof(Exec)];
232         Fgrp *f;
233         Image *img;
234         ulong magic, text, entry, data, bss;
235         Tos *tos;
236
237         indir = 0;
238         elem = nil;
239         validaddr(arg[0], 1, 0);
240         file0 = validnamedup((char*)arg[0], 1);
241         if(waserror()){
242                 free(file0);
243                 if(elem != up->text)
244                         free(elem);
245                 /* Disaster after commit */
246                 if(!up->seg[SSEG])
247                         pexit(up->errstr, 1);
248                 nexterror();
249         }
250         file = file0;
251         for(;;){
252                 tc = namec(file, Aopen, OEXEC, 0);
253                 if(waserror()){
254                         cclose(tc);
255                         nexterror();
256                 }
257                 if(!indir)
258                         kstrdup(&elem, up->genbuf);
259
260                 n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0);
261                 if(n < 2)
262                         error(Ebadexec);
263                 magic = l2be(exec.magic);
264                 text = l2be(exec.text);
265                 entry = l2be(exec.entry);
266                 if(n==sizeof(Exec) && (magic == AOUT_MAGIC)){
267                         if(text >= USTKTOP-UTZERO
268                         || entry < UTZERO+sizeof(Exec)
269                         || entry >= UTZERO+sizeof(Exec)+text)
270                                 error(Ebadexec);
271                         break; /* for binary */
272                 }
273
274                 /*
275                  * Process #! /bin/sh args ...
276                  */
277                 memmove(line, &exec, sizeof(Exec));
278                 if(indir || line[0]!='#' || line[1]!='!')
279                         error(Ebadexec);
280                 n = shargs(line, n, progarg);
281                 if(n == 0)
282                         error(Ebadexec);
283                 indir = 1;
284                 /*
285                  * First arg becomes complete file name
286                  */
287                 progarg[n++] = file;
288                 progarg[n] = 0;
289                 validaddr(arg[1], BY2WD, 1);
290                 arg[1] += BY2WD;
291                 file = progarg[0];
292                 if(strlen(elem) >= sizeof progelem)
293                         error(Ebadexec);
294                 strcpy(progelem, elem);
295                 progarg[0] = progelem;
296                 poperror();
297                 cclose(tc);
298         }
299
300         data = l2be(exec.data);
301         bss = l2be(exec.bss);
302         t = (UTZERO+sizeof(Exec)+text+(BY2PG-1)) & ~(BY2PG-1);
303         d = (t + data + (BY2PG-1)) & ~(BY2PG-1);
304         bssend = t + data + bss;
305         b = (bssend + (BY2PG-1)) & ~(BY2PG-1);
306         if(t >= KZERO || d >= KZERO || b >= KZERO)
307                 error(Ebadexec);
308
309         /*
310          * Args: pass 1: count
311          */
312         nbytes = sizeof(Tos);           /* hole for profiling clock at top of stack (and more) */
313         nargs = 0;
314         if(indir){
315                 argp = progarg;
316                 while(*argp){
317                         a = *argp++;
318                         nbytes += strlen(a) + 1;
319                         nargs++;
320                 }
321         }
322         evenaddr(arg[1]);
323         argp = (char**)arg[1];
324         validaddr((ulong)argp, BY2WD, 0);
325         while(*argp){
326                 a = *argp++;
327                 if(((ulong)argp&(BY2PG-1)) < BY2WD)
328                         validaddr((ulong)argp, BY2WD, 0);
329                 validaddr((ulong)a, 1, 0);
330                 nbytes += ((char*)vmemchr(a, 0, 0x7FFFFFFF) - a) + 1;
331                 nargs++;
332         }
333         ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1));
334
335         /*
336          * 8-byte align SP for those (e.g. sparc) that need it.
337          * execregs() will subtract another 4 bytes for argc.
338          */
339         if((ssize+4) & 7)
340                 ssize += 4;
341
342         if(PGROUND(ssize) >= USTKSIZE)
343                 error(Enovmem);
344
345         /*
346          * Build the stack segment, putting it in kernel virtual for the moment
347          */
348         qlock(&up->seglock);
349         if(waserror()){
350                 qunlock(&up->seglock);
351                 nexterror();
352         }
353
354         s = up->seg[SSEG];
355         do {
356                 tstk = s->base;
357                 if(tstk <= USTKSIZE)
358                         error(Enovmem);
359         } while((s = isoverlap(up, tstk-USTKSIZE, USTKSIZE)) != nil);
360         up->seg[ESEG] = newseg(SG_STACK, tstk-USTKSIZE, USTKSIZE/BY2PG);
361
362         /*
363          * Args: pass 2: assemble; the pages will be faulted in
364          */
365         tos = (Tos*)(tstk - sizeof(Tos));
366         tos->cyclefreq = m->cyclefreq;
367         tos->kcycles = 0;
368         tos->pcycles = 0;
369         tos->clock = 0;
370
371         argv = (char**)(tstk - ssize);
372         charp = (char*)(tstk - nbytes);
373         args = charp;
374         if(indir)
375                 argp = progarg;
376         else
377                 argp = (char**)arg[1];
378
379         for(i=0; i<nargs; i++){
380                 if(indir && *argp==0) {
381                         indir = 0;
382                         argp = (char**)arg[1];
383                 }
384                 *argv++ = charp + (USTKTOP-tstk);
385                 n = strlen(*argp) + 1;
386                 memmove(charp, *argp++, n);
387                 charp += n;
388         }
389
390         free(up->text);
391         up->text = elem;
392
393         /* copy args; easiest from new process's stack */
394         n = charp - args;
395         if(n > 128)     /* don't waste too much space on huge arg lists */
396                 n = 128;
397         a = up->args;
398         up->args = nil;
399         free(a);
400         up->args = smalloc(n);
401         memmove(up->args, args, n);
402         if(n>0 && up->args[n-1]!='\0'){
403                 /* make sure last arg is NUL-terminated */
404                 /* put NUL at UTF-8 character boundary */
405                 for(i=n-1; i>0; --i)
406                         if(fullrune(up->args+i, n-i))
407                                 break;
408                 up->args[i] = 0;
409                 n = i+1;
410         }
411         up->nargs = n;
412
413         /*
414          * Committed.
415          * Free old memory.
416          * Special segments are maintained across exec
417          */
418         for(i = SSEG; i <= BSEG; i++) {
419                 putseg(up->seg[i]);
420                 /* prevent a second free if we have an error */
421                 up->seg[i] = 0;
422         }
423         for(i = ESEG+1; i < NSEG; i++) {
424                 s = up->seg[i];
425                 if(s != 0 && (s->type&SG_CEXEC) != 0) {
426                         putseg(s);
427                         up->seg[i] = 0;
428                 }
429         }
430
431         /*
432          * Close on exec
433          */
434         if((f = up->fgrp) != nil){
435                 for(i=0; i<=f->maxfd; i++)
436                         fdclose(i, CCEXEC);
437         }
438
439         /* Text.  Shared. Attaches to cache image if possible */
440         /* attachimage returns a locked cache image */
441         img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (t-UTZERO)>>PGSHIFT);
442         ts = img->s;
443         up->seg[TSEG] = ts;
444         ts->flushme = 1;
445         ts->fstart = 0;
446         ts->flen = sizeof(Exec)+text;
447         unlock(img);
448
449         /* Data. Shared. */
450         s = newseg(SG_DATA, t, (d-t)>>PGSHIFT);
451         up->seg[DSEG] = s;
452
453         /* Attached by hand */
454         incref(img);
455         s->image = img;
456         s->fstart = ts->fstart+ts->flen;
457         s->flen = data;
458
459         /* BSS. Zero fill on demand */
460         up->seg[BSEG] = newseg(SG_BSS, d, (b-d)>>PGSHIFT);
461
462         /*
463          * Move the stack
464          */
465         s = up->seg[ESEG];
466         up->seg[ESEG] = 0;
467         s->base = USTKTOP-USTKSIZE;
468         s->top = USTKTOP;
469         relocateseg(s, USTKTOP-tstk);
470         up->seg[SSEG] = s;
471         qunlock(&up->seglock);
472         poperror();     /* seglock */
473
474         /*
475          *  '/' processes are higher priority (hack to make /ip more responsive).
476          */
477         if(devtab[tc->type]->dc == L'/')
478                 up->basepri = PriRoot;
479         up->priority = up->basepri;
480         poperror();     /* tc */
481         cclose(tc);
482         poperror();     /* file0 */
483         free(file0);
484
485         qlock(&up->debug);
486         up->nnote = 0;
487         up->notify = 0;
488         up->notified = 0;
489         up->privatemem = 0;
490         procsetup(up);
491         qunlock(&up->debug);
492
493         /*
494          *  At this point, the mmu contains info about the old address
495          *  space and needs to be flushed
496          */
497         flushmmu();
498
499         if(up->hang)
500                 up->procctl = Proc_stopme;
501         return execregs(entry, ssize, nargs);
502 }
503
504 int
505 shargs(char *s, int n, char **ap)
506 {
507         int i;
508
509         s += 2;
510         n -= 2;         /* skip #! */
511         for(i=0; s[i]!='\n'; i++)
512                 if(i == n-1)
513                         return 0;
514         s[i] = 0;
515         *ap = 0;
516         i = 0;
517         for(;;) {
518                 while(*s==' ' || *s=='\t')
519                         s++;
520                 if(*s == 0)
521                         break;
522                 i++;
523                 *ap++ = s;
524                 *ap = 0;
525                 while(*s && *s!=' ' && *s!='\t')
526                         s++;
527                 if(*s == 0)
528                         break;
529                 else
530                         *s++ = 0;
531         }
532         return i;
533 }
534
535 int
536 return0(void*)
537 {
538         return 0;
539 }
540
541 long
542 syssleep(ulong *arg)
543 {
544
545         int n;
546
547         n = arg[0];
548         if(n <= 0) {
549                 if (up->edf && (up->edf->flags & Admitted))
550                         edfyield();
551                 else
552                         yield();
553                 return 0;
554         }
555         if(n < TK2MS(1))
556                 n = TK2MS(1);
557         tsleep(&up->sleep, return0, 0, n);
558         return 0;
559 }
560
561 long
562 sysalarm(ulong *arg)
563 {
564         return procalarm(arg[0]);
565 }
566
567 long
568 sysexits(ulong *arg)
569 {
570         char *status;
571         char *inval = "invalid exit string";
572         char buf[ERRMAX];
573
574         status = (char*)arg[0];
575         if(status){
576                 if(waserror())
577                         status = inval;
578                 else{
579                         validaddr((ulong)status, 1, 0);
580                         if(vmemchr(status, 0, ERRMAX) == 0){
581                                 memmove(buf, status, ERRMAX);
582                                 buf[ERRMAX-1] = 0;
583                                 status = buf;
584                         }
585                         poperror();
586                 }
587
588         }
589         pexit(status, 1);
590         return 0;               /* not reached */
591 }
592
593 long
594 sys_wait(ulong *arg)
595 {
596         int pid;
597         Waitmsg w;
598         OWaitmsg *ow;
599
600         if(arg[0] == 0)
601                 return pwait(nil);
602
603         validaddr(arg[0], sizeof(OWaitmsg), 1);
604         evenaddr(arg[0]);
605         pid = pwait(&w);
606         if(pid >= 0){
607                 ow = (OWaitmsg*)arg[0];
608                 readnum(0, ow->pid, NUMSIZE, w.pid, NUMSIZE);
609                 readnum(0, ow->time+TUser*NUMSIZE, NUMSIZE, w.time[TUser], NUMSIZE);
610                 readnum(0, ow->time+TSys*NUMSIZE, NUMSIZE, w.time[TSys], NUMSIZE);
611                 readnum(0, ow->time+TReal*NUMSIZE, NUMSIZE, w.time[TReal], NUMSIZE);
612                 strncpy(ow->msg, w.msg, sizeof(ow->msg)-1);
613                 ow->msg[sizeof(ow->msg)-1] = '\0';
614         }
615         return pid;
616 }
617
618 long
619 sysawait(ulong *arg)
620 {
621         int i;
622         int pid;
623         Waitmsg w;
624         ulong n;
625
626         n = arg[1];
627         validaddr(arg[0], n, 1);
628         pid = pwait(&w);
629         if(pid < 0)
630                 return -1;
631         i = snprint((char*)arg[0], n, "%d %lud %lud %lud %q",
632                 w.pid,
633                 w.time[TUser], w.time[TSys], w.time[TReal],
634                 w.msg);
635
636         return i;
637 }
638
639 void
640 werrstr(char *fmt, ...)
641 {
642         va_list va;
643
644         if(up == nil)
645                 return;
646
647         va_start(va, fmt);
648         vseprint(up->syserrstr, up->syserrstr+ERRMAX, fmt, va);
649         va_end(va);
650 }
651
652 static long
653 generrstr(char *buf, uint nbuf)
654 {
655         char tmp[ERRMAX];
656
657         if(nbuf == 0)
658                 error(Ebadarg);
659         validaddr((ulong)buf, nbuf, 1);
660         if(nbuf > sizeof tmp)
661                 nbuf = sizeof tmp;
662         memmove(tmp, buf, nbuf);
663
664         /* make sure it's NUL-terminated */
665         tmp[nbuf-1] = '\0';
666         memmove(buf, up->syserrstr, nbuf);
667         buf[nbuf-1] = '\0';
668         memmove(up->syserrstr, tmp, nbuf);
669         return 0;
670 }
671
672 long
673 syserrstr(ulong *arg)
674 {
675         return generrstr((char*)arg[0], arg[1]);
676 }
677
678 /* compatibility for old binaries */
679 long
680 sys_errstr(ulong *arg)
681 {
682         return generrstr((char*)arg[0], 64);
683 }
684
685 long
686 sysnotify(ulong *arg)
687 {
688         if(arg[0] != 0)
689                 validaddr(arg[0], sizeof(ulong), 0);
690         up->notify = (int(*)(void*, char*))(arg[0]);
691         return 0;
692 }
693
694 long
695 sysnoted(ulong *arg)
696 {
697         if(arg[0]!=NRSTR && !up->notified)
698                 error(Egreg);
699         return 0;
700 }
701
702 long
703 syssegbrk(ulong *arg)
704 {
705         int i;
706         ulong addr;
707         Segment *s;
708
709         addr = arg[0];
710         for(i = 0; i < NSEG; i++) {
711                 s = up->seg[i];
712                 if(s == 0 || addr < s->base || addr >= s->top)
713                         continue;
714                 switch(s->type&SG_TYPE) {
715                 case SG_TEXT:
716                 case SG_DATA:
717                 case SG_STACK:
718                         error(Ebadarg);
719                 default:
720                         return ibrk(arg[1], i);
721                 }
722         }
723
724         error(Ebadarg);
725         return 0;               /* not reached */
726 }
727
728 long
729 syssegattach(ulong *arg)
730 {
731         return segattach(up, arg[0], (char*)arg[1], arg[2], arg[3]);
732 }
733
734 long
735 syssegdetach(ulong *arg)
736 {
737         int i;
738         ulong addr;
739         Segment *s;
740
741         qlock(&up->seglock);
742         if(waserror()){
743                 qunlock(&up->seglock);
744                 nexterror();
745         }
746
747         s = 0;
748         addr = arg[0];
749         for(i = 0; i < NSEG; i++)
750                 if(s = up->seg[i]) {
751                         qlock(&s->lk);
752                         if((addr >= s->base && addr < s->top) ||
753                            (s->top == s->base && addr == s->base))
754                                 goto found;
755                         qunlock(&s->lk);
756                 }
757
758         error(Ebadarg);
759
760 found:
761         /*
762          * Check we are not detaching the initial stack segment.
763          */
764         if(s == up->seg[SSEG]){
765                 qunlock(&s->lk);
766                 error(Ebadarg);
767         }
768         up->seg[i] = 0;
769         qunlock(&s->lk);
770         putseg(s);
771         qunlock(&up->seglock);
772         poperror();
773
774         /* Ensure we flush any entries from the lost segment */
775         flushmmu();
776         return 0;
777 }
778
779 long
780 syssegfree(ulong *arg)
781 {
782         Segment *s;
783         ulong from, to;
784
785         from = arg[0];
786         s = seg(up, from, 1);
787         if(s == nil)
788                 error(Ebadarg);
789         to = (from + arg[1]) & ~(BY2PG-1);
790         from = PGROUND(from);
791
792         if(to > s->top) {
793                 qunlock(&s->lk);
794                 error(Ebadarg);
795         }
796
797         mfreeseg(s, from, (to - from) / BY2PG);
798         qunlock(&s->lk);
799         flushmmu();
800
801         return 0;
802 }
803
804 /* For binary compatibility */
805 long
806 sysbrk_(ulong *arg)
807 {
808         return ibrk(arg[0], BSEG);
809 }
810
811 long
812 sysrendezvous(ulong *arg)
813 {
814         uintptr tag, val;
815         Proc *p, **l;
816
817         tag = arg[0];
818         l = &REND(up->rgrp, tag);
819
820         lock(up->rgrp);
821         for(p = *l; p; p = p->rendhash) {
822                 if(p->rendtag == tag) {
823                         *l = p->rendhash;
824                         val = p->rendval;
825                         p->rendval = arg[1];
826                         unlock(up->rgrp);
827
828                         ready(p);
829
830                         return val;
831                 }
832                 l = &p->rendhash;
833         }
834
835         /* Going to sleep here */
836         up->rendtag = tag;
837         up->rendval = arg[1];
838         up->rendhash = *l;
839         *l = up;
840         up->state = Rendezvous;
841         unlock(up->rgrp);
842
843         sched();
844
845         return up->rendval;
846 }
847
848 /*
849  * The implementation of semaphores is complicated by needing
850  * to avoid rescheduling in syssemrelease, so that it is safe
851  * to call from real-time processes.  This means syssemrelease
852  * cannot acquire any qlocks, only spin locks.
853  * 
854  * Semacquire and semrelease must both manipulate the semaphore
855  * wait list.  Lock-free linked lists only exist in theory, not
856  * in practice, so the wait list is protected by a spin lock.
857  * 
858  * The semaphore value *addr is stored in user memory, so it
859  * cannot be read or written while holding spin locks.
860  * 
861  * Thus, we can access the list only when holding the lock, and
862  * we can access the semaphore only when not holding the lock.
863  * This makes things interesting.  Note that sleep's condition function
864  * is called while holding two locks - r and up->rlock - so it cannot
865  * access the semaphore value either.
866  * 
867  * An acquirer announces its intention to try for the semaphore
868  * by putting a Sema structure onto the wait list and then
869  * setting Sema.waiting.  After one last check of semaphore,
870  * the acquirer sleeps until Sema.waiting==0.  A releaser of n
871  * must wake up n acquirers who have Sema.waiting set.  It does
872  * this by clearing Sema.waiting and then calling wakeup.
873  * 
874  * There are three interesting races here.  
875  
876  * The first is that in this particular sleep/wakeup usage, a single
877  * wakeup can rouse a process from two consecutive sleeps!  
878  * The ordering is:
879  * 
880  *      (a) set Sema.waiting = 1
881  *      (a) call sleep
882  *      (b) set Sema.waiting = 0
883  *      (a) check Sema.waiting inside sleep, return w/o sleeping
884  *      (a) try for semaphore, fail
885  *      (a) set Sema.waiting = 1
886  *      (a) call sleep
887  *      (b) call wakeup(a)
888  *      (a) wake up again
889  * 
890  * This is okay - semacquire will just go around the loop
891  * again.  It does mean that at the top of the for(;;) loop in
892  * semacquire, phore.waiting might already be set to 1.
893  * 
894  * The second is that a releaser might wake an acquirer who is
895  * interrupted before he can acquire the lock.  Since
896  * release(n) issues only n wakeup calls -- only n can be used
897  * anyway -- if the interrupted process is not going to use his
898  * wakeup call he must pass it on to another acquirer.
899  * 
900  * The third race is similar to the second but more subtle.  An
901  * acquirer sets waiting=1 and then does a final canacquire()
902  * before going to sleep.  The opposite order would result in
903  * missing wakeups that happen between canacquire and
904  * waiting=1.  (In fact, the whole point of Sema.waiting is to
905  * avoid missing wakeups between canacquire() and sleep().) But
906  * there can be spurious wakeups between a successful
907  * canacquire() and the following semdequeue().  This wakeup is
908  * not useful to the acquirer, since he has already acquired
909  * the semaphore.  Like in the previous case, though, the
910  * acquirer must pass the wakeup call along.
911  * 
912  * This is all rather subtle.  The code below has been verified
913  * with the spin model /sys/src/9/port/semaphore.p.  The
914  * original code anticipated the second race but not the first
915  * or third, which were caught only with spin.  The first race
916  * is mentioned in /sys/doc/sleep.ps, but I'd forgotten about it.
917  * It was lucky that my abstract model of sleep/wakeup still managed
918  * to preserve that behavior.
919  *
920  * I remain slightly concerned about memory coherence
921  * outside of locks.  The spin model does not take 
922  * queued processor writes into account so we have to
923  * think hard.  The only variables accessed outside locks
924  * are the semaphore value itself and the boolean flag
925  * Sema.waiting.  The value is only accessed with cmpswap,
926  * whose job description includes doing the right thing as
927  * far as memory coherence across processors.  That leaves
928  * Sema.waiting.  To handle it, we call coherence() before each
929  * read and after each write.           - rsc
930  */
931
932 /* Add semaphore p with addr a to list in seg. */
933 static void
934 semqueue(Segment *s, long *a, Sema *p)
935 {
936         memset(p, 0, sizeof *p);
937         p->addr = a;
938         lock(&s->sema); /* uses s->sema.Rendez.Lock, but no one else is */
939         p->next = &s->sema;
940         p->prev = s->sema.prev;
941         p->next->prev = p;
942         p->prev->next = p;
943         unlock(&s->sema);
944 }
945
946 /* Remove semaphore p from list in seg. */
947 static void
948 semdequeue(Segment *s, Sema *p)
949 {
950         lock(&s->sema);
951         p->next->prev = p->prev;
952         p->prev->next = p->next;
953         unlock(&s->sema);
954 }
955
956 /* Wake up n waiters with addr a on list in seg. */
957 static void
958 semwakeup(Segment *s, long *a, long n)
959 {
960         Sema *p;
961         
962         lock(&s->sema);
963         for(p=s->sema.next; p!=&s->sema && n>0; p=p->next){
964                 if(p->addr == a && p->waiting){
965                         p->waiting = 0;
966                         coherence();
967                         wakeup(p);
968                         n--;
969                 }
970         }
971         unlock(&s->sema);
972 }
973
974 /* Add delta to semaphore and wake up waiters as appropriate. */
975 static long
976 semrelease(Segment *s, long *addr, long delta)
977 {
978         long value;
979
980         do
981                 value = *addr;
982         while(!cmpswap(addr, value, value+delta));
983         semwakeup(s, addr, delta);
984         return value+delta;
985 }
986
987 /* Try to acquire semaphore using compare-and-swap */
988 static int
989 canacquire(long *addr)
990 {
991         long value;
992         
993         while((value=*addr) > 0)
994                 if(cmpswap(addr, value, value-1))
995                         return 1;
996         return 0;
997 }               
998
999 /* Should we wake up? */
1000 static int
1001 semawoke(void *p)
1002 {
1003         coherence();
1004         return !((Sema*)p)->waiting;
1005 }
1006
1007 /* Acquire semaphore (subtract 1). */
1008 static int
1009 semacquire(Segment *s, long *addr, int block)
1010 {
1011         int acquired;
1012         Sema phore;
1013
1014         if(canacquire(addr))
1015                 return 1;
1016         if(!block)
1017                 return 0;
1018
1019         acquired = 0;
1020         semqueue(s, addr, &phore);
1021         for(;;){
1022                 phore.waiting = 1;
1023                 coherence();
1024                 if(canacquire(addr)){
1025                         acquired = 1;
1026                         break;
1027                 }
1028                 if(waserror())
1029                         break;
1030                 sleep(&phore, semawoke, &phore);
1031                 poperror();
1032         }
1033         semdequeue(s, &phore);
1034         coherence();    /* not strictly necessary due to lock in semdequeue */
1035         if(!phore.waiting)
1036                 semwakeup(s, addr, 1);
1037         if(!acquired)
1038                 nexterror();
1039         return 1;
1040 }
1041
1042 /* Acquire semaphore or time-out */
1043 static int
1044 tsemacquire(Segment *s, long *addr, ulong ms)
1045 {
1046         int acquired, timedout;
1047         ulong t, elms;
1048         Sema phore;
1049
1050         if(canacquire(addr))
1051                 return 1;
1052         if(ms == 0)
1053                 return 0;
1054         acquired = timedout = 0;
1055         semqueue(s, addr, &phore);
1056         for(;;){
1057                 phore.waiting = 1;
1058                 coherence();
1059                 if(canacquire(addr)){
1060                         acquired = 1;
1061                         break;
1062                 }
1063                 if(waserror())
1064                         break;
1065                 t = m->ticks;
1066                 tsleep(&phore, semawoke, &phore, ms);
1067                 elms = TK2MS(m->ticks - t);
1068                 poperror();
1069                 if(elms >= ms){
1070                         timedout = 1;
1071                         break;
1072                 }
1073                 ms -= elms;
1074         }
1075         semdequeue(s, &phore);
1076         coherence();    /* not strictly necessary due to lock in semdequeue */
1077         if(!phore.waiting)
1078                 semwakeup(s, addr, 1);
1079         if(timedout)
1080                 return 0;
1081         if(!acquired)
1082                 nexterror();
1083         return 1;
1084 }
1085
1086 long
1087 syssemacquire(ulong *arg)
1088 {
1089         int block;
1090         long *addr;
1091         Segment *s;
1092
1093         validaddr(arg[0], sizeof(long), 1);
1094         evenaddr(arg[0]);
1095         addr = (long*)arg[0];
1096         block = arg[1];
1097         
1098         if((s = seg(up, (ulong)addr, 0)) == nil)
1099                 error(Ebadarg);
1100         if(*addr < 0)
1101                 error(Ebadarg);
1102         return semacquire(s, addr, block);
1103 }
1104
1105 long
1106 systsemacquire(ulong *arg)
1107 {
1108         long *addr;
1109         ulong ms;
1110         Segment *s;
1111
1112         validaddr(arg[0], sizeof(long), 1);
1113         evenaddr(arg[0]);
1114         addr = (long*)arg[0];
1115         ms = arg[1];
1116
1117         if((s = seg(up, (ulong)addr, 0)) == nil)
1118                 error(Ebadarg);
1119         if(*addr < 0)
1120                 error(Ebadarg);
1121         return tsemacquire(s, addr, ms);
1122 }
1123
1124 long
1125 syssemrelease(ulong *arg)
1126 {
1127         long *addr, delta;
1128         Segment *s;
1129
1130         validaddr(arg[0], sizeof(long), 1);
1131         evenaddr(arg[0]);
1132         addr = (long*)arg[0];
1133         delta = arg[1];
1134
1135         if((s = seg(up, (ulong)addr, 0)) == nil)
1136                 error(Ebadarg);
1137         /* delta == 0 is a no-op, not a release */
1138         if(delta < 0 || *addr < 0)
1139                 error(Ebadarg);
1140         return semrelease(s, addr, delta);
1141 }