home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / diverses / text_cla / vmm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-12  |  27.6 KB  |  1,383 lines

  1. /******************************************************************************
  2. *+
  3. ** Module Name:   Vmm.C
  4. ** 
  5. ** Description:   Virtual Memory Manager
  6. **                  
  7. **                Supports limited virtual memory management.
  8. **
  9. **                Performs cacheing of data and swapping to/from disk file.
  10. **
  11. **
  12. ** Written by:  John Tal
  13. **
  14. **
  15. **
  16. ** Modification History:
  17. **
  18. ** Date          Programmer      Mod#     Modification
  19. ** ---------------------------------------------------------------------------
  20. ** 17-FEB-1992   J. Tal          V1.0-000 New
  21. **
  22. *-
  23. */
  24.  
  25. #ifdef C_ANSI
  26. #include <string.h>
  27. #include <stdlib.h>
  28. #endif
  29.  
  30. #ifdef C_UNIX
  31. #include <sys/types.h>
  32. #endif
  33.  
  34. #include <time.h>
  35.  
  36. #include <stdio.h>
  37.  
  38. #include <memlib.h>
  39.  
  40. #include <vmm.h>
  41.  
  42.  
  43.  
  44. VMM_MGR_T  stVmmMgr;
  45. VMM_MGR_P  pstVmmMgr = &stVmmMgr;
  46.  
  47.  
  48.  
  49. /*
  50. **   VmmInit
  51. **
  52. **       Initialize virtual memory manager
  53. */
  54.  
  55. #ifdef C_ANSI
  56. SHORT
  57. VmmInit(SHORT sMemoryBytes,PCHAR pcSwapFile)
  58. #else
  59. SHORT
  60. VmmInit(sMemoryBytes,pcSwapFile)
  61. SHORT sMemoryBytes;
  62. PCHAR pcSwapFile;  
  63. #endif 
  64. {
  65.    C_DEF_MODULE("VmmInit")
  66.  
  67.    static BOOL  fVmmInit;
  68.    VMM_BLOCK_P  pstNewBlock;
  69.  
  70.    if(fVmmInit)
  71.       C_LEAVE(VMM_ERR_INIT)
  72.  
  73.    memset(&stVmmMgr,0,sizeof(VMM_MGR_T));
  74.  
  75.    pstVmmMgr -> pvBlock = (PVOID) calloc(sMemoryBytes,1);
  76.    pstVmmMgr -> lTotalBytes = sMemoryBytes;
  77.    pstVmmMgr -> lSwapBytes = 0;
  78.  
  79.    if(pstVmmMgr -> pvBlock == NULL)
  80.       C_LEAVE(VMM_ERR_MEM_EXCEEDED)
  81.  
  82.    strcpy(pstVmmMgr -> szSwapFile,pcSwapFile);
  83.  
  84.  
  85.    pstVmmMgr -> fpSwapFile = fopen(pstVmmMgr -> szSwapFile,"w+b");
  86.  
  87.    if(pstVmmMgr -> fpSwapFile == NULL)
  88.       C_LEAVE(VMM_ERR_INIT)
  89.  
  90.  
  91.    /*  create logical block for all of memory */
  92.  
  93.    C_STATUS = VmmCreateBlock(VMM_MEMORY,sMemoryBytes,VMM_OWNER_NONE,pstVmmMgr -> pvBlock,0L,&pstNewBlock);
  94.  
  95.    
  96.    if(pstVmmMgr -> fpSwapFile == NULL)
  97.      C_LEAVE(VMM_ERR_SWAP_FILE)
  98.  
  99.    fVmmInit = C_TRUE;
  100.  
  101. C_MODULE_EXIT:
  102.  
  103.    C_RETURN
  104. }
  105.  
  106.  
  107. /*
  108. **  VmmCompress
  109. **
  110. **  Compress Internal memory.  Called when there is enough space
  111. **  but not in a single continuous block.
  112. */
  113.  
  114. #ifdef C_ANSI
  115. SHORT
  116. VmmCompress(VOID)
  117. #else
  118. SHORT
  119. VmmCompress()
  120. #endif 
  121. {
  122.    C_DEF_MODULE("VmmCompress")
  123.  
  124.    VMM_BLOCK_P  pstNewBlock;
  125.    VMM_BLOCK_P  pstBlock;
  126.    PVOID   pvNewBlock;
  127.    PVOID   pvPtr;
  128.    LLIST_P pstMember;
  129.    LONG    lUseBytes = 0;
  130.    LONG    lRemBytes;
  131.    LLIST_P pstMemberNext;   
  132.  
  133.    /* get new block of memory */
  134.  
  135.    pvNewBlock = (PVOID) calloc(1,(SHORT) pstVmmMgr -> lTotalBytes);
  136.  
  137.    if(pvNewBlock == NULL)
  138.       C_LEAVE(VMM_ERR_MEM_EXCEEDED)
  139.  
  140.    pvPtr = pvNewBlock;
  141.  
  142.    /* look at all memory blocks */
  143.  
  144.    pstMember = pstVmmMgr -> pstMemList;
  145.  
  146.    while(pstMember != NULL)
  147.    {
  148.       pstBlock = (VMM_BLOCK_P) pstMember -> pvData;
  149.  
  150.       pstMemberNext = pstMember -> psNext;
  151.  
  152.       /* if active, copy into new master block
  153.                     reset block pointer
  154.                     increment current pointer into new block
  155.                     increment used bytes
  156.       */
  157.  
  158.       if(pstBlock -> sOwner != VMM_OWNER_NONE)
  159.       {
  160.          if(pstBlock -> sState == VMM_STATE_MEMORY)
  161.          {
  162.             /* retain by copying into new master bloc */
  163.  
  164.             memcpy(pvPtr,pstBlock -> pvBlock, pstBlock -> sBytes);
  165.             pstBlock -> pvBlock = pvPtr;
  166.             pvPtr = (PVOID) ((long) pvPtr + (long) pstBlock -> sBytes);
  167.             lUseBytes += pstBlock -> sBytes;
  168.          }
  169.       }
  170.       else
  171.       {
  172.          /* free block and remove control list member */
  173.  
  174.          free(pstBlock);
  175.  
  176.          MemLstDeleteMember(pstVmmMgr -> pstMemList,
  177.                             pstMember,
  178.                             &(pstVmmMgr -> pstMemList));
  179.  
  180.       }
  181.  
  182.       pstMember = pstMemberNext;
  183.    }
  184.  
  185.    /* free old block and make Vmm point to new */
  186.  
  187.    free(pstVmmMgr -> pvBlock);
  188.    pstVmmMgr -> pvBlock = pvNewBlock;
  189.  
  190.    lRemBytes = pstVmmMgr -> lTotalBytes - lUseBytes;
  191.     
  192.    
  193.    C_STATUS = VmmCreateBlock((SHORT) VMM_MEMORY,
  194.                              (SHORT) lRemBytes,
  195.                              (SHORT) VMM_OWNER_NONE,
  196.                              pvPtr,
  197.                              (LONG) 0,
  198.                              &pstNewBlock);
  199.  
  200. C_MODULE_EXIT:
  201.  
  202.       ;
  203.  
  204.    C_RETURN
  205. }
  206.  
  207.  
  208.  
  209.  
  210. /*
  211. **  VmmAlloc - Process wants a memory block
  212. */
  213.  
  214. #ifdef C_ANSI
  215. SHORT
  216. VmmAlloc(SHORT sOwner,SHORT sTotalBytes,PLONG plHandle)
  217. #else
  218. SHORT
  219. VmmAlloc(sOwner,sTotalBytes,plHandle)
  220. SHORT sOwner;
  221. SHORT sTotalBytes;
  222. PLONG plHandle;
  223. #endif
  224. {
  225.    C_DEF_MODULE("VmmAlloc")
  226.  
  227.    VMM_BLOCK_P  pstBlock = (VMM_BLOCK_P) NULL;
  228.  
  229.  
  230.    if((LONG) sTotalBytes > pstVmmMgr -> lTotalBytes)
  231.       C_LEAVE(VMM_ERR_MEM_EXCEEDED)
  232.  
  233.    while(pstBlock == NULL)
  234.    {
  235.       VmmAssignBlock(VMM_MEMORY,sTotalBytes,sOwner,&pstBlock);
  236.       if(pstBlock == NULL)
  237.          VmmSizeSwapToDisk(sTotalBytes,sOwner,&pstBlock);
  238.    }
  239.  
  240.    /* update access time */
  241.  
  242.    pstBlock -> lTimeLastAccess = VmmCurTime();
  243.  
  244.  
  245.    *plHandle = pstBlock -> lDescriptor;
  246.  
  247. C_MODULE_EXIT:
  248.    
  249.     ;
  250.  
  251.    C_RETURN
  252. }
  253.  
  254.  
  255.  
  256. /*
  257. **  VmmPrep
  258. **  
  259. **  Setup Memory block before access to ensure is in memory
  260. **  Also call before each access to update access times used
  261. **  in cacheing decisions.
  262. */
  263.  
  264. #ifdef C_ANSI
  265. SHORT
  266. VmmPrep(LONG lHandle,PPVOID ppvVirtualPtr)
  267. #else
  268. SHORT
  269. VmmPrep(lHandle,ppvVirtualPtr)
  270. LONG lHandle;
  271. PPVOID ppvVirtualPtr;
  272. #endif
  273. {
  274.  
  275.    C_DEF_MODULE("VmmPrep")
  276.  
  277.    LLIST_P  pstMember;
  278.    VMM_BLOCK_P  pstVmmBlock;
  279.  
  280.    MemLstFindMember(pstVmmMgr -> pstMemList,
  281.                     (PVOID) &lHandle,
  282.                     VmmCompareHandle,
  283.                     &pstMember);
  284.  
  285.    if(pstMember != NULL)
  286.    {
  287.       pstVmmBlock = (VMM_BLOCK_P) pstMember -> pvData;
  288.  
  289.       if(pstVmmBlock -> sState == VMM_STATE_DISK)
  290.       {
  291.          pstVmmMgr -> pstReloadBlock = pstVmmBlock;
  292.  
  293.          VmmLoadFromDisk(pstVmmBlock,pstVmmBlock -> sOwner);
  294.  
  295.          pstVmmMgr -> pstReloadBlock = (VMM_BLOCK_P) NULL;
  296.       
  297.       }
  298.  
  299.       /* update access time */
  300.  
  301.       pstVmmBlock -> lTimeLastAccess = VmmCurTime();
  302.  
  303.       *ppvVirtualPtr = pstVmmBlock -> pvBlock;
  304.  
  305.    }
  306.  
  307.    C_RETURN
  308. }
  309.       
  310.  
  311. /*
  312. **  VmmFree
  313. **
  314. **  Process is freeing an allocated block
  315. */
  316.  
  317. #ifdef C_ANSI
  318. SHORT
  319. VmmFree(LONG lDescriptor)
  320. #else
  321. SHORT
  322. VmmFree(lDescriptor)
  323. LONG lDescriptor;
  324. #endif
  325. {
  326.    C_DEF_MODULE("VmmFree")
  327.  
  328.    LLIST_P  pstMember;
  329.    VMM_BLOCK_P  pstBlock;
  330.  
  331.    pstMember = pstVmmMgr -> pstMemList;
  332.  
  333.    while(pstMember != NULL)
  334.    {
  335.       pstBlock = (VMM_BLOCK_P) pstMember -> pvData;
  336.  
  337.       if(pstBlock -> lDescriptor == lDescriptor)
  338.       {
  339.          pstBlock -> sOwner = VMM_OWNER_NONE;
  340.          
  341.          /* take care of disk block if swapped out */
  342.  
  343.          if(pstBlock -> pstMate != NULL)
  344.          {
  345.             pstBlock -> pstMate -> sOwner = VMM_OWNER_NONE;
  346.          }
  347.  
  348.          break;
  349.       }
  350.  
  351.       pstMember = pstMember -> psNext;
  352.    }
  353.  
  354.  
  355.    if(pstMember == NULL)
  356.       C_SET_STATUS(C_NOTOK)
  357.  
  358.    C_RETURN
  359. }
  360.  
  361.  
  362. /*
  363. **  VmmTerm
  364. **
  365. **  Terminate Small Memory Manager
  366. */
  367.  
  368. #ifdef C_ANSI
  369. SHORT VmmTerm(VOID)
  370. #else
  371. SHORT VmmTerm()
  372. #endif
  373. {
  374.    C_DEF_MODULE("VmmTerm")
  375.  
  376.    
  377.    LLIST_P pstMember;
  378.    LLIST_P pstMemberNext;
  379.    VMM_BLOCK_P  pstBlock;
  380.  
  381.     
  382.    fclose(pstVmmMgr -> fpSwapFile);
  383.  
  384.   
  385.    /* free main memory block */
  386.  
  387.    free(pstVmmMgr -> pvBlock);
  388.  
  389.  
  390.    /* free all sub-alloc memory blocks */
  391.    
  392.    pstMember = pstVmmMgr -> pstMemList;
  393.  
  394.    while(pstMember != NULL)
  395.    {
  396.       pstBlock = (VMM_BLOCK_P) pstMember -> pvData;
  397.  
  398.       pstMemberNext = pstMember -> psNext;
  399.  
  400.       free(pstBlock);
  401.  
  402.       pstMember = pstMemberNext;
  403.    }
  404.  
  405.  
  406.  
  407.    /* free all disk swap blocks */
  408.  
  409.    pstMember = pstVmmMgr -> pstFreeDiskBlocks;
  410.  
  411.    while(pstMember != NULL)
  412.    {
  413.       pstBlock = (VMM_BLOCK_P) pstMember -> pvData;
  414.  
  415.       pstMemberNext = pstMember -> psNext;
  416.  
  417.       free(pstBlock);
  418.  
  419.       pstMember = pstMemberNext;
  420.    }
  421.  
  422.    C_RETURN     
  423. }
  424.  
  425.  
  426.  
  427. /*
  428. **   VmmLoadFromDisk
  429. **
  430. **   A block has been swapped to disk, load it back into memory
  431. */
  432.  
  433. #ifdef C_ANSI
  434. SHORT
  435. VmmLoadFromDisk(VMM_BLOCK_P pstVmmBlock,SHORT sOwner)
  436. #else
  437. SHORT
  438. VmmLoadFromDisk(pstVmmBlock,sOwner)
  439. VMM_BLOCK_P pstVmmBlock;
  440. SHORT sOwner;
  441. #endif
  442. {
  443.    C_DEF_MODULE("VmmLoadFromDisk")
  444.  
  445.    VMM_BLOCK_P  pstBlock = NULL;
  446.  
  447.  
  448.       
  449.    while(pstBlock == NULL)
  450.    {
  451.       VmmAssignBlock(VMM_MEMORY,pstVmmBlock -> sBytes,sOwner,&pstBlock);
  452.       if(pstBlock == NULL)
  453.          VmmSizeSwapToDisk(pstVmmBlock -> sBytes,sOwner,&pstBlock);
  454.    }
  455.  
  456.  
  457.    if(pstBlock != pstVmmBlock)
  458.    {
  459.       /* problem here, another block has been created, must merge two 
  460.          together.  All we really need is the pvBlock ptr */
  461.  
  462.       pstVmmBlock -> pvBlock = pstBlock -> pvBlock;
  463.  
  464.       /* remove newly created block */
  465.       VmmVanishBlock(VMM_MEMORY,pstBlock);
  466.    }
  467.  
  468.  
  469.    fseek(pstVmmMgr -> fpSwapFile,
  470.          pstVmmBlock -> lOffset,
  471.          0);
  472.  
  473.    fread(pstVmmBlock -> pvBlock,
  474.          1,
  475.          pstVmmBlock -> sBytes,
  476.          pstVmmMgr -> fpSwapFile);
  477.  
  478.    pstVmmBlock -> sState = VMM_STATE_MEMORY;
  479.  
  480.  
  481.    /* free up disk block for other use */
  482.  
  483.    if(pstVmmBlock -> pstMate != NULL)
  484.    {
  485.       pstVmmBlock -> pstMate -> sOwner = VMM_OWNER_NONE;
  486.       pstVmmBlock -> pstMate = NULL;
  487.    }
  488.  
  489.    C_RETURN
  490. }
  491.  
  492.  
  493. /*
  494. **   VmmVanishBlock
  495. **
  496. **   A new block has been created during processing and is not needed
  497. **   (pvBlock was probably copied before this call)
  498. */
  499.  
  500. #ifdef C_ANSI
  501. SHORT
  502. VmmVanishBlock(SHORT sType,VMM_BLOCK_P pstVanishBlock)
  503. #else
  504. SHORT
  505. VmmVanishBlock(sType,pstVanishBlock)
  506. SHORT sType;
  507. VMM_BLOCK_P pstVanishBlock;
  508. #endif
  509. {
  510.   C_DEF_MODULE("VmmVanishBlock")
  511.  
  512.   LLIST_P  pstMember;
  513.   VMM_BLOCK_P  pstBlock;
  514.  
  515.   if(sType == VMM_STATE_MEMORY)
  516.      pstMember = pstVmmMgr -> pstMemList;
  517.   else
  518.      pstMember = pstVmmMgr -> pstFreeDiskBlocks;
  519.  
  520.   while(pstMember != NULL)
  521.   {
  522.      pstBlock = (VMM_BLOCK_P) pstMember -> pvData;  
  523.  
  524.      if(pstBlock == pstVanishBlock)
  525.      {
  526.         if(sType == VMM_MEMORY)
  527.         {
  528.            C_STATUS = MemLstDeleteMember(pstVmmMgr -> pstMemList,
  529.                                          pstMember,
  530.                                          &(pstVmmMgr -> pstMemList));
  531.         }
  532.         else
  533.         {
  534.            C_STATUS = MemLstDeleteMember(pstVmmMgr -> pstFreeDiskBlocks,
  535.                                          pstMember,
  536.                                          &(pstVmmMgr -> pstFreeDiskBlocks));
  537.         }
  538.         
  539.         break;
  540.      }
  541.  
  542.      pstMember = pstMember -> psNext;
  543.  
  544.   }
  545.  
  546.   
  547.   free(pstVanishBlock);
  548.  
  549.   C_RETURN
  550. }
  551.  
  552.  
  553. /*
  554. **   VmmCheckFreeBlocks
  555. **
  556. **   Check total bytes available across all free fragments
  557. */
  558.  
  559. #ifdef C_ANSI
  560. SHORT
  561. VmmCheckFreeBlocks(SHORT * pAvail)
  562. #else
  563. SHORT
  564. VmmCheckFreeBlocks(pAvail)
  565. SHORT * pAvail;
  566. #endif
  567. {
  568.    C_DEF_MODULE("VmmCheckFreeBlocks")
  569.  
  570.    LLIST_P  pstMember;
  571.    VMM_BLOCK_P  pstBlock;
  572.    SHORT  sFreeBytes = 0;
  573.  
  574.    pstMember = pstVmmMgr -> pstMemList;
  575.  
  576.    /* find oldest available block */
  577.  
  578.    while(pstMember != NULL)
  579.    {
  580.       /*  if unused block, count it */
  581.      
  582.       pstBlock = (VMM_BLOCK_P) pstMember -> pvData;
  583.  
  584.       if((pstBlock -> sOwner == VMM_OWNER_NONE) &&
  585.          (pstBlock -> sState == VMM_STATE_MEMORY))
  586.       {
  587.          sFreeBytes += pstBlock -> sBytes; 
  588.       }
  589.  
  590.       pstMember = pstMember -> psNext;
  591.  
  592.   }
  593.  
  594.   *pAvail = sFreeBytes;
  595.  
  596.   return(C_OK);
  597. }
  598.  
  599.  
  600. /*
  601. **  VmmFindStaleBlock
  602. */
  603.  
  604. #ifdef C_ANSI
  605. SHORT
  606. VmmFindStaleBlock(VMM_BLOCK_P * ppstRetBlock)
  607. #else
  608. SHORT
  609. VmmFindStaleBlock(ppstRetBlock)
  610. VMM_BLOCK_P * ppstRetBlock;
  611. #endif
  612. {
  613.    C_DEF_MODULE("VmmFindStaleBlock")
  614.  
  615.    LLIST_P  pstMember;
  616.    LLIST_P  pstMemberNext;
  617.  
  618.    VMM_BLOCK_P  pstBlock;
  619.    VMM_BLOCK_P  pstOldBlock = (VMM_BLOCK_P) NULL;
  620.    LONG     lTimeLastAccess;
  621.  
  622.  
  623.    lTimeLastAccess = VmmCurTime();
  624.  
  625.    *ppstRetBlock = (VMM_BLOCK_P) NULL;
  626.  
  627.    pstMember = pstVmmMgr -> pstMemList;
  628.  
  629.    /* find oldest available block */
  630.  
  631.    while(pstMember != NULL)
  632.    {
  633.       pstMemberNext = pstMember -> psNext;
  634.  
  635.       pstBlock = (VMM_BLOCK_P) pstMember -> pvData;
  636.  
  637.       if((pstBlock -> sOwner != VMM_OWNER_NONE) &&
  638.          (pstBlock -> sState != VMM_STATE_DISK))
  639.       {
  640.          if(pstBlock -> lTimeLastAccess <= lTimeLastAccess) 
  641.          { 
  642.             pstOldBlock = pstBlock;
  643.             lTimeLastAccess = pstBlock -> lTimeLastAccess;
  644.          }
  645.       }
  646.  
  647.       pstMember = pstMemberNext;
  648.    }
  649.  
  650.    *ppstRetBlock = pstOldBlock;
  651.  
  652.    return(C_OK);
  653. }
  654.  
  655.  
  656.  
  657. /*
  658. **   VmmAssignBlock
  659. **
  660. **   Find and assign a block for either memory or disk allocation
  661. **   Can return NULL in the return block if none found
  662. */
  663.  
  664. #ifdef C_ANSI
  665. SHORT
  666. VmmAssignBlock(SHORT sType,
  667.                SHORT sBlockSize,
  668.                SHORT sOwner,
  669.                VMM_BLOCK_P * ppstRetBlock)
  670. #else
  671. SHORT
  672. VmmAssignBlock(sType,
  673.                sBlockSize,
  674.                sOwner,
  675.                ppstRetBlock)
  676. SHORT sType;
  677. SHORT sBlockSize;
  678. SHORT sOwner;
  679. VMM_BLOCK_P * ppstRetBlock;
  680. #endif
  681. {
  682.     C_DEF_MODULE("VmmAssignBlock")
  683.  
  684.     LLIST_P  pstMember;
  685.     LLIST_P  pstMemberNext;
  686.     LLIST_P  pstMemberBlock;
  687.  
  688.     VMM_BLOCK_P  pstBlock;
  689.     BOOL     fFoundBlock = C_FALSE;
  690.     SHORT    sByteDiff;
  691.  
  692.  
  693.     VMM_BLOCK_P  pstSmallBlock = (VMM_BLOCK_P) NULL;
  694.     SHORT    sSmallBytes = 0; 
  695.  
  696.     *ppstRetBlock = (VMM_BLOCK_P) NULL;
  697.  
  698.     if(sType == VMM_STATE_MEMORY)
  699.        pstMember = pstVmmMgr -> pstMemList;
  700.     else
  701.        pstMember = pstVmmMgr -> pstFreeDiskBlocks;
  702.  
  703.     /* find smallest available block */
  704.  
  705.     while(pstMember != NULL)
  706.     {
  707.        pstMemberNext = pstMember -> psNext;
  708.  
  709.        pstBlock = (VMM_BLOCK_P) pstMember -> pvData;
  710.  
  711.        if((pstBlock -> sOwner == VMM_OWNER_NONE) &&
  712.           (pstBlock -> sBytes >= sBlockSize))
  713.        {
  714.            if(pstBlock -> sBytes == sBlockSize) /* exact match */
  715.            {
  716.               pstMemberBlock = pstMember;
  717.               pstSmallBlock = pstBlock;
  718.               sSmallBytes = pstBlock -> sBytes;
  719.               break;
  720.            }
  721.  
  722.            /* initialize for first block found >= required size */
  723.  
  724.            if(sSmallBytes == 0)
  725.            {
  726.               pstMemberBlock = pstMember;
  727.               pstSmallBlock = pstBlock;
  728.               sSmallBytes = pstBlock -> sBytes;
  729.            } 
  730.        }
  731.  
  732.        pstMember = pstMemberNext;
  733.     }
  734.  
  735.  
  736.     /* found candidate block */
  737.  
  738.     if(pstSmallBlock != NULL)
  739.     {
  740.        fFoundBlock = C_TRUE;
  741.  
  742.        pstBlock = pstSmallBlock;
  743.  
  744.        /* check if must split */
  745.  
  746.        sByteDiff = pstBlock -> sBytes - sBlockSize;
  747.  
  748.        if(sByteDiff > 0)
  749.        {
  750.           /* split current block into two */
  751.  
  752.           VmmSplitBlock(sType,pstBlock,sOwner,sBlockSize,ppstRetBlock);
  753.        }
  754.        else
  755.        {
  756.           /* found exact match */
  757.  
  758.           if(pstVmmMgr -> pstReloadBlock != NULL)
  759.           {
  760.             /* if reloading from disk, remove this empty block */
  761.  
  762.             pstVmmMgr -> pstReloadBlock -> pvBlock = pstBlock -> pvBlock;
  763.  
  764.             /* different handling for disk vs memory */
  765.           
  766.             if(sType == VMM_DISK)
  767.             {
  768.               /* if disk, am reusing block out there */
  769.  
  770.               pstBlock -> sOwner = sOwner;
  771.  
  772.               *ppstRetBlock = pstBlock;
  773.             }
  774.             else
  775.             {
  776.                /* if memory, a new block will be thrown away,
  777.                   Reloading into existing block = ReloadBlock */
  778.  
  779.                *ppstRetBlock = pstVmmMgr -> pstReloadBlock;
  780.                free(pstBlock);
  781.  
  782.                MemLstDeleteMember(pstVmmMgr -> pstMemList,
  783.                                   pstMemberBlock,
  784.                                   &(pstVmmMgr -> pstMemList));
  785.      
  786.             }
  787.                                                                           
  788.           }
  789.           else
  790.           {
  791.             pstBlock -> sOwner = sOwner;
  792.   
  793.             *ppstRetBlock = pstBlock;
  794.           }
  795.        }
  796.  
  797.     }
  798.  
  799.  
  800.     C_RETURN
  801. }
  802.  
  803.  
  804.  
  805. /*
  806. **  VmmSizeSwapToDisk  
  807. **
  808. **  Need sBytes of room for memory, swap whatever it takes
  809. */
  810.  
  811. #ifdef C_ANSI
  812. SHORT
  813. VmmSizeSwapToDisk(SHORT sBytes,SHORT sOwner,VMM_BLOCK_P * ppstBlock)
  814. #else
  815. SHORT
  816. VmmSizeSwapToDisk(sBytes,sOwner,ppstBlock)
  817. SHORT sBytes;
  818. SHORT sOwner;
  819. VMM_BLOCK_P * ppstBlock;
  820. #endif
  821. {
  822.    C_DEF_MODULE("VmmSizeSwapToDisk")
  823.  
  824.    LLIST_P  pstMember;
  825.    VMM_BLOCK_P  pstBlock;
  826.  
  827.    SHORT    sAvailBytes = 0;      /* total available bytes in memory block */
  828.    SHORT    sByte2 = 0;
  829.    SHORT    sEnoughBytes = 0;     /* size of available contingous block */
  830.  
  831.    VMM_BLOCK_P  pstEnoughBlock;   /* the block itself */
  832.    VMM_BLOCK_P  pstNewBlock;
  833.  
  834.  
  835.    *ppstBlock = (VMM_BLOCK_P) NULL;
  836.  
  837.    pstMember = pstVmmMgr -> pstMemList;
  838.  
  839.    while(sAvailBytes < sBytes)
  840.    {
  841.       VmmFindStaleBlock(&pstBlock);       /* find oldest block to swap out */
  842.       
  843.       if(pstBlock == NULL)
  844.       {
  845.          VmmCheckFreeBlocks(&sByte2);
  846.          sAvailBytes += sByte2;
  847.          if(sAvailBytes >= sBytes)
  848.             break;
  849.       }
  850.  
  851.       VmmSwapToDisk(pstBlock,sOwner);      /* move block out to swap */
  852.       sAvailBytes += pstBlock -> sBytes;   /* increment available */
  853.  
  854.       if(pstBlock -> sBytes >= sBytes)     /* see if big enough */
  855.       {
  856.          if(sEnoughBytes == 0)
  857.          {
  858.             sEnoughBytes = pstBlock->sBytes;
  859.             pstEnoughBlock = pstBlock;
  860.          }
  861.          else if(pstBlock->sBytes < sEnoughBytes)  /* remember smallest */
  862.          {
  863.             sEnoughBytes = pstBlock->sBytes;
  864.             pstEnoughBlock = pstBlock;
  865.          }              
  866.       }
  867.  
  868.    }
  869.  
  870.  
  871.  
  872.    /* have swapped out everything to get available memory */
  873.  
  874.    if(sAvailBytes >= sBytes)
  875.    {
  876.      if(sEnoughBytes < sBytes)  /* enough, but not contiguous, re-organize */
  877.         VmmCompress();
  878.      else
  879.      {
  880.         if(sEnoughBytes == sBytes)  /* exact match on size */
  881.         {
  882.            VmmCreateBlock((SHORT) VMM_MEMORY,
  883.                           sBytes,
  884.                           sOwner,
  885.                           pstEnoughBlock -> pvBlock, /* re-use memory */
  886.                           0L,
  887.                           &pstNewBlock);
  888.  
  889.            *ppstBlock = pstNewBlock;
  890.  
  891.         }
  892.         else
  893.         {
  894.            /* too big, break off a chunk */
  895.  
  896.            VmmSplitBlock((SHORT) VMM_MEMORY,
  897.                          pstEnoughBlock,
  898.                          sOwner,
  899.                          sBytes,
  900.                          ppstBlock);
  901.         }
  902.  
  903.      }
  904.    }
  905.    else
  906.      C_SET_STATUS(C_NOTOK);
  907.  
  908.    C_RETURN
  909. }
  910.  
  911.  
  912. /*
  913. **  VmmSwapToDisk
  914. **  
  915. **  A specific block must be swapped to disk.  
  916. **  Locate an available disk block large enough or create one.
  917. */
  918.  
  919. #ifdef C_ANSI
  920. SHORT
  921. VmmSwapToDisk(VMM_BLOCK_P pstVmmBlock,SHORT sOwner)
  922. #else
  923. SHORT
  924. VmmSwapToDisk(pstVmmBlock,sOwner)
  925. VMM_BLOCK_P pstVmmBlock;
  926. SHORT sOwner;
  927. #endif
  928. {
  929.    C_DEF_MODULE("VmmSwapToDisk")
  930.  
  931.    VMM_BLOCK_P  pstBlock = NULL;
  932.        
  933.  
  934.    /* try and find existing vacant disk block to use */
  935.    
  936.    VmmAssignBlock(VMM_DISK,pstVmmBlock -> sBytes,sOwner,&pstBlock);
  937.  
  938.    /* if none, create new one */
  939.  
  940.    if(pstBlock == NULL)
  941.    {
  942.       VmmCreateDiskBlock(pstVmmBlock -> sBytes,&pstBlock);
  943.       pstBlock -> sOwner = sOwner;
  944.       pstBlock -> lDescriptor = pstVmmBlock -> lDescriptor;
  945.  
  946.    }
  947.  
  948.  
  949.    /* remember disk block so can remove ownership 
  950.       when swapped back to memory */
  951.  
  952.    pstVmmBlock -> pstMate = pstBlock;
  953.  
  954.  
  955.  
  956.    /* give block in memory chain same offset as block in disk chain */   
  957.    pstVmmBlock -> lOffset = pstBlock -> lOffset;
  958.  
  959.  
  960.    fseek(pstVmmMgr -> fpSwapFile,
  961.          pstVmmBlock -> lOffset,
  962.          0);
  963.  
  964.    fwrite(pstVmmBlock -> pvBlock,
  965.          1,
  966.          pstVmmBlock -> sBytes,
  967.          pstVmmMgr -> fpSwapFile);
  968.  
  969.    pstVmmBlock -> sState = VMM_STATE_DISK;
  970.  
  971.    C_RETURN
  972. }
  973.  
  974.  
  975.  
  976. /*
  977. **  VmmCreateDiskBlock
  978. **
  979. **  Create a new disk block of a given size
  980. */
  981.  
  982. #ifdef C_ANSI
  983. SHORT
  984. VmmCreateDiskBlock(SHORT sBytes,VMM_BLOCK_P * ppstBlock)
  985. #else
  986. SHORT
  987. VmmCreateDiskBlock(sBytes,ppstBlock)
  988. SHORT sBytes;
  989. VMM_BLOCK_P * ppstBlock;
  990. #endif
  991. {
  992.    C_DEF_MODULE("VmmCreateDiskBlock")
  993.  
  994.    VMM_BLOCK_P  pstBlock;
  995.    LLIST_P      pstMember;
  996.  
  997.    pstBlock = (VMM_BLOCK_P) calloc(1,sizeof(VMM_BLOCK_T));
  998.  
  999.    pstBlock -> sBytes = sBytes;
  1000.    pstBlock -> sOwner = VMM_OWNER_NONE;
  1001.    pstBlock -> sState = VMM_DISK;
  1002.    pstBlock -> lOffset = pstVmmMgr -> lSwapBytes;   
  1003.  
  1004.    pstVmmMgr -> lSwapBytes += (LONG) sBytes;
  1005.  
  1006.  
  1007.    MemLstAllocMember(&pstMember);
  1008.  
  1009.    pstMember -> pvData = (PVOID) pstBlock;
  1010.  
  1011.    MemLstInsertMember(pstVmmMgr -> pstFreeDiskBlocks,
  1012.                       pstMember,
  1013.                       VmmCompareBlockSize,
  1014.                       &(pstVmmMgr -> pstFreeDiskBlocks));
  1015.  
  1016.  
  1017.    *ppstBlock = pstBlock;
  1018.    
  1019.    C_RETURN
  1020. }
  1021.  
  1022.  
  1023.  
  1024. /*
  1025. **  VmmSplitBlock
  1026. **  
  1027. **  Split an existing block which is larger than needed into 2 blocks
  1028. **  One will be the exact size needed, the remaining bytes will be
  1029. **  allocated from a new block.
  1030. */
  1031.  
  1032. #ifdef C_ANSI
  1033. SHORT
  1034. VmmSplitBlock(SHORT sType,
  1035.               VMM_BLOCK_P pstOrigBlock,
  1036.               SHORT sOwner,
  1037.               SHORT sBlockSize,
  1038.               VMM_BLOCK_P *ppstNewBlock)
  1039. #else
  1040. SHORT
  1041. VmmSplitBlock(sType,
  1042.               pstOrigBlock,
  1043.               sOwner,
  1044.               sBlockSize,
  1045.               ppstNewBlock)
  1046. SHORT sType;
  1047. VMM_BLOCK_P pstOrigBlock;
  1048. SHORT sOwner;
  1049. SHORT sBlockSize;
  1050. VMM_BLOCK_P *ppstNewBlock;
  1051. #endif
  1052. {
  1053.    C_DEF_MODULE("VmmSplitBlock")
  1054.  
  1055.    SHORT        sRemBytes;
  1056.    PVOID        pvPtr;
  1057.    LONG         lOffset;
  1058.  
  1059.  
  1060.    /* find size of remaining/new block */
  1061.  
  1062.    sRemBytes = pstOrigBlock -> sBytes - sBlockSize;
  1063.  
  1064.    /* calc new/reduced size of original block */
  1065.  
  1066.    pstOrigBlock -> sBytes = sRemBytes;
  1067.  
  1068.    if(sType == VMM_MEMORY)
  1069.    {
  1070.      pvPtr = (PVOID) ( (LONG) pstOrigBlock -> pvBlock + 
  1071.                                      (LONG) sRemBytes);
  1072.  
  1073.      if(pstVmmMgr -> pstReloadBlock != NULL)
  1074.      {
  1075.         pstVmmMgr -> pstReloadBlock -> pvBlock = pvPtr;
  1076.         *ppstNewBlock = pstVmmMgr -> pstReloadBlock;
  1077.      }
  1078.      else
  1079.         VmmCreateBlock(sType,sBlockSize,sOwner,pvPtr,0L,ppstNewBlock);
  1080.    }
  1081.    else
  1082.    {
  1083.      lOffset = pstOrigBlock -> lOffset + sBlockSize;
  1084.  
  1085.      VmmCreateBlock(sType,sBlockSize,sOwner,(PVOID) 0,lOffset,ppstNewBlock);
  1086.    }
  1087.  
  1088.    C_RETURN
  1089.  
  1090. }
  1091.  
  1092.  
  1093. /*
  1094. **   VmmCreateBlock
  1095. **
  1096. **   Create a new block (either disk or memory).
  1097. **   Either the lOffset or pvPtr will be assigned
  1098. */
  1099.  
  1100. #ifdef C_ANSI
  1101. SHORT VmmCreateBlock(SHORT sType,
  1102.                      SHORT sBlockSize,
  1103.                      SHORT sOwner,
  1104.                      PVOID pvPtr,
  1105.                      LONG lOffset,
  1106.                      VMM_BLOCK_P * ppstNewBlock)
  1107. #else
  1108. SHORT VmmCreateBlock(sType,
  1109.                      sBlockSize,
  1110.                      sOwner,
  1111.                      pvPtr,
  1112.                      lOffset,
  1113.                      ppstNewBlock)
  1114. SHORT sType;
  1115. SHORT sBlockSize;
  1116. SHORT sOwner;
  1117. PVOID pvPtr;
  1118. LONG lOffset;
  1119. VMM_BLOCK_P * ppstNewBlock;
  1120. #endif
  1121. {
  1122.    C_DEF_MODULE("VmmCreateBlock")
  1123.  
  1124.    VMM_BLOCK_P  pstBlock;
  1125.    LLIST_P      pstMember;
  1126.  
  1127.  
  1128.    pstBlock = (VMM_BLOCK_P) calloc(1,sizeof(VMM_BLOCK_T));
  1129.  
  1130.  
  1131.    pstBlock -> lDescriptor = pstVmmMgr -> lDescriptor;
  1132.  
  1133.    pstVmmMgr -> lDescriptor++;
  1134.  
  1135.  
  1136.    pstBlock -> sBytes = sBlockSize;
  1137.    pstBlock -> sOwner = sOwner;
  1138.    pstBlock -> sState = sType;
  1139.  
  1140.    pstBlock -> lTimeLastAccess = VmmCurTime();
  1141.  
  1142.    if(sType = VMM_MEMORY)
  1143.      pstBlock -> pvBlock = pvPtr;
  1144.    else
  1145.      pstBlock -> lOffset = lOffset;
  1146.  
  1147.  
  1148.    MemLstAllocMember(&pstMember);
  1149.  
  1150.    pstMember -> pvData = (PVOID) pstBlock;
  1151.  
  1152.    if(sType == VMM_DISK)
  1153.    {
  1154.       MemLstInsertMember(pstVmmMgr -> pstFreeDiskBlocks,
  1155.                          pstMember,
  1156.                          VmmCompareBlockSize,
  1157.                          &(pstVmmMgr -> pstFreeDiskBlocks));
  1158.    }
  1159.    else
  1160.    {
  1161.       MemLstInsertMember(pstVmmMgr -> pstMemList,
  1162.                          pstMember,
  1163.                          VmmCompareBlockSize,
  1164.                          &(pstVmmMgr -> pstMemList));
  1165.    }
  1166.  
  1167.  
  1168.    *ppstNewBlock = pstBlock;
  1169.  
  1170.    C_RETURN
  1171. }
  1172.  
  1173.  
  1174.  
  1175. /*
  1176. **  VmmCompareBlockSize
  1177. **
  1178. **  Compare function for use by MemLst for comparing memory blocks
  1179. */
  1180.  
  1181. #ifdef C_ANSI
  1182. SHORT 
  1183. VmmCompareBlockSize(PVOID pvData1, PVOID pvData2)
  1184. #else
  1185. SHORT 
  1186. VmmCompareBlockSize(pvData1,pvData2)
  1187. PVOID pvData1;
  1188. PVOID pvData2;
  1189. #endif
  1190. {
  1191.    VMM_BLOCK_P  pstBlock1;
  1192.    VMM_BLOCK_P  pstBlock2;
  1193.  
  1194.   
  1195.    pstBlock1 = (VMM_BLOCK_P) pvData1;
  1196.    pstBlock2 = (VMM_BLOCK_P) pvData2;
  1197.  
  1198.    if(pstBlock1 -> sBytes == pstBlock2 -> sBytes)
  1199.       return(0);
  1200.    else if(pstBlock1 -> sBytes > pstBlock2 -> sBytes)
  1201.       return(-1);
  1202.    else
  1203.       return(1);
  1204.  
  1205. }
  1206.  
  1207.  
  1208. /*
  1209. **  VmmCompareHandle
  1210. **
  1211. **  Compare function for use by MemLst for comparing memory blocks
  1212. */
  1213.  
  1214. #ifdef C_ANSI
  1215. SHORT 
  1216. VmmCompareHandle(PVOID pvData1, PVOID pvData2)
  1217. #else
  1218. SHORT 
  1219. VmmCompareHandle(pvData1,pvData2)
  1220. PVOID pvData1;
  1221. PVOID pvData2;
  1222. #endif
  1223. {
  1224.    VMM_BLOCK_P  pstBlock1;
  1225.    VMM_BLOCK_P  pstBlock2;
  1226.  
  1227.   
  1228.    pstBlock1 = (VMM_BLOCK_P) pvData1;
  1229.    pstBlock2 = (VMM_BLOCK_P) pvData2;
  1230.  
  1231.    if(pstBlock1 -> lDescriptor == pstBlock2 -> lDescriptor)
  1232.       return(0);
  1233.    else if(pstBlock1 -> lDescriptor > pstBlock2 -> lDescriptor)
  1234.       return(-1);
  1235.    else
  1236.       return(1);
  1237.  
  1238. }
  1239.  
  1240.  
  1241.  
  1242. /*
  1243. **  VmmCurTime
  1244. **
  1245. **  Get the current time, used in updated block access times
  1246. */
  1247.  
  1248. #ifdef C_ANSI
  1249. LONG
  1250. VmmCurTime(VOID)
  1251. #else
  1252. LONG
  1253. VmmCurTime()
  1254. #endif
  1255. {
  1256.    time_t  lTime;
  1257.  
  1258.    time(&lTime);
  1259.  
  1260.    return((LONG) lTime);
  1261. }
  1262.  
  1263.  
  1264.  
  1265.  
  1266.  
  1267. /* *******************************************************************
  1268.  
  1269.                        T E S T  C O D E
  1270.  
  1271.    ******************************************************************* */
  1272.  
  1273.  
  1274. #ifdef TEST
  1275.  
  1276. #define TEST_3
  1277.  
  1278. #define MAX_HANDLES 512
  1279.  
  1280. main()
  1281. {
  1282.    LONG lHandle1;
  1283.    LONG lHandle2;
  1284.    PCHAR pcData;
  1285.    SHORT sCnt;
  1286.    LONG lHandle[MAX_HANDLES];
  1287.    SHORT sCnt2;
  1288.  
  1289.    VmmInit(1024,"swap.dat");
  1290.  
  1291. #ifdef TEST_1
  1292.  
  1293.    VmmAlloc(1,100,&lHandle1);
  1294.    VmmPrep(lHandle1,(PPVOID) &pcData);
  1295.  
  1296.    strcpy(pcData,"Testing 123");
  1297.  
  1298.    VmmAlloc(1,100,&lHandle2);
  1299.    VmmPrep(lHandle2,(PPVOID) &pcData);
  1300.  
  1301.    strcpy(pcData,"Testing 456");
  1302.  
  1303.    VmmPrep(lHandle1,(PPVOID) &pcData);
  1304.    printf("%s\n", pcData);
  1305.  
  1306.    VmmPrep(lHandle2,(PPVOID) &pcData);
  1307.    printf("%s\n", pcData);
  1308.  
  1309.    VmmFree(lHandle1);
  1310.    VmmFree(lHandle2);
  1311.  
  1312. #endif
  1313.  
  1314. #ifdef TEST_2
  1315.  
  1316.    VmmAlloc(1,100,&lHandle1);
  1317.    VmmAlloc(1,1000,&lHandle2);
  1318.  
  1319.    VmmPrep(lHandle1, (PPVOID) &pcData);
  1320.    strcpy(pcData,"lHandle1");
  1321.  
  1322.    VmmPrep(lHandle2, (PPVOID) &pcData);
  1323.    strcpy(pcData,"lHandle2");
  1324.  
  1325.    for(sCnt = 0; sCnt < 10; sCnt++)
  1326.    {
  1327.      VmmPrep(lHandle1,(PPVOID) &pcData);
  1328.      printf("%s\n", pcData);
  1329.      sprintf(pcData,"Handle1 - %d", sCnt);
  1330.  
  1331.      VmmPrep(lHandle2,(PPVOID) &pcData);
  1332.      printf("%s\n", pcData);     
  1333.      sprintf(pcData,"Handle2 - %d", sCnt);
  1334.    }
  1335.  
  1336.    VmmFree(lHandle1);
  1337.    VmmFree(lHandle2);
  1338.  
  1339.    VmmTerm();
  1340.  
  1341. #endif
  1342.  
  1343. #ifdef TEST_3
  1344.  
  1345.    for(sCnt = 0; sCnt < MAX_HANDLES; sCnt++)
  1346.        VmmAlloc(1,16,&lHandle[sCnt]);
  1347.  
  1348. for(sCnt2 = 0; sCnt2 < MAX_HANDLES; sCnt2++)
  1349. {
  1350.    printf("Writing...\n");
  1351.    for(sCnt = 0; sCnt < MAX_HANDLES; sCnt++)
  1352.    {
  1353.       VmmPrep(lHandle[sCnt],&pcData);
  1354.       sprintf(pcData,"Handle %d %d",sCnt,sCnt2);
  1355.    }
  1356.  
  1357.    
  1358.    printf("Retrieve Ascending...\n");
  1359.    for(sCnt = 0; sCnt < MAX_HANDLES; sCnt++)
  1360.    {
  1361.       VmmPrep(lHandle[sCnt],&pcData);
  1362.       printf("%s\n",pcData);
  1363.    }
  1364.    printf("Retrieve Descending...\n");
  1365.    for(sCnt = MAX_HANDLES-1; sCnt > 0; sCnt--)
  1366.    {
  1367.       VmmPrep(lHandle[sCnt],&pcData);
  1368.       printf("%s\n",pcData);
  1369.    }
  1370.    for(sCnt = 0; sCnt < MAX_HANDLES; sCnt++)
  1371.       VmmFree(lHandle[sCnt]);
  1372.  
  1373.    VmmTerm();
  1374.  
  1375. #endif
  1376.    
  1377. #endif
  1378.  
  1379.  
  1380.  
  1381.