Back to index

lightning-sunbird  0.9+nobinonly
xpt_arena.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /* Quick arena hack for xpt. */
00039 
00040 /* XXX This exists because we don't want to drag in NSPR. It *seemed*
00041 *  to make more sense to write a quick and dirty arena than to clone
00042 *  plarena (like js/src did). This is not optimal, but it works. 
00043 *  Half of the code here is instrumentation.
00044 */
00045 
00046 #include "xpt_arena.h"
00047 #include <string.h>
00048 #include <stdio.h>
00049 #include <stdlib.h>
00050 
00051 /*************************/
00052 /* logging stats support */
00053 
00054 #if 0 && defined(DEBUG_jband)
00055 #define XPT_ARENA_LOGGING 1
00056 #endif
00057 
00058 #ifdef XPT_ARENA_LOGGING
00059 
00060 #define LOG_MALLOC(_a, _req, _used)                             \
00061     do{                                                         \
00062     XPT_ASSERT((_a));                                           \
00063     ++(_a)->LOG_MallocCallCount;                                \
00064     (_a)->LOG_MallocTotalBytesRequested += (_req);              \
00065     (_a)->LOG_MallocTotalBytesUsed += (_used);                  \
00066     } while(0)
00067 
00068 #define LOG_REAL_MALLOC(_a, _size)                              \
00069     do{                                                         \
00070     XPT_ASSERT((_a));                                           \
00071     ++(_a)->LOG_RealMallocCallCount;                            \
00072     (_a)->LOG_RealMallocTotalBytesRequested += (_size);         \
00073     } while(0)
00074 
00075 #define LOG_FREE(_a)                                            \
00076     do{                                                         \
00077     XPT_ASSERT((_a));                                           \
00078     ++(_a)->LOG_FreeCallCount;                                  \
00079     } while(0)
00080 
00081 #define LOG_DONE_LOADING(_a)                                    \
00082     do{                                                         \
00083     XPT_ASSERT((_a));                                           \
00084     (_a)->LOG_LoadingFreeCallCount = (_a)->LOG_FreeCallCount;   \
00085     } while(0)
00086 
00087 #define PRINT_STATS(_a)       xpt_DebugPrintArenaStats((_a))
00088 static void xpt_DebugPrintArenaStats(XPTArena *arena);
00089 
00090 #else /* !XPT_ARENA_LOGGING */
00091 
00092 #define LOG_MALLOC(_a, _req, _used)   ((void)0)
00093 #define LOG_REAL_MALLOC(_a, _size)    ((void)0)
00094 #define LOG_FREE(_a)                  ((void)0)
00095 
00096 #define LOG_DONE_LOADING(_a)          ((void)0)        
00097 #define PRINT_STATS(_a)               ((void)0)
00098 
00099 #endif /* XPT_ARENA_LOGGING */
00100 
00101 /****************************************************/
00102 
00103 /* Block header for each block in the arena */
00104 typedef struct BLK_HDR BLK_HDR;
00105 struct BLK_HDR
00106 {
00107     BLK_HDR *next;
00108     size_t   size;
00109 };
00110 
00111 #define XPT_MIN_BLOCK_SIZE 32
00112 
00113 /* XXX this is lame. Should clone the code to do this bitwise */
00114 #define ALIGN_RND(s,a) ((a)==1?(s):((((s)+(a)-1)/(a))*(a)))
00115 
00116 struct XPTArena
00117 {
00118     BLK_HDR *first;
00119     PRUint8 *next;
00120     size_t   space;
00121     size_t   alignment;
00122     size_t   block_size;
00123     char    *name;
00124 
00125 #ifdef XPT_ARENA_LOGGING
00126     PRUint32 LOG_MallocCallCount;
00127     PRUint32 LOG_MallocTotalBytesRequested;
00128     PRUint32 LOG_MallocTotalBytesUsed;
00129     PRUint32 LOG_FreeCallCount;
00130     PRUint32 LOG_LoadingFreeCallCount;
00131     PRUint32 LOG_RealMallocCallCount;
00132     PRUint32 LOG_RealMallocTotalBytesRequested;
00133 #endif /* XPT_ARENA_LOGGING */
00134 };
00135 
00136 XPT_PUBLIC_API(XPTArena *)
00137 XPT_NewArena(PRUint32 block_size, size_t alignment, const char* name)
00138 {
00139     XPTArena *arena = calloc(1, sizeof(XPTArena));
00140     if (arena) {
00141         XPT_ASSERT(alignment);
00142         if (alignment > sizeof(double))
00143             alignment = sizeof(double);
00144         arena->alignment = alignment;
00145 
00146         if (block_size < XPT_MIN_BLOCK_SIZE)
00147             block_size = XPT_MIN_BLOCK_SIZE;
00148         arena->block_size = ALIGN_RND(block_size, alignment);
00149 
00150         /* must have room for at least one item! */
00151         XPT_ASSERT(arena->block_size >= 
00152                    ALIGN_RND(sizeof(BLK_HDR), alignment) +
00153                    ALIGN_RND(1, alignment));
00154 
00155         if (name) {
00156             arena->name = XPT_STRDUP(arena, name);           
00157 #ifdef XPT_ARENA_LOGGING
00158             /* fudge the stats since we are using space in the arena */
00159             arena->LOG_MallocCallCount = 0;
00160             arena->LOG_MallocTotalBytesRequested = 0;
00161             arena->LOG_MallocTotalBytesUsed = 0;
00162 #endif /* XPT_ARENA_LOGGING */
00163         }
00164     }
00165     return arena;        
00166 }
00167 
00168 XPT_PUBLIC_API(void)
00169 XPT_DestroyArena(XPTArena *arena)
00170 {
00171     BLK_HDR* cur;
00172     BLK_HDR* next;
00173         
00174     cur = arena->first;
00175     while (cur) {
00176         next = cur->next;
00177         free(cur);
00178         cur = next;
00179     }
00180     free(arena);
00181 }
00182 
00183 XPT_PUBLIC_API(void)
00184 XPT_DumpStats(XPTArena *arena)
00185 {
00186     PRINT_STATS(arena);
00187 }        
00188 
00189 
00190 /* 
00191 * Our alignment rule is that we always round up the size of each allocation 
00192 * so that the 'arena->next' pointer one will point to properly aligned space.
00193 */
00194 
00195 XPT_PUBLIC_API(void *)
00196 XPT_ArenaMalloc(XPTArena *arena, size_t size)
00197 {
00198     PRUint8 *cur;
00199     size_t bytes;
00200 
00201     if (!size)
00202         return NULL;
00203 
00204     if (!arena) {
00205         XPT_ASSERT(0);
00206         return NULL;
00207     }
00208 
00209     bytes = ALIGN_RND(size, arena->alignment);
00210     
00211     LOG_MALLOC(arena, size, bytes);
00212 
00213     if (bytes > arena->space) {
00214         BLK_HDR* new_block;
00215         size_t block_header_size = ALIGN_RND(sizeof(BLK_HDR), arena->alignment);
00216         size_t new_space = arena->block_size;
00217          
00218         if (bytes > new_space - block_header_size)
00219             new_space += bytes;
00220 
00221         new_block = (BLK_HDR*) calloc(new_space/arena->alignment, 
00222                                       arena->alignment);
00223         if (!new_block) {
00224             arena->next = NULL;
00225             arena->space = 0;
00226             return NULL;
00227         }
00228 
00229         LOG_REAL_MALLOC(arena, new_space);
00230 
00231         /* link block into the list of blocks for use when we destroy */
00232         new_block->next = arena->first;
00233         arena->first = new_block;
00234 
00235         /* save other block header info */
00236         new_block->size = new_space;
00237 
00238         /* set info for current block */
00239         arena->next  = ((PRUint8*)new_block) + block_header_size;
00240         arena->space = new_space - block_header_size;
00241 
00242 #ifdef DEBUG
00243         /* mark block for corruption check */
00244         memset(arena->next, 0xcd, arena->space);
00245 #endif
00246     } 
00247     
00248 #ifdef DEBUG
00249     {
00250         /* do corruption check */
00251         size_t i;
00252         for (i = 0; i < bytes; ++i) {
00253             XPT_ASSERT(arena->next[i] == 0xcd);        
00254         }
00255         /* we guarantee that the block will be filled with zeros */
00256         memset(arena->next, 0, bytes);
00257     }        
00258 #endif
00259 
00260     cur = arena->next;
00261     arena->next  += bytes;
00262     arena->space -= bytes;
00263     
00264     return cur;    
00265 }
00266 
00267 
00268 XPT_PUBLIC_API(char *)
00269 XPT_ArenaStrDup(XPTArena *arena, const char * s)
00270 {
00271     size_t len;
00272     char* cur;
00273 
00274     if (!s)
00275         return NULL;
00276 
00277     len = strlen(s)+1;
00278     cur = XPT_ArenaMalloc(arena, len);
00279     memcpy(cur, s, len);
00280     return cur;
00281 }
00282 
00283 XPT_PUBLIC_API(void)
00284 XPT_NotifyDoneLoading(XPTArena *arena)
00285 {
00286 #ifdef XPT_ARENA_LOGGING
00287     if (arena) {
00288         LOG_DONE_LOADING(arena);        
00289     }
00290 #endif
00291 }
00292 
00293 XPT_PUBLIC_API(void)
00294 XPT_ArenaFree(XPTArena *arena, void *block)
00295 {
00296     LOG_FREE(arena);
00297 }
00298 
00299 #ifdef XPT_ARENA_LOGGING
00300 static void xpt_DebugPrintArenaStats(XPTArena *arena)
00301 {
00302     printf("()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()\n");
00303     printf("Start xpt arena stats for \"%s\"\n", 
00304             arena->name ? arena->name : "unnamed arena");
00305     printf("\n");
00306     printf("%d times arena malloc called\n", (int) arena->LOG_MallocCallCount);       
00307     printf("%d total bytes requested from arena malloc\n", (int) arena->LOG_MallocTotalBytesRequested);       
00308     printf("%d average bytes requested per call to arena malloc\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesRequested/arena->LOG_MallocCallCount) : 0);
00309     printf("%d average bytes used per call (accounts for alignment overhead)\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0);
00310     printf("%d average bytes used per call (accounts for all overhead and waste)\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_RealMallocTotalBytesRequested/arena->LOG_MallocCallCount) : 0);
00311     printf("\n");
00312     printf("%d during loading times arena free called\n", (int) arena->LOG_LoadingFreeCallCount);       
00313     printf("%d during loading approx total bytes not freed\n", (int) arena->LOG_LoadingFreeCallCount * (int) (arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0));       
00314     printf("\n");
00315     printf("%d total times arena free called\n", (int) arena->LOG_FreeCallCount);       
00316     printf("%d approx total bytes not freed until arena destruction\n", (int) arena->LOG_FreeCallCount * (int) (arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0 ));       
00317     printf("\n");
00318     printf("%d times arena called system malloc\n", (int) arena->LOG_RealMallocCallCount);       
00319     printf("%d total bytes arena requested from system\n", (int) arena->LOG_RealMallocTotalBytesRequested);       
00320     printf("%d byte block size specified at arena creation time\n", (int) arena->block_size);       
00321     printf("%d byte block alignment specified at arena creation time\n", (int) arena->alignment);       
00322     printf("\n");
00323     printf("End xpt arena stats\n");
00324     printf("()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()\n");
00325 }        
00326 #endif
00327 
00328 /***************************************************************************/
00329 
00330 #ifdef DEBUG
00331 XPT_PUBLIC_API(void)
00332 XPT_AssertFailed(const char *s, const char *file, PRUint32 lineno)
00333 {
00334     fprintf(stderr, "Assertion failed: %s, file %s, line %d\n",
00335             s, file, lineno);
00336     abort();
00337 }        
00338 #endif