/*
 * The Spread Toolkit.
 *     
 * The contents of this file are subject to the Spread Open-Source
 * License, Version 1.0 (the ``License''); you may not use
 * this file except in compliance with the License.  You may obtain a
 * copy of the License at:
 *
 * http://www.spread.org/license/
 *
 * or in the file ``license.txt'' found in this distribution.
 *
 * Software distributed under the License is distributed on an AS IS basis, 
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
 * for the specific language governing rights and limitations under the 
 * License.
 *
 * The Creators of Spread are:
 *  Yair Amir, Michal Miskin-Amir, Jonathan Stanton.
 *
 *  Copyright (C) 1993-2004 Spread Concepts LLC <spread@spreadconcepts.com>
 *
 *  All Rights Reserved.
 *
 * Major Contributor(s):
 * ---------------
 *    Cristina Nita-Rotaru crisn@cs.purdue.edu - group communication security.
 *    Theo Schlossnagle    jesus@omniti.com - Perl, skiplists, autoconf.
 *    Dan Schoenblum       dansch@cnds.jhu.edu - Java interface.
 *    John Schultz         jschultz@cnds.jhu.edu - contribution to process group membership.
 *
 */


/* memory.c
 * memory allocater and deallocater
 *
 */
#include "arch.h"

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "errors.h"
#include "memory.h"
#include "alarm.h"
#include "objects.h"

#define MAX_MEM_OBJECTS         200

/* Define SPREAD_STATUS when Memory is compiled with the Spread Status system.
 * If memory is being used outside of Spread then comment the below define out.
 */


#ifdef SPREAD_STATUS
#include "status.h"
#endif

/************************
 * Global Variables 
 ************************/

/* Total bytes currently allocated including overhead */
static unsigned int     Mem_Bytes_Allocated;
/* Total number of objects of all types allocated currently */
static unsigned int     Mem_Obj_Allocated;
/* Total number of objects currently used by the application */
static unsigned int     Mem_Obj_Inuse;
/* Maximum bytes allocated at any one time during execution */
static unsigned int     Mem_Max_Bytes;
/* Maximum number of objects allocated at any one time */
static unsigned int     Mem_Max_Objects;
/* Maximum number of ojects used by application at any one time */
static unsigned int     Mem_Max_Obj_Inuse;


typedef struct mem_header_d 
{
        int32u   obj_type;
        size_t   block_len;
} mem_header;

/* NOTE: Only num_obj_inpool is updated when debugging is turned off
 * (i.e. define NDEBUG) it is NECESSARY to track buffer pool size
 */
typedef struct mem_info_d
{
        bool            exist;  /* 1 = object registered, 0 = unused object number */
        size_t          size;   /* size of object in bytes (should be from sizeof so aligned ) */
        unsigned int    threshold;
#ifndef NDEBUG
        unsigned int    bytes_allocated;
        unsigned int    max_bytes;
        unsigned int    num_obj;
        unsigned int    max_obj;
        unsigned int    num_obj_inuse;
        unsigned int    max_obj_inuse;
#endif
        unsigned int    num_obj_inpool;
        void            **list_head;
} mem_info;

static mem_info Mem[MAX_MEM_OBJECTS];

static bool Initialized;

#ifdef  SPREAD_STATUS
static bool MemStatus_initialized;
#endif

int Mem_valid_objtype(int32u objtype) 
{
        /* if any bits set higher then max object type return failure */
        if (objtype > MAX_MEM_OBJECTS) { return(0); }

        /* if table entry is valid return that */
        return(Mem[objtype].exist);
}        

/* Size of the memory object */
static size_t sizeobj(int32u objtype)
{
        return(Mem[objtype].size);
}



/************************
 * Query Functions
 ************************/

unsigned int Mem_total_bytes() 
{
        return(Mem_Bytes_Allocated);
}
unsigned int Mem_total_inuse()
{
        return( Mem_Obj_Inuse );
}
unsigned int Mem_total_obj()              
{
        return( Mem_Obj_Allocated );
}
unsigned int Mem_total_max_bytes() 
{
        return(Mem_Max_Bytes);
}
unsigned int Mem_total_max_inuse()
{
        return( Mem_Max_Obj_Inuse );
}
unsigned int Mem_total_max_obj()              
{
        return( Mem_Max_Objects );
}
unsigned int Mem_obj_in_pool(int32u objtype)  
{
        return( Mem[objtype].num_obj_inpool);
}

