pmalloc.c

Go to the documentation of this file.
00001 /*                       P 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 pmalloc.c
00025  *  The Princeton memory allocater.
00026  *
00027  *  Functions -
00028  *      rt_pmalloc
00029  *      rt_pfree
00030  *      rt_prealloc
00031  *      rt_forget
00032  *
00033  *  Author -
00034  *      Wiliam L. Sebok
00035  *
00036  *  Modified:
00037  *      John Anderson - modified for use in multi-threaded applications.
00038  *              It now uses a field from the BRL-CAD resource structure
00039  *              to store the memory blocks. Also replaced mlindx() routine
00040  *              with a faster (but less general) version that takes advantage
00041  *              of the fact that bucket sizes increase by powers of two.
00042  *
00043  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
00044  * A  "smarter" malloc v1.0                     William L. Sebok
00045  *                                      Sept. 24, 1984 rev. June 30,1986
00046  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
00047  *
00048  *      Algorithm:
00049  *       Assign to each area an index "n". This is currently proportional to
00050  *      the log 2 of size of the area rounded down to the nearest integer.
00051  *      Then all free areas of storage whose length have the same index n are
00052  *      organized into a chain with other free areas of index n (the "bucket"
00053  *      chain). A request for allocation of storage first searches the list of
00054  *      free memory.  The search starts at the bucket chain of index equal to
00055  *      that of the storage request, continuing to higher index bucket chains
00056  *      if the first attempt fails.
00057  *      If the search fails then new memory is allocated.  Only the amount of
00058  *      new memory needed is allocated.  Any old free memory left after an
00059  *      allocation is returned to the free list.
00060  *
00061  *        All memory areas (free or busy) handled by rt_pmalloc are also chained
00062  *      sequentially by increasing address (the adjacency chain).  When memory
00063  *      is freed it is merged with adjacent free areas, if any.  If a free area
00064  *      of memory ends at the end of memory (i.e. at the break), and if the
00065  *      variable "endfree" is non-zero, then the break is contracted, freeing
00066  *      the memory back to the system.
00067  *
00068  *      Notes:
00069  *              ov_length field includes sizeof(struct overhead)
00070  *              adjacency chain includes all memory, allocated plus free.
00071  */
00072 /*@}*/
00073 
00074 #ifndef lint
00075 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/pmalloc.c,v 14.12 2006/09/16 02:04:25 lbutler Exp $ (BRL)";
00076 #endif
00077 
00078 #include "common.h"
00079 
00080 #include <stdio.h>
00081 #include <string.h>
00082 #include <math.h>
00083 #include "machine.h"
00084 #include "bu.h"
00085 #include "vmath.h"
00086 #include "bn.h"
00087 #include "raytrace.h"
00088 
00089 
00090 /*
00091  * the following items may need to be configured for a particular machine
00092  */
00093 
00094 /* alignment requirement for machine (in bytes) */
00095 #define NALIGN  sizeof(double)
00096 
00097 /* size of an integer large enough to hold a character pointer */
00098 typedef long    Size;
00099 
00100 /*
00101  * CURBRK returns the value of the current system break, i.e., the system's
00102  * idea of the highest legal address in the data area.  It is defined as
00103  * a macro for the benefit of systems that have provided an easier way to
00104  * obtain this number (such as in an external variable)
00105  */
00106 
00107 #ifndef CURBRK
00108 #define CURBRK  sbrk(0)
00109 #else  /* CURBRK */
00110 #       if      CURBRK == curbrk
00111 extern Size curbrk;
00112 #       endif
00113 #endif /* CURBRK */
00114 
00115 /*
00116  * note that it is assumed that CURBRK remembers the last requested break to
00117  * the nearest byte (or at least the nearest word) rather than the nearest page
00118  * boundary.  If this is not true then the following BRK macro should be
00119  * replaced with one that remembers the break to within word-size accuracy.
00120  */
00121 
00122 #ifndef BRK
00123 #define BRK(x)  brk(x)
00124 #endif /* Not BRK */
00125 
00126 /* END of machine dependent portion */
00127 
00128 #define MAGIC_FREE      0x548a934c
00129 #define MAGIC_BUSY      0xc139569a
00130 
00131 #if 0
00132 #define RT_PM_NBUCKETS  18
00133 
00134 struct rt_qelem {
00135         struct rt_qelem *q_forw;
00136         struct rt_qelem *q_back;
00137 };
00138 
00139 #endif
00140 struct overhead {
00141         struct rt_qelem ov_adj;         /* adjacency chain pointers */
00142         struct rt_qelem ov_buk;         /* bucket chain pointers */
00143         long            ov_magic;
00144         Size            ov_length;
00145 };
00146 
00147 /*
00148  * The following macros depend on the order of the elements in struct overhead
00149  */
00150 #define TOADJ(p)        ((struct rt_qelem *)(p))
00151 #define FROMADJ(p)      ((struct overhead *)(p))
00152 #define FROMBUK(p)      ((struct overhead *)( (char *)p - sizeof(struct rt_qelem)))
00153 #define TOBUK(p)        ((struct rt_qelem *)( (char *)p + sizeof(struct rt_qelem)))
00154 
00155 extern char endfree;
00156 
00157 static Size mlindx();
00158 static void rt_pm_insque(), rt_pm_remque();
00159 static void mllcerr();
00160 static void mlfree_end();
00161 
00162 extern void (*mlabort)();
00163 
00164 #define debug 1
00165 #ifdef debug
00166 # define ASSERT(p,q)    if (!(p)) { \
00167                                 bu_semaphore_acquire( BU_SEM_SYSCALL ); \
00168                                 mllcerr(q); \
00169                                 bu_semaphore_release( BU_SEM_SYSCALL ); \
00170                         }
00171 #else
00172 # define ASSERT(p,q)
00173 #endif
00174 
00175 #ifndef NULL
00176 #define NULL    0
00177 #endif
00178 
00179 /*
00180  * return to the system memory freed adjacent to the break
00181  * default is Off
00182  */
00183 char endfree = 0;
00184 
00185 /* sizes of buckets currently proportional to log 2() */
00186 static Size mlsizes[RT_PM_NBUCKETS] = {
00187         0, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768,
00188         65536, 131072, 262144, 524288, 1048576, 2097152, 4194304
00189 };
00190 
00191 #if 0
00192 /* head of adjacency chain */
00193 static struct rt_qelem adjhead = { &adjhead, &adjhead };
00194 
00195 /* head of bucket chains */
00196 static struct rt_qelem buck[RT_PM_NBUCKETS] = {
00197         &buck[0],  &buck[0],    &buck[1],  &buck[1],
00198         &buck[2],  &buck[2],    &buck[3],  &buck[3],
00199         &buck[4],  &buck[4],    &buck[5],  &buck[5],
00200         &buck[6],  &buck[6],    &buck[7],  &buck[7],
00201         &buck[8],  &buck[8],    &buck[9],  &buck[9],
00202         &buck[10], &buck[10],   &buck[11], &buck[11],
00203         &buck[12], &buck[12],   &buck[13], &buck[13],
00204         &buck[14], &buck[14],   &buck[15], &buck[15],
00205         &buck[16], &buck[16],   &buck[17], &buck[17]
00206 };
00207 #endif
00208 
00209 void (*mlabort)() = {0};        /* ptr to optional user-provided error handler */
00210 
00211 char *
00212 rt_pmalloc(nbytes, pmem)
00213 long nbytes;
00214 struct rt_pm_res *pmem;
00215 {
00216         register struct overhead *p, *q;
00217         register struct rt_qelem *bucket;
00218         register Size surplus;
00219 
00220         nbytes = ((nbytes + (NALIGN-1)) & ~(NALIGN-1))
00221                 + sizeof(struct overhead);
00222 
00223         for (
00224             bucket = &pmem->buckets[mlindx(nbytes)];
00225             bucket < &pmem->buckets[RT_PM_NBUCKETS];
00226             bucket++
00227         ) {
00228                 register struct rt_qelem *b;
00229                 for(b = bucket->q_forw; b != bucket; b = b->q_forw) {
00230                         p = FROMBUK(b);
00231                         ASSERT(p->ov_magic == MAGIC_FREE,
00232 "\nrt_pmalloc: Entry not marked FREE found on Free List!\n")
00233                         if (p->ov_length >= nbytes) {
00234                                 rt_pm_remque(b);
00235                                 surplus = p->ov_length - nbytes;
00236                                 goto foundit;
00237                         }
00238                 }
00239         }
00240 
00241         /* obtain additional memory from system */
00242         {
00243                 register Size i;
00244                 long ret;
00245 
00246                 bu_semaphore_acquire( BU_SEM_SYSCALL );
00247                 p = (struct overhead *)CURBRK;
00248                 i = ((Size)p)&(NALIGN-1);
00249                 if (i != 0)
00250                         p = (struct overhead *)((char *)p + NALIGN - i);
00251                 ret = (long)BRK(((char *)p) + nbytes);
00252                 bu_semaphore_release( BU_SEM_SYSCALL );
00253 
00254                 if( ret )
00255                         bu_bomb( "rt_pmalloc: brk() failure. Insufficient memory available!\n" );
00256 
00257                 p->ov_length = nbytes;
00258                 surplus = 0;
00259 
00260                 /* add to end of adjacency chain */
00261 #if 0
00262                 ASSERT((FROMADJ(pmem->adjhead.q_back)) < p,
00263 "\nrt_pmalloc: Entry in adjacency chain found with address lower than Chain head!\n"
00264                         )
00265 #endif
00266                 rt_pm_insque(TOADJ(p),pmem->adjhead.q_back);
00267         }
00268 
00269 foundit:
00270         /* mark surplus memory free */
00271         if (surplus > sizeof(struct overhead)) {
00272                 /* if big enough, split it up */
00273                 q = (struct overhead *)((char *)p + nbytes);
00274 
00275                 q->ov_length = surplus;
00276                 p->ov_length = nbytes;
00277                 q->ov_magic = MAGIC_FREE;
00278 
00279                 /* add surplus into adjacency chain */
00280                 rt_pm_insque(TOADJ(q),TOADJ(p));
00281 
00282                 /* add surplus into bucket chain */
00283                 rt_pm_insque(TOBUK(q),&pmem->buckets[mlindx(surplus)]);
00284         }
00285 
00286         p->ov_magic = MAGIC_BUSY;
00287         return((char*)p + sizeof(struct overhead));
00288 }
00289 
00290 /*
00291  * select the proper size bucket
00292  */
00293 #if 0
00294 static Size
00295 mlindx(n)
00296 register Size n;
00297 {
00298         register Size *p, *q, *r;
00299         p = &mlsizes[0];
00300         r = &mlsizes[RT_PM_NBUCKETS];
00301         /* binary search */
00302         while ((q = (p + (r-p)/2)) > p) {
00303                 if (n < *q)
00304                         r = q;
00305                 else
00306                         p = q;
00307         }
00308         return(q - &mlsizes[0]);
00309 }
00310 #else
00311 /* this version of mlindx() will only work with the original RT_PM_NBUCKETS
00312  * and mlsizes[]
00313  */
00314 static Size
00315 mlindx( n )
00316 register Size n;
00317 {
00318         register Size index=0, shifter;
00319 
00320         if( n >= mlsizes[RT_PM_NBUCKETS-1] )
00321                 index = RT_PM_NBUCKETS-1;
00322         else if( n < mlsizes[1] )
00323                 index = 0;
00324         else
00325         {
00326                 shifter = n >> 6;
00327                 while( shifter )
00328                 {
00329                         index++;
00330                         shifter = shifter >> 1;
00331                 }
00332         }
00333 
00334         return( index );
00335 }
00336 #endif
00337 
00338 static void
00339 mllcerr(p)
00340 char *p;
00341 {
00342         register char *q;
00343         q = p;
00344         while (*q++);   /* find end of string */
00345         (void)write(2,p,q-p-1);
00346         if (mlabort)
00347                 (*mlabort)();
00348         else
00349                 abort();
00350 }
00351 
00352 /*
00353  * The vax has wondrous instructions for inserting and removing items into
00354  * doubly linked queues.  On the vax the assembler output of the C compiler is
00355  * massaged by an sed script to turn these function calls into invocations of
00356  * the rt_pm_insque and rt_pm_remque machine instructions.
00357  *  In BRL's version, all machines use these functions.  No assembler.
00358  */
00359 
00360 static void
00361 rt_pm_insque(item,queu)
00362 register struct rt_qelem *item, *queu;
00363 /* insert "item" after "queu" */
00364 {
00365         register struct rt_qelem *pueu;
00366         pueu = queu->q_forw;
00367         item->q_forw = pueu;
00368         item->q_back = queu;
00369         queu->q_forw = item;
00370         pueu->q_back = item;
00371 }
00372 
00373 static void
00374 rt_pm_remque(item)
00375 register struct rt_qelem *item;
00376 /* remove "item" */
00377 {
00378         register struct rt_qelem *queu, *pueu;
00379         pueu = item->q_forw;
00380         queu = item->q_back;
00381         queu->q_forw = pueu;
00382         pueu->q_back = queu;
00383 }
00384 
00385 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
00386  *  rt_pfree                                    William L. Sebok
00387  * A "smarter" malloc v1.0              Sept. 24, 1984 rev. June 30,1986
00388  *
00389  *      rt_pfree takes a previously rt_pmalloc-allocated area at mem and frees it.
00390  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00391 
00392 void
00393 rt_pfree(mem, pmem)
00394 register char *mem;
00395 register struct rt_pm_res *pmem;
00396 {
00397         register struct overhead *p, *q;
00398 
00399         if (mem == NULL)
00400                 return;
00401 
00402         p = (struct overhead *)(mem - sizeof(struct overhead));
00403 
00404         /* not advised but allowed */
00405         if (p->ov_magic == MAGIC_FREE)
00406                 return;
00407 
00408         if (p->ov_magic != MAGIC_BUSY)
00409                 mllcerr("rt_pfree: attempt to free memory not allocated with rt_pmalloc!\n");
00410 
00411         /* try to merge with previous free area */
00412         q = FROMADJ((TOADJ(p))->q_back);
00413 
00414         if (q != FROMADJ(&pmem->adjhead)) {
00415                 ASSERT(q < p,
00416 "\nrt_pfree: While trying to merge a free area with a lower adjacent free area,\n\
00417  addresses were found out of order!\n")
00418                 /* If lower segment can be merged */
00419                 if (   q->ov_magic == MAGIC_FREE
00420                    && (char *)q + q->ov_length == (char *)p
00421                 ) {
00422                         /* remove lower address area from bucket chain */
00423                         rt_pm_remque(TOBUK(q));
00424 
00425                         /* remove upper address area from adjacency chain */
00426                         rt_pm_remque(TOADJ(p));
00427 
00428                         q->ov_length += p->ov_length;
00429                         p->ov_magic = 0;        /* decommission */
00430                         p = q;
00431                 }
00432         }
00433 
00434         /* try to merge with next higher free area */
00435         q = FROMADJ((TOADJ(p))->q_forw);
00436 
00437         if (q != FROMADJ(&pmem->adjhead)) {
00438                 /* upper segment can be merged */
00439                 ASSERT(q > p,
00440 "\nrt_pfree: While trying to merge a free area with a higher adjacent free area,\n\
00441  addresses were found out of order!\n")
00442                 if (    q->ov_magic == MAGIC_FREE
00443                    &&   (char *)p + p->ov_length == (char *)q
00444                 ) {
00445                         /* remove upper from bucket chain */
00446                         rt_pm_remque(TOBUK(q));
00447 
00448                         /* remove upper from adjacency chain */
00449                         rt_pm_remque(TOADJ(q));
00450 
00451                         p->ov_length += q->ov_length;
00452                         q->ov_magic = 0;        /* decommission */
00453                 }
00454         }
00455 
00456         p->ov_magic = MAGIC_FREE;
00457 
00458         /* place in bucket chain */
00459         rt_pm_insque(TOBUK(p),&pmem->buckets[mlindx(p->ov_length)]);
00460 
00461         if (endfree)
00462                 mlfree_end( pmem );
00463 
00464         return;
00465 }
00466 
00467 static void
00468 mlfree_end( pmem )
00469 register struct rt_pm_res *pmem;
00470 {
00471         register struct overhead *p;
00472 
00473         p = FROMADJ(pmem->adjhead.q_back);
00474         if( p->ov_magic != MAGIC_FREE )
00475                 return;
00476 
00477         bu_semaphore_acquire( BU_SEM_SYSCALL );
00478         if ( (char*)p + p->ov_length == (char *)CURBRK)
00479         {
00480                 /* area is free and at end of memory */
00481 
00482                 p->ov_magic = 0;        /* decommission (just in case) */
00483 
00484                 /* remove from end of adjacency chain */
00485                 rt_pm_remque(TOADJ(p));
00486 
00487                 /* remove from bucket chain */
00488                 rt_pm_remque(TOBUK(p));
00489 
00490                 /* release memory to system */
00491                 (void)BRK((char *)p);
00492         }
00493         bu_semaphore_release( BU_SEM_SYSCALL );
00494 
00495         return;
00496 }
00497 
00498 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
00499  *  rt_prealloc                         William L. Sebok
00500  * A  "smarter" malloc v1.0             Sept. 24, 1984 rev. June 30,1986
00501  *
00502  *      rt_prealloc takes previously rt_pmalloc-allocated area at mem, and tries
00503  *       to change its size to nbytes bytes, moving it and copying its
00504  *       contents if necessary.
00505  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00506 
00507 char *
00508 rt_prealloc(mem,nbytes, pmem)
00509 register char *mem; unsigned nbytes;
00510 register struct rt_pm_res *pmem;
00511 {
00512         register char *newmem;
00513         register struct overhead *p, *q;
00514         Size surplus, length;
00515         char oendfree;
00516 
00517         if (mem == NULL)
00518                 return(rt_pmalloc((long)nbytes, pmem));
00519 
00520         /* if beyond current arena it has to be bad */
00521         if(mem > (char*)FROMADJ(pmem->adjhead.q_back) + sizeof(struct overhead))
00522                 return(NULL);
00523 
00524         p = (struct overhead *)(mem - sizeof(struct overhead));
00525 
00526         if (p->ov_magic != MAGIC_BUSY && p->ov_magic != MAGIC_FREE)
00527                 return(NULL);   /* already gone */
00528 
00529         length = p->ov_length;
00530 
00531         nbytes = (nbytes + (NALIGN-1)) & (~(NALIGN-1));
00532 
00533         if (p->ov_magic == MAGIC_BUSY) {
00534                 oendfree = endfree;     endfree = 0;
00535                 rt_pfree(mem, pmem);    /* free it but don't let it contract break */
00536                 endfree = oendfree;
00537         }
00538 
00539         if(  p->ov_magic == MAGIC_FREE
00540          && (surplus = length - nbytes - sizeof(struct overhead)) >= 0
00541         ) {
00542                 /* shrink area in place */
00543                 if (surplus > sizeof(struct overhead)) {
00544                         q = (struct overhead *)( (char *)p + nbytes
00545                                 + sizeof(struct overhead));
00546                         q->ov_length = surplus;
00547                         q->ov_magic = MAGIC_FREE;
00548                         rt_pm_insque(TOADJ(q),TOADJ(p));
00549                         rt_pm_insque(TOBUK(q),&pmem->buckets[mlindx(surplus)]);
00550                         p->ov_length -= surplus;
00551                 }
00552                 /* declare it to be busy */
00553                 rt_pm_remque(TOBUK(p));
00554                 p->ov_magic = MAGIC_BUSY;
00555 
00556                 if (endfree)
00557                         mlfree_end( pmem );
00558                 return(mem);
00559         }
00560 
00561         /* if at break, grow in place */
00562 
00563         bu_semaphore_acquire( BU_SEM_SYSCALL );
00564         if (p->ov_magic == MAGIC_FREE && ((char *)p + p->ov_length) == (char *)CURBRK) {
00565                 nbytes += sizeof(struct overhead);
00566 
00567                 BRK((char *)p + nbytes);
00568                 bu_semaphore_release( BU_SEM_SYSCALL );
00569 
00570                 p->ov_length = nbytes;
00571                 /* declare it to be busy */
00572                 rt_pm_remque(TOBUK(p));
00573                 p->ov_magic = MAGIC_BUSY;
00574                 return(mem);
00575         }
00576         else
00577                 bu_semaphore_release( BU_SEM_SYSCALL );
00578 
00579         newmem = rt_pmalloc((long)nbytes, pmem);
00580 
00581         if (newmem != mem && newmem != NULL) {
00582                 register Size n;
00583                 n = length - sizeof(struct overhead);
00584                 nbytes = (nbytes < n) ? nbytes: n;
00585                 (void)bcopy(mem,newmem,nbytes);
00586                 /* note:
00587                  * it is assumed that bcopy does the right thing on overlapping
00588                  * extents (true on the vax)
00589                  */
00590         }
00591 
00592         if (endfree)
00593                 mlfree_end( pmem );
00594 
00595         return(newmem);
00596 }
00597 
00598 #if 0
00599 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
00600  *  rt_forget                           William L. Sebok
00601  * A "smarter" malloc v1.0              Sept. 24, 1984 rev. June 30,1986
00602  *
00603  *      rt_forget returns to the rt_pmalloc arena all memory allocated by sbrk()
00604  *       above "bpnt".
00605  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00606 
00607 void
00608 rt_forget(bpnt, pmem)
00609 char *bpnt;
00610 struct rt_pm_res *pmem;
00611 {
00612         register struct overhead *p, *q, *r, *b;
00613         register Size l;
00614         struct overhead *crbrk;
00615         char pinvalid, oendfree;
00616 
00617         /*
00618          * b = rt_forget point
00619          * p = beginning of entry
00620          * q = end of entry, beginning of gap
00621          * r = end of gap, beginning of next entry (or the break)
00622          * pinvalid = true when groveling at rt_forget point
00623          */
00624 
00625         pinvalid = 0;
00626         oendfree = endfree;     endfree = 0;
00627         b = (struct overhead *)bpnt;
00628         p = FROMADJ(pmem->adjhead.q_back);
00629         q = (struct overhead *)0;
00630         bu_semaphore_acquire( BU_SEM_SYSCALL );
00631         r = crbrk = (struct overhead *)CURBRK;
00632         bu_semaphore_release( BU_SEM_SYSCALL );
00633 
00634         for (;pinvalid == 0 && b < r; p = FROMADJ(TOADJ(r = p)->q_back)) {
00635                 if ( p == FROMADJ(&pmem->adjhead)
00636                  || (q = (struct overhead *)((char *)p + p->ov_length)) < b
00637                 ) {
00638                         pinvalid = 1;
00639                         q = b;
00640                 }
00641 
00642                 if (q == r)
00643                         continue;
00644 
00645                 ASSERT(q < r,
00646 "\nrt_forget: addresses in adjacency chain are out of order!\n")
00647 
00648                 /* end of gap is at break */
00649                 if (oendfree && r == crbrk) {
00650 
00651                         bu_semaphore_acquire( BU_SEM_SYSCALL );
00652                         (void)BRK((char *)q);   /* free it yourself */
00653                         bu_semaphore_release( BU_SEM_SYSCALL );
00654 
00655                         crbrk = r = q;
00656                         continue;
00657                 }
00658 
00659                 if (pinvalid)
00660                         q = (struct overhead *) /* align q pointer */
00661                                 (((long)q + (NALIGN-1)) & (~(NALIGN-1)));
00662 
00663                 l = (char *)r - (char *)q;
00664                 /*
00665                  * note: unless something is screwy: (l%NALIGN) == 0
00666                  * as r should be aligned by this point
00667                  */
00668 
00669                 if (l >= sizeof(struct overhead)) {
00670                         /* construct busy entry and free it */
00671                         q->ov_magic = MAGIC_BUSY;
00672                         q->ov_length = l;
00673                         rt_pm_insque(TOADJ(q),TOADJ(p));
00674                         rt_pfree((char *)q + sizeof(struct overhead));
00675                 } else if (pinvalid == 0) {
00676                         /* append it to previous entry */
00677                         p->ov_length += l;
00678                         if (p->ov_magic == MAGIC_FREE) {
00679                                 rt_pm_remque(TOBUK(p));
00680                                 rt_pm_insque(TOBUK(p),&pmem->buckets[mlindx(p->ov_length)]);
00681                         }
00682                 }
00683         }
00684         endfree = oendfree;
00685         if (endfree)
00686                 mlfree_end( pmem );
00687         return;
00688 }
00689 #endif
00690 /*
00691  *              P C A L L O C
00692  *
00693  *  Malloc() a block of memory, and clear it.
00694  */
00695 char *
00696 rt_pcalloc(num, size, pmem)
00697 register unsigned num, size;
00698 register struct rt_pm_res *pmem;
00699 {
00700         register char *p;
00701 
00702         size *= num;
00703         if ( (p = rt_pmalloc((long)size, pmem)) )  {
00704             memset( p, 0, size );
00705         }
00706         return (p);
00707 }
00708 
00709 void
00710 rt_cfree(p, num, size, pmem)
00711 char *p;
00712 unsigned num;
00713 unsigned size;
00714 struct rt_pm_res *pmem;
00715 {
00716         rt_pfree(p, pmem);
00717 }
00718 
00719 /*
00720  * Local Variables:
00721  * mode: C
00722  * tab-width: 8
00723  * c-basic-offset: 4
00724  * indent-tabs-mode: t
00725  * End:
00726  * ex: shiftwidth=4 tabstop=8
00727  */

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