2013-09-23 23:00:39 +02:00
|
|
|
#include "stdinc.h"
|
|
|
|
|
|
|
|
|
|
#include "9.h"
|
|
|
|
|
#include "dat.h"
|
|
|
|
|
#include "fns.h"
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
NConInit = 128,
|
|
|
|
|
NMsgInit = 384,
|
|
|
|
|
NMsgProcInit = 64,
|
|
|
|
|
NMsizeInit = 8192+IOHDRSZ,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct {
|
2013-09-23 23:16:25 +02:00
|
|
|
QLock alock; /* alloc */
|
2013-09-23 23:00:39 +02:00
|
|
|
Msg* ahead;
|
2013-09-23 23:16:25 +02:00
|
|
|
Rendez arendez;
|
2013-09-23 23:00:39 +02:00
|
|
|
|
|
|
|
|
int maxmsg;
|
|
|
|
|
int nmsg;
|
|
|
|
|
int nmsgstarve;
|
|
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
QLock rlock; /* read */
|
2013-09-23 23:00:39 +02:00
|
|
|
Msg* rhead;
|
|
|
|
|
Msg* rtail;
|
2013-09-23 23:16:25 +02:00
|
|
|
Rendez rrendez;
|
2013-09-23 23:00:39 +02:00
|
|
|
|
|
|
|
|
int maxproc;
|
|
|
|
|
int nproc;
|
|
|
|
|
int nprocstarve;
|
|
|
|
|
|
|
|
|
|
u32int msize; /* immutable */
|
|
|
|
|
} mbox;
|
|
|
|
|
|
|
|
|
|
static struct {
|
2013-09-23 23:16:25 +02:00
|
|
|
QLock alock; /* alloc */
|
2013-09-23 23:00:39 +02:00
|
|
|
Con* ahead;
|
2013-09-23 23:16:25 +02:00
|
|
|
Rendez arendez;
|
2013-09-23 23:00:39 +02:00
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
RWLock clock;
|
2013-09-23 23:00:39 +02:00
|
|
|
Con* chead;
|
|
|
|
|
Con* ctail;
|
|
|
|
|
|
|
|
|
|
int maxcon;
|
|
|
|
|
int ncon;
|
|
|
|
|
int nconstarve;
|
|
|
|
|
|
|
|
|
|
u32int msize;
|
|
|
|
|
} cbox;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
conFree(Con* con)
|
|
|
|
|
{
|
|
|
|
|
assert(con->version == nil);
|
|
|
|
|
assert(con->mhead == nil);
|
|
|
|
|
assert(con->whead == nil);
|
|
|
|
|
assert(con->nfid == 0);
|
|
|
|
|
assert(con->state == ConMoribund);
|
|
|
|
|
|
|
|
|
|
if(con->fd >= 0){
|
|
|
|
|
close(con->fd);
|
|
|
|
|
con->fd = -1;
|
|
|
|
|
}
|
|
|
|
|
con->state = ConDead;
|
|
|
|
|
con->aok = 0;
|
|
|
|
|
con->flags = 0;
|
|
|
|
|
con->isconsole = 0;
|
|
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&cbox.alock);
|
2013-09-23 23:00:39 +02:00
|
|
|
if(con->cprev != nil)
|
|
|
|
|
con->cprev->cnext = con->cnext;
|
|
|
|
|
else
|
|
|
|
|
cbox.chead = con->cnext;
|
|
|
|
|
if(con->cnext != nil)
|
|
|
|
|
con->cnext->cprev = con->cprev;
|
|
|
|
|
else
|
|
|
|
|
cbox.ctail = con->cprev;
|
|
|
|
|
con->cprev = con->cnext = nil;
|
|
|
|
|
|
|
|
|
|
if(cbox.ncon > cbox.maxcon){
|
|
|
|
|
if(con->name != nil)
|
2013-09-23 23:16:25 +02:00
|
|
|
vtfree(con->name);
|
|
|
|
|
vtfree(con->data);
|
|
|
|
|
vtfree(con);
|
2013-09-23 23:00:39 +02:00
|
|
|
cbox.ncon--;
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&cbox.alock);
|
2013-09-23 23:00:39 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
con->anext = cbox.ahead;
|
|
|
|
|
cbox.ahead = con;
|
|
|
|
|
if(con->anext == nil)
|
2013-09-23 23:16:25 +02:00
|
|
|
rwakeup(&cbox.arendez);
|
|
|
|
|
qunlock(&cbox.alock);
|
2013-09-23 23:00:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
msgFree(Msg* m)
|
|
|
|
|
{
|
|
|
|
|
assert(m->rwnext == nil);
|
|
|
|
|
assert(m->flush == nil);
|
|
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&mbox.alock);
|
2013-09-23 23:00:39 +02:00
|
|
|
if(mbox.nmsg > mbox.maxmsg){
|
2013-09-23 23:16:25 +02:00
|
|
|
vtfree(m->data);
|
|
|
|
|
vtfree(m);
|
2013-09-23 23:00:39 +02:00
|
|
|
mbox.nmsg--;
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&mbox.alock);
|
2013-09-23 23:00:39 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
m->anext = mbox.ahead;
|
|
|
|
|
mbox.ahead = m;
|
|
|
|
|
if(m->anext == nil)
|
2013-09-23 23:16:25 +02:00
|
|
|
rwakeup(&mbox.arendez);
|
|
|
|
|
qunlock(&mbox.alock);
|
2013-09-23 23:00:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Msg*
|
|
|
|
|
msgAlloc(Con* con)
|
|
|
|
|
{
|
|
|
|
|
Msg *m;
|
|
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&mbox.alock);
|
2013-09-23 23:00:39 +02:00
|
|
|
while(mbox.ahead == nil){
|
|
|
|
|
if(mbox.nmsg >= mbox.maxmsg){
|
|
|
|
|
mbox.nmsgstarve++;
|
2013-09-23 23:16:25 +02:00
|
|
|
rsleep(&mbox.arendez);
|
2013-09-23 23:00:39 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
2013-09-23 23:16:25 +02:00
|
|
|
m = vtmallocz(sizeof(Msg));
|
|
|
|
|
m->data = vtmalloc(mbox.msize);
|
2013-09-23 23:00:39 +02:00
|
|
|
m->msize = mbox.msize;
|
|
|
|
|
mbox.nmsg++;
|
|
|
|
|
mbox.ahead = m;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
m = mbox.ahead;
|
|
|
|
|
mbox.ahead = m->anext;
|
|
|
|
|
m->anext = nil;
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&mbox.alock);
|
2013-09-23 23:00:39 +02:00
|
|
|
|
|
|
|
|
m->con = con;
|
|
|
|
|
m->state = MsgR;
|
|
|
|
|
m->nowq = 0;
|
|
|
|
|
|
|
|
|
|
return m;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
msgMunlink(Msg* m)
|
|
|
|
|
{
|
|
|
|
|
Con *con;
|
|
|
|
|
|
|
|
|
|
con = m->con;
|
|
|
|
|
|
|
|
|
|
if(m->mprev != nil)
|
|
|
|
|
m->mprev->mnext = m->mnext;
|
|
|
|
|
else
|
|
|
|
|
con->mhead = m->mnext;
|
|
|
|
|
if(m->mnext != nil)
|
|
|
|
|
m->mnext->mprev = m->mprev;
|
|
|
|
|
else
|
|
|
|
|
con->mtail = m->mprev;
|
|
|
|
|
m->mprev = m->mnext = nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
msgFlush(Msg* m)
|
|
|
|
|
{
|
|
|
|
|
Con *con;
|
|
|
|
|
Msg *flush, *old;
|
|
|
|
|
|
|
|
|
|
con = m->con;
|
|
|
|
|
|
|
|
|
|
if(Dflag)
|
|
|
|
|
fprint(2, "msgFlush %F\n", &m->t);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If this Tflush has been flushed, nothing to do.
|
|
|
|
|
* Look for the message to be flushed in the
|
|
|
|
|
* queue of all messages still on this connection.
|
|
|
|
|
* If it's not found must assume Elvis has already
|
|
|
|
|
* left the building and reply normally.
|
|
|
|
|
*/
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&con->mlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
if(m->state == MsgF){
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&con->mlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for(old = con->mhead; old != nil; old = old->mnext)
|
|
|
|
|
if(old->t.tag == m->t.oldtag)
|
|
|
|
|
break;
|
|
|
|
|
if(old == nil){
|
|
|
|
|
if(Dflag)
|
|
|
|
|
fprint(2, "msgFlush: cannot find %d\n", m->t.oldtag);
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&con->mlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(Dflag)
|
|
|
|
|
fprint(2, "\tmsgFlush found %F\n", &old->t);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Found it.
|
|
|
|
|
* There are two cases where the old message can be
|
|
|
|
|
* truly flushed and no reply to the original message given.
|
|
|
|
|
* The first is when the old message is in MsgR state; no
|
|
|
|
|
* processing has been done yet and it is still on the read
|
|
|
|
|
* queue. The second is if old is a Tflush, which doesn't
|
|
|
|
|
* affect the server state. In both cases, put the old
|
|
|
|
|
* message into MsgF state and let MsgWrite toss it after
|
|
|
|
|
* pulling it off the queue.
|
|
|
|
|
*/
|
|
|
|
|
if(old->state == MsgR || old->t.type == Tflush){
|
|
|
|
|
old->state = MsgF;
|
|
|
|
|
if(Dflag)
|
|
|
|
|
fprint(2, "msgFlush: change %d from MsgR to MsgF\n",
|
|
|
|
|
m->t.oldtag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Link this flush message and the old message
|
|
|
|
|
* so multiple flushes can be coalesced (if there are
|
|
|
|
|
* multiple Tflush messages for a particular pending
|
|
|
|
|
* request, it is only necessary to respond to the last
|
|
|
|
|
* one, so any previous can be removed) and to be
|
|
|
|
|
* sure flushes wait for their corresponding old
|
|
|
|
|
* message to go out first.
|
|
|
|
|
* Waiting flush messages do not go on the write queue,
|
|
|
|
|
* they are processed after the old message is dealt
|
|
|
|
|
* with. There's no real need to protect the setting of
|
|
|
|
|
* Msg.nowq, the only code to check it runs in this
|
|
|
|
|
* process after this routine returns.
|
|
|
|
|
*/
|
|
|
|
|
if((flush = old->flush) != nil){
|
|
|
|
|
if(Dflag)
|
|
|
|
|
fprint(2, "msgFlush: remove %d from %d list\n",
|
|
|
|
|
old->flush->t.tag, old->t.tag);
|
|
|
|
|
m->flush = flush->flush;
|
|
|
|
|
flush->flush = nil;
|
|
|
|
|
msgMunlink(flush);
|
|
|
|
|
msgFree(flush);
|
|
|
|
|
}
|
|
|
|
|
old->flush = m;
|
|
|
|
|
m->nowq = 1;
|
|
|
|
|
|
|
|
|
|
if(Dflag)
|
|
|
|
|
fprint(2, "msgFlush: add %d to %d queue\n",
|
|
|
|
|
m->t.tag, old->t.tag);
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&con->mlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
msgProc(void*)
|
|
|
|
|
{
|
|
|
|
|
Msg *m;
|
2013-09-23 23:16:25 +02:00
|
|
|
char e[ERRMAX];
|
2013-09-23 23:00:39 +02:00
|
|
|
Con *con;
|
|
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
threadsetname("msgProc");
|
2013-09-23 23:00:39 +02:00
|
|
|
|
|
|
|
|
for(;;){
|
|
|
|
|
/*
|
|
|
|
|
* If surplus to requirements, exit.
|
|
|
|
|
* If not, wait for and pull a message off
|
|
|
|
|
* the read queue.
|
|
|
|
|
*/
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&mbox.rlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
if(mbox.nproc > mbox.maxproc){
|
|
|
|
|
mbox.nproc--;
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&mbox.rlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
while(mbox.rhead == nil)
|
2013-09-23 23:16:25 +02:00
|
|
|
rsleep(&mbox.rrendez);
|
2013-09-23 23:00:39 +02:00
|
|
|
m = mbox.rhead;
|
|
|
|
|
mbox.rhead = m->rwnext;
|
|
|
|
|
m->rwnext = nil;
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&mbox.rlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
|
|
|
|
|
con = m->con;
|
2013-09-23 23:16:25 +02:00
|
|
|
*e = 0;
|
2013-09-23 23:00:39 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the message has been flushed before
|
|
|
|
|
* any 9P processing has started, mark it so
|
|
|
|
|
* none will be attempted.
|
|
|
|
|
*/
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&con->mlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
if(m->state == MsgF)
|
2013-09-23 23:16:25 +02:00
|
|
|
strcpy(e, "flushed");
|
2013-09-23 23:00:39 +02:00
|
|
|
else
|
|
|
|
|
m->state = Msg9;
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&con->mlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
if(*e == 0){
|
2013-09-23 23:00:39 +02:00
|
|
|
/*
|
|
|
|
|
* explain this
|
|
|
|
|
*/
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&con->lock);
|
2013-09-23 23:00:39 +02:00
|
|
|
if(m->t.type == Tversion){
|
|
|
|
|
con->version = m;
|
|
|
|
|
con->state = ConDown;
|
|
|
|
|
while(con->mhead != m)
|
2013-09-23 23:16:25 +02:00
|
|
|
rsleep(&con->rendez);
|
2013-09-23 23:00:39 +02:00
|
|
|
assert(con->state == ConDown);
|
|
|
|
|
if(con->version == m){
|
|
|
|
|
con->version = nil;
|
|
|
|
|
con->state = ConInit;
|
|
|
|
|
}
|
|
|
|
|
else
|
2013-09-23 23:16:25 +02:00
|
|
|
strcpy(e, "Tversion aborted");
|
2013-09-23 23:00:39 +02:00
|
|
|
}
|
|
|
|
|
else if(con->state != ConUp)
|
2013-09-23 23:16:25 +02:00
|
|
|
strcpy(e, "connection not ready");
|
|
|
|
|
qunlock(&con->lock);
|
2013-09-23 23:00:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Dispatch if not error already.
|
|
|
|
|
*/
|
|
|
|
|
m->r.tag = m->t.tag;
|
2013-09-23 23:16:25 +02:00
|
|
|
if(*e == 0 && !(*rFcall[m->t.type])(m))
|
|
|
|
|
rerrstr(e, sizeof e);
|
|
|
|
|
if(*e != 0){
|
2013-09-23 23:00:39 +02:00
|
|
|
m->r.type = Rerror;
|
|
|
|
|
m->r.ename = e;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
m->r.type = m->t.type+1;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Put the message (with reply) on the
|
|
|
|
|
* write queue and wakeup the write process.
|
|
|
|
|
*/
|
|
|
|
|
if(!m->nowq){
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&con->wlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
if(con->whead == nil)
|
|
|
|
|
con->whead = m;
|
|
|
|
|
else
|
|
|
|
|
con->wtail->rwnext = m;
|
|
|
|
|
con->wtail = m;
|
2013-09-23 23:16:25 +02:00
|
|
|
rwakeup(&con->wrendez);
|
|
|
|
|
qunlock(&con->wlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
msgRead(void* v)
|
|
|
|
|
{
|
|
|
|
|
Msg *m;
|
|
|
|
|
Con *con;
|
|
|
|
|
int eof, fd, n;
|
|
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
threadsetname("msgRead");
|
2013-09-23 23:00:39 +02:00
|
|
|
|
|
|
|
|
con = v;
|
|
|
|
|
fd = con->fd;
|
|
|
|
|
eof = 0;
|
|
|
|
|
|
|
|
|
|
while(!eof){
|
|
|
|
|
m = msgAlloc(con);
|
|
|
|
|
|
|
|
|
|
while((n = read9pmsg(fd, m->data, con->msize)) == 0)
|
|
|
|
|
;
|
|
|
|
|
if(n < 0){
|
|
|
|
|
m->t.type = Tversion;
|
|
|
|
|
m->t.fid = NOFID;
|
|
|
|
|
m->t.tag = NOTAG;
|
|
|
|
|
m->t.msize = con->msize;
|
|
|
|
|
m->t.version = "9PEoF";
|
|
|
|
|
eof = 1;
|
|
|
|
|
}
|
|
|
|
|
else if(convM2S(m->data, n, &m->t) != n){
|
|
|
|
|
if(Dflag)
|
|
|
|
|
fprint(2, "msgRead: convM2S error: %s\n",
|
|
|
|
|
con->name);
|
|
|
|
|
msgFree(m);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if(Dflag)
|
|
|
|
|
fprint(2, "msgRead %p: t %F\n", con, &m->t);
|
|
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&con->mlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
if(con->mtail != nil){
|
|
|
|
|
m->mprev = con->mtail;
|
|
|
|
|
con->mtail->mnext = m;
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
con->mhead = m;
|
|
|
|
|
m->mprev = nil;
|
|
|
|
|
}
|
|
|
|
|
con->mtail = m;
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&con->mlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&mbox.rlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
if(mbox.rhead == nil){
|
|
|
|
|
mbox.rhead = m;
|
2013-09-23 23:16:25 +02:00
|
|
|
if(!rwakeup(&mbox.rrendez)){
|
2013-09-23 23:00:39 +02:00
|
|
|
if(mbox.nproc < mbox.maxproc){
|
2013-09-23 23:16:25 +02:00
|
|
|
if(proccreate(msgProc, nil, STACK) > 0)
|
2013-09-23 23:00:39 +02:00
|
|
|
mbox.nproc++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
mbox.nprocstarve++;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* don't need this surely?
|
2013-09-23 23:16:25 +02:00
|
|
|
rwakeup(&mbox.rrendez);
|
2013-09-23 23:00:39 +02:00
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
mbox.rtail->rwnext = m;
|
|
|
|
|
mbox.rtail = m;
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&mbox.rlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
msgWrite(void* v)
|
|
|
|
|
{
|
|
|
|
|
Con *con;
|
|
|
|
|
int eof, n;
|
|
|
|
|
Msg *flush, *m;
|
|
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
threadsetname("msgWrite");
|
2013-09-23 23:00:39 +02:00
|
|
|
|
|
|
|
|
con = v;
|
2013-09-23 23:16:25 +02:00
|
|
|
if(proccreate(msgRead, con, STACK) < 0){
|
2013-09-23 23:00:39 +02:00
|
|
|
conFree(con);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(;;){
|
|
|
|
|
/*
|
|
|
|
|
* Wait for and pull a message off the write queue.
|
|
|
|
|
*/
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&con->wlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
while(con->whead == nil)
|
2013-09-23 23:16:25 +02:00
|
|
|
rsleep(&con->wrendez);
|
2013-09-23 23:00:39 +02:00
|
|
|
m = con->whead;
|
|
|
|
|
con->whead = m->rwnext;
|
|
|
|
|
m->rwnext = nil;
|
|
|
|
|
assert(!m->nowq);
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&con->wlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
|
|
|
|
|
eof = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Write each message (if it hasn't been flushed)
|
|
|
|
|
* followed by any messages waiting for it to complete.
|
|
|
|
|
*/
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&con->mlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
while(m != nil){
|
|
|
|
|
msgMunlink(m);
|
|
|
|
|
|
|
|
|
|
if(Dflag)
|
|
|
|
|
fprint(2, "msgWrite %d: r %F\n",
|
|
|
|
|
m->state, &m->r);
|
|
|
|
|
|
|
|
|
|
if(m->state != MsgF){
|
|
|
|
|
m->state = MsgW;
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&con->mlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
|
|
|
|
|
n = convS2M(&m->r, con->data, con->msize);
|
|
|
|
|
if(write(con->fd, con->data, n) != n)
|
|
|
|
|
eof = 1;
|
|
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&con->mlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if((flush = m->flush) != nil){
|
|
|
|
|
assert(flush->nowq);
|
|
|
|
|
m->flush = nil;
|
|
|
|
|
}
|
|
|
|
|
msgFree(m);
|
|
|
|
|
m = flush;
|
|
|
|
|
}
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&con->mlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&con->lock);
|
2013-09-23 23:00:39 +02:00
|
|
|
if(eof && con->fd >= 0){
|
|
|
|
|
close(con->fd);
|
|
|
|
|
con->fd = -1;
|
|
|
|
|
}
|
|
|
|
|
if(con->state == ConDown)
|
2013-09-23 23:16:25 +02:00
|
|
|
rwakeup(&con->rendez);
|
2013-09-23 23:00:39 +02:00
|
|
|
if(con->state == ConMoribund && con->mhead == nil){
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&con->lock);
|
2013-09-23 23:00:39 +02:00
|
|
|
conFree(con);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&con->lock);
|
2013-09-23 23:00:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Con*
|
|
|
|
|
conAlloc(int fd, char* name, int flags)
|
|
|
|
|
{
|
|
|
|
|
Con *con;
|
|
|
|
|
char buf[128], *p;
|
|
|
|
|
int rfd, n;
|
|
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&cbox.alock);
|
2013-09-23 23:00:39 +02:00
|
|
|
while(cbox.ahead == nil){
|
|
|
|
|
if(cbox.ncon >= cbox.maxcon){
|
|
|
|
|
cbox.nconstarve++;
|
2013-09-23 23:16:25 +02:00
|
|
|
rsleep(&cbox.arendez);
|
2013-09-23 23:00:39 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
2013-09-23 23:16:25 +02:00
|
|
|
con = vtmallocz(sizeof(Con));
|
|
|
|
|
con->rendez.l = &con->lock;
|
|
|
|
|
con->data = vtmalloc(cbox.msize);
|
2013-09-23 23:00:39 +02:00
|
|
|
con->msize = cbox.msize;
|
2013-09-23 23:16:25 +02:00
|
|
|
con->mrendez.l = &con->mlock;
|
|
|
|
|
con->wrendez.l = &con->wlock;
|
2013-09-23 23:00:39 +02:00
|
|
|
|
|
|
|
|
cbox.ncon++;
|
|
|
|
|
cbox.ahead = con;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
con = cbox.ahead;
|
|
|
|
|
cbox.ahead = con->anext;
|
|
|
|
|
con->anext = nil;
|
|
|
|
|
|
|
|
|
|
if(cbox.ctail != nil){
|
|
|
|
|
con->cprev = cbox.ctail;
|
|
|
|
|
cbox.ctail->cnext = con;
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
cbox.chead = con;
|
|
|
|
|
con->cprev = nil;
|
|
|
|
|
}
|
|
|
|
|
cbox.ctail = con;
|
|
|
|
|
|
|
|
|
|
assert(con->mhead == nil);
|
|
|
|
|
assert(con->whead == nil);
|
|
|
|
|
assert(con->fhead == nil);
|
|
|
|
|
assert(con->nfid == 0);
|
|
|
|
|
|
|
|
|
|
con->state = ConNew;
|
|
|
|
|
con->fd = fd;
|
|
|
|
|
if(con->name != nil){
|
2013-09-23 23:16:25 +02:00
|
|
|
vtfree(con->name);
|
2013-09-23 23:00:39 +02:00
|
|
|
con->name = nil;
|
|
|
|
|
}
|
|
|
|
|
if(name != nil)
|
2013-09-23 23:16:25 +02:00
|
|
|
con->name = vtstrdup(name);
|
2013-09-23 23:00:39 +02:00
|
|
|
else
|
2013-09-23 23:16:25 +02:00
|
|
|
con->name = vtstrdup("unknown");
|
2013-09-23 23:00:39 +02:00
|
|
|
con->remote[0] = 0;
|
|
|
|
|
snprint(buf, sizeof buf, "%s/remote", con->name);
|
|
|
|
|
if((rfd = open(buf, OREAD)) >= 0){
|
|
|
|
|
n = read(rfd, buf, sizeof buf-1);
|
|
|
|
|
close(rfd);
|
|
|
|
|
if(n > 0){
|
|
|
|
|
buf[n] = 0;
|
|
|
|
|
if((p = strchr(buf, '\n')) != nil)
|
|
|
|
|
*p = 0;
|
|
|
|
|
strecpy(con->remote, con->remote+sizeof con->remote, buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
con->flags = flags;
|
|
|
|
|
con->isconsole = 0;
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&cbox.alock);
|
2013-09-23 23:00:39 +02:00
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
if(proccreate(msgWrite, con, STACK) < 0){
|
2013-09-23 23:00:39 +02:00
|
|
|
conFree(con);
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return con;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
cmdMsg(int argc, char* argv[])
|
|
|
|
|
{
|
|
|
|
|
char *p;
|
|
|
|
|
char *usage = "usage: msg [-m nmsg] [-p nproc]";
|
|
|
|
|
int maxmsg, nmsg, nmsgstarve, maxproc, nproc, nprocstarve;
|
|
|
|
|
|
|
|
|
|
maxmsg = maxproc = 0;
|
|
|
|
|
|
|
|
|
|
ARGBEGIN{
|
|
|
|
|
default:
|
|
|
|
|
return cliError(usage);
|
|
|
|
|
case 'm':
|
|
|
|
|
p = ARGF();
|
|
|
|
|
if(p == nil)
|
|
|
|
|
return cliError(usage);
|
|
|
|
|
maxmsg = strtol(argv[0], &p, 0);
|
|
|
|
|
if(maxmsg <= 0 || p == argv[0] || *p != '\0')
|
|
|
|
|
return cliError(usage);
|
|
|
|
|
break;
|
|
|
|
|
case 'p':
|
|
|
|
|
p = ARGF();
|
|
|
|
|
if(p == nil)
|
|
|
|
|
return cliError(usage);
|
|
|
|
|
maxproc = strtol(argv[0], &p, 0);
|
|
|
|
|
if(maxproc <= 0 || p == argv[0] || *p != '\0')
|
|
|
|
|
return cliError(usage);
|
|
|
|
|
break;
|
|
|
|
|
}ARGEND
|
|
|
|
|
if(argc)
|
|
|
|
|
return cliError(usage);
|
|
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&mbox.alock);
|
2013-09-23 23:00:39 +02:00
|
|
|
if(maxmsg)
|
|
|
|
|
mbox.maxmsg = maxmsg;
|
|
|
|
|
maxmsg = mbox.maxmsg;
|
|
|
|
|
nmsg = mbox.nmsg;
|
|
|
|
|
nmsgstarve = mbox.nmsgstarve;
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&mbox.alock);
|
2013-09-23 23:00:39 +02:00
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&mbox.rlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
if(maxproc)
|
|
|
|
|
mbox.maxproc = maxproc;
|
|
|
|
|
maxproc = mbox.maxproc;
|
|
|
|
|
nproc = mbox.nproc;
|
|
|
|
|
nprocstarve = mbox.nprocstarve;
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&mbox.rlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
|
|
|
|
|
consPrint("\tmsg -m %d -p %d\n", maxmsg, maxproc);
|
|
|
|
|
consPrint("\tnmsg %d nmsgstarve %d nproc %d nprocstarve %d\n",
|
|
|
|
|
nmsg, nmsgstarve, nproc, nprocstarve);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
scmp(Fid *a, Fid *b)
|
|
|
|
|
{
|
|
|
|
|
if(a == 0)
|
|
|
|
|
return 1;
|
|
|
|
|
if(b == 0)
|
|
|
|
|
return -1;
|
|
|
|
|
return strcmp(a->uname, b->uname);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Fid*
|
|
|
|
|
fidMerge(Fid *a, Fid *b)
|
|
|
|
|
{
|
|
|
|
|
Fid *s, **l;
|
|
|
|
|
|
|
|
|
|
l = &s;
|
|
|
|
|
while(a || b){
|
|
|
|
|
if(scmp(a, b) < 0){
|
|
|
|
|
*l = a;
|
|
|
|
|
l = &a->sort;
|
|
|
|
|
a = a->sort;
|
|
|
|
|
}else{
|
|
|
|
|
*l = b;
|
|
|
|
|
l = &b->sort;
|
|
|
|
|
b = b->sort;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*l = 0;
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Fid*
|
|
|
|
|
fidMergeSort(Fid *f)
|
|
|
|
|
{
|
|
|
|
|
int delay;
|
|
|
|
|
Fid *a, *b;
|
|
|
|
|
|
|
|
|
|
if(f == nil)
|
|
|
|
|
return nil;
|
|
|
|
|
if(f->sort == nil)
|
|
|
|
|
return f;
|
|
|
|
|
|
|
|
|
|
a = b = f;
|
|
|
|
|
delay = 1;
|
|
|
|
|
while(a && b){
|
|
|
|
|
if(delay) /* easy way to handle 2-element list */
|
|
|
|
|
delay = 0;
|
|
|
|
|
else
|
|
|
|
|
a = a->sort;
|
|
|
|
|
if(b = b->sort)
|
|
|
|
|
b = b->sort;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b = a->sort;
|
|
|
|
|
a->sort = nil;
|
|
|
|
|
|
|
|
|
|
a = fidMergeSort(f);
|
|
|
|
|
b = fidMergeSort(b);
|
|
|
|
|
|
|
|
|
|
return fidMerge(a, b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
cmdWho(int argc, char* argv[])
|
|
|
|
|
{
|
|
|
|
|
char *usage = "usage: who";
|
|
|
|
|
int i, l1, l2, l;
|
|
|
|
|
Con *con;
|
|
|
|
|
Fid *fid, *last;
|
|
|
|
|
|
|
|
|
|
ARGBEGIN{
|
|
|
|
|
default:
|
|
|
|
|
return cliError(usage);
|
|
|
|
|
}ARGEND
|
|
|
|
|
|
|
|
|
|
if(argc > 0)
|
|
|
|
|
return cliError(usage);
|
|
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
rlock(&cbox.clock);
|
2013-09-23 23:00:39 +02:00
|
|
|
l1 = 0;
|
|
|
|
|
l2 = 0;
|
|
|
|
|
for(con=cbox.chead; con; con=con->cnext){
|
|
|
|
|
if((l = strlen(con->name)) > l1)
|
|
|
|
|
l1 = l;
|
|
|
|
|
if((l = strlen(con->remote)) > l2)
|
|
|
|
|
l2 = l;
|
|
|
|
|
}
|
|
|
|
|
for(con=cbox.chead; con; con=con->cnext){
|
|
|
|
|
consPrint("\t%-*s %-*s", l1, con->name, l2, con->remote);
|
2013-09-23 23:16:25 +02:00
|
|
|
qlock(&con->fidlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
last = nil;
|
|
|
|
|
for(i=0; i<NFidHash; i++)
|
|
|
|
|
for(fid=con->fidhash[i]; fid; fid=fid->hash)
|
|
|
|
|
if(fid->fidno != NOFID && fid->uname){
|
|
|
|
|
fid->sort = last;
|
|
|
|
|
last = fid;
|
|
|
|
|
}
|
|
|
|
|
fid = fidMergeSort(last);
|
|
|
|
|
last = nil;
|
|
|
|
|
for(; fid; last=fid, fid=fid->sort)
|
|
|
|
|
if(last==nil || strcmp(fid->uname, last->uname) != 0)
|
|
|
|
|
consPrint(" %q", fid->uname);
|
2013-09-23 23:16:25 +02:00
|
|
|
qunlock(&con->fidlock);
|
2013-09-23 23:00:39 +02:00
|
|
|
consPrint("\n");
|
|
|
|
|
}
|
2013-09-23 23:16:25 +02:00
|
|
|
runlock(&cbox.clock);
|
2013-09-23 23:00:39 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
msgInit(void)
|
|
|
|
|
{
|
2013-09-23 23:16:25 +02:00
|
|
|
mbox.arendez.l = &mbox.alock;
|
2013-09-23 23:00:39 +02:00
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
mbox.rrendez.l = &mbox.rlock;
|
2013-09-23 23:00:39 +02:00
|
|
|
|
|
|
|
|
mbox.maxmsg = NMsgInit;
|
|
|
|
|
mbox.maxproc = NMsgProcInit;
|
|
|
|
|
mbox.msize = NMsizeInit;
|
|
|
|
|
|
|
|
|
|
cliAddCmd("msg", cmdMsg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
cmdCon(int argc, char* argv[])
|
|
|
|
|
{
|
|
|
|
|
char *p;
|
|
|
|
|
Con *con;
|
|
|
|
|
char *usage = "usage: con [-m ncon]";
|
|
|
|
|
int maxcon, ncon, nconstarve;
|
|
|
|
|
|
|
|
|
|
maxcon = 0;
|
|
|
|
|
|
|
|
|
|
ARGBEGIN{
|
|
|
|
|
default:
|
|
|
|
|
return cliError(usage);
|
|
|
|
|
case 'm':
|
|
|
|
|
p = ARGF();
|
|
|
|
|
if(p == nil)
|
|
|
|
|
return cliError(usage);
|
|
|
|
|
maxcon = strtol(argv[0], &p, 0);
|
|
|
|
|
if(maxcon <= 0 || p == argv[0] || *p != '\0')
|
|
|
|
|
return cliError(usage);
|
|
|
|
|
break;
|
|
|
|
|
}ARGEND
|
|
|
|
|
if(argc)
|
|
|
|
|
return cliError(usage);
|
|
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
wlock(&cbox.clock);
|
2013-09-23 23:00:39 +02:00
|
|
|
if(maxcon)
|
|
|
|
|
cbox.maxcon = maxcon;
|
|
|
|
|
maxcon = cbox.maxcon;
|
|
|
|
|
ncon = cbox.ncon;
|
|
|
|
|
nconstarve = cbox.nconstarve;
|
2013-09-23 23:16:25 +02:00
|
|
|
wunlock(&cbox.clock);
|
2013-09-23 23:00:39 +02:00
|
|
|
|
|
|
|
|
consPrint("\tcon -m %d\n", maxcon);
|
|
|
|
|
consPrint("\tncon %d nconstarve %d\n", ncon, nconstarve);
|
|
|
|
|
|
2013-09-23 23:16:25 +02:00
|
|
|
rlock(&cbox.clock);
|
2013-09-23 23:00:39 +02:00
|
|
|
for(con = cbox.chead; con != nil; con = con->cnext){
|
|
|
|
|
consPrint("\t%s\n", con->name);
|
|
|
|
|
}
|
2013-09-23 23:16:25 +02:00
|
|
|
runlock(&cbox.clock);
|
2013-09-23 23:00:39 +02:00
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
conInit(void)
|
|
|
|
|
{
|
2013-09-23 23:16:25 +02:00
|
|
|
cbox.arendez.l = &cbox.alock;
|
2013-09-23 23:00:39 +02:00
|
|
|
|
|
|
|
|
cbox.maxcon = NConInit;
|
|
|
|
|
cbox.msize = NMsizeInit;
|
|
|
|
|
|
|
|
|
|
cliAddCmd("con", cmdCon);
|
|
|
|
|
cliAddCmd("who", cmdWho);
|
|
|
|
|
}
|