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