#ifndef NDEBUG
unsigned int Mem_obj_in_app(int32u objtype)    
{
        return( Mem[objtype].num_obj_inuse );
}
unsigned int Mem_max_in_app(int32u objtype)
{
        return( Mem[objtype].max_obj_inuse );
}

unsigned int Mem_obj_total(int32u objtype)    
{
        return( Mem[objtype].num_obj );
}
unsigned int Mem_max_obj(int32u objtype)
{
        return( Mem[objtype].max_obj );
}
unsigned int Mem_bytes(int32u objtype)
{
        return( Mem[objtype].bytes_allocated );
}
unsigned int Mem_max_bytes(int32u objtype)
{
        return( Mem[objtype].max_bytes );
}
#endif /* NDEBUG */

/**********************
 * Internal functions
 **********************/

#define mem_header_ptr(obj)   ( (mem_header *) (((char *)obj) - sizeof(mem_header)) )

void    Mem_init_status()
{
#ifdef SPREAD_STATUS
        struct StatGroup *sgroup;
        int obj_type;
        char memobj_name[32];
        char memobj_desc[200];
        if (!MemStatus_initialized) 
        {
                sgroup = Stat_Group_Create("Memory_Summary_0", "Statistics for memory useage summarized over all memory objects");
                if (!sgroup)
                {
                        Alarm(PRINT, "Mem_init_object: Failed to create Memory Status group\n");
                } else {
                        Stat_Insert_Record("Memory_Summary_0", "Current Bytes Used", "bytes", STAT_INT, &Mem_Bytes_Allocated );
                        Stat_Group_Add_Member(sgroup, &Mem_Bytes_Allocated);
                        Stat_Insert_Record("Memory_Summary_0", "Maximum Bytes Used", "max_bytes", STAT_INT, &Mem_Max_Bytes );
                        Stat_Group_Add_Member(sgroup, &Mem_Max_Bytes);
                        Stat_Insert_Record("Memory_Summary_0", "Current Objects Used", "objs", STAT_INT, &Mem_Obj_Allocated );
                        Stat_Group_Add_Member(sgroup, &Mem_Obj_Allocated);
                        Stat_Insert_Record("Memory_Summary_0", "Maximum Objects Used", "max_objs", STAT_INT, &Mem_Max_Objects);
                        Stat_Group_Add_Member(sgroup, &Mem_Max_Objects);
                        Stat_Insert_Record("Memory_Summary_0", "Current Objects Inuse", "objs_inuse", STAT_INT, &Mem_Obj_Inuse);
                        Stat_Group_Add_Member(sgroup, &Mem_Obj_Inuse);
                        Stat_Insert_Record("Memory_Summary_0", "Maximum Objects Inuse", "max_obj_inuse", STAT_INT, &Mem_Max_Obj_Inuse);
                        Stat_Group_Add_Member(sgroup, &Mem_Max_Obj_Inuse);
                }
                MemStatus_initialized = TRUE;
        }

        for (obj_type = 1; obj_type < MAX_MEM_OBJECTS; obj_type++)
        {
                if (Mem[obj_type].exist) {
                        sprintf(memobj_name, "Memory_%d", obj_type);
                        sprintf(memobj_desc, "Memory statistics for object: %s", Objnum_to_String(obj_type) );
                        sgroup = Stat_Group_Create(memobj_name, memobj_desc);
                        if (!sgroup)
                                Alarm(PRINT, "Mem_init_object:Failed to create stat group for object: %s\n", Objnum_to_String(obj_type) );
                        else {
#ifndef NDEBUG
                                Stat_Insert_Record(memobj_name, "Current Bytes Used", "bytes", STAT_INT, &(Mem[obj_type].bytes_allocated) );
                                Stat_Group_Add_Member(sgroup, &(Mem[obj_type].bytes_allocated) );
                                Stat_Insert_Record(memobj_name, "Maximum Bytes Used", "max_bytes", STAT_INT, &(Mem[obj_type].max_bytes) );
                                Stat_Group_Add_Member(sgroup, &(Mem[obj_type].max_bytes) );
                                Stat_Insert_Record(memobj_name, "Current Objects Used", "objs", STAT_INT, &(Mem[obj_type].num_obj) );
                                Stat_Group_Add_Member(sgroup, &(Mem[obj_type].num_obj) );
                                Stat_Insert_Record(memobj_name, "Maximum Objects Used", "max_objs", STAT_INT, &(Mem[obj_type].max_obj) );
                                Stat_Group_Add_Member(sgroup, &(Mem[obj_type].max_obj) );
                                Stat_Insert_Record(memobj_name, "Current Objects Inuse", "obj_inuse", STAT_INT, &(Mem[obj_type].num_obj_inuse) );
                                Stat_Group_Add_Member(sgroup, &(Mem[obj_type].num_obj_inuse) );
                                Stat_Insert_Record(memobj_name, "Maximum Objects Inuse", "max_inuse", STAT_INT, &(Mem[obj_type].max_obj_inuse) );
                                Stat_Group_Add_Member(sgroup, &(Mem[obj_type].max_obj_inuse) );
#endif
                                Stat_Insert_Record(memobj_name, "Current Objects In Pool", "obj_inpool", STAT_INT, &(Mem[obj_type].num_obj_inpool) );
                                Stat_Group_Add_Member(sgroup, &(Mem[obj_type].num_obj_inpool) );
                        }
                } /* if exists */
        } /* for loop */
        return;
#else
        return;
#endif
}
void            Mem_init_object_abort( int32u obj_type, int32u size, unsigned int threshold, unsigned int initial )
{
        char    *obj_name;
        int     ret;

        ret = Mem_init_object( obj_type, size, threshold, initial );
        if (ret < 0 ) {
                obj_name = Objnum_to_String( obj_type );
                Alarm( EXIT, "Mem_init_object_abort: Failed to initialize a/an %s object\n", obj_name);
        }
}
/* Input: valid object type, threshold/watermark value for this object, initial objects to create
 * Output: none
 * Effects: sets watermark for type,creates initial memory buffers and updates global vars
 * Should ONLY be called once per execution of the program
 */
int            Mem_init_object(int32u obj_type, int32u size, unsigned int threshold, unsigned int initial)
{
        int mem_error = 0;
#ifdef  SPREAD_STATUS
        char memobj_name[32];
        char memobj_desc[200];
        struct StatGroup *sgroup;
#endif
        assert((obj_type > 0) && (obj_type < MAX_MEM_OBJECTS));
        assert(size > 0 );

#ifndef NDEBUG
        if (!Initialized) {
                /* do any initialization needed just once here */
                Mem_Bytes_Allocated = 0;
                Mem_Obj_Allocated = 0;
                Mem_Obj_Inuse = 0;
                Mem_Max_Bytes = 0;
                Mem_Max_Objects = 0;
                Mem_Max_Obj_Inuse = 0;
                
                Initialized = TRUE;
        }
#endif
        assert(!(Mem[obj_type].exist));

        if( obj_type == BLOCK_OBJECT )
        {
                assert(threshold == 0);
                assert(initial == 0);
        }
        
        Mem[obj_type].exist = TRUE;
        Mem[obj_type].size = size;
        Mem[obj_type].threshold = threshold;
        /* Only enabled when MEM_DISABLE_CACHE set. Disable threshold so all memory is dellocated at dispose() */
#ifdef  MEM_DISABLE_CACHE
        Mem[obj_type].threshold = 0;
#endif
#ifndef NDEBUG
        Mem[obj_type].num_obj = 0;
        Mem[obj_type].bytes_allocated = 0;
        Mem[obj_type].num_obj_inuse = 0;
        Mem[obj_type].max_bytes = 0;
        Mem[obj_type].max_obj = 0;
        Mem[obj_type].max_obj_inuse = 0;
#endif
        Mem[obj_type].num_obj_inpool = 0;
        if (initial > 0)
        {
                /* Create 'initial' objects */
                int i;
                mem_header *head_ptr;
                void  ** body_ptr;
                for(i = initial; i > 0; i--)
                {
                        head_ptr = (mem_header *) calloc(1, sizeof(mem_header) + sizeobj(obj_type) );
                        if (head_ptr == NULL) 
                        {
                                Alarm(MEMORY, "mem_init_object: Failure to calloc an initial object. Returning with existant buffers\n");
                                mem_error = 1;
                                break;
                        }


                        head_ptr->obj_type = obj_type;
                        head_ptr->block_len = sizeobj(obj_type);
                        /* We add 1 because pointer arithm. states a pointer + 1 equals a pointer
                         * to the next element in an array where each element is of a particular size.
                         * in this case that size is 8 (or 12) 
                         * (since it is a pointer to a struct of a 32bit int and a size_t)
                         * so adding one actually moves the pointer 8 (or 12) bytes forward!
                         */
                        body_ptr = (void **) (head_ptr + 1);

#ifdef TESTING
 printf("alignment objtype = %u\n", __alignof__(head_ptr->obj_type));
 printf("alignment blocklen = %u\n", __alignof__(head_ptr->block_len));
  printf("initial  head = 0x%x\n", head_ptr);
  printf("initial body = 0x%x\n", body_ptr);
 printf("alignment head = %u\n", __alignof__(head_ptr)); 
 printf("alignment body = %u\n", __alignof__(body_ptr));
 printf("sizeof body pointer = %u\n", sizeof(body_ptr));
 printf("size head = %u\t size body = %u\n", sizeof(mem_header), sizeobj(obj_type)); 
#endif

                        *body_ptr = (void *) Mem[obj_type].list_head;
                        Mem[obj_type].list_head = body_ptr;
                        Mem[obj_type].num_obj_inpool++;
#ifndef NDEBUG
                        Mem[obj_type].num_obj++;
                        Mem[obj_type].bytes_allocated += (sizeobj(obj_type) + sizeof(mem_header));
#endif
                }
#ifndef NDEBUG
                Mem[obj_type].max_bytes = Mem[obj_type].bytes_allocated;    
                Mem[obj_type].max_obj = Mem[obj_type].num_obj;

                Mem_Bytes_Allocated += Mem[obj_type].bytes_allocated;
                Mem_Obj_Allocated += Mem[obj_type].num_obj;
                if (Mem_Bytes_Allocated > Mem_Max_Bytes) 
                {
                        Mem_Max_Bytes = Mem_Bytes_Allocated;
                }
                if (Mem_Obj_Allocated > Mem_Max_Objects)
                {
                        Mem_Max_Objects = Mem_Obj_Allocated;
                } 
#endif
        }

#ifndef NDEBUG
#ifdef SPREAD_STATUS
        if (MemStatus_initialized) {
                sprintf(memobj_name, "Memory_%d", obj_type);
                sprintf(memobj_desc, "Memory statistics for object: %s", Objnum_to_String(obj_type) );
                sgroup = Stat_Group_Create(memobj_name, memobj_desc);
                if (!sgroup)
                        Alarm(PRINT, "Mem_init_object:Failed to create stat group for object: %s\n", Objnum_to_String(obj_type) );
                else {
                        Stat_Insert_Record(memobj_name, "Current Bytes Used", "bytes", STAT_INT, &(Mem[obj_type].bytes_allocated) );
                        Stat_Group_Add_Member(sgroup, &(Mem[obj_type].bytes_allocated) );
                        Stat_Insert_Record(memobj_name, "Maximum Bytes Used", "max_bytes", STAT_INT, &(Mem[obj_type].max_bytes) );
                        Stat_Group_Add_Member(sgroup, &(Mem[obj_type].max_bytes) );
                        Stat_Insert_Record(memobj_name, "Current Objects Used", "objs", STAT_INT, &(Mem[obj_type].num_obj) );
                        Stat_Group_Add_Member(sgroup, &(Mem[obj_type].num_obj) );
                        Stat_Insert_Record(memobj_name, "Maximum Objects Used", "max_objs", STAT_INT, &(Mem[obj_type].max_obj) );
                        Stat_Group_Add_Member(sgroup, &(Mem[obj_type].max_obj) );
                        Stat_Insert_Record(memobj_name, "Current Objects Inuse", "obj_inuse", STAT_INT, &(Mem[obj_type].num_obj_inuse) );
                        Stat_Group_Add_Member(sgroup, &(Mem[obj_type].num_obj_inuse) );
                        Stat_Insert_Record(memobj_name, "Maximum Objects Inuse", "max_inuse", STAT_INT, &(Mem[obj_type].max_obj_inuse) );
                        Stat_Group_Add_Member(sgroup, &(Mem[obj_type].max_obj_inuse) );
                        Stat_Insert_Record(memobj_name, "Current Objects In Pool", "obj_inpool", STAT_INT, &(Mem[obj_type].num_obj_inpool) );
                        Stat_Group_Add_Member(sgroup, &(Mem[obj_type].num_obj_inpool) );
                }
        } /* if memstatus_init */
#endif
#endif

        if (mem_error) { return(MEM_ERR); }
        return(0);
}


/* Input: a valid type of object
 * Output: a pointer to memory which will hold an object
 * Effects: will only allocate an object from system if none exist in pool
 */
void *          new(int32u obj_type)
{

        assert(Mem_valid_objtype(obj_type));

        if (Mem[obj_type].list_head == NULL) 
        {
                mem_header *    head_ptr;
                
                head_ptr = (mem_header *) calloc(1, sizeof(mem_header) + sizeobj(obj_type) );
                if (head_ptr == NULL) 
                {
                        Alarm(MEMORY, "mem_alloc_object: Failure to calloc an object. Returning NULL object\n");
                        return(NULL);
                }
                head_ptr->obj_type = obj_type;
                head_ptr->block_len = sizeobj(obj_type);

#ifndef NDEBUG
                Mem[obj_type].num_obj++;
                Mem[obj_type].num_obj_inuse++;
                Mem[obj_type].bytes_allocated += (sizeobj(obj_type) + sizeof(mem_header));
                if (Mem[obj_type].bytes_allocated > Mem[obj_type].max_bytes)
                {
                        Mem[obj_type].max_bytes = Mem[obj_type].bytes_allocated;
                }
                if (Mem[obj_type].num_obj > Mem[obj_type].max_obj)
                {       
                        Mem[obj_type].max_obj = Mem[obj_type].num_obj;
                }
                if (Mem[obj_type].num_obj_inuse > Mem[obj_type].max_obj_inuse)
                {
                        Mem[obj_type].max_obj_inuse = Mem[obj_type].num_obj_inuse;
                }

                Mem_Bytes_Allocated += (sizeobj(obj_type) + sizeof(mem_header));
                Mem_Obj_Allocated++;
                Mem_Obj_Inuse++;
                if (Mem_Bytes_Allocated > Mem_Max_Bytes) 
                {
                        Mem_Max_Bytes = Mem_Bytes_Allocated;
                }
                if (Mem_Obj_Allocated > Mem_Max_Objects)
                {
                        Mem_Max_Objects = Mem_Obj_Allocated;
                }
                if (Mem_Obj_Inuse > Mem_Max_Obj_Inuse)
                {
                        Mem_Max_Obj_Inuse = Mem_Obj_Inuse;
                }

#endif
#ifdef TESTING
        printf("alloc:object = 0x%x\n", head_ptr + 1);
        printf("alloc:mem_headerptr = 0x%x\n", head_ptr);
        printf("alloc:objtype = %u:\n", head_ptr->obj_type);
        printf("alloc:blocklen = %u:\n", head_ptr->block_len);
#endif
        Alarm(MEMORY, "new: creating pointer 0x%x to object type %d named %s\n", head_ptr + 1, obj_type, Objnum_to_String(obj_type));

                return((void *) (head_ptr + 1));
        } else
        {
                void ** body_ptr;
                assert(Mem[obj_type].num_obj_inpool > 0 );

                body_ptr = Mem[obj_type].list_head;
                Mem[obj_type].list_head = (void *) *(body_ptr);
                Mem[obj_type].num_obj_inpool--;
#ifndef NDEBUG
                Mem[obj_type].num_obj_inuse++;
                if (Mem[obj_type].num_obj_inuse > Mem[obj_type].max_obj_inuse)
                {
                        Mem[obj_type].max_obj_inuse = Mem[obj_type].num_obj_inuse;
                }
                Mem_Obj_Inuse++;
                if (Mem_Obj_Inuse > Mem_Max_Obj_Inuse)
                {
                        Mem_Max_Obj_Inuse = Mem_Obj_Inuse;
                }

#endif
#ifdef TESTING
        printf("pool:object = 0x%x\n", body_ptr);
        printf("pool:mem_headerptr = 0x%x\n", mem_header_ptr((void *) body_ptr));
        printf("pool:objtype = %u:\n", mem_header_ptr((void *) body_ptr)->obj_type);
        printf("pool:blocklen = %u:\n", mem_header_ptr((void *) body_ptr)->block_len);
#endif
                Alarm(MEMORY, "new: reusing pointer 0x%x to object type %d named %s\n", body_ptr, obj_type, Objnum_to_String(obj_type));

                return((void *) (body_ptr));
        }
}


