?? vmm.c
字號:
/******************************************************************************
*+
** Module Name: Vmm.C
**
** Description: Virtual Memory Manager
**
** Supports limited virtual memory management.
**
** Performs cacheing of data and swapping to/from disk file.
**
**
** Written by: John Tal
**
**
**
** Modification History:
**
** Date Programmer Mod# Modification
** ---------------------------------------------------------------------------
** 17-FEB-1992 J. Tal V1.0-000 New
**
*-
*/
#ifdef C_ANSI
#include <string.h>
#include <stdlib.h>
#endif
#ifdef C_UNIX
#include <sys/types.h>
#endif
#include <time.h>
#include <stdio.h>
#include <memlib.h>
#include <vmm.h>
VMM_MGR_T stVmmMgr;
VMM_MGR_P pstVmmMgr = &stVmmMgr;
/*
** VmmInit
**
** Initialize virtual memory manager
*/
#ifdef C_ANSI
SHORT
VmmInit(SHORT sMemoryBytes,PCHAR pcSwapFile)
#else
SHORT
VmmInit(sMemoryBytes,pcSwapFile)
SHORT sMemoryBytes;
PCHAR pcSwapFile;
#endif
{
C_DEF_MODULE("VmmInit")
static BOOL fVmmInit;
VMM_BLOCK_P pstNewBlock;
if(fVmmInit)
C_LEAVE(VMM_ERR_INIT)
memset(&stVmmMgr,0,sizeof(VMM_MGR_T));
pstVmmMgr -> pvBlock = (PVOID) calloc(sMemoryBytes,1);
pstVmmMgr -> lTotalBytes = sMemoryBytes;
pstVmmMgr -> lSwapBytes = 0;
if(pstVmmMgr -> pvBlock == NULL)
C_LEAVE(VMM_ERR_MEM_EXCEEDED)
strcpy(pstVmmMgr -> szSwapFile,pcSwapFile);
pstVmmMgr -> fpSwapFile = fopen(pstVmmMgr -> szSwapFile,"w+b");
if(pstVmmMgr -> fpSwapFile == NULL)
C_LEAVE(VMM_ERR_INIT)
/* create logical block for all of memory */
C_STATUS = VmmCreateBlock(VMM_MEMORY,sMemoryBytes,VMM_OWNER_NONE,pstVmmMgr -> pvBlock,0L,&pstNewBlock);
if(pstVmmMgr -> fpSwapFile == NULL)
C_LEAVE(VMM_ERR_SWAP_FILE)
fVmmInit = C_TRUE;
C_MODULE_EXIT:
C_RETURN
}
/*
** VmmCompress
**
** Compress Internal memory. Called when there is enough space
** but not in a single continuous block.
*/
#ifdef C_ANSI
SHORT
VmmCompress(VOID)
#else
SHORT
VmmCompress()
#endif
{
C_DEF_MODULE("VmmCompress")
VMM_BLOCK_P pstNewBlock;
VMM_BLOCK_P pstBlock;
PVOID pvNewBlock;
PVOID pvPtr;
LLIST_P pstMember;
LONG lUseBytes = 0;
LONG lRemBytes;
LLIST_P pstMemberNext;
/* get new block of memory */
pvNewBlock = (PVOID) calloc(1,(SHORT) pstVmmMgr -> lTotalBytes);
if(pvNewBlock == NULL)
C_LEAVE(VMM_ERR_MEM_EXCEEDED)
pvPtr = pvNewBlock;
/* look at all memory blocks */
pstMember = pstVmmMgr -> pstMemList;
while(pstMember != NULL)
{
pstBlock = (VMM_BLOCK_P) pstMember -> pvData;
pstMemberNext = pstMember -> psNext;
/* if active, copy into new master block
reset block pointer
increment current pointer into new block
increment used bytes
*/
if(pstBlock -> sOwner != VMM_OWNER_NONE)
{
if(pstBlock -> sState == VMM_STATE_MEMORY)
{
/* retain by copying into new master bloc */
memcpy(pvPtr,pstBlock -> pvBlock, pstBlock -> sBytes);
pstBlock -> pvBlock = pvPtr;
pvPtr = (PVOID) ((long) pvPtr + (long) pstBlock -> sBytes);
lUseBytes += pstBlock -> sBytes;
}
}
else
{
/* free block and remove control list member */
free(pstBlock);
MemLstDeleteMember(pstVmmMgr -> pstMemList,
pstMember,
&(pstVmmMgr -> pstMemList));
}
pstMember = pstMemberNext;
}
/* free old block and make Vmm point to new */
free(pstVmmMgr -> pvBlock);
pstVmmMgr -> pvBlock = pvNewBlock;
lRemBytes = pstVmmMgr -> lTotalBytes - lUseBytes;
C_STATUS = VmmCreateBlock((SHORT) VMM_MEMORY,
(SHORT) lRemBytes,
(SHORT) VMM_OWNER_NONE,
pvPtr,
(LONG) 0,
&pstNewBlock);
C_MODULE_EXIT:
;
C_RETURN
}
/*
** VmmAlloc - Process wants a memory block
*/
#ifdef C_ANSI
SHORT
VmmAlloc(SHORT sOwner,SHORT sTotalBytes,PLONG plHandle)
#else
SHORT
VmmAlloc(sOwner,sTotalBytes,plHandle)
SHORT sOwner;
SHORT sTotalBytes;
PLONG plHandle;
#endif
{
C_DEF_MODULE("VmmAlloc")
VMM_BLOCK_P pstBlock = (VMM_BLOCK_P) NULL;
if((LONG) sTotalBytes > pstVmmMgr -> lTotalBytes)
C_LEAVE(VMM_ERR_MEM_EXCEEDED)
while(pstBlock == NULL)
{
VmmAssignBlock(VMM_MEMORY,sTotalBytes,sOwner,&pstBlock);
if(pstBlock == NULL)
VmmSizeSwapToDisk(sTotalBytes,sOwner,&pstBlock);
}
/* update access time */
pstBlock -> lTimeLastAccess = VmmCurTime();
*plHandle = pstBlock -> lDescriptor;
C_MODULE_EXIT:
;
C_RETURN
}
/*
** VmmPrep
**
** Setup Memory block before access to ensure is in memory
** Also call before each access to update access times used
** in cacheing decisions.
*/
#ifdef C_ANSI
SHORT
VmmPrep(LONG lHandle,PPVOID ppvVirtualPtr)
#else
SHORT
VmmPrep(lHandle,ppvVirtualPtr)
LONG lHandle;
PPVOID ppvVirtualPtr;
#endif
{
C_DEF_MODULE("VmmPrep")
LLIST_P pstMember;
VMM_BLOCK_P pstVmmBlock;
MemLstFindMember(pstVmmMgr -> pstMemList,
(PVOID) &lHandle,
VmmCompareHandle,
&pstMember);
if(pstMember != NULL)
{
pstVmmBlock = (VMM_BLOCK_P) pstMember -> pvData;
if(pstVmmBlock -> sState == VMM_STATE_DISK)
{
pstVmmMgr -> pstReloadBlock = pstVmmBlock;
VmmLoadFromDisk(pstVmmBlock,pstVmmBlock -> sOwner);
pstVmmMgr -> pstReloadBlock = (VMM_BLOCK_P) NULL;
}
/* update access time */
pstVmmBlock -> lTimeLastAccess = VmmCurTime();
*ppvVirtualPtr = pstVmmBlock -> pvBlock;
}
C_RETURN
}
/*
** VmmFree
**
** Process is freeing an allocated block
*/
#ifdef C_ANSI
SHORT
VmmFree(LONG lDescriptor)
#else
SHORT
VmmFree(lDescriptor)
LONG lDescriptor;
#endif
{
C_DEF_MODULE("VmmFree")
LLIST_P pstMember;
VMM_BLOCK_P pstBlock;
pstMember = pstVmmMgr -> pstMemList;
while(pstMember != NULL)
{
pstBlock = (VMM_BLOCK_P) pstMember -> pvData;
if(pstBlock -> lDescriptor == lDescriptor)
{
pstBlock -> sOwner = VMM_OWNER_NONE;
/* take care of disk block if swapped out */
if(pstBlock -> pstMate != NULL)
{
pstBlock -> pstMate -> sOwner = VMM_OWNER_NONE;
}
break;
}
pstMember = pstMember -> psNext;
}
if(pstMember == NULL)
C_SET_STATUS(C_NOTOK)
C_RETURN
}
/*
** VmmTerm
**
** Terminate Small Memory Manager
*/
#ifdef C_ANSI
SHORT VmmTerm(VOID)
#else
SHORT VmmTerm()
#endif
{
C_DEF_MODULE("VmmTerm")
LLIST_P pstMember;
LLIST_P pstMemberNext;
VMM_BLOCK_P pstBlock;
fclose(pstVmmMgr -> fpSwapFile);
/* free main memory block */
free(pstVmmMgr -> pvBlock);
/* free all sub-alloc memory blocks */
pstMember = pstVmmMgr -> pstMemList;
while(pstMember != NULL)
{
pstBlock = (VMM_BLOCK_P) pstMember -> pvData;
pstMemberNext = pstMember -> psNext;
free(pstBlock);
pstMember = pstMemberNext;
}
/* free all disk swap blocks */
pstMember = pstVmmMgr -> pstFreeDiskBlocks;
while(pstMember != NULL)
{
pstBlock = (VMM_BLOCK_P) pstMember -> pvData;
pstMemberNext = pstMember -> psNext;
free(pstBlock);
pstMember = pstMemberNext;
}
C_RETURN
}
/*
** VmmLoadFromDisk
**
** A block has been swapped to disk, load it back into memory
*/
#ifdef C_ANSI
SHORT
VmmLoadFromDisk(VMM_BLOCK_P pstVmmBlock,SHORT sOwner)
#else
SHORT
VmmLoadFromDisk(pstVmmBlock,sOwner)
VMM_BLOCK_P pstVmmBlock;
SHORT sOwner;
#endif
{
C_DEF_MODULE("VmmLoadFromDisk")
VMM_BLOCK_P pstBlock = NULL;
while(pstBlock == NULL)
{
VmmAssignBlock(VMM_MEMORY,pstVmmBlock -> sBytes,sOwner,&pstBlock);
if(pstBlock == NULL)
VmmSizeSwapToDisk(pstVmmBlock -> sBytes,sOwner,&pstBlock);
}
if(pstBlock != pstVmmBlock)
{
/* problem here, another block has been created, must merge two
together. All we really need is the pvBlock ptr */
pstVmmBlock -> pvBlock = pstBlock -> pvBlock;
/* remove newly created block */
VmmVanishBlock(VMM_MEMORY,pstBlock);
}
fseek(pstVmmMgr -> fpSwapFile,
pstVmmBlock -> lOffset,
0);
fread(pstVmmBlock -> pvBlock,
1,
pstVmmBlock -> sBytes,
pstVmmMgr -> fpSwapFile);
pstVmmBlock -> sState = VMM_STATE_MEMORY;
/* free up disk block for other use */
if(pstVmmBlock -> pstMate != NULL)
{
pstVmmBlock -> pstMate -> sOwner = VMM_OWNER_NONE;
pstVmmBlock -> pstMate = NULL;
}
C_RETURN
}
/*
** VmmVanishBlock
**
** A new block has been created during processing and is not needed
** (pvBlock was probably copied before this call)
*/
#ifdef C_ANSI
SHORT
VmmVanishBlock(SHORT sType,VMM_BLOCK_P pstVanishBlock)
#else
SHORT
VmmVanishBlock(sType,pstVanishBlock)
SHORT sType;
VMM_BLOCK_P pstVanishBlock;
#endif
{
C_DEF_MODULE("VmmVanishBlock")
LLIST_P pstMember;
VMM_BLOCK_P pstBlock;
if(sType == VMM_STATE_MEMORY)
pstMember = pstVmmMgr -> pstMemList;
else
pstMember = pstVmmMgr -> pstFreeDiskBlocks;
while(pstMember != NULL)
{
pstBlock = (VMM_BLOCK_P) pstMember -> pvData;
if(pstBlock == pstVanishBlock)
{
if(sType == VMM_MEMORY)
{
C_STATUS = MemLstDeleteMember(pstVmmMgr -> pstMemList,
pstMember,
&(pstVmmMgr -> pstMemList));
}
else
{
C_STATUS = MemLstDeleteMember(pstVmmMgr -> pstFreeDiskBlocks,
pstMember,
&(pstVmmMgr -> pstFreeDiskBlocks));
}
break;
}
pstMember = pstMember -> psNext;
}
free(pstVanishBlock);
C_RETURN
}
/*
** VmmCheckFreeBlocks
**
** Check total bytes available across all free fragments
*/
#ifdef C_ANSI
SHORT
VmmCheckFreeBlocks(SHORT * pAvail)
#else
SHORT
VmmCheckFreeBlocks(pAvail)
SHORT * pAvail;
#endif
{
C_DEF_MODULE("VmmCheckFreeBlocks")
LLIST_P pstMember;
VMM_BLOCK_P pstBlock;
SHORT sFreeBytes = 0;
pstMember = pstVmmMgr -> pstMemList;
/* find oldest available block */
while(pstMember != NULL)
{
/* if unused block, count it */
pstBlock = (VMM_BLOCK_P) pstMember -> pvData;
if((pstBlock -> sOwner == VMM_OWNER_NONE) &&
(pstBlock -> sState == VMM_STATE_MEMORY))
{
sFreeBytes += pstBlock -> sBytes;
}
pstMember = pstMember -> psNext;
}
*pAvail = sFreeBytes;
return(C_OK);
}
/*
** VmmFindStaleBlock
*/
#ifdef C_ANSI
SHORT
VmmFindStaleBlock(VMM_BLOCK_P * ppstRetBlock)
#else
SHORT
VmmFindStaleBlock(ppstRetBlock)
VMM_BLOCK_P * ppstRetBlock;
#endif
{
C_DEF_MODULE("VmmFindStaleBlock")
LLIST_P pstMember;
LLIST_P pstMemberNext;
VMM_BLOCK_P pstBlock;
VMM_BLOCK_P pstOldBlock = (VMM_BLOCK_P) NULL;
LONG lTimeLastAccess;
lTimeLastAccess = VmmCurTime();
*ppstRetBlock = (VMM_BLOCK_P) NULL;
pstMember = pstVmmMgr -> pstMemList;
/* find oldest available block */
while(pstMember != NULL)
{
pstMemberNext = pstMember -> psNext;
pstBlock = (VMM_BLOCK_P) pstMember -> pvData;
if((pstBlock -> sOwner != VMM_OWNER_NONE) &&
(pstBlock -> sState != VMM_STATE_DISK))
{
if(pstBlock -> lTimeLastAccess <= lTimeLastAccess)
{
pstOldBlock = pstBlock;
lTimeLastAccess = pstBlock -> lTimeLastAccess;
}
}
pstMember = pstMemberNext;
}
*ppstRetBlock = pstOldBlock;
return(C_OK);
}
/*
** VmmAssignBlock
**
** Find and assign a block for either memory or disk allocation
** Can return NULL in the return block if none found
*/
#ifdef C_ANSI
SHORT
VmmAssignBlock(SHORT sType,
SHORT sBlockSize,
SHORT sOwner,
VMM_BLOCK_P * ppstRetBlock)
#else
SHORT
VmmAssignBlock(sType,
sBlockSize,
sOwner,
ppstRetBlock)
SHORT sType;
SHORT sBlockSize;
SHORT sOwner;
VMM_BLOCK_P * ppstRetBlock;
#endif
{
C_DEF_MODULE("VmmAssignBlock")
LLIST_P pstMember;
LLIST_P pstMemberNext;
LLIST_P pstMemberBlock;
VMM_BLOCK_P pstBlock;
BOOL fFoundBlock = C_FALSE;
SHORT sByteDiff;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -