home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / mslang / vm / src / vrealloc.c < prev   
Encoding:
C/C++ Source or Header  |  1993-12-15  |  7.5 KB  |  312 lines

  1. /***
  2. * vrealloc.c - Reallocate space
  3. *
  4. *       Copyright (c) 1989-1992, Microsoft Corporation.  All rights reserved.
  5. *
  6. *******************************************************************************/
  7.  
  8. #include <version.h>
  9. #include <vmassert.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <vmm.h>
  13. #include <vmbm.h>
  14.  
  15. HBK near pascal __HbkVmAllocCopy(HBK, unsigned long, unsigned long);
  16.  
  17.  
  18. /*** HbkVmReallocate
  19. *
  20. * Purpose:  To Realloc the memory
  21. *
  22. * Input:
  23. *       hbk The handle to the block to be reallocated
  24. *       cb  The new size of the allocation
  25. *
  26. * Output:
  27. *
  28. * Exceptions:
  29. *
  30. * Notes:
  31. *
  32. *   Functionality Notes:
  33. *   1) If supplied handle is NULL, realloc maps to malloc
  34. *   2) If supplied size is 0, realloc maps to free
  35. *
  36. *   Implimentation Notes:
  37. *   1) See if adjacent block to merge to, and make big block
  38. *   2) See if the block is big enough, and make free block
  39. *   3) or allocate a new area and copy
  40. *
  41. *   If the reallocate fails, there may be a side effect of merging a
  42. *   free block at the end of the old block.
  43. *
  44. *
  45. *************************************************************************/
  46. HBK VMFUNC __HbkVmReallocate(
  47. HBK             hbk,
  48. unsigned long   cb
  49. ) {
  50.    unsigned long        cbT, cbSize, cbOrg;
  51.    HBK          hbkNext;
  52.    PHDB         phdb;
  53.    PHDF         phdf;
  54.    SZBK         szbk;
  55.    HDF          hdf;
  56.    int          fMergeAbove = FALSE;
  57.  
  58.    if (!_fVmInit)
  59.       return NULL;
  60.  
  61.    // Special cases:
  62.    // (1) If handle is null, realloc maps to malloc
  63.    // (2) If size is 0, realloc maps to free
  64.    // (3) If size is > cbMaxAlloc, we can't satisfy it so return NULL.
  65.    if (hbk == NULL)
  66.        return (__HbkVmAllocate(cb));
  67.  
  68.    if ((unsigned long)hbk < (unsigned long)_hbkMin || (unsigned long)hbk > (unsigned long)_hbkMax)
  69.       return NULL;
  70.  
  71.    if (cb == 0)
  72.    {
  73.        __VmFreeHbk(hbk);
  74.     return(NULL);
  75.    }
  76.  
  77.    if( cb > cbMaxAlloc )
  78.       return(NULL);
  79.  
  80.    // round the size to an int boundary
  81.    cb = ((cb + sizeof(int) - 1) / sizeof(int)) * sizeof(int);
  82.  
  83.    // determine the actual size to allocate, must be big enough for a free
  84.    cbT = max(cb + sizeof(HDB), sizeof(HDF));
  85.  
  86.    phdb = __PVmLoadVp((VPVOID) hbk, FALSE);
  87.  
  88.    if (!phdb || phdb->fFree || phdb->cLock)
  89.       return NULL;
  90.  
  91. // do the page realloc
  92. if( phdb->fByPage ) {
  93.  
  94.     phdb = __PVmLoadVp((VPVOID) hbk, TRUE);
  95.     cbSize = phdb->cPage * (unsigned long) cbVmPage;
  96.  
  97.     // if it is smaller, just shrink the current page count
  98.     if( cbSize >= cbT ) {
  99.  
  100.     // get the page count
  101.     cbSize = phdb->cPage;
  102.     phdb->cPage = (unsigned short) ((cbT + cbVmPage - 1) / cbVmPage);
  103.  
  104.     // free all extra pages
  105.     for(cb = phdb->cPage; cb < cbSize; cb++)
  106.         __VmFreePageVp( (((VPVOID) hbk) + (cbVmPage * cb)) );
  107.     return(hbk);
  108.     }
  109.  
  110.     // must allocate and copy
  111.     else
  112.     return(__HbkVmAllocCopy(hbk, cbSize - sizeof(HDB), cb));
  113.     }
  114.  
  115. // we are dealing with blocks if we got here
  116.  
  117. // if the size stays the same
  118. cbOrg = cbSize = CbGetSize(phdb->cbSize);
  119. Assert( cbSize >= sizeof(HDF) );
  120. if( (cbSize - sizeof(HDF)) < cbT  &&
  121.      cbT <= CbGetSize(phdb->cbSize) )
  122.     return(hbk);
  123.  
  124. // if there is an adjacent free block, merge it in
  125. szbk.cbSize = phdb->cbSize;
  126. if( phdb->fAdjacent ) {
  127.  
  128.     hbkNext = AddHbk(hbk, CbGetSize(szbk.cbSize));
  129.     phdf = __PVmLoadVp((VPVOID) hbkNext, FALSE);
  130.  
  131.     // if it is free, merge in with the current hbk
  132.     if( phdf->fFree  &&
  133.        (cbSize + CbGetSize(phdf->cbSize)) < cbBig ) {
  134.  
  135.     fMergeAbove = TRUE;
  136.     hdf = *phdf;
  137.  
  138.     // get the size of the new block
  139.     szbk.cbSize = CbMakeSize(CbGetSize(phdf->cbSize) + (unsigned short) cbSize,
  140.                  phdf->fAdjacent);
  141.  
  142.     _gvmbm.cFree--;
  143.     if( hbkNext == _gvmbm.hbkLastBlock )
  144.         _gvmbm.hbkLastBlock = hbk;
  145.     }
  146.     }
  147.  
  148. cbSize = CbGetSize(szbk.cbSize);
  149. // make a free block
  150. if( (cbSize - sizeof(HDF)) >= cbT ) {
  151.  
  152.     // make the size of the free block and tell the one above
  153.     // about it
  154.     szbk.cbSize = CbMakeSize((cbSize - cbT), szbk.fAdjacent);
  155.     if(szbk.fAdjacent) {
  156.     phdb = __PVmLoadVp((VPVOID) AddHbk(hbk, cbSize), TRUE);
  157.     phdb->szbkBack = szbk;
  158.     }
  159.  
  160.     // make the free page and add it to the list
  161.     hbkNext = AddHbk(hbk, cbT);
  162.     phdf = __PVmLoadVp((VPVOID) hbkNext, TRUE);
  163.     _fmemset( phdf, 0, sizeof(HDF) );
  164.     phdf->cbSize = szbk.cbSize;
  165.     phdf->szbkBack.cbSize = CbMakeSize(cbT, TRUE);
  166.     phdf->fFree = TRUE;
  167.  
  168.     // if the new free block is the last block
  169.     if( hbk == _gvmbm.hbkLastBlock )
  170.     _gvmbm.hbkLastBlock = hbkNext;
  171.  
  172.     // put in the free list
  173.     if( fMergeAbove )
  174.     __VmFreeLinkIn(hbkNext, CbGetSize(szbk.cbSize),
  175.               hdf.hbkBackHdf, hdf.hbkNextHdf);
  176.     else
  177.     __VmFreeLinkEnd(hbkNext, CbGetSize(szbk.cbSize));
  178.  
  179.     // make the new allocation
  180.     phdb = __PVmLoadVp((VPVOID) hbk, TRUE);
  181.     Assert( phdb->fFree == FALSE );
  182.     phdb->cbSize = CbMakeSize(cbT, TRUE);
  183.     }
  184.  
  185. // must allocate and copy
  186. else {
  187.  
  188.     // fix the next entry but only if we merged, otherwise the
  189.     // next entry will be fine.
  190.     if(fMergeAbove) {
  191.  
  192.     if( szbk.fAdjacent ) {
  193.         phdb = __PVmLoadVp((VPVOID) AddHbk(hbk, cbSize), TRUE);
  194.         phdb->szbkBack = szbk;
  195.         }
  196.  
  197.     // if there was a merge, then there is a dangling free
  198.     // that must be removed
  199.     __VmFreeLink(hdf.hbkBackHdf, hdf.hbkNextHdf);
  200.  
  201.     // make the new allocation
  202.     phdb = __PVmLoadVp((VPVOID) hbk, TRUE);
  203.     Assert( phdb->fFree == FALSE );
  204.     phdb->cbSize = szbk.cbSize;
  205.     }
  206.  
  207.     if( cbSize < cbT )
  208.     hbk = __HbkVmAllocCopy(hbk, cbOrg - sizeof(HDB), cb);
  209.     }
  210.  
  211. return(hbk);
  212. }
  213.  
  214. /*** HbkVmAllocCopy
  215. *
  216. * Purpose:  To do a byte copy from one block to another
  217. *
  218. * Input:
  219. *       hbk     The old block to copy from
  220. *       cbCopy  The number to copy
  221. *       cbNew   The size of the new allocation block
  222. *
  223. * Output:
  224. *   Return:     The new allocated hbk or NULL on error
  225. *
  226. * Exceptions:
  227. *
  228. * Notes:
  229. *     The old block is freed
  230. *
  231. *
  232. *************************************************************************/
  233. HBK near pascal __HbkVmAllocCopy(
  234. HBK             hbk,
  235. unsigned long   cbCopy,
  236. unsigned long   cbNew
  237. ) {
  238. HBK             hbkNew = NULL;
  239. VPVOID          vp, vpLock;
  240.  
  241. Assert( cbCopy <= cbNew );
  242.  
  243. // allocate the new block
  244. if( (hbkNew = __HbkVmAllocate(cbNew)) ) {
  245.  
  246.     vp      = VpHbk(hbkNew);
  247.     vpLock  = VpHbk(hbk);
  248.  
  249.     if( __VpMemCopyVp(vp, vpLock, cbCopy) )
  250.         __VmFreeHbk( hbk );
  251.     else {
  252.         __VmFreeHbk(hbkNew);
  253.     hbkNew = NULL;
  254.     }
  255.     }
  256.  
  257. return(hbkNew);
  258. }
  259.  
  260.  
  261. /*** VpMemCopyVp
  262. *
  263. * Purpose:  To do a byte copy from one block to another
  264. *
  265. * Input:
  266. *       hbk     The old block to copy from
  267. *       cbCopy  The number to copy
  268. *       cbNew   The size of the new allocation block
  269. *
  270. * Output:
  271. *   Return:     The new allocated hbk or NULL on error
  272. *
  273. * Exceptions:
  274. *
  275. * Notes:
  276. *     The old block is freed
  277. *
  278. *
  279. *************************************************************************/
  280. int VMFUNC __VpMemCopyVp(
  281. VPVOID          vp,
  282. VPVOID          vpLock,
  283. unsigned long   cbCopy
  284. ) {
  285. unsigned long   cb;
  286. PVOID           pvoidLock, pvoid;
  287.  
  288. // copy the data
  289. while(cbCopy) {
  290.  
  291.     // how much to copy this time
  292.     cb = min(cbEndPage(vp), cbEndPage(vpLock));
  293.     cb = min(cb, cbCopy);
  294.  
  295.     // if I can't lock the page, I'm done
  296.     if( !(pvoidLock = __PVmLockVp( vpLock )) )
  297.         return(FALSE);
  298.  
  299.     pvoid     = __PVmLoadVp( vp, TRUE );
  300.     _fmemcpy(pvoid, pvoidLock, (unsigned) cb);
  301.  
  302.     __VmUnlockVp(vpLock, FALSE);
  303.  
  304.     // move to the next place to copy
  305.     cbCopy  -= cb;
  306.     vpLock  += cb;
  307.     vp      += cb;
  308.     }
  309.  
  310. return(TRUE);
  311. }
  312.