⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sflmem.c

📁 短小精悍的C语言标准函数库。提供450个以上的可移植的算法和工具代码。
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  ----------------------------------------------------------------<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 + -