Main Page | Alphabetical List | Class List | File List | Class Members | File Members

bsdmalloc.h

Go to the documentation of this file.
00001 /* =============
00002  * apeNEXT/nlibc
00003  * =============
00004  *
00005  * $Id: bsdmalloc.h,v 1.6 2005/10/27 20:04:59 morinl Exp $
00006  * -------------------------------------------------------------------------- */
00007 
00008 #ifndef _NLIBC_BSDMALLOC_H_
00009 #define _NLIBC_BSDMALLOC_H_
00010 
00011 #include <nlibc.h>
00012 
00013 /*
00014  * Copyright (c) 1983 Regents of the University of California.
00015  * All rights reserved.
00016  *
00017  * Redistribution and use in source and binary forms, with or without
00018  * modification, are permitted provided that the following conditions
00019  * are met:
00020  * 1. Redistributions of source code must retain the above copyright
00021  *    notice, this list of conditions and the following disclaimer.
00022  * 2. Redistributions in binary form must reproduce the above copyright
00023  *    notice, this list of conditions and the following disclaimer in the
00024  *    documentation and/or other materials provided with the distribution.
00025  * 3. All advertising materials mentioning features or use of this software
00026  *    must display the following acknowledgement:
00027  *      This product includes software developed by the University of
00028  *      California, Berkeley and its contributors.
00029  * 4. Neither the name of the University nor the names of its contributors
00030  *    may be used to endorse or promote products derived from this software
00031  *    without specific prior written permission.
00032  *
00033  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00034  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00035  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00036  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00037  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00038  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00039  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00040  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00041  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00042  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00043  * SUCH DAMAGE.
00044  */
00045 
00046 /*static char *sccsid = "from: @(#)malloc.c     5.11 (Berkeley) 2/23/91";*/
00047 
00048 /*
00049  * malloc.c (Caltech) 2/21/82
00050  * Chris Kingsley, kingsley@cit-20.
00051  *
00052  * This is a very fast storage allocator.  It allocates blocks of a small 
00053  * number of different sizes, and keeps free lists of each size.  Blocks that
00054  * don't exactly fit are passed up to the next larger size.  In this 
00055  * implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long.
00056  * This is designed for use in a virtual memory environment.
00057  */
00058 
00059 #include <unistd.h>
00060 
00061 #if !defined(__cflow_processed) || defined(_uses_getpagesize_bsdmalloc_h)
00062 inline int getpagesize() { 
00063   return 0x200;
00064 }
00065 #endif // _uses_getpagesize_bsdmalloc_h
00066 
00067 static void morecore();
00068 static int findbucket();
00069 
00070 /*
00071  * The overhead on a block is at least 4 bytes.  When free, this space
00072  * contains a pointer to the next free block, and the bottom two bits must
00073  * be zero.  When in use, the first byte is set to MAGIC, and the second
00074  * byte is the size index.  The remaining bytes are for alignment.
00075  * If range checking is enabled then a second word holds the size of the
00076  * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC).
00077  * The order of elements is critical: ov_magic must overlay the low order
00078  * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern.
00079  */
00080 
00081 // some namespace protection
00082 #define overhead __malloc_overhead
00083 #define pagebucket __malloc_pagebucket
00084 #define pagesz __malloc_pagesz
00085 #define nmalloc __malloc_nmalloc
00086 #define realloc_srchlen __malloc_realloc_srchlen
00087 
00088 union   overhead {
00089         union   overhead *ov_next;      /* when free */
00090         struct {
00091                 unsigned        ovu_magic;      /* magic number */
00092                 unsigned        ovu_index;      /* bucket # */
00093 #ifdef RCHECK
00094                 unsigned        ovu_rmagic;     /* range magic number */
00095                 unsigned        ovu_size;       /* actual block size */
00096 #endif // RCHECK
00097         } ovu;
00098 #define ov_magic        ovu.ovu_magic
00099 #define ov_index        ovu.ovu_index
00100 #define ov_rmagic       ovu.ovu_rmagic
00101 #define ov_size         ovu.ovu_size
00102 };
00103 
00104 #define MAGIC           0xef            /* magic # on accounting info */
00105 #define RMAGIC          0x5555          /* magic # on range info */
00106 
00107 #ifdef RCHECK
00108 #define RSLOP           sizeof (unsigned)
00109 #else
00110 #define RSLOP           0
00111 #endif  // RCHECK
00112 
00113 
00114 /*
00115  * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
00116  * smallest allocatable block is 8 words (128 bytes).  The overhead information
00117  * precedes the data area returned to the user.
00118  */
00119 #define NBUCKETS 30
00120 static  union overhead *nextf[NBUCKETS];
00121 
00122 static  int pagebucket = 0;             /* page size bucket */
00123 static  int pagesz = 0;                 /* page size */
00124 
00125 #ifdef MSTATS
00126 /*
00127  * nmalloc[i] is the difference between the number of mallocs and frees
00128  * for a given block size.
00129  */
00130 static  unsigned nmalloc[NBUCKETS];
00131 #include <stdio.h>
00132 #endif // MSTATS
00133 
00134 #if defined(DEBUG) || defined(RCHECK)
00135 #define MALLOC_ASSERT(p)   if (!(p)) botch("p")
00136 #include <stdio.h>
00137 
00138 #ifndef __HAS_MAIN
00139 /* extern void botch(char *s); */
00140 #else
00141 #if !defined(__cflow_processed) || defined(_uses_botch_bsdmalloc_h)
00142 static void botch(char *s)
00143 {
00144         fprintf(stderr, "\r\nassertion botched: %s\r\n", s);
00145         abort();
00146 }
00147 #endif // _uses_botch_bsdmalloc_h
00148 #endif // Has Main
00149 
00150 #else
00151 #define MALLOC_ASSERT(p)
00152 #endif  // DEBUG && RCHECK
00153 
00154 #define w_sizeof(OBJ) (sizeof_aligned(OBJ)>>4)
00155 
00156 #define malloc(BYTES)  wmalloc(((BYTES)+15)>>4)
00157 
00158 #ifndef __HAS_MAIN
00159 extern void * wmalloc(size_t nwords);
00160 #else
00161 #if !defined(__cflow_processed) || defined(_uses_wmalloc_bsdmalloc_h)
00162 void * wmalloc(size_t nwords)
00163 {
00164         register union overhead *op;
00165         register int bucket, n;
00166         register unsigned amt;
00167 
00168         /*
00169          * First time malloc is called, setup page size and
00170          * align break pointer so all data will be page aligned.
00171          * Also, make sure that nextf[] is initialized to zero
00172          */
00173         if (pagesz == 0) {
00174                 pagesz = n = getpagesize();
00175                 op = (union overhead *)w_sbrk(w_sizeof(union overhead));
00176                 n = n - w_sizeof(*op) - ((int)op & (n - 1));
00177                 if (n < 0)
00178                         n += pagesz;
00179                 if (n) {
00180                         if (w_sbrk(n) == (char *)-1)
00181                                 return (NULL);
00182                 }
00183                 bucket = 0;
00184                 amt = 8;
00185                 while (pagesz > amt) {
00186                         amt <<= 1;
00187                         bucket++;
00188                 }
00189                 pagebucket = bucket;
00190                 memset(nextf, 0, NBUCKETS * sizeof_aligned(union overhead *));
00191 #ifdef MSTATS
00192                 memset(nmalloc, 0, NBUCKETS * sizeof_aligned(unsigned));
00193 #endif // MSTATS
00194         }
00195         /*
00196          * Convert amount of memory requested into closest block size
00197          * stored in hash buckets which satisfies request.
00198          * Account for space used per block for accounting.
00199          */
00200         if (nwords <= (n = pagesz - w_sizeof(*op) - RSLOP)) {
00201 #ifndef RCHECK
00202                 amt = 8;        /* size of first bucket */
00203                 bucket = 0;
00204 #else
00205                 amt = 16;       /* size of first bucket */
00206                 bucket = 1;
00207 #endif // RCHECK
00208                 n = -(int)(w_sizeof(*op) + RSLOP);
00209         } else {
00210                 amt = pagesz;
00211                 bucket = pagebucket;
00212         }
00213         while (nwords > amt + n) {
00214                 amt <<= 1;
00215                 if (amt == 0)
00216                         return (NULL);
00217                 bucket++;
00218         }
00219         /*
00220          * If nothing in hash bucket right now,
00221          * request more memory from the system.
00222          */
00223         if ((op = nextf[bucket]) == NULL) {
00224                 morecore(bucket);
00225                 if ((op = nextf[bucket]) == NULL)
00226                         return (NULL);
00227         }
00228         /* remove from linked list */
00229         nextf[bucket] = op->ov_next;
00230         op->ov_magic = MAGIC;
00231         op->ov_index = bucket;
00232 #ifdef MSTATS
00233         nmalloc[bucket]++;
00234 #endif // MSTATS
00235 #ifdef RCHECK
00236         /*
00237          * Record allocated size of block and
00238          * bound space with magic numbers.
00239          */
00240         op->ov_size = (nwords + RSLOP - 1) & ~(RSLOP - 1);
00241         op->ov_rmagic = RMAGIC;
00242         *(unsigned *)((unsigned)(op + 1) + op->ov_size) = RMAGIC;
00243 #endif // RCHECK
00244         return ((char *)(op + 1));
00245 }
00246 #endif // _uses_wmalloc_bsdmalloc_h
00247 #endif // Has Main
00248 
00249 /*
00250  * Allocate more memory to the indicated bucket.
00251  */
00252 #ifndef __HAS_MAIN
00253 #else
00254 #if !defined(__cflow_processed) || defined(_uses_morecore_bsdmalloc_h)
00255 static void morecore(int bucket)
00256 {
00257         register union overhead *op;
00258         register int sz;                /* size of desired block [words] */
00259         int amt;                        /* amount to allocate [words] */
00260         int nblks;                      /* how many blocks we get */
00261 
00262         sz = 1 << (bucket + 3);
00263 #ifdef DEBUG
00264         MALLOC_ASSERT(sz > 0);
00265 #else
00266         if (sz <= 0)
00267                 return;
00268 #endif // DEBUG
00269         if (sz < pagesz) {
00270                 amt = pagesz;
00271                 nblks = amt / sz;
00272         } else {
00273                 amt = sz + pagesz;
00274                 nblks = 1;
00275         }
00276         op = (union overhead *)w_sbrk(amt);
00277         /* no more room! */
00278         if ((int)op == -1)
00279                 return;
00280         /*
00281          * Add new memory allocated to that on
00282          * free list for this hash bucket.
00283          */
00284         nextf[bucket] = op;
00285         while (--nblks > 0) {
00286                 op->ov_next = (union overhead *)((unsigned)op + sz);
00287                 op = (union overhead *)((unsigned)op + sz);
00288         }
00289         op->ov_next = NULL;
00290 } 
00291 #endif // _uses_morecore_bsdmalloc_h
00292 #endif // Has Main
00293 
00294 
00295 #ifndef __HAS_MAIN
00296 extern void free(void *cp);
00297 #else
00298 #if !defined(__cflow_processed) || defined(_uses_free_bsdmalloc_h)
00299 void free(void *cp)
00300 {   
00301         register int size;
00302         register union overhead *op;
00303 
00304         if (cp == NULL)
00305                 return;
00306         op = (union overhead *)((unsigned)cp - w_sizeof (union overhead));
00307 #ifdef DEBUG
00308         MALLOC_ASSERT(op->ov_magic == MAGIC);           /* make sure it was in use */
00309 #else
00310         if (op->ov_magic != MAGIC)
00311                 return;                         /* sanity */
00312 #endif // DEBUG
00313 #ifdef RCHECK
00314         MALLOC_ASSERT(op->ov_rmagic == RMAGIC);
00315         MALLOC_ASSERT(*(unsigned *)((unsigned)(op + 1) + op->ov_size) == RMAGIC);
00316 #endif // RCHECK
00317         size = op->ov_index;
00318         MALLOC_ASSERT(size < NBUCKETS);
00319         op->ov_next = nextf[size];      /* also clobbers ov_magic */
00320         nextf[size] = op;
00321 #ifdef MSTATS
00322         nmalloc[size]--;
00323 #endif // MSTATS
00324 }
00325 #endif // _uses_free_bsdmalloc_h
00326 #endif // Has Main
00327 
00328 /*
00329  * When a program attempts "storage compaction" as mentioned in the
00330  * old malloc man page, it realloc's an already freed block.  Usually
00331  * this is the last block it freed; occasionally it might be farther
00332  * back.  We have to search all the free lists for the block in order
00333  * to determine its bucket: 1st we make one pass thru the lists
00334  * checking only the first block in each; if that fails we search
00335  * ``realloc_srchlen'' blocks in each list for a match (the variable
00336  * is extern so the caller can modify it).  If that fails we just copy
00337  * however many bytes was given to realloc() and hope it's not huge.
00338  */
00339 int realloc_srchlen = 4;        /* 4 should be plenty, -1 =>'s whole list */
00340 
00341 #define realloc(PTR, NBYTES)  wrealloc(PTR,((NBYTES)+15)>>4)
00342 
00343 #ifndef __HAS_MAIN
00344 extern void *wrealloc(void *cp, size_t nwords);
00345 #else
00346 #if !defined(__cflow_processed) || defined(_uses_wrealloc_bsdmalloc_h)
00347 void *wrealloc(void *cp, size_t nwords)
00348 {
00349         register unsigned onb;
00350         register int i;
00351         union overhead *op;
00352         char *res;
00353         int was_alloced = 0;
00354 
00355         if (cp == NULL)
00356                 return (wmalloc(nwords));
00357         op = (union overhead *)((unsigned)cp - w_sizeof (union overhead));
00358         if (op->ov_magic == MAGIC) {
00359                 was_alloced++;
00360                 i = op->ov_index;
00361         } else {
00362                 /*
00363                  * Already free, doing "compaction".
00364                  *
00365                  * Search for the old block of memory on the
00366                  * free list.  First, check the most common
00367                  * case (last element free'd), then (this failing)
00368                  * the last ``realloc_srchlen'' items free'd.
00369                  * If all lookups fail, then assume the size of
00370                  * the memory block being realloc'd is the
00371                  * largest possible (so that all "nwords" of new
00372                  * memory are copied into).  Note that this could cause
00373                  * a memory fault if the old area was tiny, and the moon
00374                  * is gibbous.  However, that is very unlikely.
00375                  */
00376                 if ((i = findbucket(op, 1)) < 0 &&
00377                     (i = findbucket(op, realloc_srchlen)) < 0)
00378                         i = NBUCKETS;
00379         }
00380         onb = 1 << (i + 3);
00381         if (onb < pagesz)
00382                 onb -= w_sizeof (*op) + RSLOP;
00383         else
00384                 onb += pagesz - w_sizeof (*op) - RSLOP;
00385         /* avoid the copy if same size block */
00386         if (was_alloced) {
00387                 if (i) {
00388                         i = 1 << (i + 2);
00389                         if (i < pagesz)
00390                                 i -= w_sizeof (*op) + RSLOP;
00391                         else
00392                                 i += pagesz - w_sizeof (*op) - RSLOP;
00393                 }
00394                 if (nwords <= onb && nwords > i) {
00395 #ifdef RCHECK
00396                         op->ov_size = (nwords + RSLOP - 1) & ~(RSLOP - 1);
00397                         *(unsigned *)((unsigned)(op + 1) + op->ov_size) = RMAGIC;
00398 #endif // RCHECK
00399                         return(cp);
00400                 } else
00401                         free(cp);
00402         }
00403         if ((res = wmalloc(nwords)) == NULL)
00404                 return (NULL);
00405         if (cp != res)          /* common optimization if "compacting" */
00406                 wmemcpy(res, cp, (nwords < onb) ? nwords : onb);
00407         return (res);
00408 }
00409 #endif // _uses_realloc_bsdmalloc_h
00410 #endif // Has Main
00411 
00419 #define calloc(N,BYTESIZE) wcalloc((N),((BYTESIZE+15)>>4))
00420 
00428 #if !defined(__cflow_processed) || defined(_uses_wcalloc_bsdmalloc_h)
00429 inline void *wcalloc(size_t nmemb, size_t words)
00430 {
00431    void *p = wmalloc( nmemb * words );
00432    if( p ) { 
00433         wmemset(p,0,nmemb * words);
00434    }
00435    return p;
00436 }
00437 #endif // _uses_wcalloc_bsdmalloc_h
00438 
00439 /*
00440  * Search ``srchlen'' elements of each free list for a block whose
00441  * header starts at ``freep''.  If srchlen is -1 search the whole list.
00442  * Return bucket number, or -1 if not found.
00443  */
00444 
00445 #ifndef __HAS_MAIN
00446 #else
00447 #if !defined(__cflow_processed) || defined(_uses_findbucket_bsdmalloc_h)
00448 static int findbucket( union overhead *freep, int srchlen)
00449 {
00450         register union overhead *p;
00451         register int i, j;
00452 
00453         for (i = 0; i < NBUCKETS; i++) {
00454                 j = 0;
00455                 for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
00456                         if (p == freep)
00457                                 return (i);
00458                         j++;
00459                 }
00460         }
00461         return (-1);
00462 }
00463 #endif // _uses_findbucket_bsdmalloc_h
00464 #endif // Has Main
00465 
00466 #ifdef MSTATS
00467 /*
00468  * mstats - print out statistics about malloc
00469  * 
00470  * Prints two lines of numbers, one showing the length of the free list
00471  * for each size category, the second showing the number of mallocs -
00472  * frees for each size category.
00473  */
00474 
00475 #ifndef __HAS_MAIN
00476 extern int mstats(char *s);
00477 #else
00478 #if !defined(__cflow_processed) || defined(_uses_mstats_bsdmalloc_h)
00479 int mstats(char *s)
00480 {
00481         register int i, j;
00482         register union overhead *p;
00483         int totfree = 0,
00484         totused = 0;
00485 
00486         fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
00487         for (i = 0; i < NBUCKETS; i++) {
00488                 for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
00489                         ;
00490                 fprintf(stderr, " %d", j);
00491                 totfree += j * (1 << (i + 3));
00492         }
00493         fprintf(stderr, "\nused:\t");
00494         for (i = 0; i < NBUCKETS; i++) {
00495                 fprintf(stderr, " %d", nmalloc[i]);
00496                 totused += nmalloc[i] * (1 << (i + 3));
00497         }
00498         fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n",
00499             totused, totfree);
00500 }
00501 #endif // _uses_mstats_bsdmalloc_h
00502 #endif // Has Main
00503 
00504 #endif // MSTATS
00505 
00506 #undef overhead
00507 #undef pagebucket
00508 #undef pagesz
00509 #undef nmalloc
00510 #undef realloc_srchlen
00511 
00512 #endif // _BSDMALLOC_H_
00513 

Generated on Fri Jul 14 10:51:31 2006 for nlibc by doxygen 1.3.5