/* Input: a size of memory block desired
 * Output: a pointer to memory which will hold the block
 * Effects: 
 */
void *          Mem_alloc( unsigned int length)
{
        mem_header * head_ptr;

        if (length == 0) { return(NULL); }
        if( !Mem[BLOCK_OBJECT].exist )
        { 
                Mem[BLOCK_OBJECT].exist = TRUE;
                Mem[BLOCK_OBJECT].size = 0;
                Mem[BLOCK_OBJECT].threshold = 0;
        }

        
        head_ptr = (mem_header *) calloc(1, sizeof(mem_header) + length);
        if (head_ptr == NULL) 
        {
                Alarm(MEMORY, "mem_alloc: Failure to calloc a block. Returning NULL block\n");
                return(NULL);
        }
        head_ptr->obj_type = BLOCK_OBJECT;
        head_ptr->block_len = length;

#ifndef NDEBUG

        Mem[BLOCK_OBJECT].num_obj++;
        Mem[BLOCK_OBJECT].num_obj_inuse++;
        Mem[BLOCK_OBJECT].bytes_allocated += (length + sizeof(mem_header));
        if (Mem[BLOCK_OBJECT].bytes_allocated > Mem[BLOCK_OBJECT].max_bytes)
        {
                Mem[BLOCK_OBJECT].max_bytes = Mem[BLOCK_OBJECT].bytes_allocated;
        }
        if (Mem[BLOCK_OBJECT].num_obj > Mem[BLOCK_OBJECT].max_obj)
        {       
                Mem[BLOCK_OBJECT].max_obj = Mem[BLOCK_OBJECT].num_obj;
        }
        if (Mem[BLOCK_OBJECT].num_obj_inuse > Mem[BLOCK_OBJECT].max_obj_inuse)
        {
                Mem[BLOCK_OBJECT].max_obj_inuse = Mem[BLOCK_OBJECT].num_obj_inuse;
        }
        
        Mem_Bytes_Allocated += (length + sizeof(mem_header));
        Mem_Obj_Allocated++;
        Mem_Obj_Inuse++;
        if (Mem_Bytes_Allocated > Mem_Max_Bytes) 
        {
                Mem_Max_Bytes = Mem_Bytes_Allocated;
        }
        if (Mem_Obj_Allocated > Mem_Max_Objects)
        {
                Mem_Max_Objects = Mem_Obj_Allocated;
        }
        if (Mem_Obj_Inuse > Mem_Max_Obj_Inuse)
        {
                Mem_Max_Obj_Inuse = Mem_Obj_Inuse;
        }

#endif        
        return((void *) (head_ptr + 1));
}


