📄 sysproc.c
字号:
{ int i; s += 2; n -= 2; /* skip #! */ for(i=0; s[i]!='\n'; i++) if(i == n-1) return 0; s[i] = 0; *ap = 0; i = 0; for(;;) { while(*s==' ' || *s=='\t') s++; if(*s == 0) break; i++; *ap++ = s; *ap = 0; while(*s && *s!=' ' && *s!='\t') s++; if(*s == 0) break; else *s++ = 0; } return i;}intreturn0(void *v){ return 0;}longsyssleep(ulong *arg){ int n; n = arg[0]; if(n <= 0) { yield(); return 0; } if(n < TK2MS(1)) n = TK2MS(1); tsleep(&up->sleep, return0, 0, n); return 0;}longsysalarm(ulong *arg){ return procalarm(arg[0]);}longsysexits(ulong *arg){ char *status; char *inval = "invalid exit string"; char buf[ERRMAX]; if(arg[0]){ if(waserror()) status = inval; else{ status = uvalidaddr(arg[0], 1, 0); if(vmemchr(status, 0, ERRMAX) == 0){ memmove(buf, status, ERRMAX); buf[ERRMAX-1] = 0; status = buf; } poperror(); } }else status = nil; pexit(status, 1); return 0; /* not reached */}longsys_wait(ulong *arg){ int pid; Waitmsg w; OWaitmsg *ow; if(arg[0] == 0) return pwait(nil); ow = uvalidaddr(arg[0], sizeof(OWaitmsg), 1); evenaddr(arg[0]); pid = pwait(&w); if(pid >= 0){ readnum(0, ow->pid, NUMSIZE, w.pid, NUMSIZE); readnum(0, ow->time+TUser*NUMSIZE, NUMSIZE, w.time[TUser], NUMSIZE); readnum(0, ow->time+TSys*NUMSIZE, NUMSIZE, w.time[TSys], NUMSIZE); readnum(0, ow->time+TReal*NUMSIZE, NUMSIZE, w.time[TReal], NUMSIZE); strncpy(ow->msg, w.msg, sizeof(ow->msg)); ow->msg[sizeof(ow->msg)-1] = '\0'; } return pid;}longsysawait(ulong *arg){ int i; int pid; Waitmsg w; ulong n; char *buf; n = arg[1]; buf = uvalidaddr(arg[0], n, 1); pid = pwait(&w); if(pid < 0) return -1; i = snprint(buf, n, "%d %lud %lud %lud %q", w.pid, w.time[TUser], w.time[TSys], w.time[TReal], w.msg); return i;}voidwerrstr(char *fmt, ...){ va_list va; if(up == nil) return; va_start(va, fmt); vseprint(up->syserrstr, up->syserrstr+ERRMAX, fmt, va); va_end(va);}static longgenerrstr(ulong addr, uint nbuf){ char tmp[ERRMAX]; char *buf; if(nbuf == 0) error(Ebadarg); buf = uvalidaddr(addr, nbuf, 1); if(nbuf > sizeof tmp) nbuf = sizeof tmp; memmove(tmp, buf, nbuf); /* make sure it's NUL-terminated */ tmp[nbuf-1] = '\0'; memmove(buf, up->syserrstr, nbuf); buf[nbuf-1] = '\0'; memmove(up->syserrstr, tmp, nbuf); return 0;}longsyserrstr(ulong *arg){ return generrstr(arg[0], arg[1]);}/* compatibility for old binaries */longsys_errstr(ulong *arg){ return generrstr(arg[0], 64);}longsysnotify(ulong *arg){ if(arg[0] != 0) uvalidaddr(arg[0], 1, 0); up->notify = arg[0]; /* checked again when used */ return 0;}longsysnoted(ulong *arg){ if(arg[0]!=NRSTR && !up->notified) error(Egreg); return 0;}longsyssegbrk(ulong *arg){ int i; ulong addr; Segment *s; addr = arg[0]; for(i = 0; i < NSEG; i++) { s = up->seg[i]; if(s == 0 || addr < s->base || addr >= s->top) continue; switch(s->type&SG_TYPE) { case SG_TEXT: case SG_DATA: case SG_STACK: error(Ebadarg); default: return ibrk(arg[1], i); } } error(Ebadarg); return 0; /* not reached */}longsyssegattach(ulong *arg){ return segattach(up, arg[0], uvalidaddr(arg[1], 1, 0), arg[2], arg[3]);}longsyssegdetach(ulong *arg){ int i; ulong addr; Segment *s; qlock(&up->seglock); if(waserror()){ qunlock(&up->seglock); nexterror(); } s = 0; addr = arg[0]; for(i = 0; i < NSEG; i++) if((s = up->seg[i])) { qlock(&s->lk); if((addr >= s->base && addr < s->top) || (s->top == s->base && addr == s->base)) goto found; qunlock(&s->lk); } error(Ebadarg);found: /* * Check we are not detaching the initial stack segment. */ if(s == up->seg[SSEG]){ qunlock(&s->lk); error(Ebadarg); } up->seg[i] = 0; qunlock(&s->lk); putseg(s); qunlock(&up->seglock); poperror(); /* Ensure we flush any entries from the lost segment */ flushmmu(); return 0;}longsyssegfree(ulong *arg){ Segment *s; ulong from, to; from = arg[0]; s = seg(up, from, 1); if(s == nil) error(Ebadarg); to = (from + arg[1]) & ~(BY2PG-1); from = PGROUND(from); if(to > s->top) { qunlock(&s->lk); error(Ebadarg); } mfreeseg(s, from, (to - from) / BY2PG); qunlock(&s->lk); flushmmu(); return 0;}/* For binary compatibility */longsysbrk_(ulong *arg){ return ibrk(arg[0], BSEG);}longsysrendezvous(ulong *arg){ uintptr tag, val; Proc *p, **l; tag = arg[0]; l = &REND(up->rgrp, tag); up->rendval = ~(uintptr)0; lock(&up->rgrp->ref.lk); for(p = *l; p; p = p->rendhash) { if(p->rendtag == tag) { *l = p->rendhash; val = p->rendval; p->rendval = arg[1]; while(p->mach != 0) ; ready(p); unlock(&up->rgrp->ref.lk); return val; } l = &p->rendhash; } /* Going to sleep here */ up->rendtag = tag; up->rendval = arg[1]; up->rendhash = *l; *l = up; up->state = Rendezvous; unlock(&up->rgrp->ref.lk); sched(); return up->rendval;}/* * The implementation of semaphores is complicated by needing * to avoid rescheduling in syssemrelease, so that it is safe * to call from real-time processes. This means syssemrelease * cannot acquire any qlocks, only spin locks. * * Semacquire and semrelease must both manipulate the semaphore * wait list. Lock-free linked lists only exist in theory, not * in practice, so the wait list is protected by a spin lock. * * The semaphore value *addr is stored in user memory, so it * cannot be read or written while holding spin locks. * * Thus, we can access the list only when holding the lock, and * we can access the semaphore only when not holding the lock. * This makes things interesting. Note that sleep's condition function * is called while holding two locks - r and up->rlock - so it cannot * access the semaphore value either. * * An acquirer announces its intention to try for the semaphore * by putting a Sema structure onto the wait list and then * setting Sema.waiting. After one last check of semaphore, * the acquirer sleeps until Sema.waiting==0. A releaser of n * must wake up n acquirers who have Sema.waiting set. It does * this by clearing Sema.waiting and then calling wakeup. * * There are three interesting races here. * The first is that in this particular sleep/wakeup usage, a single * wakeup can rouse a process from two consecutive sleeps! * The ordering is: * * (a) set Sema.waiting = 1 * (a) call sleep * (b) set Sema.waiting = 0 * (a) check Sema.waiting inside sleep, return w/o sleeping * (a) try for semaphore, fail * (a) set Sema.waiting = 1 * (a) call sleep * (b) call wakeup(a) * (a) wake up again * * This is okay - semacquire will just go around the loop * again. It does mean that at the top of the for(;;) loop in * semacquire, phore.waiting might already be set to 1. * * The second is that a releaser might wake an acquirer who is * interrupted before he can acquire the lock. Since * release(n) issues only n wakeup calls -- only n can be used * anyway -- if the interrupted process is not going to use his * wakeup call he must pass it on to another acquirer. * * The third race is similar to the second but more subtle. An * acquirer sets waiting=1 and then does a final canacquire() * before going to sleep. The opposite order would result in * missing wakeups that happen between canacquire and * waiting=1. (In fact, the whole point of Sema.waiting is to * avoid missing wakeups between canacquire() and sleep().) But * there can be spurious wakeups between a successful * canacquire() and the following semdequeue(). This wakeup is * not useful to the acquirer, since he has already acquired * the semaphore. Like in the previous case, though, the * acquirer must pass the wakeup call along. * * This is all rather subtle. The code below has been verified * with the spin model /sys/src/9/port/semaphore.p. The * original code anticipated the second race but not the first * or third, which were caught only with spin. The first race * is mentioned in /sys/doc/sleep.ps, but I'd forgotten about it. * It was lucky that my abstract model of sleep/wakeup still managed * to preserve that behavior. * * I remain slightly concerned about memory coherence * outside of locks. The spin model does not take * queued processor writes into account so we have to * think hard. The only variables accessed outside locks * are the semaphore value itself and the boolean flag * Sema.waiting. The value is only accessed with cmpswap, * whose job description includes doing the right thing as * far as memory coherence across processors. That leaves * Sema.waiting. To handle it, we call coherence() before each * read and after each write. - rsc *//* Add semaphore p with addr a to list in seg. */static voidsemqueue(Segment *s, long *a, Sema *p){ memset(p, 0, sizeof *p); p->addr = a; lock(&s->sema.rendez.lk); /* uses s->sema.Rendez.Lock, but no one else is */ p->next = &s->sema; p->prev = s->sema.prev; p->next->prev = p; p->prev->next = p; unlock(&s->sema.rendez.lk);}/* Remove semaphore p from list in seg. */static voidsemdequeue(Segment *s, Sema *p){ lock(&s->sema.rendez.lk); p->next->prev = p->prev; p->prev->next = p->next; unlock(&s->sema.rendez.lk);}/* Wake up n waiters with addr a on list in seg. */static voidsemwakeup(Segment *s, long *a, long n){ Sema *p; lock(&s->sema.rendez.lk); for(p=s->sema.next; p!=&s->sema && n>0; p=p->next){ if(p->addr == a && p->waiting){ p->waiting = 0; coherence(); wakeup(&p->rendez); n--; } } unlock(&s->sema.rendez.lk);}/* Add delta to semaphore and wake up waiters as appropriate. */static longsemrelease(Segment *s, long *addr, long delta){ long value; do value = *addr; while(!cmpswap(addr, value, value+delta)); semwakeup(s, addr, delta); return value+delta;}/* Try to acquire semaphore using compare-and-swap */static intcanacquire(long *addr){ long value; while((value=*addr) > 0) if(cmpswap(addr, value, value-1)) return 1; return 0;} /* Should we wake up? */static intsemawoke(void *p){ coherence(); return !((Sema*)p)->waiting;}/* Acquire semaphore (subtract 1). */static intsemacquire(Segment *s, long *addr, int block){ int acquired; Sema phore; if(canacquire(addr)) return 1; if(!block) return 0; acquired = 0; semqueue(s, addr, &phore); for(;;){ phore.waiting = 1; coherence(); if(canacquire(addr)){ acquired = 1; break; } if(waserror()) break; sleep(&phore.rendez, semawoke, &phore); poperror(); } semdequeue(s, &phore); coherence(); /* not strictly necessary due to lock in semdequeue */ if(!phore.waiting) semwakeup(s, addr, 1); if(!acquired) nexterror(); return 1;}longsyssemacquire(ulong *arg){ int block; long *addr; Segment *s; addr = uvalidaddr(arg[0], sizeof(long), 1); evenaddr(arg[0]); block = arg[1]; if((s = seg(up, arg[0], 0)) == nil) /* this can't happen if validaddr succeeded, can it? */ error(Ebadarg); if(*addr < 0) error(Ebadarg); return semacquire(s, addr, block);}longsyssemrelease(ulong *arg){ long *addr, delta; Segment *s; addr = uvalidaddr(arg[0], sizeof(long), 1); evenaddr(arg[0]); delta = arg[1]; if((s = seg(up, arg[0], 0)) == nil) /* again, this can't happen! */ error(Ebadarg); if(delta < 0 || *addr < 0) error(Ebadarg); return semrelease(s, addr, arg[1]);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -