long sysrendezvous(ulong *arg) { uintptr tag, val; Proc *p, **l; tag = arg[0]; l = &REND(up->rgrp, tag); up->rendval = ~(uintptr)0; lock(up->rgrp); 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); 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); sched(); return up->rendval; }
/* * if waking a sleeping process, this routine must hold both * p->rlock and r->lock. However, it can't know them in * the same order as wakeup causing a possible lock ordering * deadlock. We break the deadlock by giving up the p->rlock * lock if we can't get the r->lock and retrying. */ int postnote(Proc *p, int dolock, char *n, int flag) { int s, ret; QLock *q; if(p == nil) return 0; if(dolock) qlock(&p->debug); if(p->pid == 0){ if(dolock) qunlock(&p->debug); return 0; } if(n != nil && flag != NUser && (p->notify == 0 || p->notified)) p->nnote = 0; ret = 0; if(p->nnote < NNOTE && n != nil) { kstrcpy(p->note[p->nnote].msg, n, ERRMAX); p->note[p->nnote++].flag = flag; ret = 1; } p->notepending = 1; if(dolock) qunlock(&p->debug); /* this loop is to avoid lock ordering problems. */ for(;;){ Rendez *r; s = splhi(); lock(&p->rlock); r = p->r; /* waiting for a wakeup? */ if(r == nil) break; /* no */ /* try for the second lock */ if(canlock(r)){ if(p->state != Wakeme || r->p != p) panic("postnote: state %d %d %d", r->p != p, p->r != r, p->state); p->r = nil; r->p = nil; ready(p); unlock(r); break; } /* give other process time to get out of critical section and try again */ unlock(&p->rlock); splx(s); sched(); } unlock(&p->rlock); splx(s); switch(p->state){ case Queueing: /* Try and pull out of a eqlock */ if((q = p->eql) != nil){ lock(&q->use); if(p->state == Queueing && p->eql == q){ Proc *d, *l; for(l = nil, d = q->head; d != nil; l = d, d = d->qnext){ if(d == p){ if(l != nil) l->qnext = p->qnext; else q->head = p->qnext; if(p->qnext == nil) q->tail = l; p->qnext = nil; p->eql = nil; /* not taken */ ready(p); break; } } } unlock(&q->use); } break; case Rendezvous: /* Try and pull out of a rendezvous */ lock(p->rgrp); if(p->state == Rendezvous) { Proc *d, **l; l = &REND(p->rgrp, p->rendtag); for(d = *l; d != nil; d = d->rendhash) { if(d == p) { *l = p->rendhash; p->rendval = ~0; ready(p); break; } l = &d->rendhash; } } unlock(p->rgrp); break; } return ret; }
/* * if waking a sleeping process, this routine must hold both * p->rlock and r->lock. However, it can't know them in * the same order as wakeup causing a possible lock ordering * deadlock. We break the deadlock by giving up the p->rlock * lock if we can't get the r->lock and retrying. */ int postnote(Proc *p, int dolock, char *n, int flag) { Mpl pl; int ret; Rendez *r; Proc *d, **l; if(dolock) qlock(&p->debug); if(flag != NUser && (p->notify == 0 || p->notified)) p->nnote = 0; ret = 0; if(p->nnote < NNOTE) { strcpy(p->note[p->nnote].msg, n); p->note[p->nnote++].flag = flag; ret = 1; } p->notepending = 1; /* NIX */ if(p->state == Exotic){ /* it could be that the process is not running * in the AC when we interrupt the AC, but then * we'd only get an extra interrupt in the AC, and * nothing should happen. */ intrac(p); } if(dolock) qunlock(&p->debug); /* this loop is to avoid lock ordering problems. */ for(;;){ pl = splhi(); lock(&p->rlock); r = p->r; /* waiting for a wakeup? */ if(r == nil) break; /* no */ /* try for the second lock */ if(canlock(r)){ if(p->state != Wakeme || r->_p != p) panic("postnote: state %d %d %d", r->_p != p, p->r != r, p->state); p->r = nil; r->_p = nil; ready(p); unlock(r); break; } /* give other process time to get out of critical section and try again */ unlock(&p->rlock); splx(pl); sched(); } unlock(&p->rlock); splx(pl); if(p->state != Rendezvous){ if(p->state == Semdown) ready(p); return ret; } /* Try and pull out of a rendezvous */ lock(p->rgrp); if(p->state == Rendezvous) { p->rendval = ~0; l = &REND(p->rgrp, p->rendtag); for(d = *l; d; d = d->rendhash) { if(d == p) { *l = p->rendhash; break; } l = &d->rendhash; } ready(p); } unlock(p->rgrp); return ret; }
/* * if waking a sleeping process, this routine must hold both * p->rlock and r->lock. However, it can't know them in * the same order as wakeup causing a possible lock ordering * deadlock. We break the deadlock by giving up the p->rlock * lock if we can't get the r->lock and retrying. */ int postnote(Proc *p, int dolock, char *n, int flag) { int s, ret; Rendez *r; Proc *d, **l; if(dolock) qlock(&p->debug); if(flag != NUser && (p->notify == 0 || p->notified)) p->nnote = 0; ret = 0; if(p->nnote < NNOTE) { strcpy(p->note[p->nnote].msg, n); p->note[p->nnote++].flag = flag; ret = 1; } p->notepending = 1; if(dolock) qunlock(&p->debug); /* this loop is to avoid lock ordering problems. */ for(;;){ s = splhi(); lock(&p->rlock); r = p->r; /* waiting for a wakeup? */ if(r == nil) break; /* no */ /* try for the second lock */ if(canlock(r)){ if(p->state != Wakeme || r->p != p) panic("postnote: state %d %d %d", r->p != p, p->r != r, p->state); p->r = nil; r->p = nil; ready(p); unlock(r); break; } /* give other process time to get out of critical section and try again */ unlock(&p->rlock); splx(s); sched(); } unlock(&p->rlock); splx(s); if(p->state != Rendezvous) return ret; /* Try and pull out of a rendezvous */ lock(p->rgrp); if(p->state == Rendezvous) { p->rendval = ~0; l = &REND(p->rgrp, p->rendtag); for(d = *l; d; d = d->rendhash) { if(d == p) { *l = p->rendhash; break; } l = &d->rendhash; } ready(p); } unlock(p->rgrp); return ret; }