V8/usr/sys/chunix/challoc.c
/*
* challoc.c
* Storage allocation routines for the Chaos N.C.P. for allocating
* packets, connections, and (possibly) tty structures for connections treated
* as UNIX tty's
*/
#include "../chunix/chsys.h"
#include "../chunix/chconf.h"
#include "../chaos/chaos.h"
#include "../h/buf.h"
#define BUFPRI PRIBIO /* Sleep priority for buffers */
#define b_bits b_blkno /* Bit map for chaos bufs in buffer (0=free) */
#define b_list b_resid /* Index in chsize that buffer belongs to */
#define b_nfree b_bcount /* Number of free chaos buffers in buffer */
#ifdef VMUNIX
#define CHMAXBUF 25
#define CHNMAXPKT 18
#define CHBSIZE BUFSIZE
#else
#define CHMAXBUF 12
#define CHNMAXPKT 9
#ifdef UCB_BUFOUT
#define CHBSIZE BUFSIZE
extern char abuffers[NABUF][CHBSIZE];
#else
#define CHBSIZE (BSIZE(0)+BSLOP)
extern char buffers[NBUF][CHBSIZE];
#endif UCB_BUFOUT
#endif VMUNIX
/*
* Structure for keeping track of various sizes of chaos buffers.
* Initialized values should be parameterized.
*/
struct chsize {
short ch_bufsize; /* Size of packets to allocate from buffer */
short ch_mxbufs; /* Maximum buffers to allocate to this size */
short ch_bufcount; /* The count of buffers already allocated */
short ch_buffree; /* Number of free buffers on this list now */
struct buf *ch_bufptr; /* Pointer to buffers of this size */
} Chsizes[] = {
#define CHMINPKT 32
{ CHMINPKT, 1, },
{ 128, 2, },
{ 512, CHNMAXPKT, },
#endif
};
#define NSIZES (sizeof(Chsizes)/sizeof(Chsizes[0]))
int Chbufwait; /* Someone's waiting for buffers */
struct buf *Chbuflist; /* Unassigned buffers */
int Chnbufs;
/*
* Allocate a chunk at least "size" large,
* set flag means called from interrupt level - don't hang waiting for buffers
* just return NULL
*/
char *
ch_alloc(size, flag)
{
register struct chsize *sp;
register struct buf *bp;
register int j;
long bit;
int opl;
opl = spl6();
again:
for (sp = Chsizes; sp < &Chsizes[NSIZES]; sp++) {
if (sp->ch_bufsize < size)
continue;
if (sp->ch_buffree == 0) {
if (sp->ch_bufcount == sp->ch_mxbufs ||
(bp = Chbuflist) == NULL)
continue;
Chbuflist = bp->av_forw;
bp->av_forw = sp->ch_bufptr;
sp->ch_bufptr = bp;
bp->b_nfree = j = BSIZE(0) / sp->ch_bufsize;
bp->b_bits = 0;
bp->b_list = sp - Chsizes;
sp->ch_buffree += j;
sp->ch_bufcount++;
} else
for (bp = sp->ch_bufptr;; bp = bp->av_forw)
if (bp == NULL)
panic("buffer lost somewhere");
else if (bp->b_nfree != 0)
break;
/* Here bp points to a buffer to allocate */
for (bit = 1L, j = 0; ; bit <<= 1, j++)
if (!(bit & bp->b_bits))
break;
bp->b_bits |= bit;
bp->b_nfree--;
sp->ch_buffree--;
debug(DALLOC,printf("Alloc: size=%d,adr = %x\n", size, bp->b_un.b_addr+(j * sp->ch_bufsize)));
splx(opl);
return (bp->b_un.b_addr+(j * sp->ch_bufsize));
}
if (!flag) {
Chbufwait++;
sleep((caddr_t)&Chbufwait, BUFPRI);
goto again;
}
debug(DALLOC|DABNOR,printf("Alloc: size=%d, failed\n", size));
splx(opl);
return((caddr_t)0);
}
/*
* Free the previously allocated storage at "p"
*/
ch_free(p)
char *p;
{
register struct buf *bp;
register struct chsize *sp;
register int opl;
long bit;
#ifdef UCB_BUFOUT
bp = &abuf[(p - abuffers) / CHBSIZE];
#else
bp = &buf[(p - buffers) / CHBSIZE];
#endif
sp = &Chsizes[bp->b_list];
debug(DALLOC,printf("Free: addr=%x\n", p));
bit = 1L << ((p - bp->b_un.b_addr) / sp->ch_bufsize);
if (!(bp->b_bits & bit)) {
printf("Free: buffer %x already freed\n", p);
panic("Chaos buffer already freed");
}
bp->b_nfree++;
bp->b_bits &= ~bit;
sp->ch_buffree++;
opl = spl6();
if (Chbufwait) {
wakeup((caddr_t)&Chbufwait);
Chbufwait = 0;
}
splx(opl);
}
#ifdef DEBUG
/*
* Check that address p is in the range of possible allocated packets
*/
ch_badaddr(p)
char *p;
{
register struct buf *bp;
register struct chsize *sp;
register int opl = spl6();
for (sp = Chsizes; sp < &Chsizes[NSIZES]; sp++)
for (bp = sp->ch_bufptr; bp; bp = bp->av_forw)
if (p >= bp->b_un.b_addr &&
p < bp->b_un.b_addr + BSIZE(0)) {
splx(opl);
return(0);
}
splx(opl);
return(1);
}
#endif
/*
* Return the size of the place pointed at by "p"
*/
ch_size(p)
char *p;
{
register struct buf *bp;
#ifdef UCB_BUFOUT
bp = &abuf[(p - abuffers) / CHBSIZE];
#else
bp = &buf[(p - buffers) / CHBSIZE];
#endif
return (Chsizes[bp->b_list].ch_bufsize);
}
/*
* Allocate some space when a new connection is created
*/
ch_bufalloc()
{
register int cnt;
register struct buf *bp;
struct buf *geteblk();
if (sizeof(bp->b_bits) != 4)
panic("challoc bits");
if (Chnbufs < 8)
cnt = 4;
else
cnt = 1;
if ((Chnbufs + cnt) > CHMAXBUF)
return;
Chnbufs += cnt;
for (; cnt > 0; cnt--) {
#ifndef VMUNIX
#ifdef UCB_BUFOUT
if (abfreelist.av_forw == &abfreelist)
#else
if (bfreelist.av_forw == &bfreelist)
#endif
break;
#endif VMUNIX
bp = geteblk();
LOCK;
bp->av_forw = Chbuflist;
Chbuflist = bp;
UNLOCK;
}
Chnbufs -= cnt;
}
ch_buffree()
{
register int cnt;
register struct buf *bp;
if (Chnbufs <= 8)
cnt = 4;
else
cnt = 1;
if (Chnbufs - cnt >= CHMAXBUF)
return;
LOCK;
for (; cnt > 0 && (bp = Chbuflist) != NULL; cnt--) {
Chbuflist = bp->av_forw;
#ifdef UCB_BUFOUT
abrelse(bp);
#else
brelse(bp);
#endif
Chnbufs--;
}
UNLOCK;
}