1034 lines · 15.9 KB · C
RawDownload
/*  * 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.