From b04539f2fc1c8912b28680309b78dbe748156027 Mon Sep 17 00:00:00 2001 From: Iliyan Malchev Date: Wed, 10 Sep 2008 15:13:41 -0700 Subject: initial Signed-off-by: Iliyan Malchev --- ccutil/memry.cpp | 532 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 532 insertions(+) create mode 100644 ccutil/memry.cpp (limited to 'ccutil/memry.cpp') diff --git a/ccutil/memry.cpp b/ccutil/memry.cpp new file mode 100644 index 0000000..dfd1f90 --- /dev/null +++ b/ccutil/memry.cpp @@ -0,0 +1,532 @@ +/********************************************************************** + * File: memry.c (Formerly memory.c) + * Description: Memory allocation with builtin safety checks. + * Author: Ray Smith + * Created: Wed Jan 22 09:43:33 GMT 1992 + * + * (C) Copyright 1992, Hewlett-Packard Ltd. + ** Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + * + **********************************************************************/ + +#include "mfcpch.h" +#include +#ifdef __UNIX__ +#include +#endif +#include "stderr.h" +#include "tprintf.h" +#include "memblk.h" +#include "memry.h" + +//#define COUNTING_CLASS_STRUCTURES + +/********************************************************************** + * new + * + * Replace global new to get at memory leaks etc. + **********************************************************************/ +/* +void* operator new( //allocate memory +size_t size //amount to allocate +) +{ + if (size==0) + { + err.log(RESULT_LOGICAL_ERROR,E_LOC,ERR_PRIMITIVES, + ERR_SCROLLING,ERR_CONTINUE,ERR_ERROR, + "Zero requested of new"); + size=1; + } + return alloc_big_mem(size); +} + +void operator delete( //free memory +void* addr //mem to free +) +{ + free_big_mem(addr); +}*/ + +/********************************************************************** + * check_mem + * + * Check consistency of all memory controlled by alloc_mem. + **********************************************************************/ + +DLLSYM void check_mem( //check consistency + const char *string, //context message + inT8 level //level of check + ) { + big_mem.check (string, level); + main_mem.check (string, level); + check_structs(level); +} + + +/********************************************************************** + * alloc_string + * + * Allocate space for a string. The space can only be used for chars as + * it is not aligned. Allocation is guaranteed to be fast and not cause + * fragmentation for small strings (upto 10*worst alignment). Calls for + * larger strings will be satisfied with alloc_mem. + * Use free_string to free the space from alloc_string. + **********************************************************************/ + +DLLSYM char *alloc_string( //allocate string + inT32 count //no of chars required + ) { +#ifdef RAYS_MALLOC + char *string; //allocated string + + if (count < 1 || count > MAX_CHUNK) { + tprintf ("Invalid size %d requested of alloc_string", count); + return NULL; + } + + count++; //add size byte + if (count <= MAX_STRUCTS * sizeof (MEMUNION)) { + string = (char *) alloc_struct (count, "alloc_string"); + //get a fast structure + if (string == NULL) { + tprintf ("No memory for alloc_string"); + return NULL; + } + string[0] = (inT8) count; //save its length + } + else { + //get a big block + string = (char *) alloc_mem (count); + if (string == NULL) { + tprintf ("No memory for alloc_string"); + return NULL; + } + string[0] = 0; //mark its id + } + return &string[1]; //string for user +#else + // Round up the amount allocated to a multiple of 4 + return static_cast(malloc((count + 3) & ~3)); +#endif +} + + +/********************************************************************** + * free_string + * + * Free a string allocated by alloc_string. + **********************************************************************/ + +DLLSYM void free_string( //free a string + char *string //string to free + ) { +#ifdef RAYS_MALLOC + if (((ptrdiff_t) string & 3) == 1) { //one over word + string--; //get id marker + if (*string == 0) { + free_mem(string); //generally free it + return; + } + else if (*string <= MAX_STRUCTS * sizeof (MEMUNION)) { + //free structure + free_struct (string, *string, "alloc_string"); + return; + } + } + tprintf ("Non-string given to free_string"); +#else + free(string); +#endif +} + + +/********************************************************************** + * alloc_struct + * + * Allocate space for a structure. This function is designed to be + * fast and fragmentation free for arbitrary combinations of small + * objects. (Upto 40 bytes in length.) + * It can be used for any size of object up to 512K, but you must use + * free_struct to release the memory it gives. alloc_mem is better + * for arbitrary data blocks of large size (>40 bytes.) + * alloc_struct always aborts if the allocation fails. + **********************************************************************/ + +DLLSYM void * +alloc_struct ( //allocate memory +inT32 count, //no of chars required +#if defined COUNTING_CLASS_STRUCTURES +const char *name //name of type +#else +const char * //name of type +#endif +) { +#ifdef RAYS_MALLOC + MEMUNION *element; //current element + MEMUNION *returnelement; //return value + inT32 struct_count; //no of required structs + inT32 blocksize; //no of structs in block + inT32 index; //index to structure + + if (count < 1 || count > MAX_CHUNK) { + tprintf ("Invalid size %d requested of alloc_struct", count); + return NULL; + } + + // tprintf("Allocating structure of size %d\n",count); + //no of MEMUNIONS-1 + struct_count = (count - 1) / sizeof (MEMUNION); + if (struct_count < MAX_STRUCTS) { + //can do fixed sizes + #ifdef COUNTING_CLASS_STRUCTURES + if (name != NULL) { + index = identify_struct_owner (struct_count, name); + if (index < MAX_CLASSES) + owner_counts[struct_count][index]++; + } + #endif + //head of freelist + returnelement = free_structs[struct_count]; + if (returnelement == NULL) { + //need a new block + //get one + element = (MEMUNION *) new_struct_block (); + if (element == NULL) { + tprintf ("No memory to satisfy request for %d", (int) count); + return NULL; + } + //add to block list + element->ptr = struct_blocks[struct_count]; + struct_blocks[struct_count] = element; + blocks_in_use[struct_count]++; + element++; //free cell + returnelement = element; //going to return 1st + blocksize = STRUCT_BLOCK_SIZE / (struct_count + 1) - 1; + + for (index = 1; index < blocksize; index++) { + //make links + element->ptr = element + struct_count + 1; + element += struct_count + 1; + } + element->ptr = NULL; //end of freelist + } + //new free one + free_structs[struct_count] = returnelement->ptr; + //count number issued + structs_in_use[struct_count]++; + } + else { + //just get some + returnelement = (MEMUNION *) alloc_mem (count); + if (returnelement == NULL) { + tprintf ("No memory to satisfy request for %d", (int) count); + return NULL; + } + } + return returnelement; //free cell +#else + return malloc(count); +#endif +} + + +/********************************************************************** + * free_struct + * + * Free memory allocated by alloc_struct. The size must be supplied. + **********************************************************************/ + +DLLSYM void +free_struct ( //free a structure +void *deadstruct, //structure to free +inT32 count, //no of bytes +#if defined COUNTING_CLASS_STRUCTURES +const char *name //name of type +#else +const char * //name of type +#endif +) { +#ifdef RAYS_MALLOC + MEMUNION *end_element; //current element + MEMUNION *element; //current element + MEMUNION *prev_element; //previous element + MEMUNION *prev_block; //previous element + MEMUNION *nextblock; //next block in list + MEMUNION *block; //next block in list + inT32 struct_count; //no of required structs + inT32 index; //to structure counts + + if (count < 1 || count > MAX_CHUNK) { + tprintf ("Invalid size %d requested of free_struct", count); + return; + } + + // tprintf("Freeing structure of size %d\n",count); + //no of MEMUNIONS-1 + struct_count = (count - 1) / sizeof (MEMUNION); + + if (deadstruct == NULL) { + //not really legal + check_struct(MEMCHECKS, count); + } + else { + if (struct_count < MAX_STRUCTS) { + //can do fixed sizes + #ifdef COUNTING_CLASS_STRUCTURES + if (name != NULL) { + index = identify_struct_owner (struct_count, name); + if (index < MAX_CLASSES) { + owner_counts[struct_count][index]--; + ASSERT_HOST (owner_counts[struct_count][index] >= 0); + } + } + #endif + element = (MEMUNION *) deadstruct; + //add to freelist + element->ptr = free_structs[struct_count]; + free_structs[struct_count] = element; + //one less in use + structs_in_use[struct_count]--; + if (structs_in_use[struct_count] == 0) { + index = 0; + for (element = struct_blocks[struct_count]; + element != NULL; element = nextblock) { + //traverse and destroy + nextblock = element->ptr; + //free all the blocks + old_struct_block(element); + index++; + } + //none left any more + struct_blocks[struct_count] = NULL; + //no free structs + free_structs[struct_count] = NULL; + blocks_in_use[struct_count] = 0; + } + else if (structs_in_use[struct_count] < 0) { + tprintf ("Negative number of structs of size %d in use", + (int) count); + } + else if (structs_in_use[struct_count] < blocks_in_use[struct_count]) { + prev_block = NULL; + for (block = struct_blocks[struct_count]; + block != NULL; block = nextblock) { + nextblock = block; + index = STRUCT_BLOCK_SIZE / (struct_count + 1) - 1; + end_element = block + STRUCT_BLOCK_SIZE; + for (element = free_structs[struct_count]; + element != NULL; element = element->ptr) { + if (element > nextblock && element < end_element) { + index--; + if (index == 0) + break; + } + } + if (index == 0) { + index = STRUCT_BLOCK_SIZE / (struct_count + 1) - 1; + for (element = + free_structs[struct_count], prev_element = NULL; + element != NULL; element = element->ptr) { + if (element > nextblock && element < end_element) { + index--; + if (prev_element != NULL) + prev_element->ptr = element->ptr; + else + free_structs[struct_count] = element->ptr; + if (index == 0) + break; + } + else + prev_element = element; + } + if (prev_block != NULL) + prev_block->ptr = block->ptr; + else + struct_blocks[struct_count] = block->ptr; + nextblock = block->ptr; + blocks_in_use[struct_count]--; + //free all the blocks + old_struct_block(block); + } + else { + prev_block = block; + //traverse and destroy + nextblock = block->ptr; + } + } + } + } + else + free_mem(deadstruct); //free directly + } +#else + free(deadstruct); +#endif +} + + +/********************************************************************** + * alloc_mem_p + * + * Allocate permanent space which will never be returned. + * This space is allocated from the top end of a memory block to + * avoid the fragmentation which would result from alternate use + * of alloc_mem for permanent and temporary blocks. + **********************************************************************/ + +//#ifdef __UNIX__ +//#pragma OPT_LEVEL 0 +//#endif +DLLSYM void *alloc_mem_p( //allocate permanent space + inT32 count //block size to allocate + ) { + #ifdef RAYS_MALLOC + #ifdef TESTING_BIGSTUFF + if (main_mem.biggestblock == 0) + main_mem.init (alloc_big_mem, free_big_mem, + FIRSTSIZE, LASTSIZE, MAX_CHUNK); + #else + if (main_mem.biggestblock == 0) + main_mem.init ((void *(*)(inT32)) malloc, free, + FIRSTSIZE, LASTSIZE, MAX_CHUNK); + #endif + if (mem_mallocdepth > 0) + return main_mem.alloc_p (count, trace_caller (mem_mallocdepth)); + else + return main_mem.alloc_p (count, NULL); + #else + return malloc ((size_t) count); + #endif +} + + +/********************************************************************** + * alloc_mem + * + * Return a pointer to a buffer of count bytes aligned for any type. + **********************************************************************/ + +DLLSYM void *alloc_mem( //get some memory + inT32 count //no of bytes to get + ) { + #ifdef RAYS_MALLOC + #ifdef TESTING_BIGSTUFF + if (main_mem.biggestblock == 0) + main_mem.init (alloc_big_mem, free_big_mem, + FIRSTSIZE, LASTSIZE, MAX_CHUNK); + #else + if (main_mem.biggestblock == 0) + main_mem.init ((void *(*)(inT32)) malloc, free, + FIRSTSIZE, LASTSIZE, MAX_CHUNK); + #endif + if (mem_mallocdepth > 0) + return main_mem.alloc (count, trace_caller (mem_mallocdepth)); + else + return main_mem.alloc (count, NULL); + #else + return malloc ((size_t) count); + #endif +} + + +/********************************************************************** + * alloc_big_mem + * + * Return a pointer to a buffer of count bytes aligned for any type. + **********************************************************************/ + +DLLSYM void *alloc_big_mem( //get some memory + inT32 count //no of bytes to get + ) { + #ifdef TESTING_BIGSTUFF + if (big_mem.biggestblock == 0) + big_mem.init ((void *(*)(inT32)) malloc, free, + BIGSIZE, BIGSIZE, MAX_BIGCHUNK); + if (mem_mallocdepth > 0) + return big_mem.alloc (count, trace_caller (mem_mallocdepth)); + else + return big_mem.alloc (count, NULL); + #else + return malloc ((size_t) count); + #endif +} + + +/********************************************************************** + * alloc_big_zeros + * + * Return a pointer to a buffer of count bytes aligned for any type. + **********************************************************************/ + +DLLSYM void *alloc_big_zeros( //get some memory + inT32 count //no of bytes to get + ) { + #ifdef TESTING_BIGSTUFF + if (big_mem.biggestblock == 0) + big_mem.init ((void *(*)(inT32)) malloc, free, + BIGSIZE, BIGSIZE, MAX_BIGCHUNK); + void *buf; //return value + + if (mem_mallocdepth > 0) + buf = big_mem.alloc (count, trace_caller (mem_mallocdepth)); + else + buf = big_mem.alloc (count, NULL); + memset (buf, 0, count); + return buf; + #else + return calloc ((size_t) count, 1); + #endif +} + + +/********************************************************************** + * free_mem + * + * Free a block allocated by alloc_mem (or alloc_mem_p). + * It checks that the pointer is legal and maintains counts of the + * amount of free memory above and below the current free pointer. + **********************************************************************/ + +DLLSYM void free_mem( //free mem from alloc_mem + void *oldchunk //chunk to free + ) { + #ifdef RAYS_MALLOC + if (mem_freedepth > 0 && main_mem.callers != NULL) + main_mem.dealloc (oldchunk, trace_caller (mem_freedepth)); + else + main_mem.dealloc (oldchunk, NULL); + #else + free(oldchunk); + #endif +} + + +/********************************************************************** + * free_big_mem + * + * Free a block allocated by alloc_big_mem. + * It checks that the pointer is legal and maintains counts of the + * amount of free memory above and below the current free pointer. + **********************************************************************/ + +DLLSYM void free_big_mem( //free mem from alloc_mem + void *oldchunk //chunk to free + ) { + #ifdef TESTING_BIGSTUFF + if (mem_freedepth > 0 && main_mem.callers != NULL) + big_mem.dealloc (oldchunk, trace_caller (mem_freedepth)); + else + big_mem.dealloc (oldchunk, NULL); + #else + free(oldchunk); + #endif +} -- cgit v1.2.3