|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T a
Length: 9964 (0x26ec)
Types: TextFile
Names: »alloc.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦2fafebccf⟧ »EurOpenD3/mail/smail3.1.19.tar.Z«
└─⟦bcd2bc73f⟧
└─⟦this⟧ »src/alloc.c«
/* @(#)alloc.c 3.13 8/18/88 01:43:36 */
/*
* Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
*
* See the file COPYING, distributed with smail, for restriction
* and warranty information.
*
* namei master id: @(#)alloc.c 3.13 8/18/88 01:43:36
*/
/*
* alloc.c:
* storage allocation with panics on errors
* The functions in this file may be replaced in the future when
* daemon mode is implemented, to make it easier to reclaim
* storage.
*
* block storage allocation
* This allows a given stroage allocation to be associated
* with a group of other storage allocations. It is
* possible to free or test for existence of the class.
*
* A block a pointer to a chain of segments. Each segment
* refers to one storage allocation. A block also contains
* the total number of bytes allocated. If this number is
* zero, then no stroage is associated with the block.
*
* external functions: xmalloc, xrealloc, xfree,
* balloc, brealloc, bfree,
* alloc_block, re_block, free_block
*/
#include <stdio.h>
#include "defs.h"
#include "smail.h"
#include "exitcodes.h"
#include "log.h"
#include "alloc.h"
#ifndef DEPEND
# include "extern.h"
#endif
/* the master block of blocks */
static struct block master = {(struct bseg *)0, 0};
/* the block for pmalloc(), prealloc() and pfree() macros */
static struct block perm_block = {(struct bseg *)0, 0};
struct block *perm = &perm_block;
/* default block for 0 based life time */
static struct block default_block = {(struct bseg *)0, 0};
static struct block *def_block = &default_block;
/* variable exported for the X_CHECK macro */
int x_dont_panic = TRUE; /* if TRUE, X_CHECK won't call panic */
\f
/*
* xmalloc, xrealloc, xfree - per message malloc and realloc and free
* with aborts on error
*
* The following two routines are an interface to xmalloc and xrealloc
* which frees other functions from having to worry about whether
* a memory full error occurs. There is seldom anything graceful
* to do when this happens, and it happens seldom on machines with
* a reasonable VM space. So just panic about the problem and don't
* bother returning.
*
* In the future, the x-style allocation routines will be used for
* allocation of spaces which will be reclaimed after processing one
* message.
*/
char *
xmalloc(size)
unsigned size; /* size of region to allocate */
{
extern char *malloc();
register char *ret; /* region returned by malloc */
ret = malloc(size + sizeof(int));
if (!ret) {
panic(EX_SOFTWARE, "malloc(%d) returned NULL", size);
/*NOTREACHED*/
}
*(int *)ret = X_MAGIC;
return ret + sizeof(int);
}
char *
xrealloc(region, size)
char *region; /* region to be realloc'd */
unsigned size; /* realloc size */
{
extern char *realloc();
register char *ret; /* region returned by realloc */
if (X_CHECK(region) == FAIL) {
/* what to do with realloc that is reasonable to avoid a panic? */
/* copy the region to an entirely new malloc'd area */
ret = xmalloc(size);
memcpy(ret, region, size);
return ret;
}
((int *)region)[-1] = 0; /* clear the magic number */
ret = realloc(region - sizeof(int), size + sizeof(int));
if (!ret) {
panic(EX_SOFTWARE, "realloc(0x%lx, %d) returned NULL",
(long)region, size);
/*NOTREACHED*/
}
*(int *)ret = X_MAGIC; /* put a magic number back */
return ret + sizeof(int);
}
void
xfree(region)
char *region;
{
extern void free();
if (X_CHECK(region) == FAIL) {
/* it should be safe to ignore double free's */
return;
}
((int *)region)[-1] = 0;
(void)free(region - sizeof(int));
}
\f
/*
* bmalloc - allocate memory and associate it with a block
*
* input:
* size - number of bytes to allocate
* block - the block to associate it with, 0 ==> master
*
* output:
* returns a pointer to the allocated storage
*/
char *
bmalloc(size, block)
unsigned size; /* number of bytes to allocate */
struct block *block; /* block that data belongs to */
{
struct bseg *newseg; /* the new segment for this alloc */
/* a zero block implies master block */
if (block == 0) {
block = def_block;
}
/* add a new segment to the block */
if ((newseg = (struct bseg *)malloc(sizeof(struct bseg))) == NULL) {
panic(EX_SOFTWARE, "bmalloc: malloc of bseg failed");
/* NOTREACHED */
}
newseg->next = block->next;
block->next = newseg;
/* allocate the storage */
if ((newseg->data = malloc(size)) == NULL) {
panic(EX_SOFTWARE, "bmalloc: malloc of %d bytes failed", size);
/* NOTREACHED */
}
++block->cnt;
/* return the pointer */
return newseg->data;
}
/*
* brealloc - reallocate stroage associated with a block
*
* Resize a storagg from a block, and perform all needed
* accounting adjustments.
*
* input:
* data - pointer to data being realloced
* size - the new size
* block - the block that data belongs
*
* output:
* returns a pointer to the re-allocated storage
*/
char *
brealloc(data, size, block)
char *data; /* data being re-allocated */
unsigned size; /* number of bytes to re-allocate */
struct block *block; /* block that data belongs to */
{
struct bseg *oldseg; /* old segment associated with data */
/* a zero block implies master block */
if (block == 0) {
block = def_block;
}
/* find the segment */
for (oldseg=block->next;
oldseg != NULL && oldseg->data != data;
oldseg=oldseg->next) {
}
if (oldseg == NULL) {
panic(EX_SOFTWARE,
"brealloc: seg (at 0x%lx) not in block (at 0x%lx, cnt:%d)",
(long)oldseg, (long)block, block->cnt);
/* NOTREACHED */
}
/* reallocate */
if ((oldseg->data = realloc(data, size)) == NULL) {
panic(EX_SOFTWARE,
"brealloc: realloc to %d bytes (at 0x%lx) failed",
size, (long)oldseg->data);
/* NOTREACHED */
}
/* return the pointer */
return oldseg->data;
}
/*
* bfree - free a signle segment from a block
*
* Free a storage from a block, and perform all needed accounting adjustments.
*
* input:
* data - pointer to data being freed
* block - the block that data belongs
*/
void
bfree(data, block)
char *data; /* data being freed */
struct block *block; /* block that data belongs to */
{
struct bseg *oldseg; /* old segment associated with data */
struct bseg *lastseg; /* the segment before the deleted segment */
/* firewall */
if (block == NULL) {
panic(EX_SOFTWARE, "brealloc: block is NULL");
/* NOTREACHED */
}
/* delete the segment from the block */
for (lastseg=NULL, oldseg=block->next;
oldseg!=NULL && oldseg->data!=data;
lastseg=oldseg, oldseg=oldseg->next) {
}
if (oldseg == NULL) {
panic(EX_SOFTWARE,
"bfree: data (at 0x%lx) not in block (at 0x%lx, cnt: %d)",
(long)data, (long)block, block->cnt);
/* NOTREACHED */
}
if (lastseg == NULL) {
block->next = oldseg->next;
} else {
lastseg->next = oldseg->next;
}
--block->cnt;
/* free the data and segment */
(void) free(oldseg->data);
(void) free((char *)oldseg);
}
\f
/*
* malloc_block - form a new storage block
*
* Start a new storage block with no storage allociated with it.
*
* NOTE: the block structore becomes a segment from the master block
*
* input:
* none
*
* output:
* returns a pointer to the new block
*/
struct block *
malloc_block()
{
struct block *block; /* the new block */
/* allocate the block */
block = (struct block *)bmalloc(sizeof(struct block), master);
block->cnt = 0;
block->next = NULL;
/* return the new block */
return block;
}
/*
* realloc_block - move a segment from one block to another
*
* input:
* data - the data being moved
* oldblock - the block where the segment currently resides
* newblock - the block that will hold the new segment
*/
void
realloc_block(data, oldblock, newblock)
char *data; /* the data to move */
struct block *oldblock; /* the old block */
struct block *newblock; /* the new block */
{
struct bseg *oldseg; /* old segment associated with data */
struct bseg *lastseg; /* the segment before the deleted segment */
/* firewall */
if (oldblock == NULL && newblock == NULL) {
panic(EX_SOFTWARE, "realloc_block: oldblock or newblock is NULL");
/* NOTREACHED */
}
/* delete the segment from the oldblock */
for (lastseg=NULL, oldseg=oldblock->next;
oldseg!=NULL && oldseg->data!=data;
lastseg=oldseg, oldseg=oldseg->next) {
}
if (oldseg == NULL) {
panic(EX_SOFTWARE,
"realloc_block: data (at 0x%lx) not in block (at 0x%lx, cnt: %d)",
(long)data, (long)oldblock, oldblock->cnt);
/* NOTREACHED */
}
if (lastseg == NULL) {
oldblock->next = oldseg->next;
} else {
lastseg->next = oldseg->next;
}
--oldblock->cnt;
/* add the segment to the new block */
oldseg->next = newblock->next;
newblock->next = oldseg;
++newblock->cnt;
}
/*
* free_block - free everything in a block
*
* input:
* block - the block to free all segments on
*/
void
free_block(block)
struct block *block; /* the new to free all segments on */
{
struct bseg *oldseg; /* the segement to free */
/* firewall */
if (block == NULL) {
panic(EX_SOFTWARE, "free_block: block is NULL");
/* NOTREACHED */
}
/* free the chain */
for(oldseg = block->next;
block->cnt > 0 && block->next != NULL;
--block->cnt, block->next = oldseg->next) {
/* free the data */
(void) free(block->next->data);
/* free the segemtn */
(void) free((char *)block->next);
--block->cnt;
}
/* firewall */
if (block->cnt != 0 || block->next != NULL) {
panic(EX_SOFTWARE,
"free_block: freed block (at 0x%lx) has cnt:%d, next:0x%lx",
(long)block, block->cnt, (long)block->next);
/* NOTREACHED */
}
}