/* Input: a valid pointer to an object or block  created by new or mem_alloc
 * Output: none
 * Effects: destroys the object and frees memory associated with it if necessary 
 */
void            dispose(void *object)
{
        int32u obj_type;

        if (object == NULL) { return; }

        obj_type = mem_header_ptr(object)->obj_type;
#ifdef TESTING
        printf("disp:object = 0x%x\n", object);
        printf("disp:mem_headerptr = 0x%x\n", mem_header_ptr(object));
        printf("disp:objtype = %u:\n", mem_header_ptr(object)->obj_type);
        printf("disp:blocklen = %u:\n", mem_header_ptr(object)->block_len);
#endif
        assert(Mem_valid_objtype(obj_type));
#ifndef NDEBUG
        assert(Mem[obj_type].num_obj_inuse > 0);
        assert(Mem[obj_type].num_obj > 0);
        assert(Mem[obj_type].bytes_allocated >= mem_header_ptr(object)->block_len + sizeof(mem_header));

        Alarm(MEMORY, "dispose: disposing pointer 0x%x to object type %d named %s\n", object, obj_type, Objnum_to_String(obj_type));

        Mem[obj_type].num_obj_inuse--;
        Mem_Obj_Inuse--;
        if (obj_type == BLOCK_OBJECT) 
        {
                assert(Mem[obj_type].num_obj_inpool == 0);
                assert(Mem[obj_type].threshold == 0);
        }

#endif
        if ( Mem_obj_in_pool(obj_type) >= Mem[obj_type].threshold)
        {
#ifndef NDEBUG
                Mem[obj_type].num_obj--;
                Mem[obj_type].bytes_allocated -= (sizeobj(obj_type) + sizeof(mem_header));
                Mem_Obj_Allocated--;
                Mem_Bytes_Allocated -= (sizeobj(obj_type) + sizeof(mem_header));
#endif
                free(mem_header_ptr(object));

        } else 
        {
                void ** body_ptr;
                
                body_ptr = (void **) object;
                *body_ptr = (void *) Mem[obj_type].list_head;
                Mem[obj_type].list_head = body_ptr;
                Mem[obj_type].num_obj_inpool++;
        }
}
/* Input: A valid pointer to an object/block created with new or mem_alloc
 * Output: the obj_type of this block of memory
 */
