wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

commit 4c8870dda37c19d1b7518c307415937d09b06a36
parent 9322b3cfd4578eb9110131a5f3e32c5a2ced895f
Author: Kris Maglione <bsdaemon@wmii.de>
Date:   Wed, 21 Jun 2006 02:51:25 -0400

Made connection cleanup in ixp a bit more pedantic


Diffstat:
libixp/intmap.c | 3++-
libixp/ixp.h | 9++++-----
libixp/request.c | 79++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
3 files changed, 60 insertions(+), 31 deletions(-)

diff --git a/libixp/intmap.c b/libixp/intmap.c @@ -6,8 +6,9 @@ struct Intlist { unsigned long id; - void* aux; + void* aux; Intlist* link; + unsigned int ref; }; static unsigned long diff --git a/libixp/ixp.h b/libixp/ixp.h @@ -250,6 +250,7 @@ typedef struct IXPClient { typedef struct P9Conn P9Conn; typedef struct Fid { + P9Conn *conn; unsigned long fid; char omode; char *uid; @@ -258,22 +259,18 @@ typedef struct Fid { /* Implementation details */ /* do not use */ - P9Conn *conn; Intmap *map; } Fid; typedef struct Req Req; struct Req { + P9Conn *conn; Fid *fid; Fid *newfid; Req *oldreq; Fcall ifcall; Fcall ofcall; void *aux; - - /* Implementation detail */ - /* do not use */ - P9Conn *conn; }; typedef struct P9Srv { @@ -341,6 +338,8 @@ void serve_9pcon(IXPConn *c); /* intmap.c */ void initmap(Intmap *m, unsigned long nhash, void *hash); +void incref_map(Intmap *m); +void decref_map(Intmap *m); void freemap(Intmap *map, void (*destroy)(void*)); void execmap(Intmap *map, void (*destroy)(void*)); void* lookupkey(Intmap *map, unsigned long id); diff --git a/libixp/request.c b/libixp/request.c @@ -11,17 +11,19 @@ static void ixp_handle_req(Req *r); +/* We use string literals rather than arrays here because + * they're allocated in a readonly section */ static char - Eduptag[] = "tag in use", - Edupfid[] = "fid in use", - Enofunc[] = "function not implemented", - Ebotch[] = "9P protocol botch", - Enofile[] = "file does not exist", - Enofid[] = "fid does not exist", - Enotag[] = "tag does not exist", - Enotdir[] = "not a directory", - Einterrupted[] = "interrupted", - Eisdir[] = "cannot perform operation on a directory"; + *Eduptag = "tag in use", + *Edupfid = "fid in use", + *Enofunc = "function not implemented", + *Ebotch = "9P protocol botch", + *Enofile = "file does not exist", + *Enofid = "fid does not exist", + *Enotag = "tag does not exist", + *Enotdir = "not a directory", + *Einterrupted = "interrupted", + *Eisdir = "cannot perform operation on a directory"; enum { TAG_BUCKETS = 64, FID_BUCKETS = 64 }; @@ -35,8 +37,15 @@ struct P9Conn { IXPConn *conn; unsigned int msize; unsigned char *buf; + unsigned int ref; }; +static void +free_p9conn(P9Conn *pc) { + free(pc->buf); + free(pc); +} + void * createfid(Intmap *map, int fid, P9Conn *pc) { Fid *f = cext_emallocz(sizeof(Fid)); @@ -253,12 +262,18 @@ respond(Req *r, char *error) { free(r->ifcall.data); break; case TREMOVE: + destroyfid(pc, r->fid->fid); + break; case TCLUNK: destroyfid(pc, r->fid->fid); + if(!pc->conn && r->ifcall.tag == IXP_NOTAG) + pc->ref--; break; case TFLUSH: if((r->oldreq = lookupkey(&pc->tagmap, r->ifcall.oldtag))) respond(r->oldreq, Einterrupted); + if(!pc->conn && r->ifcall.tag == IXP_NOTAG) + pc->ref--; break; case TREAD: case TSTAT: @@ -288,61 +303,75 @@ respond(Req *r, char *error) { deletekey(&pc->tagmap, r->ifcall.tag);; free(r); + + if(!pc->conn && pc->ref == 0) + free_p9conn(pc); } -/* XXX: This cleanup code *needs* to be cleaned up */ +/* Pending request cleanup */ static void ixp_void_request(void *t) { - unsigned int tag; Req *r, *tr; P9Conn *pc; r = t; pc = r->conn; - /* XXX: need a better way of doing this */ - for(tag=0; lookupkey(&pc->tagmap, tag); tag++); tr = cext_emallocz(sizeof(Req)); tr->conn = pc; tr->ifcall.type = TFLUSH; - tr->ifcall.tag = tag; + tr->ifcall.tag = IXP_NOTAG; tr->ifcall.oldtag = r->ifcall.tag; ixp_handle_req(tr); } +/* Open FID cleanup */ static void ixp_void_fid(void *t) { - unsigned int tag; P9Conn *pc; Req *tr; Fid *f; f = t; pc = f->conn; - /* XXX: need a better way of doing this */ - for(tag=0; lookupkey(&pc->tagmap, tag); tag++); tr = cext_emallocz(sizeof(Req)); tr->fid = f; tr->conn = pc; tr->ifcall.type = TCLUNK; - tr->ifcall.tag = tag; + tr->ifcall.tag = IXP_NOTAG; tr->ifcall.fid = f->fid; ixp_handle_req(tr); } static void +ixp_p9conn_incref(void *r) { + P9Conn *pc = *(P9Conn **)r; + pc->ref++; +} + +/* To cleanup a connction, we increase the ref count for + * each open FID and pending request and generate clunk and + * flush requests. As each request is responded to and each + * FID is clunked, we decrease the ref count. When the ref + * count is 0, we free the P9Conn and its buf. The IXPConn + * is taken care of in server.c */ +static void ixp_cleanup_conn(IXPConn *c) { P9Conn *pc = c->aux; pc->conn = nil; - execmap(&pc->tagmap, ixp_void_request); - freemap(&pc->tagmap, nil); - execmap(&pc->fidmap, ixp_void_fid); - freemap(&pc->fidmap, nil); - free(pc->buf); - free(pc); + pc->ref = 1; + execmap(&pc->tagmap, ixp_p9conn_incref); + execmap(&pc->fidmap, ixp_p9conn_incref); + if(pc->ref > 1) { + execmap(&pc->tagmap, ixp_void_request); + execmap(&pc->fidmap, ixp_void_fid); + } + if(--pc->ref == 0) + free_p9conn(pc); } +/* Handle incoming 9P connections */ void serve_9pcon(IXPConn *c) { int fd = accept(c->fd, nil, nil);