/* * Print a string on the console. Convert \n to \r\n for serial * line consoles. Locking of the queues is left up to the screen * or uart code. Multi-line messages to serial consoles may get * interspersed with other messages. */ static void putstrn0(char *str, int n, int usewrite) { if(!islo()) usewrite = 0; /* * how many different output devices do we need? */ kmesgputs(str, n); /* * if someone is reading /dev/kprint, * put the message there. * if not and there's an attached bit mapped display, * put the message there. * * if there's a serial line being used as a console, * put the message there. */ if(kprintoq != nil && !qisclosed(kprintoq)){ if(usewrite) qwrite(kprintoq, str, n); else qiwrite(kprintoq, str, n); }else if(screenputs != nil) screenputs(str, n); uartputs(str, n); #if 0 // Plan 9 VX if(serialoq == nil){ uartputs(str, n); return; } while(n > 0) { t = memchr(str, '\n', n); if(t && !kbd.raw) { m = t-str; if(usewrite){ qwrite(serialoq, str, m); qwrite(serialoq, "\r\n", 2); } else { qiwrite(serialoq, str, m); qiwrite(serialoq, "\r\n", 2); } n -= m+1; str = t+1; } else { if(usewrite) qwrite(serialoq, str, n); else qiwrite(serialoq, str, n); break; } } #endif }
/* * move blocks between queues if they are ready. * schedule an interrupt for the next interesting time. * * must be called with the link ilocked. */ static void pushlink(Link *link, vlong now) { Block *bp; vlong tout, tin; /* * put another block in the link queue */ ilock(link); if(link->iq == nil || link->oq == nil){ iunlock(link); return; } timerdel(&link->ci); /* * put more blocks into the xmit queue * use the time the last packet was supposed to go out * as the start time for the next packet, rather than * the current time. this more closely models a network * device which can queue multiple output packets. */ tout = link->tout; if(!tout) tout = now; while(tout <= now){ bp = qget(link->oq); if(bp == nil){ tout = 0; break; } /* * can't send the packet before it gets queued */ tin = gtime(bp->rp); if(tin > tout) tout = tin; tout = tout + (BLEN(bp) - Tmsize) * link->delayn; /* * drop packets */ if(link->droprate && nrand(link->droprate) == 0) link->drops++; else{ ptime(bp->rp, tout + link->delay0ns); if(link->tq == nil) link->tq = bp; else link->tqtail->next = bp; link->tqtail = bp; } } /* * record the next time a packet can be sent, * but don't schedule an interrupt if none is waiting */ link->tout = tout; if(!qcanread(link->oq)) tout = 0; /* * put more blocks into the receive queue */ tin = 0; while(bp = link->tq){ tin = gtime(bp->rp); if(tin > now) break; bp->rp += Tmsize; link->tq = bp->next; bp->next = nil; if(!link->indrop) qpassnolim(link->iq, bp); else if(qpass(link->iq, bp) < 0) link->soverflows++; tin = 0; } if(bp == nil && qisclosed(link->oq) && !qcanread(link->oq) && !qisclosed(link->iq)) qhangup(link->iq, nil); link->tin = tin; if(!tin || tin > tout && tout) tin = tout; link->ci.ns = tin - now; if(tin){ if(tin < now) panic("loopback unfinished business"); timeradd(&link->ci); } iunlock(link); }
static Chan* ipopen(Chan* c, int omode) { Conv *cv, *nc; Proto *p; int perm; Fs *f; perm = m2p[omode&3]; f = ipfs[c->dev]; switch(TYPE(c->qid)) { default: break; case Qndb: if(omode & (OWRITE|OTRUNC) && !iseve()) error(Eperm); if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC)) f->ndb[0] = 0; break; case Qlog: netlogopen(f); break; case Qiproute: case Qarp: if(omode != OREAD && !iseve()) error(Eperm); break; case Qtopdir: case Qprotodir: case Qconvdir: case Qstatus: case Qremote: case Qlocal: case Qstats: case Qbootp: case Qipselftab: if(omode != OREAD) error(Eperm); break; case Qsnoop: if(omode != OREAD) error(Eperm); p = f->p[PROTO(c->qid)]; cv = p->conv[CONV(c->qid)]; if(strcmp(ATTACHER(c), cv->owner) != 0 && !iseve()) error(Eperm); incref(&cv->snoopers); break; case Qclone: p = f->p[PROTO(c->qid)]; qlock(p); if(waserror()){ qunlock(p); nexterror(); } cv = Fsprotoclone(p, ATTACHER(c)); qunlock(p); poperror(); if(cv == nil) { error(Enodev); break; } mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE); break; case Qdata: case Qctl: case Qerr: p = f->p[PROTO(c->qid)]; qlock(p); cv = p->conv[CONV(c->qid)]; qlock(cv); if(waserror()) { qunlock(cv); qunlock(p); nexterror(); } if((perm & (cv->perm>>6)) != perm) { if(strcmp(ATTACHER(c), cv->owner) != 0) error(Eperm); if((perm & cv->perm) != perm) error(Eperm); } cv->inuse++; if(cv->inuse == 1){ kstrdup(&cv->owner, ATTACHER(c)); cv->perm = 0660; } qunlock(cv); qunlock(p); poperror(); break; case Qlisten: cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)]; if((perm & (cv->perm>>6)) != perm) { if(strcmp(ATTACHER(c), cv->owner) != 0) error(Eperm); if((perm & cv->perm) != perm) error(Eperm); } if(cv->state != Announced) error("not announced"); if(waserror()){ closeconv(cv); nexterror(); } qlock(cv); cv->inuse++; qunlock(cv); nc = nil; while(nc == nil) { /* give up if we got a hangup */ if(qisclosed(cv->rq)) error("listen hungup"); qlock(&cv->listenq); if(waserror()) { qunlock(&cv->listenq); nexterror(); } /* wait for a connect */ sleep(&cv->listenr, incoming, cv); qlock(cv); nc = cv->incall; if(nc != nil){ cv->incall = nc->next; mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE); kstrdup(&cv->owner, ATTACHER(c)); } qunlock(cv); qunlock(&cv->listenq); poperror(); } closeconv(cv); poperror(); break; } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; }