/* libc-malloc.c - PIW replacements for standard malloc functions.
 *
 * author(s): Tom Lord
 ****************************************************************
 * Copyright (C) 1998 UUNET Technologies, Inc.
 *
 * See the file "COPYING.PIW" for further information
 * about the copyright status of this work.
 */

/************************************************************************
 *(h1 "Standard Allocation Functions"
 *    :includes ("hackerlab/piw-malloc/malloc.h"))
 * 
 * This section documents the standard allocation functions (such as
 * `malloc') provided by PIW.  The debugging features of these
 * functions are described in the next section.
 * 
 */


/* We don't need stdlib.h for this file (unistd.h would do), but
 * stdlib declares malloc and a client of the library might include
 * both stdlib and the PIW version of malloc.h.  If that would cause
 * errors, we want to find out while compiling PIW, not while
 * compiling the client program.
 */
#include <stdlib.h>
#include "hackerlab/os/unistd.h"
#include "hackerlab/mem/mem.h"
#include "hackerlab/piw-malloc/piw-malloc.h"
#include "hackerlab/piw-malloc/libc-malloc.h"


/****************************************************************
 * This module is a front-end to piw-malloc.c, which contains
 * the allocator itself.  This module provides standard entry
 * points.
 *
 * It is safe to bypass this module and call the `piw_' allocator
 * functions directly.
 */

char * malloc_options;

/*(c malloc)
 * void * malloc (size_t n_bytes);
 * 
 * Allocate at least `n_bytes' of storage and return a pointer to the
 * allocated memory.  Return 0 if the allocation request can not be
 * satisfied.
 *
 * All allocated regions are suitably aligned for any type.
 * Allocations of more than a single page (as determined by
 * `getpagesize') are page-aligned.
 */
void *
malloc (size_t n_bytes)
{
  int errn;
  void * answer;

  answer = piw_malloc (&errn, n_bytes);
  return answer;
}


/*(c calloc)
 * void * calloc (size_t n_items, size_t sizeof_item);
 * 
 * Allocate at least `n_bytes' of storage and return a pointer to the
 * allocated memory.  Return 0 if the allocation request can not be
 * satisfied.  The allocated memory is filled with 0 bytes.
 *
 * All allocated regions are suitably aligned for any type.
 * Allocations of more than a single page (as determined by
 * `getpagesize') are page-aligned.
 */
void *
calloc (size_t n_items, size_t sizeof_item)
{
  long size;
  void *p;

  size = sizeof_item * n_items;
  p = malloc(size);
  if (p)
    mem_set0 ((t_uchar *)p, size);
  return p;
}


/*(c valloc)
 * void * valloc (size_t n_bytes);
 * 
 * Allocate at least `n_bytes' of storage and return a pointer to the
 * allocated memory.  Return 0 if the allocation request can not be
 * satisfied.
 *
 * All allocated regions are page-aligned.  (Requests for regions
 * smaller than one page are satisfied by allocating at least one page
 * of memory but programs should not rely on this behavior.)
 * 
 * This is not a standard function.  It is included for compatability
 * with many versions of BSD.
 */
void *
valloc (size_t n_bytes)
{
  static size_t page_size = 0;
  
  if (!page_size)
    page_size = getpagesize ();

  /* malloc returns page aligned memory for requests >= page_size
   */
  if (n_bytes >= page_size)
    return malloc (n_bytes);	
  else
    return malloc (page_size);
}


/*(c realloc)
 * void * realloc (void * block, size_t n_bytes);
 * 
 * Allocate at least `n_bytes' of storage and return a pointer to the
 * allocated memory.
 * 
 * `block' may be 0 or a previously allocated block of memory.  If
 * `block' already points to at least `n_bytes' of allocated storage,
 * `block' may be returned with no new allocation taking place.
 * 
 * If `block' is not 0 and a new allocation succeeds, up to `n_bytes' of
 * data (or the size of `block', whichever is smaller) is copied from
 * `block' to the new region and `block' is freed.  
 * 
 * If new allocation fails, 0 is returned and `block' is unchanged.
 */ 
void *
realloc (void * block, size_t n_bytes)
{
  int errn;
  void * answer;

  answer = piw_realloc (&errn, block, n_bytes);
  return answer;
}


/*(c reallocf)
 * void * reallocf (void * block, size_t n_bytes);
 * 
 * `reallocf' is identical to `realloc' with one exception:
 * if reallocation fails, `block' is freed.
 * 
 * This is not a standard function.  It is included for compatability
 * with many versions of BSD.
 */
void *
reallocf (void * block, size_t n_bytes)
{
  void * answer;

  answer = realloc (block, n_bytes);
  if (!answer)
    free (block);
  return answer;
}


/*(c free)
 * void free (void * block);
 * 
 * Free `block', a previously allocated block of memory.
 * 
 * Freeing a null pointer has no effect.
 */
void
free (void * block)
{
  int errn;

  piw_free (&errn, block);
}


/*(c cfree)
 * void cfree (void * block);
 * 
 * `cfree' is equivalent to `free' and is provided only for
 * compatability with some systems.
 */
void
cfree (void * block)
{
  int errn;

  piw_free (&errn, block);
}
