/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <venti.h>#include <libsec.h> typedef struct Mem Mem;typedef struct Frag Frag; enum { BigMemSize = MaxFragSize, SmallMemSize = BigMemSize/8, NLocalFrag = 2}; /* position to carve out of a Mem */enum { PFront, PMiddle, PEnd}; struct Mem{ Lock lk; int ref; uchar *bp; uchar *ep; uchar *rp; uchar *wp; Mem *next;}; enum { FragLocalFree, FragLocalAlloc, FragGlobal}; struct Frag{ int state; Mem *mem; uchar *rp; uchar *wp; Frag *next; void (*free)(void*); void *a; Packet *p; /* parent packet, for debugging only */}; struct Packet{ int size; int asize; /* allocated memory - greater than size unless foreign frags */ ulong pc; Packet *next; Frag *first; Frag *last; Frag local[NLocalFrag];}; static Frag *fragalloc(Packet*, int n, int pos, Frag *next);static Frag *fragdup(Packet*, Frag*);static void fragfree(Frag*); static Mem *memalloc(int, int);static void memfree(Mem*);static int memhead(Mem *m, uchar *rp, int n);static int memtail(Mem *m, uchar *wp, int n); static char EPacketSize[] = "bad packet size";static char EPacketOffset[] = "bad packet offset";static char EBadSize[] = "bad size"; #ifdef NOTDEFstatic void checkpacket(Packet*);#endif /* * the free list is primarily for speed, but it is * also necessary for packetsplit that packets * are never freed -- a packet can contain a different * packet's local fragments, thanks to packetsplit! */static struct { Lock lk; Packet *packet; int npacket; Frag *frag; int nfrag; Mem *bigmem; int nbigmem; Mem *smallmem; int nsmallmem;} freelist; #define FRAGSIZE(f) ((f)->wp - (f)->rp)#define FRAGASIZE(f) ((f)->mem ? (f)->mem->ep - (f)->mem->bp : 0) #define NOTFREE(p) assert((p)->size>=0)/*; checkpacket(p)*/ Packet *packetalloc(void){ Packet *p; lock(&freelist.lk); p = freelist.packet; if(p != nil) freelist.packet = p->next; else freelist.npacket++; unlock(&freelist.lk); if(p == nil) p = vtbrk(sizeof(Packet)); else assert(p->size == -1); p->size = 0; p->asize = 0; p->first = nil; p->last = nil; p->next = nil; p->pc = getcallerpc((char*)&p+8); /* might not work, but fine */ NOTFREE(p); return p;} voidpacketfree(Packet *p){ Frag *f, *ff; if(p == nil) return; NOTFREE(p); p->pc = getcallerpc(&p); for(f=p->first; f!=nil; f=ff) { ff = f->next; fragfree(f); } p->first = (void*)0xDeadBeef; p->last = (void*)0xDeadBeef; p->size = -1; lock(&freelist.lk); p->next = freelist.packet; freelist.packet = p; unlock(&freelist.lk);} Packet *packetdup(Packet *p, int offset, int n){ Frag *f, *ff; Packet *pp; NOTFREE(p); if(offset < 0 || n < 0 || offset+n > p->size) { werrstr(EBadSize); return nil; } pp = packetalloc(); pp->pc = getcallerpc(&p); if(n == 0){ NOTFREE(pp); return pp; } pp->size = n; /* skip offset */ for(f=p->first; offset >= FRAGSIZE(f); f=f->next) offset -= FRAGSIZE(f); /* first frag */ ff = fragdup(pp, f); ff->rp += offset; pp->first = ff; n -= FRAGSIZE(ff); pp->asize += FRAGASIZE(ff); /* the remaining */ while(n > 0) { f = f->next; ff->next = fragdup(pp, f); ff = ff->next; n -= FRAGSIZE(ff); pp->asize += FRAGASIZE(ff); } /* fix up last frag: note n <= 0 */ ff->wp += n; ff->next = nil; pp->last = ff; NOTFREE(pp); NOTFREE(p); return pp;} Packet *packetsplit(Packet *p, int n){ Packet *pp; Frag *f, *ff; NOTFREE(p); if(n < 0 || n > p->size) { werrstr(EPacketSize); return nil; } pp = packetalloc(); pp->pc = getcallerpc(&p); if(n == 0){ NOTFREE(pp); return pp; } pp->size = n; p->size -= n; ff = nil; for(f=p->first; n > 0 && n >= FRAGSIZE(f); f=f->next) { n -= FRAGSIZE(f); p->asize -= FRAGASIZE(f); pp->asize += FRAGASIZE(f); f->p = pp; ff = f; } /* split shared frag */ if(n > 0) { f->p = pp; ff = f; f = fragdup(p, ff); pp->asize += FRAGASIZE(ff); ff->wp = ff->rp + n; f->rp += n; } pp->first = p->first; pp->last = ff; ff->next = nil; p->first = f; if(f == nil || f->next == nil) p->last = f; NOTFREE(pp); NOTFREE(p); return pp;} intpacketconsume(Packet *p, uchar *buf, int n){ NOTFREE(p); if(buf && packetcopy(p, buf, 0, n) < 0) return -1; return packettrim(p, n, p->size-n);} intpackettrim(Packet *p, int offset, int n){ Frag *f, *ff; NOTFREE(p); if(offset < 0 || offset > p->size) { werrstr(EPacketOffset); return -1; } if(n < 0 || offset + n > p->size) { werrstr(EPacketOffset); return -1; } p->size = n; /* easy case */ if(n == 0) { for(f=p->first; f != nil; f=ff) { ff = f->next; fragfree(f); } p->first = p->last = nil; p->asize = 0; NOTFREE(p); return 0; } /* free before offset */ for(f=p->first; offset >= FRAGSIZE(f); f=ff) { p->asize -= FRAGASIZE(f); offset -= FRAGSIZE(f); ff = f->next; fragfree(f); } /* adjust frag */ f->rp += offset; p->first = f; /* skip middle */ for(; n > 0 && n > FRAGSIZE(f); f=f->next) n -= FRAGSIZE(f); /* adjust end */ f->wp = f->rp + n; p->last = f; ff = f->next; f->next = nil; /* free after */ for(f=ff; f != nil; f=ff) { p->asize -= FRAGASIZE(f); ff = f->next; fragfree(f); } NOTFREE(p); return 0;} uchar *packetheader(Packet *p, int n){ Frag *f; Mem *m; NOTFREE(p); if(n <= 0 || n > MaxFragSize) { werrstr(EPacketSize); return nil; } p->size += n; /* try and fix in current frag */ f = p->first; if(f != nil) { m = f->mem; if(n <= f->rp - m->bp) if(m->ref == 1 || memhead(m, f->rp, n) >= 0) { f->rp -= n; NOTFREE(p); return f->rp; } } /* add frag to front */ f = fragalloc(p, n, PEnd, p->first); p->asize += FRAGASIZE(f); if(p->first == nil) p->last = f; p->first = f; NOTFREE(p); return f->rp;} uchar *packettrailer(Packet *p, int n){ Mem *m; Frag *f; NOTFREE(p); if(n <= 0 || n > MaxFragSize) { werrstr(EPacketSize); return nil; } p->size += n; /* try and fix in current frag */ if(p->first != nil) { f = p->last; m = f->mem; if(n <= m->ep - f->wp) if(m->ref == 1 || memtail(m, f->wp, n) >= 0) { f->wp += n; NOTFREE(p); return f->wp - n; } } /* add frag to end */ f = fragalloc(p, n, (p->first == nil)?PMiddle:PFront, nil); p->asize += FRAGASIZE(f); if(p->first == nil) p->first = f; else p->last->next = f; p->last = f; NOTFREE(p); return f->rp;} voidpacketprefix(Packet *p, uchar *buf, int n){ Frag *f; int nn; Mem *m; NOTFREE(p); if(n <= 0) return; p->size += n; /* try and fix in current frag */ f = p->first; if(f != nil) { m = f->mem; nn = f->rp - m->bp; if(nn > n) nn = n; if(m->ref == 1 || memhead(m, f->rp, nn) >= 0) { f->rp -= nn; n -= nn; memmove(f->rp, buf+n, nn); } } while(n > 0) { nn = n; if(nn > MaxFragSize) nn = MaxFragSize; f = fragalloc(p, nn, PEnd, p->first); p->asize += FRAGASIZE(f); if(p->first == nil) p->last = f; p->first = f; n -= nn; memmove(f->rp, buf+n, nn); } NOTFREE(p);} voidpacketappend(Packet *p, uchar *buf, int n){ Frag *f; int nn; Mem *m; NOTFREE(p); if(n <= 0) return; p->size += n; /* try and fix in current frag */ if(p->first != nil) { f = p->last; m = f->mem; nn = m->ep - f->wp; if(nn > n) nn = n; if(m->ref == 1 || memtail(m, f->wp, nn) >= 0) { memmove(f->wp, buf, nn); f->wp += nn; buf += nn; n -= nn; } } while(n > 0) { nn = n; if(nn > MaxFragSize) nn = MaxFragSize; f = fragalloc(p, nn, (p->first == nil)?PMiddle:PFront, nil); p->asize += FRAGASIZE(f); if(p->first == nil) p->first = f; else p->last->next = f; p->last = f; memmove(f->rp, buf, nn); buf += nn; n -= nn; } NOTFREE(p);} Lines 1–500 of 1034. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h> #include <libc.h> #include <venti.h> #include <libsec.h> typedef struct Mem Mem; typedef struct Frag Frag; enum { BigMemSize = MaxFragSize, SmallMemSize = BigMemSize/8, NLocalFrag = 2 }; /* position to carve out of a Mem */ enum { PFront, PMiddle, PEnd }; struct Mem { Lock lk; int ref; uchar *bp; uchar *ep; uchar *rp; uchar *wp; Mem *next; }; enum { FragLocalFree, FragLocalAlloc, FragGlobal }; struct Frag { int state; Mem *mem; uchar *rp; uchar *wp; Frag *next; void (*free)(void*); void *a; Packet *p; /* parent packet, for debugging only */ }; struct Packet { int size; int asize; /* allocated memory - greater than size unless foreign frags */ ulong pc; Packet *next; Frag *first; Frag *last; Frag local[NLocalFrag]; }; static Frag *fragalloc(Packet*, int n, int pos, Frag *next); static Frag *fragdup(Packet*, Frag*); static void fragfree(Frag*); static Mem *memalloc(int, int); static void memfree(Mem*); static int memhead(Mem *m, uchar *rp, int n); static int memtail(Mem *m, uchar *wp, int n); static char EPacketSize[] = "bad packet size"; static char EPacketOffset[] = "bad packet offset"; static char EBadSize[] = "bad size"; #ifdef NOTDEF static void checkpacket(Packet*); #endif /* * the free list is primarily for speed, but it is * also necessary for packetsplit that packets * are never freed -- a packet can contain a different * packet's local fragments, thanks to packetsplit! */ static struct { Lock lk; Packet *packet; int npacket; Frag *frag; int nfrag; Mem *bigmem; int nbigmem; Mem *smallmem; int nsmallmem; } freelist; #define FRAGSIZE(f) ((f)->wp - (f)->rp) #define FRAGASIZE(f) ((f)->mem ? (f)->mem->ep - (f)->mem->bp : 0) #define NOTFREE(p) assert((p)->size>=0)/*; checkpacket(p)*/ Packet * packetalloc(void) { Packet *p; lock(&freelist.lk); p = freelist.packet; if(p != nil) freelist.packet = p->next; else freelist.npacket++; unlock(&freelist.lk); if(p == nil) p = vtbrk(sizeof(Packet)); else assert(p->size == -1); p->size = 0; p->asize = 0; p->first = nil; p->last = nil; p->next = nil; p->pc = getcallerpc((char*)&p+8); /* might not work, but fine */ NOTFREE(p); return p; } void packetfree(Packet *p) { Frag *f, *ff; if(p == nil) return; NOTFREE(p); p->pc = getcallerpc(&p); for(f=p->first; f!=nil; f=ff) { ff = f->next; fragfree(f); } p->first = (void*)0xDeadBeef; p->last = (void*)0xDeadBeef; p->size = -1; lock(&freelist.lk); p->next = freelist.packet; freelist.packet = p; unlock(&freelist.lk); } Packet * packetdup(Packet *p, int offset, int n) { Frag *f, *ff; Packet *pp; NOTFREE(p); if(offset < 0 || n < 0 || offset+n > p->size) { werrstr(EBadSize); return nil; } pp = packetalloc(); pp->pc = getcallerpc(&p); if(n == 0){ NOTFREE(pp); return pp; } pp->size = n; /* skip offset */ for(f=p->first; offset >= FRAGSIZE(f); f=f->next) offset -= FRAGSIZE(f); /* first frag */ ff = fragdup(pp, f); ff->rp += offset; pp->first = ff; n -= FRAGSIZE(ff); pp->asize += FRAGASIZE(ff); /* the remaining */ while(n > 0) { f = f->next; ff->next = fragdup(pp, f); ff = ff->next; n -= FRAGSIZE(ff); pp->asize += FRAGASIZE(ff); } /* fix up last frag: note n <= 0 */ ff->wp += n; ff->next = nil; pp->last = ff; NOTFREE(pp); NOTFREE(p); return pp; } Packet * packetsplit(Packet *p, int n) { Packet *pp; Frag *f, *ff; NOTFREE(p); if(n < 0 || n > p->size) { werrstr(EPacketSize); return nil; } pp = packetalloc(); pp->pc = getcallerpc(&p); if(n == 0){ NOTFREE(pp); return pp; } pp->size = n; p->size -= n; ff = nil; for(f=p->first; n > 0 && n >= FRAGSIZE(f); f=f->next) { n -= FRAGSIZE(f); p->asize -= FRAGASIZE(f); pp->asize += FRAGASIZE(f); f->p = pp; ff = f; } /* split shared frag */ if(n > 0) { f->p = pp; ff = f; f = fragdup(p, ff); pp->asize += FRAGASIZE(ff); ff->wp = ff->rp + n; f->rp += n; } pp->first = p->first; pp->last = ff; ff->next = nil; p->first = f; if(f == nil || f->next == nil) p->last = f; NOTFREE(pp); NOTFREE(p); return pp; } int packetconsume(Packet *p, uchar *buf, int n) { NOTFREE(p); if(buf && packetcopy(p, buf, 0, n) < 0) return -1; return packettrim(p, n, p->size-n); } int packettrim(Packet *p, int offset, int n) { Frag *f, *ff; NOTFREE(p); if(offset < 0 || offset > p->size) { werrstr(EPacketOffset); return -1; } if(n < 0 || offset + n > p->size) { werrstr(EPacketOffset); return -1; } p->size = n; /* easy case */ if(n == 0) { for(f=p->first; f != nil; f=ff) { ff = f->next; fragfree(f); } p->first = p->last = nil; p->asize = 0; NOTFREE(p); return 0; } /* free before offset */ for(f=p->first; offset >= FRAGSIZE(f); f=ff) { p->asize -= FRAGASIZE(f); offset -= FRAGSIZE(f); ff = f->next; fragfree(f); } /* adjust frag */ f->rp += offset; p->first = f; /* skip middle */ for(; n > 0 && n > FRAGSIZE(f); f=f->next) n -= FRAGSIZE(f); /* adjust end */ f->wp = f->rp + n; p->last = f; ff = f->next; f->next = nil; /* free after */ for(f=ff; f != nil; f=ff) { p->asize -= FRAGASIZE(f); ff = f->next; fragfree(f); } NOTFREE(p); return 0; } uchar * packetheader(Packet *p, int n) { Frag *f; Mem *m; NOTFREE(p); if(n <= 0 || n > MaxFragSize) { werrstr(EPacketSize); return nil; } p->size += n; /* try and fix in current frag */ f = p->first; if(f != nil) { m = f->mem; if(n <= f->rp - m->bp) if(m->ref == 1 || memhead(m, f->rp, n) >= 0) { f->rp -= n; NOTFREE(p); return f->rp; } } /* add frag to front */ f = fragalloc(p, n, PEnd, p->first); p->asize += FRAGASIZE(f); if(p->first == nil) p->last = f; p->first = f; NOTFREE(p); return f->rp; } uchar * packettrailer(Packet *p, int n) { Mem *m; Frag *f; NOTFREE(p); if(n <= 0 || n > MaxFragSize) { werrstr(EPacketSize); return nil; } p->size += n; /* try and fix in current frag */ if(p->first != nil) { f = p->last; m = f->mem; if(n <= m->ep - f->wp) if(m->ref == 1 || memtail(m, f->wp, n) >= 0) { f->wp += n; NOTFREE(p); return f->wp - n; } } /* add frag to end */ f = fragalloc(p, n, (p->first == nil)?PMiddle:PFront, nil); p->asize += FRAGASIZE(f); if(p->first == nil) p->first = f; else p->last->next = f; p->last = f; NOTFREE(p); return f->rp; } void packetprefix(Packet *p, uchar *buf, int n) { Frag *f; int nn; Mem *m; NOTFREE(p); if(n <= 0) return; p->size += n; /* try and fix in current frag */ f = p->first; if(f != nil) { m = f->mem; nn = f->rp - m->bp; if(nn > n) nn = n; if(m->ref == 1 || memhead(m, f->rp, nn) >= 0) { f->rp -= nn; n -= nn; memmove(f->rp, buf+n, nn); } } while(n > 0) { nn = n; if(nn > MaxFragSize) nn = MaxFragSize; f = fragalloc(p, nn, PEnd, p->first); p->asize += FRAGASIZE(f); if(p->first == nil) p->last = f; p->first = f; n -= nn; memmove(f->rp, buf+n, nn); } NOTFREE(p); } void packetappend(Packet *p, uchar *buf, int n) { Frag *f; int nn; Mem *m; NOTFREE(p); if(n <= 0) return; p->size += n; /* try and fix in current frag */ if(p->first != nil) { f = p->last; m = f->mem; nn = m->ep - f->wp; if(nn > n) nn = n; if(m->ref == 1 || memtail(m, f->wp, nn) >= 0) { memmove(f->wp, buf, nn); f->wp += nn; buf += nn; n -= nn; } } while(n > 0) { nn = n; if(nn > MaxFragSize) nn = MaxFragSize; f = fragalloc(p, nn, (p->first == nil)?PMiddle:PFront, nil); p->asize += FRAGASIZE(f); if(p->first == nil) p->first = f; else p->last->next = f; p->last = f; memmove(f->rp, buf, nn); buf += nn; n -= nn; } NOTFREE(p); }