📄 sflmem.c
字号:
/* ----------------------------------------------------------------<Prolog>-
Name: sflmem.c
Title: Memory allocation functions
Package: Standard Function Library (SFL)
Written: 1996/06/08 iMatix SFL project team <sfl@imatix.com>
Revised: 1999/12/28
Synopsis: Encapsulated memory allocation functions.
Copyright: Copyright (c) 1996-2000 iMatix Corporation
License: This is free software; you can redistribute it and/or modify
it under the terms of the SFL License Agreement as provided
in the file LICENSE.TXT. This software is distributed in
the hope that it will be useful, but without any warranty.
------------------------------------------------------------------</Prolog>-*/
#include "prelude.h" /* Universal header file */
#include "sfllist.h" /* Linked-list functions */
#include "sfltron.h" /* Tracing functions */
#include "sflmem.h" /* Prototypes for functions */
/*- Constants ---------------------------------------------------------------*/
#define MEMTAG 0xa55aU /* Value for mh_tag */
#define MEMUNTAG 0x5aa5U /* Invalidated tag */
/*- Macros ------------------------------------------------------------------*/
#define ALIGN_SIZE sizeof (double)
#define RESERVE_SIZE (((sizeof (MEMHDR) + (ALIGN_SIZE - 1)) \
/ ALIGN_SIZE) * ALIGN_SIZE)
#define MEMTRN_SIZE sizeof (MEMTRN)
#define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
#define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
/*- Put the #define last to enable tracing ----------------------------------*/
#define MEM_TRACE 1 /* Enable all trace() calls */
#undef MEM_TRACE /* Don't even compile them */
/*- Local type definitions --------------------------------------------------*/
struct _MEMTRN { /* Transaction info */
MEMTRN *next; /* Next transaction */
MEMTRN *prev; /* Previous transaction */
char *file; /* File allocation was from */
size_t line; /* Line allocation was from */
LIST memhdr; /* Header for list of blocks */
};
struct _MEMHDR { /* Memory block header info */
MEMHDR *next; /* Next memory block */
MEMHDR *prev; /* Previous memory block */
word tag; /* Special ident tag */
size_t size; /* Size of allocation block */
const char *file; /* File allocation was from */
size_t line; /* Line allocation was from */
};
typedef struct _SCAVFCT { /* Scavenger function registration */
struct _SCAVFCT
*next, *prev; /* Doubly-linked list */
scavenger scav_fct; /* Address of function */
void * scav_arg; /* Argument for function */
} SCAVFCT;
/* -------------------------------------------------------------------------
* Global variables local to this source
*/
static LIST /* List of scavenger functions */
scavfcts = {
&scavfcts,
&scavfcts
};
static long
mem_total = 0; /* Amount of memory used */
static MEMTRN /* Dummy transaction, actually the */
mem_list = {&mem_list, &mem_list, /* main list of committed blocks */
NULL, 0,
{&mem_list.memhdr,
&mem_list.memhdr}
};
static LIST
tr_list = {&tr_list, &tr_list}; /* List of transaction blocks */
static long
mem_alloc_count = 0, /* We keep count of calls to */
mem_free_count = 0; /* mem_alloc() and mem_free() */
/*- Local functions ---------------------------------------------------------*/
static void mem_tag_err (void *ptr, const char *filename, size_t lineno);
static void mem_scavenge (void);
static void mem_del_trans (MEMTRN *trn);
static void mem_display_list (MEMHDR *ptr, FILE *fp);
static void mem_check_list (MEMHDR *ptr, const char *filename, size_t lineno);
static void mem_free_list (MEMHDR *ptr);
/* ---------------------------------------------------------------------[<]-
Function: mem_alloc_
Synopsis: Allocates a memory block. Use the mem_alloc() macro to call
this function! Use mem_free_() to free blocks allocated with this
function. Returns a pointer to the allocated memory block, or NULL if
there was not enough memory available. The supplied source file name
is assumed to be in a static area. The requested block size must be
greater than zero bytes.
---------------------------------------------------------------------[>]-*/
void *
mem_alloc_ (
MEMTRN *trn, /* Associated transaction */
size_t size, /* Desired size of memory block */
const char *filename, /* Name of source file making call */
size_t lineno /* Line number in calling source */
)
{
MEMHDR
*ptr; /* Allocated memory block */
/* Allocate block with extra space for the header */
ASSERT (size > 0); /* Cannot allocate zero bytes! */
ptr = malloc (RESERVE_SIZE + size);
if (ptr == NULL) /* If nothing free, do a hunt */
{ /* and try again... */
mem_scavenge ();
ptr = malloc (RESERVE_SIZE + size);
if (ptr == NULL)
return (NULL); /* Really in trouble now! */
}
# if (defined (MEM_TRACE))
trace ("%s (%ld): alloc %d bytes->%p",
filename? filename: "-", (long) lineno, size, ptr);
# endif
ptr-> tag = MEMTAG; /* Initialise block header */
ptr-> size = size; /* Size of block */
ptr-> file = filename; /* Who allocated it */
ptr-> line = lineno; /* and where */
if (!trn) /* If no transaction then use the */
trn = &mem_list; /* main block list */
list_reset (ptr); /* Set up new block as list */
list_relink_before (ptr, /* Add to list of blocks */
&trn-> memhdr);
mem_total += size; /* Keep count of space used */
mem_alloc_count += 1; /* and number of allocations */
return (HDR_2_CLIENT (ptr)); /* and return client address */
}
/* ---------------------------------------------------------------------------
* mem_scavenge -- internal
*
* Calls all registered scavenger functions.
*/
static void
mem_scavenge (void)
{
SCAVFCT
*entry; /* Entry in list of functions */
for (entry = scavfcts.next;
entry != (SCAVFCT *) &scavfcts;
entry = entry-> next)
(*entry-> scav_fct) (entry-> scav_arg);
}
/* ---------------------------------------------------------------------[<]-
Function: mem_realloc_
Synopsis: Reallocates a memory block, which remains part of the same
transaction. Use the mem_realloc() macro to call this function!
Accepts a pointer to a memory block and the desired size of the new
memory block. Returns the address of the new memory block, or NULL if
there was not enough memory available. If the specified block was not
correctly allocated, dumps the memory allocation list and exits. The
desired size must be greater than zero.
---------------------------------------------------------------------[>]-*/
void *
mem_realloc_ (
void *client_ptr, /* Block of memory to reallocate */
size_t size, /* Desired size of memory block */
const char *filename, /* Name of source file making call */
size_t lineno /* Line number in calling source */
)
{
MEMHDR
*ptr,
*next;
ASSERT (client_ptr);
ASSERT (size > 0);
/* Check that block is valid */
ptr = CLIENT_2_HDR (client_ptr);
if (ptr-> tag != MEMTAG)
mem_tag_err (ptr, filename, lineno);
/* Invalidate header */
ptr-> tag = MEMUNTAG;
mem_total -= ptr-> size;
mem_free_count += 1;
next = ptr-> next; /* Save where we were linked */
list_unlink (ptr); /* and unlink */
/* Reallocate memory block */
ptr = (MEMHDR *) realloc (ptr, RESERVE_SIZE + size);
if (ptr == NULL) /* If nothing free, do a hunt */
{ /* and try again... */
mem_scavenge ();
ptr = (MEMHDR *) realloc (ptr, RESERVE_SIZE + size);
if (ptr == NULL)
return (NULL); /* Really in trouble now! */
}
# if (defined (MEM_TRACE))
trace ("%s (%ld): realloc %d bytes ->%p",
filename? filename: "-", (long) lineno, size, ptr);
# endif
/* Update header */
ptr-> tag = MEMTAG;
ptr-> size = size;
ptr-> file = filename;
ptr-> line = lineno;
list_reset (ptr); /* Set up block as list */
list_relink_before (ptr, next); /* And link where old block was */
mem_total += size; /* Keep count of space used */
mem_alloc_count += 1; /* and number of allocations */
return (HDR_2_CLIENT (ptr));
}
/* ---------------------------------------------------------------------------
* mem_tag_err -- internal
*
* Display memory tag error
*/
static void
mem_tag_err (void *ptr, const char *filename, size_t lineno)
{
fprintf (stdout, "Memory tag error - %p - %s (%ld)\n",
ptr, filename? filename: "<Unknown>", (long) lineno);
fflush (stdout);
abort ();
}
/* ---------------------------------------------------------------------[<]-
Function: mem_strdup_
Synopsis: Saves a string in dynamic memory. Use the mem_strdup macro
to call this function! The caller is responsible for freeing the space
allocated when it is no longer needed. Returns a pointer to the
allocated string, which holds a copy of the parameter string. Returns
NULL if there was insufficient heap storage available to allocate the
string, or if the original string was itself NULL.
---------------------------------------------------------------------[>]-*/
char *
mem_strdup_ (
MEMTRN *trn, /* Associated transaction */
const char *string, /* String to copy */
const char *filename, /* Name of source file making call */
size_t lineno /* Line number in calling source */
)
{
char *copy;
size_t str_len;
if (string) /* If string not null, copy it */
{
str_len = strlen (string) + 1;
copy = mem_alloc_ (trn, str_len, filename, lineno);
if (copy)
strncpy (copy, string, str_len);
}
else
copy = NULL; /* Just pass-through a NULL */
return (copy);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -