diff --git a/src/servers/app/server/BGet++.cpp b/src/servers/app/server/BGet++.cpp new file mode 100644 index 0000000000..220be48168 --- /dev/null +++ b/src/servers/app/server/BGet++.cpp @@ -0,0 +1,933 @@ +/*------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: bget++.cpp +// Author: John Walker +// DarkWyrm +// Description: public domain BGET pool allocator converted to C++ +// Distributed with OpenBeOS under MIT license +// +//------------------------------------------------------------------------------*/ + + +// Buffer allocation size quantum: all buffers allocated are a multiple of this size. ' +// This MUST be a power of two. +#define SizeQuant 4 + +#include +#include +#include +#include +#include + +// Declare the interface, including the requested buffer size type, ssize_t. +#include "BGet++.h" + +// Queue links +struct qlinks +{ + struct bfhead *flink; // Forward link + struct bfhead *blink; // Backward link +}; + +// Header in allocated and free buffers +struct bhead +{ + // Relative link back to previous free buffer in memory or 0 if previous + // buffer is allocated. + ssize_t prevfree; + + // Buffer size: positive if free, negative if allocated. + ssize_t bsize; +}; + +#define BH(p) ((struct bhead *) (p)) + +// Header in directly allocated buffers (by acqfcn) +struct bdhead +{ + ssize_t tsize; // Total size, including overhead + struct bhead bh; // Common header +}; + +#define BDH(p) ((struct bdhead *) (p)) + +// Header in free buffers +struct bfhead +{ + // Common allocated/free header + struct bhead bh; + + // Links on free list + struct qlinks ql; +}; + +#define BFH(p) ((struct bfhead *) (p)) + +static struct bfhead freelist = +{ + // List of free buffers + {0, 0}, + {&freelist, &freelist} +}; + + +// Total space currently allocated +//static ssize_t totalloc = 0; + +// Number of GetBuffer() and ReleaseBuffer() calls +//static long numget = 0, numrel = 0; + +// Number of pool blocks +//static long numpblk = 0; + + // Number of block gets and rels +//static long numpget = 0, numprel = 0; + +// Number of direct gets and rels +//static long numdget = 0, numdrel = 0; + +// Expansion block size +//static ssize_t exp_incr = 0; + +// 0: no AddToPool calls have been made +// -1: not all pool blocks are the same size +// >0: (common) block size for all AddToPool calls made so far +//static ssize_t pool_len = 0; + +// Automatic expansion block management functions +//static int (*compfcn)(ssize_t sizereq, int sequence) = NULL; +//static void *(*acqfcn)(ssize_t size) = NULL; +//static void (*relfcn)(void *buf) = NULL; + + +// Minimum allocation quantum: +#define QLSize (sizeof(struct qlinks)) +#define SizeQ ((SizeQuant > QLSize) ? SizeQuant : QLSize) + +// End sentinel: value placed in bsize field of dummy block delimiting end of +// pool block. The most negative number which will fit in a ssize_t, +// defined in a way that the compiler will accept. +#define ESent ((ssize_t) (-(((1L << (sizeof(ssize_t) * 8 - 2)) - 1) * 2) - 2)) + + +MemPool::MemPool(void) + : totalloc(0), + numget(0), + numrel(0), + numpblk(0), + numpget(0), + numprel(0), + numdget(0), + numdrel(0), + exp_incr(0), + pool_len(0) +{ +} + +MemPool::~MemPool(void) +{ +} + + + + + + + + + + + +// BGET -- Allocate a buffer. +void *MemPool::GetBuffer(ssize_t requested_size, bool zero) +{ + ssize_t size = requested_size; + struct bfhead *b; + + struct bfhead *best; + void *buf; + + int compactseq = 0; + + assert(size > 0); + + if (size < (ssize_t)SizeQ) + { + // Need at least room for the queue links. + size = SizeQ; + } + +#if SizeQuant > 1 + size = (size + (SizeQuant - 1)) & (~(SizeQuant - 1)); +#endif + + // Add overhead in allocated buffer to size required. + size += sizeof(struct bhead); + + // If a compact function was provided in the call to bectl(), wrap + // a loop around the allocation process to allow compaction to + // intervene in case we don't find a suitable buffer in the chain. + while (1) + { + b = freelist.ql.flink; + best = &freelist; + + + // Scan the free list searching for the first buffer big enough + // to hold the requested size buffer. + + while (b != &freelist) + { + if (b->bh.bsize >= size) + { + if ((best == &freelist) || (b->bh.bsize < best->bh.bsize)) + { + best = b; + } + } + + b = b->ql.flink; // Link to next buffer + } + b = best; + + while (b != &freelist) + { + if ((ssize_t) b->bh.bsize >= size) + { + + // Buffer is big enough to satisfy the request. Allocate it to the caller. + // We must decide whether the buffer is large enough to split into the part + // given to the caller and a free buffer that remains on the free list, or + // whether the entire buffer should be removed from the free list and given + // to the caller in its entirety. We only split the buffer if enough room + // remains for a header plus the minimum quantum of allocation. + + if ((b->bh.bsize - size) > (ssize_t)(SizeQ + (sizeof(struct bhead)))) + { + struct bhead *ba, *bn; + + ba = BH(((char *) b) + (b->bh.bsize - size)); + bn = BH(((char *) ba) + size); + assert(bn->prevfree == b->bh.bsize); + + // Subtract size from length of free block. + b->bh.bsize -= size; + + // Link allocated buffer to the previous free buffer. + ba->prevfree = b->bh.bsize; + + // Plug negative size into user buffer. + ba->bsize = -(ssize_t) size; + + // Mark buffer after this one not preceded by free block. + bn->prevfree = 0; + + totalloc += size; + numget++; // Increment number of GetBuffer() calls + + buf = (void *) ((((char *) ba) + sizeof(struct bhead))); + return buf; + } + else + { + struct bhead *ba; + + ba = BH(((char *) b) + b->bh.bsize); + assert(ba->prevfree == b->bh.bsize); + + // The buffer isn't big enough to split. Give the whole + // shebang to the caller and remove it from the free list. + + assert(b->ql.blink->ql.flink == b); + assert(b->ql.flink->ql.blink == b); + b->ql.blink->ql.flink = b->ql.flink; + b->ql.flink->ql.blink = b->ql.blink; + + totalloc += b->bh.bsize; + numget++; // Increment number of GetBuffer() calls + + // Negate size to mark buffer allocated. + b->bh.bsize = -(b->bh.bsize); + + // Zero the back pointer in the next buffer in memory + // to indicate that this buffer is allocated. + ba->prevfree = 0; + + // Give user buffer starting at queue links. + buf = (void *) &(b->ql); + return buf; + } + } + b = b->ql.flink; // Link to next buffer + } + + + // We failed to find a buffer. If there's a compact function + // defined, notify it of the size requested. If it returns + // TRUE, try the allocation again. + + if(!CompactMem(size, ++compactseq)) + break; + } + + // No buffer available with requested size free. + + // Don't give up yet -- look in the reserve supply. + if (size > (ssize_t)(exp_incr - sizeof(struct bhead))) + { + // Request is too large to fit in a single expansion + // block. Try to satisy it by a direct buffer acquisition. + struct bdhead *bdh; + + size += sizeof(struct bdhead) - sizeof(struct bhead); + if ((bdh = BDH(AcquireMem((ssize_t) size))) != NULL) + { + // Mark the buffer special by setting the size field + // of its header to zero. + bdh->bh.bsize = 0; + bdh->bh.prevfree = 0; + bdh->tsize = size; + + totalloc += size; + + // Increment number of GetBuffer() calls + numget++; + + // Direct GetBuffer() call count + numdget++; + + buf = (void *) (bdh + 1); + return buf; + } + + } + else + { + + // Try to obtain a new expansion block + void *newpool; + + if ((newpool = AcquireMem((ssize_t) exp_incr)) != NULL) + { + AddToPool(newpool, exp_incr); + + // This can't, I say, can't get into a loop + buf = GetBuffer(requested_size); + + return buf; + } + } + + // Still no buffer available + return NULL; + + // Code from bgetz -- zeroing code +/* + char *buf = (char *) GetBuffer(size); + + if (buf != NULL) + { + struct bhead *b; + ssize_t rsize; + + b = BH(buf - sizeof(struct bhead)); + rsize = -(b->bsize); + + if (rsize == 0) + { + struct bdhead *bd; + + bd = BDH(buf - sizeof(struct bdhead)); + rsize = bd->tsize - sizeof(struct bdhead); + } + else + { + rsize -= sizeof(struct bhead); + } + + assert(rsize >= size); + memset(buf, 0, (MemSize) rsize); + } + return ((void *) buf); +*/ + +} + +// BGETZ -- Allocate a buffer and clear its contents to zero. We clear +// the entire contents of the buffer to zero, not just the region +// requested by the caller. +/* +void *bgetz(ssize_t size) +{ + char *buf = (char *) GetBuffer(size); + + if (buf != NULL) + { + struct bhead *b; + ssize_t rsize; + + b = BH(buf - sizeof(struct bhead)); + rsize = -(b->bsize); + + if (rsize == 0) + { + struct bdhead *bd; + + bd = BDH(buf - sizeof(struct bdhead)); + rsize = bd->tsize - sizeof(struct bdhead); + } + else + { + rsize -= sizeof(struct bhead); + } + + assert(rsize >= size); + memset(buf, 0, (MemSize) rsize); + } + return ((void *) buf); +} +*/ + +// BGETR -- Reallocate a buffer. This is a minimal implementation, +// simply in terms of ReleaseBuffer() and GetBuffer(). It could be +// enhanced to allow the buffer to grow into adjacent free +// blocks and to avoid moving data unnecessarily. + +void *MemPool::ReallocateBuffer(void *buf, ssize_t size) +{ + void *nbuf; + + // Old size of buffer + ssize_t osize; + struct bhead *b; + + if ((nbuf = GetBuffer(size)) == NULL) + { + // Acquire new buffer + return NULL; + } + + if (buf == NULL) + { + return nbuf; + } + b = BH(((char *) buf) - sizeof(struct bhead)); + osize = -b->bsize; + + if (osize == 0) + { + // Buffer acquired directly through acqfcn. + struct bdhead *bd; + + bd = BDH(((char *) buf) - sizeof(struct bdhead)); + osize = bd->tsize - sizeof(struct bdhead); + } + else + osize -= sizeof(struct bhead); + assert(osize > 0); + + // Copy the data + memcpy((char *) nbuf, (char *) buf, (int) ((size < osize) ? size : osize)); + ReleaseBuffer(buf); + return nbuf; +} + +// BREL -- Release a buffer. +void MemPool::ReleaseBuffer(void *buf) +{ + struct bfhead *b, *bn; + + b = BFH(((char *) buf) - sizeof(struct bhead)); + + // Increment number of ReleaseBuffer() calls + numrel++; + + assert(buf != NULL); + + // Directly-acquired buffer? + if (b->bh.bsize == 0) + { + struct bdhead *bdh; + + bdh = BDH(((char *) buf) - sizeof(struct bdhead)); + assert(b->bh.prevfree == 0); + + totalloc -= bdh->tsize; + assert(totalloc >= 0); + + // Number of direct releases + numdrel++; + + memset((char *) buf, 0x55, (int) (bdh->tsize - sizeof(struct bdhead))); + + // Release it directly. + ReleaseMem((void *) bdh); + return; + } + + + // Buffer size must be negative, indicating that the buffer is allocated. + if (b->bh.bsize >= 0) + { + bn = NULL; + } + assert(b->bh.bsize < 0); + + // Back pointer in next buffer must be zero, indicating the same thing: + assert(BH((char *) b - b->bh.bsize)->prevfree == 0); + + totalloc += b->bh.bsize; + assert(totalloc >= 0); + + + // If the back link is nonzero, the previous buffer is free. + + if (b->bh.prevfree != 0) + { + // The previous buffer is free. Consolidate this buffer with it + // by adding the length of this buffer to the previous free + // buffer. Note that we subtract the size in the buffer being + // released, since it's negative to indicate that the buffer is allocated. + + register ssize_t size = b->bh.bsize; + + // Make the previous buffer the one we're working on. + assert(BH((char *) b - b->bh.prevfree)->bsize == b->bh.prevfree); + b = BFH(((char *) b) - b->bh.prevfree); + b->bh.bsize -= size; + } + else + { + // The previous buffer isn't allocated. Insert this buffer on the + // free list as an isolated free block. + assert(freelist.ql.blink->ql.flink == &freelist); + assert(freelist.ql.flink->ql.blink == &freelist); + b->ql.flink = &freelist; + b->ql.blink = freelist.ql.blink; + freelist.ql.blink = b; + b->ql.blink->ql.flink = b; + b->bh.bsize = -b->bh.bsize; + } + + // Now we look at the next buffer in memory, located by advancing from + // the start of this buffer by its size, to see if that buffer is + // free. If it is, we combine this buffer with the next one in + // memory, dechaining the second buffer from the free list. + + bn = BFH(((char *) b) + b->bh.bsize); + if (bn->bh.bsize > 0) + { + // The buffer is free. Remove it from the free list and add + // its size to that of our buffer. + assert(BH((char *) bn + bn->bh.bsize)->prevfree == bn->bh.bsize); + assert(bn->ql.blink->ql.flink == bn); + assert(bn->ql.flink->ql.blink == bn); + bn->ql.blink->ql.flink = bn->ql.flink; + bn->ql.flink->ql.blink = bn->ql.blink; + b->bh.bsize += bn->bh.bsize; + + // Finally, advance to the buffer that follows the newly + // consolidated free block. We must set its backpointer to the + // head of the consolidated free block. We know the next block + // must be an allocated block because the process of recombination + // guarantees that two free blocks will never be contiguous in + // memory. + bn = BFH(((char *) b) + b->bh.bsize); + } + + memset(((char *) b) + sizeof(struct bfhead), 0x55,(int) (b->bh.bsize - sizeof(struct bfhead))); + + assert(bn->bh.bsize < 0); + + // The next buffer is allocated. Set the backpointer in it to point + // to this buffer; the previous free buffer in memory. + bn->bh.prevfree = b->bh.bsize; + + // If a block-release function is defined, and this free buffer + // constitutes the entire block, release it. Note that pool_len + // is defined in such a way that the test will fail unless all + // pool blocks are the same size. + + if (((ssize_t) b->bh.bsize) == (ssize_t)(pool_len - sizeof(struct bhead))) + { + assert(b->bh.prevfree == 0); + assert(BH((char *) b + b->bh.bsize)->bsize == ESent); + assert(BH((char *) b + b->bh.bsize)->prevfree == b->bh.bsize); + + // Unlink the buffer from the free list + b->ql.blink->ql.flink = b->ql.flink; + b->ql.flink->ql.blink = b->ql.blink; + + ReleaseMem(b); + + // Nr of expansion block releases + numprel++; + + // Total number of blocks + numpblk--; + assert(numpblk == numpget - numprel); + } +} + +/* +// BECTL -- Establish automatic pool expansion control +void bectl( int (*compact) (ssize_t sizereq, int sequence), + void *(*acquire) (ssize_t size), + void (*release) (void *buf), + ssize_t pool_incr ) +{ + compfcn = compact; + acqfcn = acquire; + relfcn = release; + exp_incr = pool_incr; +} +*/ + +// BPOOL -- Add a region of memory to the buffer pool. +void MemPool::AddToPool(void *buf, ssize_t len) +{ + struct bfhead *b = BFH(buf); + struct bhead *bn; + + len &= ~(SizeQuant - 1); + + if (pool_len == 0) + { + pool_len = len; + } + else + if (len != pool_len) + { + pool_len = -1; + } + + // Number of block acquisitions + numpget++; + + // Number of blocks total + numpblk++; + assert(numpblk == numpget - numprel); + + // Since the block is initially occupied by a single free buffer, + // it had better not be (much) larger than the largest buffer + // whose size we can store in bhead.bsize. + assert(len - sizeof(struct bhead) <= -((ssize_t) ESent + 1)); + + // Clear the backpointer at the start of the block to indicate that + // there is no free block prior to this one. That blocks + // recombination when the first block in memory is released. + b->bh.prevfree = 0; + + // Chain the new block to the free list. + assert(freelist.ql.blink->ql.flink == &freelist); + assert(freelist.ql.flink->ql.blink == &freelist); + b->ql.flink = &freelist; + b->ql.blink = freelist.ql.blink; + freelist.ql.blink = b; + b->ql.blink->ql.flink = b; + + // Create a dummy allocated buffer at the end of the pool. This dummy + // buffer is seen when a buffer at the end of the pool is released and + // blocks recombination of the last buffer with the dummy buffer at + // the end. The length in the dummy buffer is set to the largest + // negative number to denote the end of the pool for diagnostic + // routines (this specific value is not counted on by the actual + // allocation and release functions). + + len -= sizeof(struct bhead); + b->bh.bsize = (ssize_t) len; + + memset(((char *) b) + sizeof(struct bfhead), 0x55,(int) (len - sizeof(struct bfhead))); + + bn = BH(((char *) b) + len); + bn->prevfree = (ssize_t) len; + + // Definition of ESent assumes two's complement! + assert((~0) == -1); + bn->bsize = ESent; +} + + +// BSTATS -- Return buffer allocation free space statistics. +void MemPool::Stats(ssize_t *curalloc, ssize_t *totfree, ssize_t *maxfree, + long *nget, long *nrel) +{ + struct bfhead *b = freelist.ql.flink; + + *nget = numget; + *nrel = numrel; + *curalloc = totalloc; + *totfree = 0; + *maxfree = -1; + while (b != &freelist) + { + assert(b->bh.bsize > 0); + *totfree += b->bh.bsize; + if (b->bh.bsize > *maxfree) + { + *maxfree = b->bh.bsize; + } + + // Link to next buffer + b = b->ql.flink; + } +} + + +// BSTATSE -- Return extended statistics +void MemPool::ExtendedStats(ssize_t *pool_incr, long *npool, long *npget, long *nprel, + long *ndget, long *ndrel) +{ + *pool_incr = (pool_len < 0) ? -exp_incr : exp_incr; + *npool = numpblk; + *npget = numpget; + *nprel = numprel; + *ndget = numdget; + *ndrel = numdrel; +} + + + +// BUFDUMP -- Dump the data in a buffer. This is called with the user +// data pointer, and backs up to the buffer header. It will +// dump either a free block or an allocated one. +void MemPool::BufferDump(void *buf) +{ + struct bfhead *b; + unsigned char *bdump; + ssize_t bdlen; + + b = BFH(((char *) buf) - sizeof(struct bhead)); + assert(b->bh.bsize != 0); + if (b->bh.bsize < 0) + { + bdump = (unsigned char *) buf; + bdlen = (-b->bh.bsize) - sizeof(struct bhead); + } + else + { + bdump = (unsigned char *) (((char *) b) + sizeof(struct bfhead)); + bdlen = b->bh.bsize - sizeof(struct bfhead); + } + + while (bdlen > 0) + { + int i, dupes = 0; + ssize_t l = bdlen; + char bhex[50], bascii[20]; + + if (l > 16) + { + l = 16; + } + + for (i = 0; i < l; i++) + { + sprintf(bhex + i * 3, "%02X ", bdump[i]); + bascii[i] = isprint(bdump[i]) ? bdump[i] : ' '; + } + bascii[i] = 0; + printf("%-48s %s\n", bhex, bascii); + bdump += l; + bdlen -= l; + while ((bdlen > 16) && (memcmp((char *) (bdump - 16),(char *) bdump, 16) == 0)) + { + dupes++; + bdump += 16; + bdlen -= 16; + } + + if (dupes > 1) + { + printf(" (%d lines [%d bytes] identical to above line skipped)\n", + dupes, dupes * 16); + } + else + { + if (dupes == 1) + { + bdump -= 16; + bdlen += 16; + } + } + } +} + +// BPOOLD -- Dump a buffer pool. The buffer headers are always listed. +// If DUMPALLOC is nonzero, the contents of allocated buffers +// are dumped. If DUMPFREE is nonzero, free blocks are +// dumped as well. If FreeWipe checking is enabled, free +// blocks which have been clobbered will always be dumped. +void MemPool::PoolDump(void *buf, bool dumpalloc, bool dumpfree) +{ + struct bfhead *b = BFH(buf); + + while (b->bh.bsize != ESent) + { + ssize_t bs = b->bh.bsize; + + if (bs < 0) + { + bs = -bs; + printf("Allocated buffer: size %6ld bytes.\n", (long) bs); + if (dumpalloc) + { + BufferDump((void *) (((char *) b) + sizeof(struct bhead))); + } + } + else + { + char *lerr = ""; + + assert(bs > 0); + if ((b->ql.blink->ql.flink != b) || (b->ql.flink->ql.blink != b)) + { + lerr = " (Bad free list links)"; + } + printf("Free block: size %6ld bytes.%s\n", + (long) bs, lerr); + + lerr = ((char *) b) + sizeof(struct bfhead); + if ((bs > (ssize_t)sizeof(struct bfhead)) && ((*lerr != 0x55) || + (memcmp(lerr, lerr + 1, (int) (bs - (sizeof(struct bfhead) + 1))) != 0))) + { + printf("(Contents of above free block have been overstored.)\n"); + BufferDump((void *) (((char *) b) + sizeof(struct bhead))); + } + else + { + if (dumpfree) + { + BufferDump((void *) (((char *) b) + sizeof(struct bhead))); + } + } + } + b = BFH(((char *) b) + bs); + } +} + +// BPOOLV -- Validate a buffer pool. +int MemPool::Validate(void *buf) +{ + struct bfhead *b = BFH(buf); + + while (b->bh.bsize != ESent) + { + ssize_t bs = b->bh.bsize; + + if (bs < 0) + { + bs = -bs; + } + else + { + char *lerr = ""; + + assert(bs > 0); + if (bs <= 0) + { + return 0; + } + + if ((b->ql.blink->ql.flink != b) || (b->ql.flink->ql.blink != b)) + { + printf("Free block: size %6ld bytes. (Bad free list links)\n", + (long) bs); + assert(0); + return 0; + } + + lerr = ((char *) b) + sizeof(struct bfhead); + if ((bs > (ssize_t)sizeof(struct bfhead)) && ((*lerr != 0x55) || + (memcmp(lerr, lerr + 1,(int) (bs - (sizeof(struct bfhead) + 1))) != 0))) + { + printf("(Contents of above free block have been overstored.)\n"); + BufferDump((void *) (((char *) b) + sizeof(struct bhead))); + assert(0); + return 0; + } + + } + b = BFH(((char *) b) + bs); + } + return 1; +} + +int *MemPool::CompactMem(ssize_t sizereq, int sequence) +{ + return NULL; +} + +void *MemPool::AcquireMem(ssize_t size) +{ + return NULL; +} + +void MemPool::ReleaseMem(void *buffer) +{ +} + +AreaPool::AreaPool(void) +{ +} + +AreaPool::~AreaPool(void) +{ +} + +void *AreaPool::AcquireMem(ssize_t size) +{ + long areasize=0; + area_id a; + int *parea; + + if(size + +class MemPool +{ +public: + MemPool(void); + virtual ~MemPool(void); + + void AddToPool(void *buffer, ssize_t len); + void *GetBuffer(ssize_t size, bool zero=false); + void *ReallocateBuffer(void *buffer, ssize_t size); + void ReleaseBuffer(void *buffer); + + virtual int *CompactMem(ssize_t sizereq, int sequence); + virtual void *AcquireMem(ssize_t size); + virtual void ReleaseMem(void *buffer); + void SetPoolIncrement(ssize_t increment); + ssize_t PoolIncrement(void); + + void Stats(ssize_t *curalloc, ssize_t *totfree, ssize_t *maxfree, + long *nget, long *nrel); + + void ExtendedStats(ssize_t *pool_incr, long *npool, long *npget, + long *nprel, long *ndget, long *ndrel); + + void BufferDump(void *buf); + void PoolDump(void *pool, bool dumpalloc, bool dumpfree); + int Validate(void *buffer); + +private: + ssize_t totalloc; + long numget, numrel; + long numpblk; + long numpget, numprel; + long numdget, numdrel; + ssize_t exp_incr; + ssize_t pool_len; + +}; + +class AreaPool : public MemPool +{ +public: + AreaPool(void); + virtual ~AreaPool(void); + virtual void *AcquireMem(ssize_t size); + virtual void ReleaseMem(void *buffer); +}; + +#endif diff --git a/src/servers/app/server/BitmapManager.cpp b/src/servers/app/server/BitmapManager.cpp index 2e9a4aee4d..270bb325b5 100644 --- a/src/servers/app/server/BitmapManager.cpp +++ b/src/servers/app/server/BitmapManager.cpp @@ -27,40 +27,18 @@ #include "BitmapManager.h" #include "ServerBitmap.h" #include +#include "BGet++.h" //! The bitmap allocator for the server. Memory is allocated/freed by the AppServer class BitmapManager *bitmapmanager=NULL; -//! BGET function calls - defined here because of C++ name mangling causing link problems -typedef long bufsize; -extern "C" void bpool(void *buffer, bufsize len); -extern "C" void *bget(bufsize size); -extern "C" void *bgetz(bufsize size); -extern "C" void *bgetr(void *buffer, bufsize newsize); -extern "C" void brel(void *buf); -extern "C" void bectl(int (*compact)(bufsize sizereq, int sequence), - void *(*acquire)(bufsize size), - void (*release)(void *buf), bufsize pool_incr); -extern "C" void bstats(bufsize *curalloc, bufsize *totfree, bufsize *maxfree, - long *nget, long *nrel); -extern "C" void bstatse(bufsize *pool_incr, long *npool, long *npget, - long *nprel, long *ndget, long *ndrel); -extern "C" void bufdump(void *buf); -extern "C" void bpoold(void *pool, int dumpalloc, int dumpfree); -extern "C" int bpoolv(void *pool); - -/*! - \brief This is a call which makes BGET use a couple of home-grown functions which - manage the buffer via area functions -*/ -extern "C" void set_area_buffer_management(void); - //! Number of bytes to allocate to each area used for bitmap storage #define BITMAP_AREA_SIZE B_PAGE_SIZE * 2 //! Sets up stuff to be ready to allocate space for bitmaps BitmapManager::BitmapManager(void) { + fMemPool=new AreaPool; bmplist=new BList(0); // When create_area is passed the B_ANY_ADDRESS flag, the address of the area @@ -76,8 +54,7 @@ BitmapManager::BitmapManager(void) if(lock<0) printf("PANIC: BitmapManager couldn't allocate locking semaphore!!\n"); - set_area_buffer_management(); - bpool(buffer,BITMAP_AREA_SIZE); + fMemPool->AddToPool(buffer,BITMAP_AREA_SIZE); } //! Deallocates everything associated with the manager @@ -92,12 +69,13 @@ BitmapManager::~BitmapManager(void) tbmp=(ServerBitmap*)bmplist->RemoveItem(0L); if(tbmp) { - brel(tbmp->_buffer); + fMemPool->ReleaseBuffer(tbmp->_buffer); delete tbmp; tbmp=NULL; } } } + delete fMemPool; delete bmplist; delete_area(bmparea); delete_sem(lock); @@ -120,7 +98,7 @@ ServerBitmap * BitmapManager::CreateBitmap(BRect bounds, color_space space, int3 // Server version of this code will also need to handle such things as // bitmaps which accept child views by checking the flags. - uint8 *bmpbuffer=(uint8 *)bget(bmp->BitsLength()); + uint8 *bmpbuffer=(uint8 *)fMemPool->GetBuffer(bmp->BitsLength()); if(!bmpbuffer) { @@ -158,7 +136,7 @@ void BitmapManager::DeleteBitmap(ServerBitmap *bitmap) } // Server code will require a check to ensure bitmap doesn't have its own area - brel(tbmp->_buffer); + fMemPool->ReleaseBuffer(tbmp->_buffer); delete tbmp; release_sem(lock); diff --git a/src/servers/app/server/Jamfile b/src/servers/app/server/Jamfile index ddababdd90..33ded7ea98 100644 --- a/src/servers/app/server/Jamfile +++ b/src/servers/app/server/Jamfile @@ -9,9 +9,8 @@ UsePrivateHeaders app interface [ FDirName servers app ] ; UseFreeTypeHeaders ; SharedLibrary appserver : - areafunc.c Angle.cpp - bget.c + BGet++.cpp BitmapManager.cpp ColorSet.cpp Decorator.cpp diff --git a/src/servers/app/server/areafunc.c b/src/servers/app/server/areafunc.c deleted file mode 100644 index 913a2f0b52..0000000000 --- a/src/servers/app/server/areafunc.c +++ /dev/null @@ -1,75 +0,0 @@ -/*------------------------------------------------------------------------------ -// Copyright (c) 2001-2002, OpenBeOS -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. -// -// File Name: areafunc.c -// Author: DarkWyrm -// Description: C functions for interfacing with the BGET pool allocator -// -//------------------------------------------------------------------------------*/ -#include -#include "bget.h" -#include - -void set_area_buffer_management(void); -void * expand_area_storage(long size); -void contract_area_storage(void *buffer); - -void set_area_buffer_management(void) -{ - bectl(NULL, expand_area_storage, contract_area_storage, B_PAGE_SIZE); -} - -void * expand_area_storage(long size) -{ - long areasize=0; - area_id a; - int *parea; - - if(size -// Description: BGET pool allocator. Originally released into public domain. -// Distributed with OpenBeOS under MIT license -// -//------------------------------------------------------------------------------*/ -/*#define DoTestProg 1*/ /* defined if not used as a library */ -#define NDEBUG -#define TestProg 20000 /* Generate built-in test program - if defined. The value specifies - how many buffer allocation attempts - the test program should make. */ - -#define SizeQuant 4 /* Buffer allocation size quantum: - all buffers allocated are a - multiple of this size. This - MUST be a power of two. */ - -#define BufDump 1 /* Define this symbol to enable the - bpoold() function which dumps the - buffers in a buffer pool. */ - -#define BufValid 1 /* Define this symbol to enable the - bpoolv() function for validating - a buffer pool. */ - -#define DumpData 1 /* Define this symbol to enable the - bufdump() function which allows - dumping the contents of an allocated - or free buffer. */ - -#define BufStats 1 /* Define this symbol to enable the - bstats() function which calculates - the total free space in the buffer - pool, the largest available - buffer, and the total space - currently allocated. */ - -#define FreeWipe 1 /* Wipe free buffers to a guaranteed - pattern of garbage to trip up - miscreants who attempt to use - pointers into released buffers. */ - -#define BestFit 1 /* Use a best fit algorithm when - searching for space for an - allocation request. This uses - memory more efficiently, but - allocation will be much slower. */ - -#define BECtl 1 /* Define this symbol to enable the - bectl() function for automatic - pool space control. */ - -#include - -#ifdef lint -#define NDEBUG /* Exits in asserts confuse lint */ -/* LINTLIBRARY */ /* Don't complain about def, no ref */ -extern char *sprintf(); /* Sun includes don't define sprintf */ -#endif - -#include -#include - -#ifdef BufDump /* BufDump implies DumpData */ -#ifndef DumpData -#define DumpData 1 -#endif -#endif - -#ifdef DumpData -#include -#endif - -/* Declare the interface, including the requested buffer size type, - bufsize. */ - -#include "bget.h" - -#define MemSize int /* Type for size arguments to memxxx() - functions such as memcmp(). */ - -/* Queue links */ - -struct qlinks { - struct bfhead *flink; /* Forward link */ - struct bfhead *blink; /* Backward link */ -}; - -/* Header in allocated and free buffers */ - -struct bhead { - bufsize prevfree; /* Relative link back to previous - free buffer in memory or 0 if - previous buffer is allocated. */ - bufsize bsize; /* Buffer size: positive if free, - negative if allocated. */ -}; -#define BH(p) ((struct bhead *) (p)) - -/* Header in directly allocated buffers (by acqfcn) */ - -struct bdhead { - bufsize tsize; /* Total size, including overhead */ - struct bhead bh; /* Common header */ -}; -#define BDH(p) ((struct bdhead *) (p)) - -/* Header in free buffers */ - -struct bfhead { - struct bhead bh; /* Common allocated/free header */ - struct qlinks ql; /* Links on free list */ -}; -#define BFH(p) ((struct bfhead *) (p)) - -static struct bfhead freelist = { /* List of free buffers */ - {0, 0}, - {&freelist, &freelist} -}; - - -#ifdef BufStats -static bufsize totalloc = 0; /* Total space currently allocated */ -static long numget = 0, numrel = 0; /* Number of bget() and brel() calls */ -#ifdef BECtl -static long numpblk = 0; /* Number of pool blocks */ -static long numpget = 0, numprel = 0; /* Number of block gets and rels */ -static long numdget = 0, numdrel = 0; /* Number of direct gets and rels */ -#endif /* BECtl */ -#endif /* BufStats */ - -#ifdef BECtl - -/* Automatic expansion block management functions */ - -static int (*compfcn) _((bufsize sizereq, int sequence)) = NULL; -static void *(*acqfcn) _((bufsize size)) = NULL; -static void (*relfcn) _((void *buf)) = NULL; - -static bufsize exp_incr = 0; /* Expansion block size */ -static bufsize pool_len = 0; /* 0: no bpool calls have been made - -1: not all pool blocks are - the same size - >0: (common) block size for all - bpool calls made so far - */ -#endif - -/* Minimum allocation quantum: */ - -#define QLSize (sizeof(struct qlinks)) -#define SizeQ ((SizeQuant > QLSize) ? SizeQuant : QLSize) - -#define V (void) /* To denote unwanted returned values */ - -/* End sentinel: value placed in bsize field of dummy block delimiting - end of pool block. The most negative number which will fit in a - bufsize, defined in a way that the compiler will accept. */ - -#define ESent ((bufsize) (-(((1L << (sizeof(bufsize) * 8 - 2)) - 1) * 2) - 2)) - -/* BGET -- Allocate a buffer. */ - -void *bget(requested_size) - bufsize requested_size; -{ - bufsize size = requested_size; - struct bfhead *b; -#ifdef BestFit - struct bfhead *best; -#endif - void *buf; -#ifdef BECtl - int compactseq = 0; -#endif - - assert(size > 0); - - if (size < (bufsize)SizeQ) { /* Need at least room for the */ - size = SizeQ; /* queue links. */ - } -#ifdef SizeQuant -#if SizeQuant > 1 - size = (size + (SizeQuant - 1)) & (~(SizeQuant - 1)); -#endif -#endif - - size += sizeof(struct bhead); /* Add overhead in allocated buffer - to size required. */ - -#ifdef BECtl - /* If a compact function was provided in the call to bectl(), wrap - a loop around the allocation process to allow compaction to - intervene in case we don't find a suitable buffer in the chain. */ - - while (1) { -#endif - b = freelist.ql.flink; -#ifdef BestFit - best = &freelist; -#endif - - - /* Scan the free list searching for the first buffer big enough - to hold the requested size buffer. */ - -#ifdef BestFit - while (b != &freelist) { - if (b->bh.bsize >= size) { - if ((best == &freelist) || (b->bh.bsize < best->bh.bsize)) { - best = b; - } - } - b = b->ql.flink; /* Link to next buffer */ - } - b = best; -#endif /* BestFit */ - - while (b != &freelist) { - if ((bufsize) b->bh.bsize >= size) { - - /* Buffer is big enough to satisfy the request. Allocate it - to the caller. We must decide whether the buffer is large - enough to split into the part given to the caller and a - free buffer that remains on the free list, or whether the - entire buffer should be removed from the free list and - given to the caller in its entirety. We only split the - buffer if enough room remains for a header plus the minimum - quantum of allocation. */ - - if ((b->bh.bsize - size) > (bufsize)(SizeQ + (sizeof(struct bhead)))) { - struct bhead *ba, *bn; - - ba = BH(((char *) b) + (b->bh.bsize - size)); - bn = BH(((char *) ba) + size); - assert(bn->prevfree == b->bh.bsize); - /* Subtract size from length of free block. */ - b->bh.bsize -= size; - /* Link allocated buffer to the previous free buffer. */ - ba->prevfree = b->bh.bsize; - /* Plug negative size into user buffer. */ - ba->bsize = -(bufsize) size; - /* Mark buffer after this one not preceded by free block. */ - bn->prevfree = 0; - -#ifdef BufStats - totalloc += size; - numget++; /* Increment number of bget() calls */ -#endif - buf = (void *) ((((char *) ba) + sizeof(struct bhead))); - return buf; - } else { - struct bhead *ba; - - ba = BH(((char *) b) + b->bh.bsize); - assert(ba->prevfree == b->bh.bsize); - - /* The buffer isn't big enough to split. Give the whole - shebang to the caller and remove it from the free list. */ - - assert(b->ql.blink->ql.flink == b); - assert(b->ql.flink->ql.blink == b); - b->ql.blink->ql.flink = b->ql.flink; - b->ql.flink->ql.blink = b->ql.blink; - -#ifdef BufStats - totalloc += b->bh.bsize; - numget++; /* Increment number of bget() calls */ -#endif - /* Negate size to mark buffer allocated. */ - b->bh.bsize = -(b->bh.bsize); - - /* Zero the back pointer in the next buffer in memory - to indicate that this buffer is allocated. */ - ba->prevfree = 0; - - /* Give user buffer starting at queue links. */ - buf = (void *) &(b->ql); - return buf; - } - } - b = b->ql.flink; /* Link to next buffer */ - } -#ifdef BECtl - - /* We failed to find a buffer. If there's a compact function - defined, notify it of the size requested. If it returns - TRUE, try the allocation again. */ - - if ((compfcn == NULL) || (!(*compfcn)(size, ++compactseq))) { - break; - } - } - - /* No buffer available with requested size free. */ - - /* Don't give up yet -- look in the reserve supply. */ - - if (acqfcn != NULL) { - if (size > (bufsize)(exp_incr - sizeof(struct bhead))) { - - /* Request is too large to fit in a single expansion - block. Try to satisy it by a direct buffer acquisition. */ - - struct bdhead *bdh; - - size += sizeof(struct bdhead) - sizeof(struct bhead); - if ((bdh = BDH((*acqfcn)((bufsize) size))) != NULL) { - - /* Mark the buffer special by setting the size field - of its header to zero. */ - bdh->bh.bsize = 0; - bdh->bh.prevfree = 0; - bdh->tsize = size; -#ifdef BufStats - totalloc += size; - numget++; /* Increment number of bget() calls */ - numdget++; /* Direct bget() call count */ -#endif - buf = (void *) (bdh + 1); - return buf; - } - - } else { - - /* Try to obtain a new expansion block */ - - void *newpool; - - if ((newpool = (*acqfcn)((bufsize) exp_incr)) != NULL) { - bpool(newpool, exp_incr); - buf = bget(requested_size); /* This can't, I say, can't - get into a loop. */ - return buf; - } - } - } - - /* Still no buffer available */ - -#endif /* BECtl */ - - return NULL; -} - -/* BGETZ -- Allocate a buffer and clear its contents to zero. We clear - the entire contents of the buffer to zero, not just the - region requested by the caller. */ - -void *bgetz(size) - bufsize size; -{ - char *buf = (char *) bget(size); - - if (buf != NULL) { - struct bhead *b; - bufsize rsize; - - b = BH(buf - sizeof(struct bhead)); - rsize = -(b->bsize); - if (rsize == 0) { - struct bdhead *bd; - - bd = BDH(buf - sizeof(struct bdhead)); - rsize = bd->tsize - sizeof(struct bdhead); - } else { - rsize -= sizeof(struct bhead); - } - assert(rsize >= size); - V memset(buf, 0, (MemSize) rsize); - } - return ((void *) buf); -} - -/* BGETR -- Reallocate a buffer. This is a minimal implementation, - simply in terms of brel() and bget(). It could be - enhanced to allow the buffer to grow into adjacent free - blocks and to avoid moving data unnecessarily. */ - -void *bgetr(buf, size) - void *buf; - bufsize size; -{ - void *nbuf; - bufsize osize; /* Old size of buffer */ - struct bhead *b; - - if ((nbuf = bget(size)) == NULL) { /* Acquire new buffer */ - return NULL; - } - if (buf == NULL) { - return nbuf; - } - b = BH(((char *) buf) - sizeof(struct bhead)); - osize = -b->bsize; -#ifdef BECtl - if (osize == 0) { - /* Buffer acquired directly through acqfcn. */ - struct bdhead *bd; - - bd = BDH(((char *) buf) - sizeof(struct bdhead)); - osize = bd->tsize - sizeof(struct bdhead); - } else -#endif - osize -= sizeof(struct bhead); - assert(osize > 0); - V memcpy((char *) nbuf, (char *) buf, /* Copy the data */ - (MemSize) ((size < osize) ? size : osize)); - brel(buf); - return nbuf; -} - -/* BREL -- Release a buffer. */ - -void brel(buf) - void *buf; -{ - struct bfhead *b, *bn; - - b = BFH(((char *) buf) - sizeof(struct bhead)); -#ifdef BufStats - numrel++; /* Increment number of brel() calls */ -#endif - assert(buf != NULL); - -#ifdef BECtl - if (b->bh.bsize == 0) { /* Directly-acquired buffer? */ - struct bdhead *bdh; - - bdh = BDH(((char *) buf) - sizeof(struct bdhead)); - assert(b->bh.prevfree == 0); -#ifdef BufStats - totalloc -= bdh->tsize; - assert(totalloc >= 0); - numdrel++; /* Number of direct releases */ -#endif /* BufStats */ -#ifdef FreeWipe - V memset((char *) buf, 0x55, - (MemSize) (bdh->tsize - sizeof(struct bdhead))); -#endif /* FreeWipe */ - assert(relfcn != NULL); - (*relfcn)((void *) bdh); /* Release it directly. */ - return; - } -#endif /* BECtl */ - - /* Buffer size must be negative, indicating that the buffer is - allocated. */ - - if (b->bh.bsize >= 0) { - bn = NULL; - } - assert(b->bh.bsize < 0); - - /* Back pointer in next buffer must be zero, indicating the - same thing: */ - - assert(BH((char *) b - b->bh.bsize)->prevfree == 0); - -#ifdef BufStats - totalloc += b->bh.bsize; - assert(totalloc >= 0); -#endif - - /* If the back link is nonzero, the previous buffer is free. */ - - if (b->bh.prevfree != 0) { - - /* The previous buffer is free. Consolidate this buffer with it - by adding the length of this buffer to the previous free - buffer. Note that we subtract the size in the buffer being - released, since it's negative to indicate that the buffer is - allocated. */ - - register bufsize size = b->bh.bsize; - - /* Make the previous buffer the one we're working on. */ - assert(BH((char *) b - b->bh.prevfree)->bsize == b->bh.prevfree); - b = BFH(((char *) b) - b->bh.prevfree); - b->bh.bsize -= size; - } else { - - /* The previous buffer isn't allocated. Insert this buffer - on the free list as an isolated free block. */ - - assert(freelist.ql.blink->ql.flink == &freelist); - assert(freelist.ql.flink->ql.blink == &freelist); - b->ql.flink = &freelist; - b->ql.blink = freelist.ql.blink; - freelist.ql.blink = b; - b->ql.blink->ql.flink = b; - b->bh.bsize = -b->bh.bsize; - } - - /* Now we look at the next buffer in memory, located by advancing from - the start of this buffer by its size, to see if that buffer is - free. If it is, we combine this buffer with the next one in - memory, dechaining the second buffer from the free list. */ - - bn = BFH(((char *) b) + b->bh.bsize); - if (bn->bh.bsize > 0) { - - /* The buffer is free. Remove it from the free list and add - its size to that of our buffer. */ - - assert(BH((char *) bn + bn->bh.bsize)->prevfree == bn->bh.bsize); - assert(bn->ql.blink->ql.flink == bn); - assert(bn->ql.flink->ql.blink == bn); - bn->ql.blink->ql.flink = bn->ql.flink; - bn->ql.flink->ql.blink = bn->ql.blink; - b->bh.bsize += bn->bh.bsize; - - /* Finally, advance to the buffer that follows the newly - consolidated free block. We must set its backpointer to the - head of the consolidated free block. We know the next block - must be an allocated block because the process of recombination - guarantees that two free blocks will never be contiguous in - memory. */ - - bn = BFH(((char *) b) + b->bh.bsize); - } -#ifdef FreeWipe - V memset(((char *) b) + sizeof(struct bfhead), 0x55, - (MemSize) (b->bh.bsize - sizeof(struct bfhead))); -#endif - assert(bn->bh.bsize < 0); - - /* The next buffer is allocated. Set the backpointer in it to point - to this buffer; the previous free buffer in memory. */ - - bn->bh.prevfree = b->bh.bsize; - -#ifdef BECtl - - /* If a block-release function is defined, and this free buffer - constitutes the entire block, release it. Note that pool_len - is defined in such a way that the test will fail unless all - pool blocks are the same size. */ - - if (relfcn != NULL && - ((bufsize) b->bh.bsize) == (bufsize)(pool_len - sizeof(struct bhead))) { - - assert(b->bh.prevfree == 0); - assert(BH((char *) b + b->bh.bsize)->bsize == ESent); - assert(BH((char *) b + b->bh.bsize)->prevfree == b->bh.bsize); - /* Unlink the buffer from the free list */ - b->ql.blink->ql.flink = b->ql.flink; - b->ql.flink->ql.blink = b->ql.blink; - - (*relfcn)(b); -#ifdef BufStats - numprel++; /* Nr of expansion block releases */ - numpblk--; /* Total number of blocks */ - assert(numpblk == numpget - numprel); -#endif /* BufStats */ - } -#endif /* BECtl */ -} - -#ifdef BECtl - -/* BECTL -- Establish automatic pool expansion control */ - -void bectl(compact, acquire, release, pool_incr) - int (*compact) _((bufsize sizereq, int sequence)); - void *(*acquire) _((bufsize size)); - void (*release) _((void *buf)); - bufsize pool_incr; -{ - compfcn = compact; - acqfcn = acquire; - relfcn = release; - exp_incr = pool_incr; -} -#endif - -/* BPOOL -- Add a region of memory to the buffer pool. */ - -void bpool(buf, len) - void *buf; - bufsize len; -{ - struct bfhead *b = BFH(buf); - struct bhead *bn; - -#ifdef SizeQuant - len &= ~(SizeQuant - 1); -#endif -#ifdef BECtl - if (pool_len == 0) { - pool_len = len; - } else if (len != pool_len) { - pool_len = -1; - } -#ifdef BufStats - numpget++; /* Number of block acquisitions */ - numpblk++; /* Number of blocks total */ - assert(numpblk == numpget - numprel); -#endif /* BufStats */ -#endif /* BECtl */ - - /* Since the block is initially occupied by a single free buffer, - it had better not be (much) larger than the largest buffer - whose size we can store in bhead.bsize. */ - - assert(len - sizeof(struct bhead) <= -((bufsize) ESent + 1)); - - /* Clear the backpointer at the start of the block to indicate that - there is no free block prior to this one. That blocks - recombination when the first block in memory is released. */ - - b->bh.prevfree = 0; - - /* Chain the new block to the free list. */ - - assert(freelist.ql.blink->ql.flink == &freelist); - assert(freelist.ql.flink->ql.blink == &freelist); - b->ql.flink = &freelist; - b->ql.blink = freelist.ql.blink; - freelist.ql.blink = b; - b->ql.blink->ql.flink = b; - - /* Create a dummy allocated buffer at the end of the pool. This dummy - buffer is seen when a buffer at the end of the pool is released and - blocks recombination of the last buffer with the dummy buffer at - the end. The length in the dummy buffer is set to the largest - negative number to denote the end of the pool for diagnostic - routines (this specific value is not counted on by the actual - allocation and release functions). */ - - len -= sizeof(struct bhead); - b->bh.bsize = (bufsize) len; -#ifdef FreeWipe - V memset(((char *) b) + sizeof(struct bfhead), 0x55, - (MemSize) (len - sizeof(struct bfhead))); -#endif - bn = BH(((char *) b) + len); - bn->prevfree = (bufsize) len; - /* Definition of ESent assumes two's complement! */ - assert((~0) == -1); - bn->bsize = ESent; -} - -#ifdef BufStats - -/* BSTATS -- Return buffer allocation free space statistics. */ - -void bstats(curalloc, totfree, maxfree, nget, nrel) - bufsize *curalloc, *totfree, *maxfree; - long *nget, *nrel; -{ - struct bfhead *b = freelist.ql.flink; - - *nget = numget; - *nrel = numrel; - *curalloc = totalloc; - *totfree = 0; - *maxfree = -1; - while (b != &freelist) { - assert(b->bh.bsize > 0); - *totfree += b->bh.bsize; - if (b->bh.bsize > *maxfree) { - *maxfree = b->bh.bsize; - } - b = b->ql.flink; /* Link to next buffer */ - } -} - -#ifdef BECtl - -/* BSTATSE -- Return extended statistics */ - -void bstatse(pool_incr, npool, npget, nprel, ndget, ndrel) - bufsize *pool_incr; - long *npool, *npget, *nprel, *ndget, *ndrel; -{ - *pool_incr = (pool_len < 0) ? -exp_incr : exp_incr; - *npool = numpblk; - *npget = numpget; - *nprel = numprel; - *ndget = numdget; - *ndrel = numdrel; -} -#endif /* BECtl */ -#endif /* BufStats */ - -#ifdef DumpData - -/* BUFDUMP -- Dump the data in a buffer. This is called with the user - data pointer, and backs up to the buffer header. It will - dump either a free block or an allocated one. */ - -void bufdump(buf) - void *buf; -{ - struct bfhead *b; - unsigned char *bdump; - bufsize bdlen; - - b = BFH(((char *) buf) - sizeof(struct bhead)); - assert(b->bh.bsize != 0); - if (b->bh.bsize < 0) { - bdump = (unsigned char *) buf; - bdlen = (-b->bh.bsize) - sizeof(struct bhead); - } else { - bdump = (unsigned char *) (((char *) b) + sizeof(struct bfhead)); - bdlen = b->bh.bsize - sizeof(struct bfhead); - } - - while (bdlen > 0) { - int i, dupes = 0; - bufsize l = bdlen; - char bhex[50], bascii[20]; - - if (l > 16) { - l = 16; - } - - for (i = 0; i < l; i++) { - V sprintf(bhex + i * 3, "%02X ", bdump[i]); - bascii[i] = isprint(bdump[i]) ? bdump[i] : ' '; - } - bascii[i] = 0; - V printf("%-48s %s\n", bhex, bascii); - bdump += l; - bdlen -= l; - while ((bdlen > 16) && (memcmp((char *) (bdump - 16), - (char *) bdump, 16) == 0)) { - dupes++; - bdump += 16; - bdlen -= 16; - } - if (dupes > 1) { - V printf( - " (%d lines [%d bytes] identical to above line skipped)\n", - dupes, dupes * 16); - } else if (dupes == 1) { - bdump -= 16; - bdlen += 16; - } - } -} -#endif - -#ifdef BufDump - -/* BPOOLD -- Dump a buffer pool. The buffer headers are always listed. - If DUMPALLOC is nonzero, the contents of allocated buffers - are dumped. If DUMPFREE is nonzero, free blocks are - dumped as well. If FreeWipe checking is enabled, free - blocks which have been clobbered will always be dumped. */ - -void bpoold(buf, dumpalloc, dumpfree) - void *buf; - int dumpalloc, dumpfree; -{ - struct bfhead *b = BFH(buf); - - while (b->bh.bsize != ESent) { - bufsize bs = b->bh.bsize; - - if (bs < 0) { - bs = -bs; - V printf("Allocated buffer: size %6ld bytes.\n", (long) bs); - if (dumpalloc) { - bufdump((void *) (((char *) b) + sizeof(struct bhead))); - } - } else { - char *lerr = ""; - - assert(bs > 0); - if ((b->ql.blink->ql.flink != b) || - (b->ql.flink->ql.blink != b)) { - lerr = " (Bad free list links)"; - } - V printf("Free block: size %6ld bytes.%s\n", - (long) bs, lerr); -#ifdef FreeWipe - lerr = ((char *) b) + sizeof(struct bfhead); - if ((bs > (bufsize)sizeof(struct bfhead)) && ((*lerr != 0x55) || - (memcmp(lerr, lerr + 1, - (MemSize) (bs - (sizeof(struct bfhead) + 1))) != 0))) { - V printf( - "(Contents of above free block have been overstored.)\n"); - bufdump((void *) (((char *) b) + sizeof(struct bhead))); - } else -#endif - if (dumpfree) { - bufdump((void *) (((char *) b) + sizeof(struct bhead))); - } - } - b = BFH(((char *) b) + bs); - } -} -#endif /* BufDump */ - -#ifdef BufValid - -/* BPOOLV -- Validate a buffer pool. If NDEBUG isn't defined, - any error generates an assertion failure. */ - -int bpoolv(buf) - void *buf; -{ - struct bfhead *b = BFH(buf); - - while (b->bh.bsize != ESent) { - bufsize bs = b->bh.bsize; - - if (bs < 0) { - bs = -bs; - } else { - char *lerr = ""; - - assert(bs > 0); - if (bs <= 0) { - return 0; - } - if ((b->ql.blink->ql.flink != b) || - (b->ql.flink->ql.blink != b)) { - V printf("Free block: size %6ld bytes. (Bad free list links)\n", - (long) bs); - assert(0); - return 0; - } -#ifdef FreeWipe - lerr = ((char *) b) + sizeof(struct bfhead); - if ((bs > (bufsize)sizeof(struct bfhead)) && ((*lerr != 0x55) || - (memcmp(lerr, lerr + 1, - (MemSize) (bs - (sizeof(struct bfhead) + 1))) != 0))) { - V printf( - "(Contents of above free block have been overstored.)\n"); - bufdump((void *) (((char *) b) + sizeof(struct bhead))); - assert(0); - return 0; - } -#endif - } - b = BFH(((char *) b) + bs); - } - return 1; -} -#endif /* BufValid */ - - /***********************\ - * * - * Built-in test program * - * * - \***********************/ - -#ifdef DoTestProg -#ifdef TestProg - -#define Repeatable 1 /* Repeatable pseudorandom sequence */ - /* If Repeatable is not defined, a - time-seeded pseudorandom sequence - is generated, exercising BGET with - a different pattern of calls on each - run. */ -#define OUR_RAND /* Use our own built-in version of - rand() to guarantee the test is - 100% repeatable. */ - -#ifdef BECtl -#define PoolSize 300000 /* Test buffer pool size */ -#else -#define PoolSize 50000 /* Test buffer pool size */ -#endif -#define ExpIncr 32768 /* Test expansion block size */ -#define CompactTries 10 /* Maximum tries at compacting */ - -#define dumpAlloc 0 /* Dump allocated buffers ? */ -#define dumpFree 0 /* Dump free buffers ? */ - -#ifndef Repeatable -extern long time(); -#endif - -extern char *malloc(); -extern int free _((char *)); - -static char *bchain = NULL; /* Our private buffer chain */ -static char *bp = NULL; /* Our initial buffer pool */ - -#include - -#ifdef OUR_RAND - -static unsigned long int next = 1; - -/* Return next random integer */ - -int rand() -{ - next = next * 1103515245L + 12345; - return (unsigned int) (next / 65536L) % 32768L; -} - -/* Set seed for random generator */ - -void srand(seed) - unsigned int seed; -{ - next = seed; -} - -#endif /* TestProg */ -#endif /* DoTestProg */ - -/* STATS -- Edit statistics returned by bstats() or bstatse(). */ - -static void stats(when) - char *when; -{ - bufsize cural, totfree, maxfree; - long nget, nfree; -#ifdef BECtl - bufsize pincr; - long totblocks, npget, nprel, ndget, ndrel; -#endif - - bstats(&cural, &totfree, &maxfree, &nget, &nfree); - V printf( - "%s: %ld gets, %ld releases. %ld in use, %ld free, largest = %ld\n", - when, nget, nfree, (long) cural, (long) totfree, (long) maxfree); -#ifdef BECtl - bstatse(&pincr, &totblocks, &npget, &nprel, &ndget, &ndrel); - V printf( - " Blocks: size = %ld, %ld (%ld bytes) in use, %ld gets, %ld frees\n", - (long)pincr, totblocks, pincr * totblocks, npget, nprel); - V printf(" %ld direct gets, %ld direct frees\n", ndget, ndrel); -#endif /* BECtl */ -} - -#ifdef BECtl -static int protect = 0; /* Disable compaction during bgetr() */ - -/* BCOMPACT -- Compaction call-back function. */ - -static int bcompact(bsize, seq) - bufsize bsize; - int seq; -{ -#ifdef CompactTries - char *bc = bchain; - int i = rand() & 0x3; - -#ifdef COMPACTRACE - V printf("Compaction requested. %ld bytes needed, sequence %d.\n", - (long) bsize, seq); -#endif - - if (protect || (seq > CompactTries)) { -#ifdef COMPACTRACE - V printf("Compaction gave up.\n"); -#endif - return 0; - } - - /* Based on a random cast, release a random buffer in the list - of allocated buffers. */ - - while (i > 0 && bc != NULL) { - bc = *((char **) bc); - i--; - } - if (bc != NULL) { - char *fb; - - fb = *((char **) bc); - if (fb != NULL) { - *((char **) bc) = *((char **) fb); - brel((void *) fb); - return 1; - } - } - -#ifdef COMPACTRACE - V printf("Compaction bailed out.\n"); -#endif -#endif /* CompactTries */ - return 0; -} - -/* BEXPAND -- Expand pool call-back function. */ - -static void *bexpand(size) - bufsize size; -{ - void *np = NULL; - bufsize cural, totfree, maxfree; - long nget, nfree; - - /* Don't expand beyond the total allocated size given by PoolSize. */ - - bstats(&cural, &totfree, &maxfree, &nget, &nfree); - - if (cural < PoolSize) { - np = (void *) malloc((unsigned) size); - } -#ifdef EXPTRACE - V printf("Expand pool by %ld -- %s.\n", (long) size, - np == NULL ? "failed" : "succeeded"); -#endif - return np; -} - -/* BSHRINK -- Shrink buffer pool call-back function. */ - -static void bshrink(buf) - void *buf; -{ - if (((char *) buf) == bp) { -#ifdef EXPTRACE - V printf("Initial pool released.\n"); -#endif - bp = NULL; - } -#ifdef EXPTRACE - V printf("Shrink pool.\n"); -#endif - free((char *) buf); -} - -#endif /* BECtl */ - -/* Restrict buffer requests to those large enough to contain our pointer and - small enough for the CPU architecture. */ - -static bufsize blimit(bs) - bufsize bs; -{ - if (bs < sizeof(char *)) { - bs = sizeof(char *); - } - - /* This is written out in this ugly fashion because the - cool expression in sizeof(int) that auto-configured - to any length int befuddled some compilers. */ - - if (sizeof(int) == 2) { - if (bs > 32767) { - bs = 32767; - } - } else { - if (bs > 200000) { - bs = 200000; - } - } - return bs; -} - -#ifdef DoTestProg - -int main() -{ - int i; - double x; - - /* Seed the random number generator. If Repeatable is defined, we - always use the same seed. Otherwise, we seed from the clock to - shake things up from run to run. */ - -#ifdef Repeatable - V srand(1234); -#else - V srand((int) time((long *) NULL)); -#endif - - /* Compute x such that pow(x, p) ranges between 1 and 4*ExpIncr as - p ranges from 0 to ExpIncr-1, with a concentration in the lower - numbers. */ - - x = 4.0 * ExpIncr; - x = log(x); - x = exp(log(4.0 * ExpIncr) / (ExpIncr - 1.0)); - -#ifdef BECtl - bectl(bcompact, bexpand, bshrink, (bufsize) ExpIncr); - bp = malloc(ExpIncr); - assert(bp != NULL); - bpool((void *) bp, (bufsize) ExpIncr); -#else - bp = malloc(PoolSize); - assert(bp != NULL); - bpool((void *) bp, (bufsize) PoolSize); -#endif - - stats("Create pool"); - V bpoolv((void *) bp); - bpoold((void *) bp, dumpAlloc, dumpFree); - - for (i = 0; i < TestProg; i++) { - char *cb; - bufsize bs = pow(x, (double) (rand() & (ExpIncr - 1))); - - assert(bs <= (((bufsize) 4) * ExpIncr)); - bs = blimit(bs); - if (rand() & 0x400) { - cb = (char *) bgetz(bs); - } else { - cb = (char *) bget(bs); - } - if (cb == NULL) { -#ifdef EasyOut - break; -#else - char *bc = bchain; - - if (bc != NULL) { - char *fb; - - fb = *((char **) bc); - if (fb != NULL) { - *((char **) bc) = *((char **) fb); - brel((void *) fb); - } - continue; - } -#endif - } - *((char **) cb) = (char *) bchain; - bchain = cb; - - /* Based on a random cast, release a random buffer in the list - of allocated buffers. */ - - if ((rand() & 0x10) == 0) { - char *bc = bchain; - int i = rand() & 0x3; - - while (i > 0 && bc != NULL) { - bc = *((char **) bc); - i--; - } - if (bc != NULL) { - char *fb; - - fb = *((char **) bc); - if (fb != NULL) { - *((char **) bc) = *((char **) fb); - brel((void *) fb); - } - } - } - - /* Based on a random cast, reallocate a random buffer in the list - to a random size */ - - if ((rand() & 0x20) == 0) { - char *bc = bchain; - int i = rand() & 0x3; - - while (i > 0 && bc != NULL) { - bc = *((char **) bc); - i--; - } - if (bc != NULL) { - char *fb; - - fb = *((char **) bc); - if (fb != NULL) { - char *newb; - - bs = pow(x, (double) (rand() & (ExpIncr - 1))); - bs = blimit(bs); -#ifdef BECtl - protect = 1; /* Protect against compaction */ -#endif - newb = (char *) bgetr((void *) fb, bs); -#ifdef BECtl - protect = 0; -#endif - if (newb != NULL) { - *((char **) bc) = newb; - } - } - } - } - } - stats("\nAfter allocation"); - if (bp != NULL) { - V bpoolv((void *) bp); - bpoold((void *) bp, dumpAlloc, dumpFree); - } - - while (bchain != NULL) { - char *buf = bchain; - - bchain = *((char **) buf); - brel((void *) buf); - } - stats("\nAfter release"); -#ifndef BECtl - if (bp != NULL) { - V bpoolv((void *) bp); - bpoold((void *) bp, dumpAlloc, dumpFree); - } -#endif - - return 0; -} -#endif - -#endif /* DoTestProg */ diff --git a/src/servers/app/server/bget.h b/src/servers/app/server/bget.h deleted file mode 100644 index e98eed439c..0000000000 --- a/src/servers/app/server/bget.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - - Interface definitions for bget.c, the memory management package. - -*/ -#define PROTOTYPES - -#ifndef _ -#ifdef PROTOTYPES -#define _(x) x /* If compiler knows prototypes */ -#else -#define _(x) () /* It it doesn't */ -#endif /* PROTOTYPES */ -#endif - -typedef long bufsize; -void bpool _((void *buffer, bufsize len)); -void *bget _((bufsize size)); -void *bgetz _((bufsize size)); -void *bgetr _((void *buffer, bufsize newsize)); -void brel _((void *buf)); -void bectl _((int (*compact)(bufsize sizereq, int sequence), - void *(*acquire)(bufsize size), - void (*release)(void *buf), bufsize pool_incr)); -void bstats _((bufsize *curalloc, bufsize *totfree, bufsize *maxfree, - long *nget, long *nrel)); -void bstatse _((bufsize *pool_incr, long *npool, long *npget, - long *nprel, long *ndget, long *ndrel)); -void bufdump _((void *buf)); -void bpoold _((void *pool, int dumpalloc, int dumpfree)); -int bpoolv _((void *pool));