head 1.26; access; symbols MM_1_4_2:1.25 MM_1_4_1:1.25 MM_1_4_0:1.22 MM_1_3_1:1.19 MM_1_3_0:1.18 MM_1_2_2:1.18 MM_1_2_1:1.16 MM_1_2_0:1.16 MM_1_1_3:1.14 MM_1_1_2:1.13 MM_1_1_1:1.13 MM_1_1_0:1.13 MM_1_0_12:1.11 MM_1_0_11:1.11 MM_1_0_10:1.11 MM_1_0_9:1.11 MM_1_0_8:1.10 MM_1_0_7:1.10 MM_1_0_6:1.9 MM_1_0_5:1.7 MM_1_0_4:1.7 MM_1_0_3:1.6 MM_1_0_1:1.5 MM_1_0_0:1.4 MM_1_0b6:1.4 MM_1_0b5:1.4 MM_1_0b4:1.3 MM_1_0b3:1.3 MM_1_0b2plus:1.1.1.1 RSE:1.1.1; locks; strict; comment @ * @; 1.26 date 2007.01.01.18.26.34; author rse; state Exp; branches; next 1.25; commitid xbmVq17WhC8zJP0s; 1.25 date 2006.08.10.19.00.33; author rse; state Exp; branches; next 1.24; commitid zS8gipIRuG1bykIr; 1.24 date 2006.06.10.21.25.54; author rse; state Exp; branches; next 1.23; commitid MFCthRi9H63BjvAr; 1.23 date 2006.06.10.21.12.35; author rse; state Exp; branches; next 1.22; commitid yh47L1Jei9T3fvAr; 1.22 date 2005.09.02.20.00.46; author rse; state Exp; branches; next 1.21; 1.21 date 2005.09.02.19.50.34; author rse; state Exp; branches; next 1.20; 1.20 date 2004.11.15.16.48.06; author rse; state Exp; branches; next 1.19; 1.19 date 2004.09.12.18.35.01; author rse; state Exp; branches; next 1.18; 1.18 date 2002.12.19.09.25.24; author rse; state Exp; branches; next 1.17; 1.17 date 2002.12.19.09.14.58; author rse; state Exp; branches; next 1.16; 1.16 date 2002.07.26.09.59.34; author rse; state Exp; branches; next 1.15; 1.15 date 2001.01.29.20.27.22; author rse; state Exp; branches; next 1.14; 1.14 date 2000.06.20.06.59.36; author rse; state Exp; branches; next 1.13; 1.13 date 2000.03.23.16.15.53; author rse; state Exp; branches; next 1.12; 1.12 date 2000.01.09.20.19.40; author rse; state Exp; branches; next 1.11; 1.11 date 99.07.02.20.01.04; author rse; state Exp; branches; next 1.10; 1.10 date 99.06.22.13.23.51; author rse; state Exp; branches; next 1.9; 1.9 date 99.06.06.11.03.21; author rse; state Exp; branches; next 1.8; 1.8 date 99.06.06.10.07.51; author rse; state Exp; branches; next 1.7; 1.7 date 99.05.21.21.20.09; author rse; state Exp; branches; next 1.6; 1.6 date 99.05.15.11.45.22; author rse; state Exp; branches; next 1.5; 1.5 date 99.04.18.10.39.51; author rse; state Exp; branches; next 1.4; 1.4 date 99.03.18.09.02.13; author rse; state Exp; branches; next 1.3; 1.3 date 99.03.15.13.25.48; author rse; state Exp; branches; next 1.2; 1.2 date 99.03.15.12.58.49; author rse; state Exp; branches; next 1.1; 1.1 date 99.03.15.11.12.50; author rse; state Exp; branches 1.1.1.1; next ; 1.1.1.1 date 99.03.15.11.12.50; author rse; state Exp; branches; next ; desc @@ 1.26 log @Updated all copyright messages for year 2007 @ text @/* ==================================================================== * Copyright (c) 1999-2007 Ralf S. Engelschall * Copyright (c) 1999-2007 The OSSP Project * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by * Ralf S. Engelschall ." * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by * Ralf S. Engelschall ." * * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== */ /* ** ** mm_alloc.c -- Standard Malloc-Style API ** */ #define MM_PRIVATE #include "mm.h" /* * Create a memory pool */ MM *mm_create(size_t usize, const char *file) { MM *mm = NULL; void *core; size_t size; size_t maxsize; /* defaults */ maxsize = mm_maxsize(); if (usize == 0) usize = maxsize; if (usize > maxsize) usize = maxsize; if (usize < MM_ALLOC_MINSIZE) usize = MM_ALLOC_MINSIZE; /* determine size */ size = usize+SIZEOF_mem_pool; /* get a shared memory area */ if ((core = mm_core_create(size, file)) == NULL) return NULL; /* fill in the memory pool structure */ mm = (MM *)core; mm->mp_size = size; mm->mp_offset = SIZEOF_mem_pool; /* first element of list of free chunks counts existing chunks */ mm->mp_freechunks.mc_size = 0; /* has to be 0 forever */ mm->mp_freechunks.mc_usize = 0; /* counts chunks */ mm->mp_freechunks.mc_u.mc_next = NULL; return mm; } /* * Set permissions on memory pool's underlaying disk files */ int mm_permission(MM *mm, mode_t mode, uid_t owner, gid_t group) { if (mm == NULL) return -1; return mm_core_permission((void *)mm, mode, owner, group); } /* * Reset a memory pool. */ void mm_reset(MM *mm) { if (mm == NULL) return; mm->mp_offset = SIZEOF_mem_pool; mm->mp_freechunks.mc_usize = 0; mm->mp_freechunks.mc_u.mc_next = NULL; return; } /* * Destroy a memory pool */ void mm_destroy(MM *mm) { if (mm == NULL) return; /* wipe out the whole area to be safe */ memset(mm, 0, mm->mp_size); /* and delete the core area */ (void)mm_core_delete((void *)mm); return; } /* * Lock a memory pool */ int mm_lock(MM *mm, mm_lock_mode mode) { if (mm == NULL) return FALSE; return mm_core_lock((void *)mm, mode); } /* * Unlock a memory pool */ int mm_unlock(MM *mm) { if (mm == NULL) return FALSE; return mm_core_unlock((void *)mm); } /* * Display debugging information */ void mm_display_info(MM *mm) { mem_chunk *mc; int nFree; int nAlloc; int i; if (!mm_core_lock((void *)mm, MM_LOCK_RD)) return; mc = &(mm->mp_freechunks); nFree = 0; while (mc->mc_u.mc_next != NULL) { mc = mc->mc_u.mc_next; nFree += mc->mc_size; } nAlloc = mm->mp_offset-SIZEOF_mem_pool-nFree; fprintf(stderr, "Information for MM\n"); fprintf(stderr, " memory area = 0x%lx - 0x%lx\n", (unsigned long)mm, (unsigned long)(mm+mm->mp_size)); fprintf(stderr, " memory size = %d\n", mm->mp_size); fprintf(stderr, " memory offset = %d\n", mm->mp_offset); fprintf(stderr, " bytes spare = %d\n", mm->mp_size-mm->mp_offset); fprintf(stderr, " bytes free = %d (%d chunk%s)\n", nFree, mm->mp_freechunks.mc_usize, mm->mp_freechunks.mc_usize == 1 ? "" : "s"); fprintf(stderr, " bytes allocated = %d\n", nAlloc); fprintf(stderr, " List of free chunks:\n"); if (mm->mp_freechunks.mc_usize > 0) { mc = &(mm->mp_freechunks); i = 1; while (mc->mc_u.mc_next != NULL) { mc = mc->mc_u.mc_next; fprintf(stderr, " chunk #%03d: 0x%lx-0x%lx (%d bytes)\n", i++, (unsigned long)mc, (unsigned long)(mc+mc->mc_size), mc->mc_size); } } else { fprintf(stderr, " \n"); } mm_core_unlock((void *)mm); return; } /* * Insert a chunk to the list of free chunks. Algorithm used is: * Insert in sorted manner to the list and merge with previous * and/or next chunk when possible to form larger chunks out of * smaller ones. */ static void mm_insert_chunk(MM *mm, mem_chunk *mcInsert) { mem_chunk *mc; mem_chunk *mcPrev; mem_chunk *mcPrevPrev; mem_chunk *mcNext; if (!mm_core_lock((void *)mm, MM_LOCK_RW)) return; mc = &(mm->mp_freechunks); mcPrevPrev = mc; while (mc->mc_u.mc_next != NULL && (char *)(mc->mc_u.mc_next) < (char *)mcInsert) { mcPrevPrev = mc; mc = mc->mc_u.mc_next; } mcPrev = mc; mcNext = mc->mc_u.mc_next; if (mcPrev == mcInsert || mcNext == mcInsert) { mm_core_unlock((void *)mm); ERR(MM_ERR_ALLOC, "chunk of memory already in free list"); return; } if ((char *)mcPrev+(mcPrev->mc_size) == (char *)mcInsert && (mcNext != NULL && (char *)mcInsert+(mcInsert->mc_size) == (char *)mcNext)) { /* merge with previous and next chunk */ mcPrev->mc_size += mcInsert->mc_size + mcNext->mc_size; mcPrev->mc_u.mc_next = mcNext->mc_u.mc_next; mm->mp_freechunks.mc_usize -= 1; } else if ((char *)mcPrev+(mcPrev->mc_size) == (char *)mcInsert && (char *)mcInsert+(mcInsert->mc_size) == ((char *)mm + mm->mp_offset)) { /* merge with previous and spare block (to increase spare area) */ mcPrevPrev->mc_u.mc_next = mcPrev->mc_u.mc_next; mm->mp_offset -= (mcInsert->mc_size + mcPrev->mc_size); mm->mp_freechunks.mc_usize -= 1; } else if ((char *)mcPrev+(mcPrev->mc_size) == (char *)mcInsert) { /* merge with previous chunk */ mcPrev->mc_size += mcInsert->mc_size; } else if (mcNext != NULL && (char *)mcInsert+(mcInsert->mc_size) == (char *)mcNext) { /* merge with next chunk */ mcInsert->mc_size += mcNext->mc_size; mcInsert->mc_u.mc_next = mcNext->mc_u.mc_next; mcPrev->mc_u.mc_next = mcInsert; } else if ((char *)mcInsert+(mcInsert->mc_size) == ((char *)mm + mm->mp_offset)) { /* merge with spare block (to increase spare area) */ mm->mp_offset -= mcInsert->mc_size; } else { /* no merging possible, so insert as new chunk */ mcInsert->mc_u.mc_next = mcNext; mcPrev->mc_u.mc_next = mcInsert; mm->mp_freechunks.mc_usize += 1; } mm_core_unlock((void *)mm); return; } /* * Retrieve a chunk from the list of free chunks. Algorithm used * is: Search for minimal-sized chunk which is larger or equal * than the request size. But when the retrieved chunk is still a * lot larger than the requested size, split out the requested * size to not waste memory. */ static mem_chunk *mm_retrieve_chunk(MM *mm, size_t size) { mem_chunk *mc; mem_chunk **pmcMin; mem_chunk *mcRes; size_t sMin; size_t s; if (size == 0) return NULL; if (mm->mp_freechunks.mc_usize == 0) return NULL; if (!mm_core_lock((void *)mm, MM_LOCK_RW)) return NULL; /* find best-fitting chunk */ pmcMin = NULL; sMin = mm->mp_size; /* initialize with maximum possible */ mc = &(mm->mp_freechunks); while (mc->mc_u.mc_next != NULL) { s = mc->mc_u.mc_next->mc_size; if (s >= size && s < sMin) { pmcMin = &(mc->mc_u.mc_next); sMin = s; if (s == size) break; } mc = mc->mc_u.mc_next; } /* create result chunk */ if (pmcMin == NULL) mcRes = NULL; else { mcRes = *pmcMin; if (mcRes->mc_size >= (size + min_of(2*size,128))) { /* split out in part */ s = mcRes->mc_size - size; mcRes->mc_size = size; /* add back remaining chunk part as new chunk */ mc = (mem_chunk *)((char *)mcRes + size); mc->mc_size = s; mc->mc_u.mc_next = mcRes->mc_u.mc_next; *pmcMin = mc; } else { /* split out as a whole */ *pmcMin = mcRes->mc_u.mc_next; mm->mp_freechunks.mc_usize--; } } mm_core_unlock((void *)mm); return mcRes; } /* * Allocate a chunk of memory */ void *mm_malloc(MM *mm, size_t usize) { mem_chunk *mc; size_t size; void *vp; if (mm == NULL || usize == 0) return NULL; size = mm_core_align2word(SIZEOF_mem_chunk+usize); if ((mc = mm_retrieve_chunk(mm, size)) != NULL) { mc->mc_usize = usize; return &(mc->mc_u.mc_base.mw_cp); } if (!mm_core_lock((void *)mm, MM_LOCK_RW)) return NULL; if ((mm->mp_size - mm->mp_offset) < size) { mm_core_unlock((void *)mm); ERR(MM_ERR_ALLOC, "out of memory"); errno = ENOMEM; return NULL; } mc = (mem_chunk *)((char *)mm + mm->mp_offset); mc->mc_size = size; mc->mc_usize = usize; vp = (void *)&(mc->mc_u.mc_base.mw_cp); mm->mp_offset += size; mm_core_unlock((void *)mm); return vp; } /* * Reallocate a chunk of memory */ void *mm_realloc(MM *mm, void *ptr, size_t usize) { size_t size; mem_chunk *mc; void *vp; if (mm == NULL || usize == 0) return NULL; if (ptr == NULL) return mm_malloc(mm, usize); /* POSIX.1 semantics */ mc = (mem_chunk *)((char *)ptr - SIZEOF_mem_chunk); if (usize <= mc->mc_usize) { mc->mc_usize = usize; return ptr; } size = mm_core_align2word(SIZEOF_mem_chunk+usize); if (size <= mc->mc_size) { mc->mc_usize = usize; return ptr; } if ((vp = mm_malloc(mm, usize)) == NULL) return NULL; memcpy(vp, ptr, mc->mc_usize); mm_free(mm, ptr); return vp; } /* * Free a chunk of memory */ void mm_free(MM *mm, void *ptr) { mem_chunk *mc; if (mm == NULL || ptr == NULL) return; mc = (mem_chunk *)((char *)ptr - SIZEOF_mem_chunk); mm_insert_chunk(mm, mc); return; } /* * Allocate and initialize a chunk of memory */ void *mm_calloc(MM *mm, size_t number, size_t usize) { void *vp; if (mm == NULL || number*usize == 0) return NULL; if ((vp = mm_malloc(mm, number*usize)) == NULL) return NULL; memset(vp, 0, number*usize); return vp; } /* * Duplicate a string */ char *mm_strdup(MM *mm, const char *str) { int n; void *vp; if (mm == NULL || str == NULL) return NULL; n = strlen(str); if ((vp = mm_malloc(mm, n+1)) == NULL) return NULL; memcpy(vp, str, n+1); return vp; } /* * Determine user size of a memory chunk */ size_t mm_sizeof(MM *mm, const void *ptr) { mem_chunk *mc; if (mm == NULL || ptr == NULL) return -1; mc = (mem_chunk *)((char *)ptr - SIZEOF_mem_chunk); return mc->mc_usize; } /* * Determine maximum size of an allocateable memory pool */ size_t mm_maxsize(void) { return (mm_core_maxsegsize()-SIZEOF_mem_pool); } /* * Determine available memory */ size_t mm_available(MM *mm) { mem_chunk *mc; int nFree; if (!mm_core_lock((void *)mm, MM_LOCK_RD)) return 0; nFree = mm->mp_size-mm->mp_offset; mc = &(mm->mp_freechunks); while (mc->mc_u.mc_next != NULL) { mc = mc->mc_u.mc_next; nFree += mc->mc_size; } mm_core_unlock((void *)mm); return nFree; } /* * Return last error string */ char *mm_error(void) { return mm_lib_error_get(); } /*EOF*/ @ 1.25 log @bump copyright for year 2006 @ text @d2 2 a3 2 * Copyright (c) 1999-2006 Ralf S. Engelschall * Copyright (c) 1999-2006 The OSSP Project @ 1.24 log @Add new API function MM_reset() and mm_reset(). Submitted by: Neil Conway @ text @d2 2 a3 2 * Copyright (c) 1999-2005 Ralf S. Engelschall * Copyright (c) 1999-2005 The OSSP Project @ 1.23 log @fix more typos @ text @d101 13 @ 1.22 log @adjust copyright year @ text @d91 1 a91 1 * Set permissions on memory pools underlaying disk files @ 1.21 log @Optimize insertion of free memory chunks by merging with the spare area if possible to decrease memory fragmentation. @ text @d2 2 a3 2 * Copyright (c) 1999-2004 Ralf S. Engelschall * Copyright (c) 1999-2004 The OSSP Project @ 1.20 log @Fix mm_realloc() function: If the memory chunk passed to mm_realloc() can't be extended and a new chunk must be allocated, the old memory is copied into the new chunk with a call to memcpy(3). However, the used size is the length of the new data and will cause memcpy(3) to access memory beyond the old data chunk's boundaries. Submitted by: Kirk Petersen @ text @d191 1 d197 3 a199 1 while (mc->mc_u.mc_next != NULL && (char *)(mc->mc_u.mc_next) < (char *)mcInsert) d201 1 d216 7 d233 4 @ 1.19 log @adjust year in copyright messages @ text @d353 1 a353 1 memcpy(vp, ptr, usize); @ 1.18 log @Updated all copyright messages with forthcoming year 2003, added OSSP project as secondary copyright holder, added standard OSSP ASCII-art logo to documents, etc. @ text @d2 2 a3 2 * Copyright (c) 1999-2003 Ralf S. Engelschall * Copyright (c) 1999-2003 The OSSP Project @ 1.17 log @Stripped trailing whitespaces from all files in source tree. @ text @d2 2 a3 1 * Copyright (c) 1999-2002 Ralf S. Engelschall. All rights reserved. @ 1.16 log @bump copyright year @ text @d9 1 a9 1 * notice, this list of conditions and the following disclaimer. d114 1 a114 1 * Lock a memory pool d124 1 a124 1 * Unlock a memory pool d158 1 a158 1 fprintf(stderr, " bytes free = %d (%d chunk%s)\n", d169 1 a169 1 fprintf(stderr, " chunk #%03d: 0x%lx-0x%lx (%d bytes)\n", d191 1 a191 1 d316 1 a316 1 return NULL; @ 1.15 log @*** empty log message *** @ text @d2 1 a2 1 * Copyright (c) 1999-2001 Ralf S. Engelschall. All rights reserved. @ 1.14 log @*** empty log message *** @ text @d2 1 a2 1 * Copyright (c) 1999-2000 Ralf S. Engelschall. All rights reserved. @ 1.13 log @*** empty log message *** @ text @d82 2 a83 2 mm->mp_freechunks.mc_size = 0; mm->mp_freechunks.mc_usize = 0; d199 7 a205 2 if ((char *)mcPrev+mcPrev->mc_size == (char *)mcInsert && (mcNext != NULL && (char *)mcInsert+mcInsert->mc_size == (char *)mcNext)) { d211 1 a211 1 else if ((char *)mcPrev+mcPrev->mc_size == (char *)mcInsert) { d215 1 a215 1 else if (mcNext != NULL && (char *)mcInsert+mcInsert->mc_size == (char *)mcNext) { d246 2 d252 1 d255 1 a255 1 sMin = mm->mp_size; /* maximum possible */ d267 1 d289 1 d314 1 a314 1 ERR(MM_ERR_ALLOC, "Out of memory"); @ 1.12 log @*** empty log message *** @ text @a61 4 if (usize < 0) { errno = EINVAL; return NULL; } @ 1.11 log @*** empty log message *** @ text @d2 1 a2 1 * Copyright (c) 1999 Ralf S. Engelschall. All rights reserved. @ 1.10 log @*** empty log message *** @ text @d122 1 a122 1 if (mm == NULL); d132 1 a132 1 if (mm == NULL); @ 1.9 log @*** empty log message *** @ text @d147 2 a148 1 mm_core_lock((void *)mm, MM_LOCK_RD); d196 2 a197 1 mm_core_lock((void *)mm, MM_LOCK_RW); d247 2 a248 1 mm_core_lock((void *)mm, MM_LOCK_RW); d304 2 a305 1 mm_core_lock((void *)mm, MM_LOCK_RW); d426 2 a427 1 mm_core_lock((void *)mm, MM_LOCK_RD); @ 1.8 log @*** empty log message *** @ text @d238 2 a239 2 mem_chunk *mcMinLast; mem_chunk *mcMin; d246 3 a249 3 mcMinLast = mc; mcMin = NULL; sMin = mm->mp_size; /* maximum possible */ d251 7 a258 5 if (mc->mc_size >= size && mc->mc_size < sMin) { mcMin = mc; sMin = mc->mc_size; } mcMinLast = mc; d260 6 a265 2 if (mcMin != NULL) { if (mcMin->mc_size > size+1024) { d267 2 a268 3 s = mcMin->mc_size - size; mcMin->mc_size = size; d270 1 a270 1 mc = (mem_chunk *)((char *)mcMin + size); d272 2 a273 2 mc->mc_u.mc_next = mcMin->mc_u.mc_next; mcMinLast->mc_u.mc_next = mc; d277 1 a277 1 mcMinLast->mc_u.mc_next = mcMin->mc_u.mc_next; d282 1 a282 1 return mcMin; @ 1.7 log @*** empty log message *** @ text @d294 1 a294 1 return mc; d296 1 d298 1 d308 1 @ 1.6 log @*** empty log message *** @ text @d58 1 d61 3 a63 1 if (usize < 0) d65 1 d67 4 a70 2 usize = MM_ALLOC_MAXSIZE; if (usize <= MM_ALLOC_MINSIZE) a71 2 if (usize >= MM_ALLOC_MAXSIZE) usize = MM_ALLOC_MAXSIZE; d74 1 a74 1 size = mm_core_align2page(usize+SIZEOF_mem_pool); d399 1 a399 1 * Determine maximum size of an allocateable memory poo d403 1 a403 1 return MM_ALLOC_MAXSIZE; @ 1.5 log @*** empty log message *** @ text @d90 10 d113 3 d123 3 @ 1.4 log @*** empty log message *** @ text @d53 1 a53 1 MM *mm_create(size_t usize, char *file) d368 1 a368 1 size_t mm_sizeof(MM *mm, void *ptr) @ 1.3 log @*** empty log message *** @ text @d379 8 @ 1.2 log @*** empty log message *** @ text @d103 1 a103 1 int mm_lock(MM *mm, unsigned int mode) @ 1.1 log @Initial revision @ text @d103 1 a103 1 int mm_lock(MM *mm) d107 1 a107 1 return mm_core_lock((void *)mm); d127 1 a127 1 mm_core_lock((void *)mm); d175 1 a175 1 mm_core_lock((void *)mm); d225 1 a225 1 mm_core_lock((void *)mm); d386 1 a386 1 mm_core_lock((void *)mm); @ 1.1.1.1 log @Import into CVS @ text @@