memalloc.c

Go to the documentation of this file.
00001 /*                      M E M A L L O C . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 2004-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup librt */
00023 /*@{*/
00024 /** @file memalloc.c
00025  *
00026  * Functions -
00027  *      rt_memalloc     allocate 'size' of memory from a given map
00028  *      rt_memget       allocate 'size' of memory from map at 'place'
00029  *      rt_memfree      return 'size' of memory to map at 'place'
00030  *      rt_mempurge     free everything on current memory chain
00031  *      rt_memprint     print a map
00032  *      rt_memclose
00033  *
00034  * The structure of the displaylist memory map chains
00035  * consists of non-zero count and base address of that many contiguous units.
00036  * The addresses are increasing and the list is terminated with the
00037  * first zero link.
00038  *
00039  * rt_memalloc() and rt_memfree() use these tables to allocate displaylist memory.
00040  *
00041  *      For each Memory Map there exists a queue (coremap).
00042  *      There also exists a queue of free buffers which are enqueued
00043  *      on to either of the previous queues.  Initially all of the buffers
00044  *      are placed on the `freemap' queue.  Whenever a buffer is freed
00045  *      because of coallescing ends in rt_memfree() or zero size in rt_memalloc()
00046  *      the mapping buffer is taken off from the respective queue and
00047  *      returned to the `freemap' queue.
00048  *
00049  *  Authors -
00050  *      George E. Toth
00051  *      Michael John Muuss
00052  *
00053  *  Source -
00054  *      SECAD/VLD Computing Consortium, Bldg 394
00055  *      The U. S. Army Ballistic Research Laboratory
00056  *      Aberdeen Proving Ground, Maryland  21005
00057  */
00058 /*@}*/
00059 
00060 #ifndef lint
00061 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/memalloc.c,v 14.9 2006/09/16 02:04:25 lbutler Exp $ (BRL)";
00062 #endif
00063 
00064 #include "common.h"
00065 
00066 
00067 
00068 #include <stdio.h>
00069 #include "machine.h"
00070 #include "vmath.h"
00071 #include "raytrace.h"
00072 
00073 
00074 /* XXX not PARALLEL */
00075 /* Allocation/Free spaces */
00076 static struct mem_map *rt_mem_freemap = MAP_NULL;       /* Freelist of buffers */
00077 
00078 /* Flags used by `type' in rt_memfree() */
00079 #define M_TMTCH 00001   /* Top match */
00080 #define M_BMTCH 00002   /* Bottom match */
00081 #define M_TOVFL 00004   /* Top overflow */
00082 #define M_BOVFL 00010   /* Bottom overflow */
00083 
00084 /*
00085  *                      R T _ M E M A L L O C
00086  *
00087  *      Takes:          & pointer of map,
00088  *                      size.
00089  *
00090  *      Returns:        NULL    Error
00091  *                      <addr>  Othewise
00092  *
00093  *      Comments:
00094  *      Algorithm is first fit.
00095  */
00096 unsigned long
00097 rt_memalloc(struct mem_map **pp, register unsigned int size)
00098 {
00099         register struct mem_map *prevp = MAP_NULL;
00100         register struct mem_map *curp;
00101         unsigned long   addr;
00102 
00103         if( size == 0 )
00104                 return( 0L );   /* fail */
00105 
00106         for( curp = *pp; curp; curp = (prevp=curp)->m_nxtp )  {
00107                 if( curp->m_size >= size )
00108                         break;
00109         }
00110 
00111         if( curp == MAP_NULL )
00112                 return(0L);             /* No more space */
00113 
00114         addr = curp->m_addr;
00115         curp->m_addr += size;
00116 
00117         /* If the element size goes to zero, put it on the freelist */
00118 
00119         if( (curp->m_size -= size) == 0 )  {
00120                 if( prevp )
00121                         prevp->m_nxtp = curp->m_nxtp;
00122                 else
00123                         *pp = curp->m_nxtp;     /* Click list down at start */
00124                 curp->m_nxtp = rt_mem_freemap;          /* Link it in */
00125                 rt_mem_freemap = curp;                  /* Make it the start */
00126         }
00127 
00128         return( addr );
00129 }
00130 
00131 /*
00132  *                      R T _ M E M A L L O C _ N O S P L I T
00133  *
00134  *      Takes:          & pointer of map,
00135  *                      size.
00136  *
00137  *      Returns:        NULL    Error
00138  *                      <addr>  Othewise
00139  *
00140  *      Comments:
00141  *      Algorithm is BEST fit.
00142  */
00143 struct mem_map *
00144 rt_memalloc_nosplit(struct mem_map **pp, register unsigned int size)
00145 {
00146         register struct mem_map *prevp = MAP_NULL;
00147         register struct mem_map *curp;
00148         register struct mem_map *best = MAP_NULL, *best_prevp = MAP_NULL;
00149 
00150         if( size == 0 )
00151                 return MAP_NULL;        /* fail */
00152 
00153         for( curp = *pp; curp; curp = (prevp=curp)->m_nxtp )  {
00154                 if( curp->m_size < size )  continue;
00155                 if( curp->m_size == size )  {
00156                         best = curp;
00157                         best_prevp = prevp;
00158                         break;
00159                 }
00160                 /* This element has enough size */
00161                 if( best == MAP_NULL || curp->m_size < best->m_size )  {
00162                         best = curp;
00163                         best_prevp = prevp;
00164                 }
00165         }
00166         if( !best )
00167                 return MAP_NULL;                /* No space */
00168 
00169         /* Move this element to free list, return it, unsplit */
00170         if( best_prevp )
00171                 best_prevp->m_nxtp = best->m_nxtp;
00172         else
00173                 *pp = best->m_nxtp;     /* Click list down at start */
00174         best->m_nxtp = rt_mem_freemap;          /* Link it in */
00175         rt_mem_freemap = best;                  /* Make it the start */
00176 
00177         return best;
00178 }
00179 
00180 /*
00181  *                      R T _ M E M G E T
00182  *
00183  *      Returns:        NULL    Error
00184  *                      -1      Zero Request
00185  *                      <addr>  Othewise
00186  *
00187  *      Comments:
00188  *      Algorithm is first fit.
00189  *      Free space can be split
00190  */
00191 unsigned long
00192 rt_memget(struct mem_map **pp, register unsigned int size, unsigned int place)
00193 {
00194         register struct mem_map *prevp, *curp;
00195         unsigned int addr;
00196 
00197         prevp = MAP_NULL;               /* special for first pass through */
00198         if( size == 0 )
00199                 rt_bomb("rt_memget() size==0\n");
00200 
00201         curp = *pp;
00202         while( curp )  {
00203                 /*
00204                  * Assumption:  We will always be APPENDING to an existing
00205                  * memory allocation, so we search for a free piece of memory
00206                  * which begins at 'place', without worrying about ones which
00207                  * could begin earlier but be long enough to satisfy this
00208                  * request.
00209                  */
00210                 if( curp->m_addr == place && curp->m_size >= size )
00211                         break;
00212                 curp = (prevp=curp)->m_nxtp;
00213         }
00214 
00215         if( curp == MAP_NULL )
00216                 return(0L);             /* No space here */
00217 
00218         addr = curp->m_addr;
00219         curp->m_addr += size;
00220 
00221         /* If the element size goes to zero, put it on the freelist */
00222         if( (curp->m_size -= size) == 0 )  {
00223                 if( prevp )
00224                         prevp->m_nxtp = curp->m_nxtp;
00225                 else
00226                         *pp = curp->m_nxtp;     /* Click list down at start */
00227                 curp->m_nxtp = rt_mem_freemap;          /* Link it in */
00228                 rt_mem_freemap = curp;                  /* Make it the start */
00229         }
00230         return( addr );
00231 }
00232 
00233 /*
00234  *                      R T _ M E M G E T _ N O S P L I T
00235  *
00236  *      Returns:        0       Unable to satisfy request
00237  *                      <size>  Actual size of free block, may be larger
00238  *                              than requested size.
00239  *
00240  *
00241  *      Comments:
00242  *              Caller is responsible for returning unused portion.
00243  */
00244 unsigned long
00245 rt_memget_nosplit(struct mem_map **pp, register unsigned int size, unsigned int place)
00246 {
00247         register struct mem_map *prevp, *curp;
00248 
00249         prevp = MAP_NULL;               /* special for first pass through */
00250         if( size == 0 )
00251                 bu_bomb("rt_memget_nosplit() size==0\n");
00252 
00253         curp = *pp;
00254         while( curp )  {
00255                 /*
00256                  * Assumption:  We will always be APPENDING to an existing
00257                  * memory allocation, so we search for a free piece of memory
00258                  * which begins at 'place', without worrying about ones which
00259                  * could begin earlier but be long enough to satisfy this
00260                  * request.
00261                  */
00262                 if( curp->m_addr == place && curp->m_size >= size )  {
00263                         size = curp->m_size;
00264                         /* put this element on the freelist */
00265                         if( prevp )
00266                                 prevp->m_nxtp = curp->m_nxtp;
00267                         else
00268                                 *pp = curp->m_nxtp;     /* Click list down at start */
00269                         curp->m_nxtp = rt_mem_freemap;          /* Link it in */
00270                         rt_mem_freemap = curp;                  /* Make it the start */
00271                         return size;            /* actual size found */
00272                 }
00273                 curp = (prevp=curp)->m_nxtp;
00274         }
00275 
00276         return 0L;              /* No space found */
00277 }
00278 
00279 /*
00280  *                      M E M F R E E
00281  *
00282  *      Takes:
00283  *                      size,
00284  *                      address.
00285  *
00286  *      Comments:
00287  *      The routine does not check for wrap around when increasing sizes
00288  *      or changing addresses.  Other wrap-around conditions are flagged.
00289  */
00290 void
00291 rt_memfree(struct mem_map **pp, unsigned int size, long unsigned int addr)
00292 {
00293         register int type = 0;
00294         register struct mem_map *prevp = MAP_NULL;
00295         register struct mem_map *curp;
00296         long il;
00297         struct mem_map *tmap;
00298 
00299         if( size == 0 )
00300                 return;         /* Nothing to free */
00301 
00302         /* Find the position in the list such that (prevp)<(addr)<(curp) */
00303         for( curp = *pp; curp; curp = (prevp=curp)->m_nxtp )
00304                 if( addr < curp->m_addr )
00305                         break;
00306 
00307         /* Make up the `type' variable */
00308 
00309         if( prevp )  {
00310                 if( (il=prevp->m_addr+prevp->m_size) > addr )
00311                         type |= M_BOVFL;
00312                 if( il == addr )
00313                         type |= M_BMTCH;
00314         }
00315         if( curp )  {
00316                 if( (il=addr+size) > curp->m_addr )
00317                         type |= M_TOVFL;
00318                 if( il == curp->m_addr )
00319                         type |= M_TMTCH;
00320         }
00321 
00322         if( type & (M_TOVFL|M_BOVFL) )  {
00323                 bu_log("rt_memfree(addr=x%x,size=%d)  ERROR type=0%o\n",
00324                         addr, size, type );
00325                 if( prevp )
00326                         bu_log("prevp: m_addr=x%x, m_size=%d\n",
00327                                 prevp->m_addr, prevp->m_size );
00328                 if( curp )
00329                         bu_log("curp: m_addr=x%x, m_size=%d\n",
00330                                 curp->m_addr, curp->m_size );
00331                 return;
00332         }
00333 
00334         /*
00335          * Now we do the surgery:
00336          * If there are no matches on boundaries we allocate a buffer
00337          * If there is one match we expand the appropriate buffer
00338          * If there are two matches we will have a free buffer returned.
00339          */
00340 
00341         switch( type & (M_BMTCH|M_TMTCH) )  {
00342         case M_TMTCH|M_BMTCH:   /* Deallocate top element and expand bottom */
00343                 prevp->m_size += size + curp->m_size;
00344                 prevp->m_nxtp = curp->m_nxtp;
00345                 curp->m_nxtp = rt_mem_freemap;          /* Link into rt_mem_freemap */
00346                 rt_mem_freemap = curp;
00347                 break;
00348 
00349         case M_BMTCH:           /* Expand bottom element */
00350                 prevp->m_size += size;
00351                 break;
00352 
00353         case M_TMTCH:           /* Expand top element downward */
00354                 curp->m_size += size;
00355                 curp->m_addr -= size;
00356                 break;
00357 
00358         default:                /* No matches; allocate and insert */
00359                 if( (tmap=rt_mem_freemap) == MAP_NULL )
00360                         tmap = (struct mem_map *)bu_malloc(sizeof(struct mem_map), "struct mem_map " BU_FLSTR);
00361                 else
00362                         rt_mem_freemap = rt_mem_freemap->m_nxtp;        /* Click one off */
00363 
00364                 if( prevp )
00365                         prevp->m_nxtp = tmap;
00366                 else
00367                         *pp = tmap;
00368 
00369                 tmap->m_size = size;
00370                 tmap->m_addr = addr;
00371                 tmap->m_nxtp = curp;
00372         }
00373 }
00374 
00375 /*
00376  *                      M E M P U R G E
00377  *
00378  *  Take everything on the current memory chain, and place it on
00379  *  the freelist.
00380  */
00381 void
00382 rt_mempurge(struct mem_map **pp)
00383 {
00384         register struct mem_map *prevp = MAP_NULL;
00385         register struct mem_map *curp;
00386 
00387         if( *pp == MAP_NULL )
00388                 return;
00389 
00390         /* Find the end of the (busy) list */
00391         for( curp = *pp; curp; curp = (prevp=curp)->m_nxtp )
00392                 ;
00393 
00394         /* Put the whole busy list onto the free list */
00395         prevp->m_nxtp = rt_mem_freemap;
00396         rt_mem_freemap = *pp;
00397 
00398         *pp = MAP_NULL;
00399 }
00400 
00401 /*
00402  *                      M E M P R I N T
00403  *
00404  *  Print a memory chain.
00405  */
00406 void
00407 rt_memprint(struct mem_map **pp)
00408 {
00409         register struct mem_map *curp;
00410 
00411         bu_log("rt_memprint(x%x):  address, length\n", *pp);
00412         for( curp = *pp; curp; curp = curp->m_nxtp )
00413                 bu_log(" a=x%.8lx, l=%.5d\n", curp->m_addr, curp->m_size );
00414 }
00415 
00416 /*
00417  *                      M E M C L O S E
00418  *
00419  *  Return all the storage used by the rt_mem_freemap.
00420  */
00421 void
00422 rt_memclose(void)
00423 {
00424         register struct mem_map *mp;
00425 
00426         while( (mp = rt_mem_freemap) != MAP_NULL )  {
00427                 rt_mem_freemap = mp->m_nxtp;
00428                 bu_free( (char *)mp, "struct mem_map " BU_FLSTR);
00429         }
00430 }
00431 
00432 /*
00433  * Local Variables:
00434  * mode: C
00435  * tab-width: 8
00436  * c-basic-offset: 4
00437  * indent-tabs-mode: t
00438  * End:
00439  * ex: shiftwidth=4 tabstop=8
00440  */

Generated on Mon Sep 18 01:24:52 2006 for BRL-CAD by  doxygen 1.4.6