/*
 * LIB/ALLOC.C	- memory allocation
 *
 * (c)Copyright 1998, Matthew Dillon, All Rights Reserved.  Refer to
 *    the COPYRIGHT file in the base directory of this distribution
 *    for specific rights granted.
 *
 * These routines are used to allocate buffers with the express intent 
 * of being able to *truely* deallocate the memory when we free it.
 * malloc()/free() does not normally do this, which will bloat the binary
 * and cause inefficiencies on fork().
 *
 * If you are running a large number of incoming connections or outgoing
 * feeds, using either USE_ANON_MMAP or USE_FALL_MMAP is an absolute 
 * requirement.  If you are not, then it doesn't matter.
 *
 * USE_ANON_MMAP is supported on BSDish platforms.  It uses MAP_ANON to
 *		 allocate areas of swap-backed memory.
 *
 * USE_ZERO_MMAP uses MAP_PRIVATE on /dev/zero to allocate memory, which
 *               might be better than the below approach with creating a
 *               temporary file.
 *
 * USE_FALL_MMAP should be supported on all platforms.  It creates a file
 *		 in /tmp and maps it MAP_PRIVATE, then remove()s the file.
 *		 Since this is a private map, the file is not actually used
 *		 for backing store so there is no real filesystem overhead.
 *		 The memory winds up being swap-backed.
 *
 * If neither option is set, malloc/free is used.  This is not recommended
 * if you run more then 10 feeds.
 */

#include "defs.h"

Prototype void *pagealloc(int *psize, int bytes);
Prototype void pagefree(void *p, int bytes);
Prototype int ZoneFd;		/* only necessary for USE_FALL_MMAP   */
Prototype int ZoneBytes;	/* for USE_ZERO_MMAP need only ZoneFd */

static int PageSize = 0;
static int PageMask;
int ZoneFd = -1;		/* only necessary for USE_FALL_MMAP   */
int ZoneBytes = 0;		/* for USE_ZERO_MMAP need only ZoneFd */

#if USE_ANON_MMAP

/*
 * Our first choice is to use MAP_ANON if the system understands it
 */

void *
pagealloc(int *psize, int bytes)
{
    void *b;
    if (PageSize == 0) {
	PageSize = getpagesize();
	PageMask = PageSize - 1;
    }
    bytes = (bytes + PageMask) & ~PageMask;

    if (bytes == 0)	/* degenerate case */
	bytes = PageSize;

    *psize = bytes;
    b = (void *)mmap((caddr_t)0, bytes, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
    if (b == NULL || b == (void *)-1) {
	logit(LOG_EMERG, "mmap/allocation/1 failed: %s", strerror(errno));
	exit(1);
    }
    return(b);
}

void
pagefree(void *page, int bytes)
{
    bytes = (bytes + PageMask) & ~PageMask;

    if (bytes == 0)
	bytes = PageSize;

    if (page != NULL) {
	munmap((caddr_t)page, bytes);
    }
}

#else
#if USE_ZERO_MMAP

/*
 * Our second choice is to use a MAP_PRIVATE mmap() on /dev/zero
 */

void *
pagealloc(int *psize, int bytes)
{
    void *b;

    if (PageSize == 0) {
	PageSize = getpagesize();
	PageMask = PageSize - 1;
    }
    bytes = (bytes + PageMask) & ~PageMask;

    if (bytes == 0)	/* degenerate case */
	bytes = PageSize;

    if (ZoneFd < 0) {
	ZoneFd=open("/dev/zero", O_RDWR);
	if (ZoneFd < 0) {
	    logit(LOG_EMERG, "unable to open %dK zone file /dev/zero: %s", 
		bytes / 1024,
		strerror(errno)
	    );
	    exit(1);
	}
	fcntl(ZoneFd, F_SETFD, 1);	/* set close-on-exec */
    }

    *psize = bytes;
    b = (void *)mmap((caddr_t)0, bytes, PROT_READ|PROT_WRITE, MAP_PRIVATE, ZoneFd, 0);
    if (b == NULL || b == (void *)-1) {
	logit(LOG_EMERG, "mmap/allocation/3 failed: %s", strerror(errno));
	exit(1);
    }
    return(b);
}

void
pagefree(void *page, int bytes)
{
    bytes = (bytes + PageMask) & ~PageMask;

    if (bytes == 0)
	bytes = PageSize;

    if (page != NULL) {
	munmap((caddr_t)page, bytes);
    }
}

#else
#if USE_FALL_MMAP

/*
 * Our third choice is to use a MAP_PRIVATE file mmap()
 */

void *
pagealloc(int *psize, int bytes)
{
    void *b;

    if (PageSize == 0) {
	PageSize = getpagesize();
	PageMask = PageSize - 1;
    }
    bytes = (bytes + PageMask) & ~PageMask;

    if (bytes == 0)	/* degenerate case */
	bytes = PageSize;

    if (ZoneFd < 0) {
	int i;
	int pid = (int)getpid();

	for (i = 0; i < 1000; ++i) {
	    char path[256];

	    sprintf(path, "/tmp/diablo.zone.%d.%d", pid, i);
	    if ((ZoneFd=open(path, O_CREAT|O_TRUNC|O_RDWR|O_EXCL, 0600)) >= 0){
		remove(path);
		break;
	    }
	}
	if (ZoneFd < 0) {
	    logit(LOG_EMERG, "unable to create %dK zone file in /tmp: %s", 
		bytes / 1024,
		strerror(errno)
	    );
	    exit(1);
	}
	fcntl(ZoneFd, F_SETFD, 1);	/* set close-on-exec */
    }

    if (bytes > ZoneBytes) {
	if (ftruncate(ZoneFd, bytes) < 0) {
	    logit(LOG_EMERG, "unable to extend zone file in /tmp: %s", 
		strerror(errno)
	    );
	    exit(1);
	}
	ZoneBytes = bytes;
    }

    *psize = bytes;
    b = (void *)mmap((caddr_t)0, bytes, PROT_READ|PROT_WRITE, MAP_PRIVATE, ZoneFd, 0);
    if (b == NULL || b == (void *)-1) {
	logit(LOG_EMERG, "mmap/allocation/2 failed: %s", strerror(errno));
	exit(1);
    }
    return(b);
}

void
pagefree(void *page, int bytes)
{
    bytes = (bytes + PageMask) & ~PageMask;

    if (bytes == 0)
	bytes = PageSize;

    if (page != NULL) {
	munmap((caddr_t)page, bytes);
    }
}

#else

void *
pagealloc(int *psize, int bytes)
{
    void *b;

    if (PageSize == 0) {
	PageSize = getpagesize();
	PageMask = PageSize - 1;
    }
    bytes = (bytes + PageMask) & ~PageMask;

    *psize = bytes;
    b = malloc(bytes);
    if (b == NULL) {
	logit(LOG_EMERG, "mmap/allocation/4 failed: %s", strerror(errno));
	exit(1);
    }
    bzero(b, bytes);
    return(b);
}

void
pagefree(void *page, int bytes)
{
    /* bytes = (bytes + PageMask) & ~PageMask; */

    if (page != NULL) {
	free(page);
    }
}

#endif
#endif
#endif



syntax highlighted by Code2HTML, v. 0.9.1