G:/ScriptBasic/source/myalloc.c

Go to the documentation of this file.
00001 /* 
00002 FILE:   myalloc.c
00003 HEADER: myalloc.h
00004 
00005 --GNU LGPL
00006 This library is free software; you can redistribute it and/or
00007 modify it under the terms of the GNU Lesser General Public
00008 License as published by the Free Software Foundation; either
00009 version 2.1 of the License, or (at your option) any later version.
00010 
00011 This library is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 Lesser General Public License for more details.
00015 
00016 You should have received a copy of the GNU Lesser General Public
00017 License along with this library; if not, write to the Free Software
00018 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 */
00021 
00022 
00023 /* Define it 0 if you do not want to compile a multi threaded version */
00024 #ifndef MTHREAD
00025 #define MTHREAD 0
00026 #endif
00027 
00028 #include <stdlib.h>
00029 #include <stdio.h>
00030 
00031 /* for offsetof */
00032 #include <stddef.h>
00033 #ifdef _DEBUG
00034 #include <memory.h>
00035 #endif
00036 
00037 #include "myalloc.h"
00038 
00039 static unsigned long MaxNetSize,
00040                      MinNetSize,
00041                      MaxBruSize,
00042                      MinBruSize,
00043                      ActNetSize,
00044                      ActBruSize;
00045 #if MTHREAD
00046 #include "thread.h"
00047 
00048 #define LOCK_SEGMENT    thread_LockMutex(&(pMemorySegment->mxSegment));
00049 #define UNLOCK_SEGMENT  thread_UnlockMutex(&(pMemorySegment->mxSegment));
00050 
00051 static unsigned char fLockMalloc=0;
00052 static MUTEX mxMalloc;
00053 #define LOCK_MALLOC   if( fLockMalloc )thread_LockMutex(&mxMalloc);
00054 #define UNLOCK_MALLOC if( fLockMalloc )thread_UnlockMutex(&mxMalloc);
00055 
00056 static MUTEX mxStat;
00057 #define LOCK_STAT   thread_LockMutex(&mxStat);
00058 #define UNLOCK_STAT thread_UnlockMutex(&mxStat);
00059 
00060 #else
00061 
00062 #define LOCK_SEGMENT
00063 #define UNLOCK_SEGMENT
00064 #define LOCK_MALLOC
00065 #define UNLOCK_MALLOC
00066 #define LOCK_STAT
00067 #define UNLOCK_STAT
00068 #endif
00069 
00070 /* lock the statistics, the modify the global values */
00071 #define STAT_ADD(NET,BRU) LOCK_STAT \
00072                           ActNetSize += (NET); \
00073                           if( ActNetSize > MaxNetSize )MaxNetSize = ActNetSize; \
00074                           if( ActNetSize < MinNetSize )MinNetSize = ActNetSize; \
00075                           ActBruSize += (BRU); \
00076                           if( ActBruSize > MaxBruSize )MaxBruSize = ActBruSize; \
00077                           if( ActBruSize < MinBruSize )MinBruSize = ActBruSize; \
00078                           UNLOCK_STAT
00079 
00080 #define STAT_SUB(NET,BRU) LOCK_STAT \
00081                           ActNetSize -= (NET); \
00082                           if( ActNetSize > MaxNetSize )MaxNetSize = ActNetSize; \
00083                           if( ActNetSize < MinNetSize )MinNetSize = ActNetSize; \
00084                           ActBruSize -= (BRU); \
00085                           if( ActBruSize > MaxBruSize )MaxBruSize = ActBruSize; \
00086                           if( ActBruSize < MinBruSize )MinBruSize = ActBruSize; \
00087                           UNLOCK_STAT
00088 
00089 typedef struct _AllocUnit {
00090   unsigned long      Size;          /* size of the chunk */
00091   struct _AllocUnit *next;     /* link to the next unit */
00092   struct _AllocUnit *prev;     /* the previous unit */
00093   unsigned char      memory[1];     /* one or more bytes reserved */
00094   } AllocUnit, *pAllocUnit;
00095 /* Note that the last member before 'memory' is a pointer which should
00096    provide sufficient alignment for 'memory' on 32bit and on 64bit systems as well */
00097 
00098 typedef struct _MyAlloc {
00099 #if MTHREAD
00100   MUTEX mxSegment;
00101 #endif
00102   void * (*memory_allocating_function)(size_t);
00103   void (*memory_releasing_function)(void *);
00104 
00105   unsigned long MaxSize,CurrentSize,
00106                 MaxNetSize,MinNetSize;
00107 
00108   pAllocUnit FirstUnit;
00109   } MyAlloc, *pMyAlloc;
00110 
00111 
00112 /*POD
00113 =H Multi-thread use of this module
00114 
00115 You can use this module in multi threaded environment. In this case the module depend on the module T<thread.c>
00116 which contains the thread and mutex interface functions that call the operating system thread and mutex functions
00117 on UNIX and on Windows NT.
00118 
00119 In single thread environment there is no need to use the locking mechanism. To get a single-thread version either you can
00120 edit this file (T<myalloc.c>) or compile is using the option T<-DMTHREAD=0> The default compilation is multi threaded.
00121 
00122 Multi thread implementation has two levels. One is that the subroutines implemented in this module call
00123 the appropriate locking functions to ensure that no two concurrent threads access and modify the same data at a time
00124 and thus assure that the data of the module is correct. The other level is that you can tell the module that the
00125 underlying memory allocation and deallocation modules are mot thread safe. There are global variables
00126 implementing global mutexes that are locked and unlocked if you use the module that way. This can be useful in some
00127 environment where T<malloc> and T<free> are not thread safe.
00128 
00129 Note that this should not be the case if you call T<malloc> and T<free> or you linked the wrong versio of libc.
00130 However you may use a non-thread safe debug layer for example the one that ScriptBasic uses.
00131 
00132 CUT*/
00133 
00134 /*POD
00135 =H alloc_InitSegment()
00136 
00137 Call this function to get a new segment. You should specify the functions that the segement should use to
00138 get memory from the operating system, and the function the segment should use to release the memory to the
00139 operating system. These functions should be like T<malloc> and T<free>.
00140 
00141 If the second argument is T<NULL> then the function will treat the first argument as an already
00142 allocated and initialized memory segment and the memory allocation and freeing functions will be
00143 inherited from that segment.
00144 
00145 /*FUNCTION*/
00146 void *alloc_InitSegment(void * (*maf)(size_t), /* a 'malloc' and a 'free' like functions */
00147                         void   (*mrf)(void *)
00148   ){
00149 /*noverbatim
00150 
00151 The return value is a T<void*> pointer which identifies the segment and should be passed to the other functions
00152 as segment argument.
00153 
00154 The first argument is the T<malloc> like function and the second if the T<free> like function.
00155 CUT*/
00156   pMyAlloc pMemorySegment;
00157 
00158   /* If the second argument is T<NULL> then the first argument is a valid and initialized memory
00159      segment and in this case the primitive allocation functions are inherited */
00160   if( mrf == NULL ){
00161     pMemorySegment = (pMyAlloc)maf;
00162     maf = pMemorySegment->memory_allocating_function;
00163     mrf = pMemorySegment->memory_releasing_function;
00164     }
00165 
00166 #if MTHREAD
00167   if( fLockMalloc )thread_LockMutex(&mxMalloc);
00168 #endif
00169 
00170   pMemorySegment = (pMyAlloc)maf(sizeof(MyAlloc));
00171   STAT_ADD( 0 , sizeof(MyAlloc) )
00172 
00173 #if MTHREAD
00174   if( fLockMalloc )thread_UnlockMutex(&mxMalloc);
00175 #endif
00176 
00177   if( pMemorySegment == NULL )return NULL;
00178   pMemorySegment->memory_allocating_function = maf;
00179   pMemorySegment->memory_releasing_function = mrf;
00180   pMemorySegment->FirstUnit = NULL;
00181   pMemorySegment->CurrentSize = 0; /* the segment is initialized, no memory is allocated */
00182   pMemorySegment->MaxSize = 0; /* there is no limit by default */
00183   pMemorySegment->MaxNetSize = 0;
00184   pMemorySegment->MinNetSize = 0;
00185 #if MTHREAD
00186   thread_InitMutex(&(pMemorySegment->mxSegment));
00187 #endif
00188   return (void *)pMemorySegment;
00189   }
00190 
00191 /*POD
00192 =H alloc_GlobalUseGlobalMutex()
00193 
00194 Some installation use memory allocation function that are not thread safe. On some
00195 UNIX installations T<malloc> is not thread safe. To tell the module that all the allocation
00196 function primitives are not thread safe call this function before initializing any segment.
00197 
00198 /*FUNCTION*/
00199 void alloc_GlobalUseGlobalMutex(
00200   ){
00201 /*noverbatim
00202 CUT*/
00203 #if MTHREAD
00204   fLockMalloc = 1;
00205   thread_InitMutex(&mxMalloc);
00206 #else
00207   exit(63);
00208 #endif
00209   }
00210 
00211 /*POD
00212 =H alloc_SegmentLimit()
00213 
00214 You can call this function to set a segment limit. Each segment keeps track of the actual memory
00215 allocated to the segment. When a new piece of memory allocated in a segment the calculated segment
00216 size is increased by the size of the memory chunk. When a piece of memory is release the calculated
00217 size of the segment is decreased.
00218 
00219 Whenever a segment approaches its limit the next allocation function requesting memory
00220 that would exceed the limit returns T<NULL> and does not allocate memory.
00221 
00222 The value of the limit is the number of bytes allowed for the segment. This is the requested number of
00223 bytes without the segment management overhead.
00224 
00225 Setting the limit to zero means no limit except the limits of the underlying memory allocation layers,
00226 usually T<malloc>.
00227 
00228 You can dynamically set the limit during handling the memory at any time except that you should not
00229 set the limit to zero unless the segment is empty and you should not set the limit to a positive value
00230 when the actual limit is zero (no limit) and the segment is not empty. This restriction is artificial
00231 in this release but is needed to be followed to be compatible with planned future developments.
00232 
00233 This function sets the limit for the segment pointed by T<p> and returns the old value of the segment.
00234 /*FUNCTION*/
00235 long alloc_SegmentLimit(void *p,
00236                         unsigned long NewMaxSize
00237   ){
00238 /*noverbatim
00239 CUT*/
00240   pMyAlloc pMemorySegment = (pMyAlloc)p;
00241   unsigned long lOldValue;
00242 
00243   LOCK_SEGMENT
00244   lOldValue = pMemorySegment->MaxSize;
00245   pMemorySegment->MaxSize = NewMaxSize;
00246   UNLOCK_SEGMENT
00247   return lOldValue;
00248   }
00249 /*POD
00250 =H alloc_FreeSegment()
00251 
00252 Use this function to release all the memory that was allocated to the segment T<p>.
00253 Note that after calling this function the segment is still usable, only the memory
00254 that it handled was released. If you do not need the segment anymore call the function
00255 R<alloc_FinishSegment()> that calls this function and then releases the memory allocated to store
00256 the segment information.
00257 
00258 Sloppy programmers may pass T<NULL> as argument, it just returns.
00259 /*FUNCTION*/
00260 void alloc_FreeSegment(void *p
00261   ){
00262 /*noverbatim
00263 CUT*/
00264   pMyAlloc pMemorySegment = (pMyAlloc)p;
00265   void   (*mrf)(void *);
00266   pAllocUnit pAllU = pMemorySegment->FirstUnit;
00267   pAllocUnit pNext;
00268 
00269   if( !p )return;
00270   mrf = pMemorySegment->memory_releasing_function;
00271   LOCK_SEGMENT
00272   while( pAllU ){
00273     pNext = pAllU->next;
00274     LOCK_MALLOC
00275     STAT_SUB( pAllU->Size , pAllU->Size+sizeof(AllocUnit)-1 )
00276 #ifdef _DEBUG
00277 //    memset(pAllU,0x80,pAllU->Size+sizeof(AllocUnit)-1);
00278 #endif
00279     mrf(pAllU);
00280     UNLOCK_MALLOC
00281     pAllU = pNext;
00282     }
00283   pMemorySegment->FirstUnit = NULL;
00284   pMemorySegment->CurrentSize = 0; /* the segment is initialized, no memory is allocated */
00285   pMemorySegment->MinNetSize = 0; /* MinNetSiez can not be smaller, and MaxNetSize can only be larger. */
00286   UNLOCK_SEGMENT
00287   }
00288 
00289 /*POD
00290 =H alloc_FinishSegment()
00291 
00292 Use this function to release all the memory that was allocated to the segment T<p>.
00293 This function also releases the memory of the segment head and therefore the
00294 segment pointed by T<p> is not usable anymore.
00295 
00296 /*FUNCTION*/
00297 void alloc_FinishSegment(void *p
00298   ){
00299 /*noverbatim
00300 CUT*/
00301   pMyAlloc pMemorySegment = (pMyAlloc)p;
00302   void   (*mrf)(void *);
00303 
00304   if( !p )return;
00305   mrf = pMemorySegment->memory_releasing_function;
00306   alloc_FreeSegment(p);
00307 #if MTHREAD
00308   thread_FinishMutex(&(pMemorySegment->mxSegment));
00309 #endif
00310   /* here we can not lock the segment because the segment including the mutex is deleted */
00311   LOCK_MALLOC
00312   mrf(pMemorySegment);
00313   UNLOCK_MALLOC
00314   STAT_SUB( 0 , sizeof(pMyAlloc) );
00315   }
00316 
00317 /*POD
00318 =H alloc_Alloc()
00319 
00320 Use this function to allocate a memory piece from a segment.
00321 
00322 /*FUNCTION*/
00323 void *alloc_Alloc(size_t n,
00324                   void *p
00325   ){
00326 /*noverbatim
00327 
00328 The first argument is the size to be allocated. The second argument is the
00329 segment which should be used for the allocation.
00330 
00331 If the memory allocation fails the function returns T<NULL>.
00332 CUT*/
00333   pMyAlloc pMemorySegment = (pMyAlloc)p;
00334   pAllocUnit pAllU;
00335 
00336   if( n == 0 )
00337     return NULL;
00338 #ifdef _DEBUG
00339   if( pMemorySegment == NULL ){
00340     exit(666);
00341     }
00342 #endif
00343   /* Check if there is any limit for this segment and if we have reached the limit. */
00344   if( pMemorySegment->MaxSize && pMemorySegment->MaxSize < pMemorySegment->CurrentSize + n )
00345     return NULL;
00346 
00347   LOCK_SEGMENT
00348 
00349   LOCK_MALLOC
00350 
00351 /* When we debug the buffer over runs should be detected by all means. When in release mode
00352    the bugs if any should be handled more generous. Do not kill the program if I still forgot
00353    to correct some code where the string terminating zero was neglected and no buffer allocated
00354    for it. Anyway: older code allocated extra memory because of gaps in the structure.
00355 */
00356 #ifdef _DEBUG
00357 #define EXTRA_BYTE (0)
00358 #else
00359 #define EXTRA_BYTE (1)
00360 #endif
00361 
00362   pAllU = (pAllocUnit)pMemorySegment->memory_allocating_function( n + offsetof(struct _AllocUnit,memory) + EXTRA_BYTE);
00363   UNLOCK_MALLOC
00364 
00365   if( pAllU == NULL ){
00366     UNLOCK_SEGMENT
00367     return NULL;
00368     }
00369 
00370   pAllU->prev = NULL;
00371   pAllU->next = pMemorySegment->FirstUnit;
00372   pAllU->Size = n;
00373 
00374   pMemorySegment->CurrentSize += n;
00375   if( pMemorySegment->CurrentSize > pMemorySegment->MaxNetSize )
00376     pMemorySegment->MaxNetSize = pMemorySegment->CurrentSize;
00377 
00378   if( pMemorySegment->FirstUnit )pMemorySegment->FirstUnit->prev = pAllU;
00379   pMemorySegment->FirstUnit = pAllU;
00380   /* return a void* pointer that points to the allocated memory after the header */
00381   UNLOCK_SEGMENT
00382 
00383   STAT_ADD( n , n-1 + sizeof(AllocUnit) )
00384   return (void *)( pAllU->memory );
00385   }
00386 
00387 /*POD
00388 =H alloc_Free()
00389 
00390 You should call this function whenever you want to release a single piece of memory
00391 allocated from a segment. Note that you also have to pass the segment pointer as the
00392 second argument, because the segment head pointed by this T<void> pointer contains the
00393 memory releasing function pointer.
00394 
00395 Sloppy programmers may try to release T<NULL> pointer without harm.
00396 /*FUNCTION*/
00397 void alloc_Free(void *pMem, void *p
00398   ){
00399 /*noverbatim
00400 CUT*/
00401   pMyAlloc pMemorySegment = (pMyAlloc)p;
00402   pAllocUnit pAllU,pAllUi;
00403 
00404   if( pMemorySegment == NULL )return;
00405   if( pMem == NULL )return;
00406   LOCK_SEGMENT
00407   pAllU = (pAllocUnit)( ((unsigned char *)pMem) - offsetof(struct _AllocUnit,memory) ); 
00408 #ifdef _DEBUG
00409   pAllUi = pMemorySegment->FirstUnit;
00410   while( pAllUi ){
00411     if( pAllUi == pAllU )break;
00412     pAllUi = pAllUi->next;
00413     }
00414   if( pAllUi == NULL ){
00415     printf("Memory segment was released not belonging to the segment.\n");
00416     exit(1);
00417     }
00418 #endif
00419   pMemorySegment->CurrentSize -= pAllU->Size;
00420   if( pMemorySegment->CurrentSize < pMemorySegment->MinNetSize )
00421     pMemorySegment->MinNetSize = pMemorySegment->CurrentSize;
00422 
00423   if( pAllU->next )
00424     pAllU->next->prev = pAllU->prev;
00425   if( pAllU->prev )
00426     pAllU->prev->next = pAllU->next;
00427   else
00428     pMemorySegment->FirstUnit = pAllU->next;
00429 
00430   STAT_SUB( pAllU->Size , pAllU->Size + sizeof(AllocUnit) -1 )
00431 
00432 #ifdef _DEBUG
00433 //    memset(pAllU,0x80,pAllU->Size+sizeof(AllocUnit)-1);
00434 #endif
00435   LOCK_MALLOC
00436   pMemorySegment->memory_releasing_function(pAllU);
00437   UNLOCK_MALLOC
00438 
00439   UNLOCK_SEGMENT
00440   }
00441 
00442 /*POD
00443 =H alloc_Merge()
00444 
00445 Call this function in case you want to merge a segment into another. This can be the
00446 case when your program builds up a memory structure in several steps.
00447 
00448 This function merges the segment T<p2> into T<p1>. This means that the segment T<p1> will
00449 contain all the memory pieces that belonged to T<p2> before and T<p2> will not contain any
00450 allocated memory. However the segment T<p2> is still valid and can be used to allocated memory
00451 from. If you also want to finish the segment T<p2> call the function R<alloc_MergeAndFinish()>.
00452 
00453 /*FUNCTION*/
00454 void alloc_Merge(void *p1, void *p2
00455   ){
00456 /*noverbatim
00457 
00458 Note that the two segments SHOULD use the same, or at least compatible system memory handling functions!
00459 You better use the same functions for both segments.
00460 
00461 Example:
00462 
00463 ScriptBasic builds up a sophisticated memory structure during syntactical analysis. This memory structure
00464 contains the internal code generated from the program lines of the basic program. When ScriptBasic analyses
00465 a line it tries several syntax descriptions. It checks each syntax defintion against the tokens of the line
00466 until it finds one that fits. These checks need to build up memory structure. However if the check fails and
00467 ScriptBasic should go for the next syntac definition line to check the memory allocated during the failed
00468 checking should be released. Therefore these memory pieces are allocated from a segment that the program
00469 calls T<pMyMemorySegment>. If the syntax check fails this segment if freed. If the syntax check succedes this
00470 segment is merged into another segement that contains the memory structures allocated from the previous basic program
00471 lines.
00472 CUT*/
00473   pMyAlloc p1MemorySegment = (pMyAlloc)p1;
00474   pMyAlloc p2MemorySegment = (pMyAlloc)p2;
00475   pAllocUnit *p,q;
00476 
00477 #if MTHREAD
00478   thread_LockMutex(&(p1MemorySegment->mxSegment));
00479   thread_LockMutex(&(p2MemorySegment->mxSegment));
00480 #endif
00481   /* go to the end of the segment #1 */
00482   p = &(p1MemorySegment->FirstUnit);
00483   q = p1MemorySegment->FirstUnit;
00484   while( *p )p = &((q=*p)->next);
00485   /* link the first unit of segment #2 */
00486   *p = p2MemorySegment->FirstUnit;
00487   if( *p )(*p)->prev = q;
00488 
00489   /* hook off the allocated units from segment #2 */
00490   p2MemorySegment->FirstUnit = NULL;
00491   p1MemorySegment->CurrentSize += p2MemorySegment->CurrentSize;
00492 #if MTHREAD
00493   thread_UnlockMutex(&(p2MemorySegment->mxSegment));
00494   thread_UnlockMutex(&(p1MemorySegment->mxSegment));
00495 #endif
00496   }
00497 
00498 /*POD
00499 =H alloc_MergeAndFinish()
00500 Use this function in case you not only want to merge a segment into another but you also
00501 want to finish the segment that was merged into the other.
00502 
00503 
00504 See also R<alloc_Merge()>
00505 /*FUNCTION*/
00506 void alloc_MergeAndFinish(void *p1, void *p2
00507   ){
00508 /*noverbatim
00509 CUT*/
00510   /* we should not lock either of the segments because the underlying functions do the locking */
00511   alloc_Merge(p1,p2);
00512   /* and clean up segment #2 */
00513   alloc_FinishSegment( p2 );
00514   }
00515 
00516 /*POD
00517 =H alloc_InitStat()
00518 
00519 This function initializes the global statistical variables. These variables
00520 can be used in a program to measure the memory usage.
00521 
00522 This function should be called before any other memory handling function.
00523 
00524 /*FUNCTION*/
00525 void alloc_InitStat(
00526   ){
00527 /*noverbatim
00528 CUT*/
00529 
00530 #if MTHREAD
00531   thread_InitMutex(&mxStat);
00532 #endif
00533 
00534   MaxNetSize = 0;
00535   MinNetSize = 0;
00536   MaxBruSize = 0;
00537   MinBruSize = 0;
00538   ActNetSize = 0;
00539   ActBruSize = 0;
00540   }
00541 
00542 /*POD
00543 =H alloc_GlobalGetStat()
00544 
00545 From period to period the code using this memory management layer may need to know
00546 how much memory the program is using.
00547 
00548 Calling this function from time to time you can get the minimum and maximum memory
00549 that the program used via this layer since the last call to this function or since
00550 program start in case of the first call.
00551 
00552 /*FUNCTION*/
00553 void alloc_GlobalGetStat(unsigned long *pNetMax,
00554                          unsigned long *pNetMin,
00555                          unsigned long *pBruMax,
00556                          unsigned long *pBruMin,
00557                          unsigned long *pNetSize,
00558                          unsigned long *pBruSize
00559   ){
00560 /*noverbatim
00561 CUT*/
00562 
00563   LOCK_STAT
00564 
00565   if( pNetMax )*pNetMax = MaxNetSize;
00566   MaxNetSize = ActNetSize;
00567   if( pNetMin )*pNetMin = MinNetSize;
00568   MinNetSize = ActNetSize;
00569   if( pBruMax )*pBruMax = MaxBruSize;
00570   MaxBruSize = ActBruSize;
00571   if( pBruMin )*pBruMin = MinBruSize;
00572   MinBruSize = ActBruSize;
00573 
00574   if( pNetSize )*pNetSize = ActNetSize;
00575   if( pBruSize )*pBruSize = ActBruSize;
00576 
00577   UNLOCK_STAT
00578   }
00579 
00580 /*POD
00581 =H alloc_GetStat()
00582 
00583 From period to period the code using this memory management layer may need to know
00584 how much memory the program is using.
00585 
00586 Calling this function from time to time you can get the minimum and maximum memory
00587 that the program used via this layer since the last call to this function or since
00588 program start in case of the first call.
00589 
00590 /*FUNCTION*/
00591 void alloc_GetStat(void *p,
00592                    unsigned long *pMax,
00593                    unsigned long *pMin,
00594                    unsigned long *pActSize
00595   ){
00596 /*noverbatim
00597 CUT*/
00598   pMyAlloc pMemorySegment = (pMyAlloc)p;
00599 
00600   LOCK_SEGMENT
00601   if( pMax )*pMax = pMemorySegment->MaxNetSize;
00602   pMemorySegment->MaxNetSize = pMemorySegment->CurrentSize;
00603   if( pMin )*pMin = pMemorySegment->MinNetSize;
00604   pMemorySegment->MinNetSize = pMemorySegment->CurrentSize;
00605 
00606   if( pActSize )*pActSize = pMemorySegment->CurrentSize;
00607   UNLOCK_SEGMENT
00608 
00609   }

Generated on Sun Mar 12 23:56:31 2006 for ScriptBasic by  doxygen 1.4.6-NO