int32u  Mem_Obj_Type(const void *object)
{
        int32u  obj_type;

        assert(NULL != object);
        obj_type = mem_header_ptr(object)->obj_type;
        assert(Mem_valid_objtype(obj_type));

        return(obj_type);
}

/* Input: a valid pointer to an object/block created with memalloc_object or mem_alloc
 * Output: a pointer to an object/block which is an identical copy of the object input
 * Effects: same as memalloc_object or mem_alloc
 */
void *      Mem_copy(const void *object)
{
        void * new_object;
        int32u obj_type;

        if (object == NULL) { return(NULL); }

        obj_type = mem_header_ptr(object)->obj_type;
        assert(Mem_valid_objtype(obj_type));
        if (obj_type == BLOCK_OBJECT)
        {
                new_object = (void *) Mem_alloc(mem_header_ptr(object)->block_len);
        } else 
        {
                new_object =(void *) new(obj_type);
        }
        if (new_object == NULL) { return(NULL); }

        new_object =(void*)
 memcpy(new_object, object, mem_header_ptr(object)->block_len);

        mem_header_ptr(new_object)->obj_type = mem_header_ptr(object)->obj_type;
        mem_header_ptr(new_object)->block_len = mem_header_ptr(object)->block_len;

        return(new_object);

}

#if ( SPREAD_PROTOCOL == 3 )
char    *Objnum_to_String(int32u oid)
{

        switch(oid)
        {
        case BASE_OBJ:
                return("base_obj");
        case PACK_HEAD_OBJ:
                return("pack_head_obj");
        case MESSAGE_OBJ:
                return("message_obj");
        case MSG_FRAG_OBJ:
                return("msg_frag_obj");
        case RET_REQ_OBJ:
                return("ret_req_obj");
        case LINK_ACK_OBJ:
                return("link_ack_obj");
        case ARU_UPDATE_OBJ:
                return("aru_update_obj");
        case TOKEN_HEAD_OBJ:
                return("token_head_obj");
        case TOKEN_BODY_OBJ:
                return("token_body_obj");
        case JOIN_OBJ:
                return("join_obj");
        case REFER_OBJ:
                return("refer_obj");
        case ALIVE_OBJ:
                return("alive_obj");
        case SCATTER:
                return("scatter");
        case QUEUE_ELEMENT:
                return("queue_element");
        case QUEUE:
                return("queue");
        case RETRANS_ENTRY:
                return("retrans_entry");
        case RING_LINK_OBJ:
                return("ring_link_obj");
        case HOP_LINK_OBJ:
                return("hop_link_obj");
        case MESSAGE_LINK:
                return("message_link");
        case DOWN_LINK:
                return("down_link");
        case TREE_NODE:
                return("tree_node");
        case MESSAGE_FRAG_LIST:
                return("message_frag_list");
        case LBUCKET:
                return("leaky_bucket");
        case GROUP:
                return("group");
        case MEMBER:
                return("member");
        case MSG_LIST_ENTRY:
                return("msg_list_entry");
        case SESS_SEQ_ENTRY:
                return("sess_seq_entry");
        case TIME_EVENT:
                return("time_event");
	case ROUTE_WEIGHTS:
	        return("route_weights");
        case PROF_FUNCT:
                return("prof_funct");
        case QUEUE_SET:
                return("queue_set");
        case MQUEUE_ELEMENT:
                return("mqueue_element");
        case TCP_LINK_OBJ:
                return("tcp_link_object");
        case MESSAGE_META_OBJ:
                return("message_meta_object");
        case PROC_RECORD:
                return("proc_info");
        case SYS_SCATTER:
                return("sys_scatter");
        case STAT_RECORD:
                return("status_record");
        case STAT_GROUP:
                return("status_group");
        case STAT_REFRECORD:
                return("status_refrecord");
        case STATETRANS_OBJ:
                return("statetrans_obj");
        case PACKET_BODY:
                return("packet_body");
        case SESSION_AUTH_INFO:
                return("session_auth_info");
        default:
                return("Unknown_obj");
        }       
}
#endif



syntax highlighted by Code2HTML, v. 0.9.1