/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */ /* See COPYRIGHT */ #include #include #include /* * If you fork off two procs running muxrecvproc and muxsendproc, * then muxrecv/muxsend (and thus muxrpc) will never block except on * rendevouses, which is nice when it's running in one thread of many. */ void _muxrecvproc(void *v) { void *p; Mux *mux; Muxqueue *q; mux = v; q = _muxqalloc(); qlock(&mux->lk); mux->readq = q; qlock(&mux->inlk); rwakeup(&mux->rpcfork); qunlock(&mux->lk); while((p = mux->recv(mux)) != nil) if(_muxqsend(q, p) < 0){ free(p); break; } qunlock(&mux->inlk); qlock(&mux->lk); _muxqhangup(q); while((p = _muxnbqrecv(q)) != nil) free(p); free(q); mux->readq = nil; rwakeup(&mux->rpcfork); qunlock(&mux->lk); } void _muxsendproc(void *v) { Muxqueue *q; void *p; Mux *mux; mux = v; q = _muxqalloc(); qlock(&mux->lk); mux->writeq = q; qlock(&mux->outlk); rwakeup(&mux->rpcfork); qunlock(&mux->lk); while((p = _muxqrecv(q)) != nil) if(mux->send(mux, p) < 0) break; qunlock(&mux->outlk); qlock(&mux->lk); _muxqhangup(q); while((p = _muxnbqrecv(q)) != nil) free(p); free(q); mux->writeq = nil; rwakeup(&mux->rpcfork); qunlock(&mux->lk); return; } void* _muxrecv(Mux *mux) { void *p; qlock(&mux->lk); /* if(mux->state != VtStateConnected){ werrstr("not connected"); qunlock(&mux->lk); return nil; } */ if(mux->readq){ qunlock(&mux->lk); return _muxqrecv(mux->readq); } qlock(&mux->inlk); qunlock(&mux->lk); p = mux->recv(mux); qunlock(&mux->inlk); /* if(!p) vthangup(mux); */ return p; } int _muxsend(Mux *mux, void *p) { qlock(&mux->lk); /* if(mux->state != VtStateConnected){ packetfree(p); werrstr("not connected"); qunlock(&mux->lk); return -1; } */ if(mux->writeq){ qunlock(&mux->lk); if(_muxqsend(mux->writeq, p) < 0){ free(p); return -1; } return 0; } qlock(&mux->outlk); qunlock(&mux->lk); if(mux->send(mux, p) < 0){ qunlock(&mux->outlk); /* vthangup(mux); */ return -1; } qunlock(&mux->outlk); return 0; }