📄 page.c
字号:
||(opfe->md.mel == NULL )||( opfe->dbn_id == PAGEFILE_ID )) { /* Check for invalid pages although they are unlikely to exist. */ err = E_MACV; goto err_ret2; } /* Pages are write-protected before copy-on-write is performed, but sometimes * updated by BMS. In such a case, return an error so that such pages do not * remain on the disk cache. */ if ( isUpdateP(pte.w) ) { opfe->err = TRUE; } /* Cancel the cache content to replace physical memory. */ InvalidateCachePage(laddr, lsid); /* Reserve new page frame * Turn old page frames into unregistered pages temporarily so that * they are not paged out. */ opfe->reg = FALSE; npfe = GetPFM(PFS_use, FALSE); opfe->reg = TRUE; if ( npfe == NULL ) { /* If new page frames cannot be reserved, reuse old page frames. */ err = PageOut(opfe, FALSE); if ( err < E_OK ) { goto err_ret2; } /* Deregister from DBH and separate from queue. */ RemoveDBH(opfe); removePageFrameQue(opfe); /* Initialize opfe content. */ bzero(opfe, (size_t)sizeof(PFE)); /* Register in queue */ RegistPageFrame(opfe, PFS_use); if ( isLocalSpace(laddr) != 0 ) { /* Update process statistical information Reset the count by PageOut(). */ PINFO *pinfo = GetPINFO_lsid(lsid); if ( pinfo != NULL ) { pinfo->allocpage++; pinfo->poutcount--; } } npfe = opfe; } else { /* Copy content to new page frames */ memcpy(p = PFEtoLADR(npfe), PFEtoLADR(opfe), (size_t)PAGESIZE); WriteBackDCachePage(p, 0); } /* Set PFE */ npfe->md.page.lsid = lsid; npfe->md.page.pn = (UW)laddr / (UW)PAGESIZE; /* Update page table */ pte.c.pfa = PFEtoPFA(npfe); pte.w |= PT_Writable; SetPTE(&pth, pte.w, TRUE);norm_ret: EndPTH(&pth, FALSE); return E_OK;err_ret2: EndPTH(&pth, FALSE);err_ret1: DEBUG_PRINT(("CopyOnWrite err = %d\n", err)); return err;}/* ------------------------------------------------------------------------ *//* * Obtain/release page frame *//* * Connect to page frame queue */LOCAL void insertPageFrameQue( PFE *pfe, PFS stat ){ pfe->stat = stat; /* Register in queue */ switch ( stat ) { case PFS_lock: InsertPFE_Q(&LockPFE_Q, pfe); break; case PFS_use: InsertPFE_Q(&UsePFE_Q, pfe); break; case PFS_free: InsertPFE_Q(&FreePFE_Q, pfe); break; case PFS_uninit: PutUninitPFE(pfe); break; default: /* nothing to do */ break; }}/* * Disconnect from page frame queue */LOCAL void removePageFrameQue( PFE *pfe ){ switch ( pfe->stat ) { case PFS_lock: RemovePFE_Q(&LockPFE_Q, pfe); break; case PFS_use: RemovePFE_Q(&UsePFE_Q, pfe); break; case PFS_free: RemovePFE_Q(&FreePFE_Q, pfe); break; case PFS_uninit: RemoveUninitPFE(pfe); break; default: /* nothing to do */ break; }}/* * Register page frame queue * Register pfe in stat queue. * "stat = PFS_uninit" is not acceptable. */EXPORT void RegistPageFrame( PFE *pfe, PFS stat ){ /* Register in DBH */ RegistDBH(pfe); /* Register in queue */ insertPageFrameQue(pfe, stat); pfe->reg = TRUE; /* Page frame already registered */}/* * Move page frame queue * Move from pfe->stat queue to stat queue. * "PFS_uninit" is not acceptable for both queues. */EXPORT void MovePageFrame( PFE *pfe, PFS stat ){ removePageFrameQue(pfe); insertPageFrameQue(pfe, stat);}/* * Cancel page frames * "pfe->stat = PFS_uninit" is not acceptable. */EXPORT void DiscardPageFrame( PFE *pfe ){ /* Deregister from DBH. */ RemoveDBH(pfe); /* Separate from queue */ removePageFrameQue(pfe); /* Register in uninitialized page */ PutUninitPFE(pfe);}/* * Cancel page frames * Cancel all page frames that have de disk content. */EXPORT void DiscardPageFrameDE( DE *de ){ ID did = toDiskID(de); PFE *pfe; PFN npfn; W i; for ( i = 0; i < (W)MaxDBH; i++ ) { npfn = DiskBlockHash[i]; while( npfn != 0U ) { pfe = PFNtoPFE(npfn); npfn = pfe->dbh; if ( pfe->dbn_id == did ) { DiscardPageFrame(pfe); } } }}/* * Obtain a page frame that follows ppfe. * If it could not be obtained, return NULL. */LOCAL PFE* getNextPageFrame( PFE *ppfe, UW rank ){ PFE *pfe = ppfe + 1; ER err; if ( PFEtoPFN(pfe) > MaxPages ) { return NULL; } /* High ranks are not acceptable. */ if ( pfe->rank < rank ) { return NULL; } switch ( pfe->stat ) { case PFS_lock: return NULL; /* Pages must not be locked. */ case PFS_use: break; case PFS_free: break; case PFS_uninit: return RemoveUninitPFE(pfe); default: /* nothing to do */ break; } /* Unregistered pages must not be allocated. */ if ( !pfe->reg ) { return NULL; } /* Page out. */ err = PageOut(pfe, FALSE); if ( err < E_OK ) { goto err_ret; } /* Deregister from DBH and separate from queue. */ RemoveDBH(pfe); removePageFrameQue(pfe); SnatchCount++; return pfe;err_ret: DEBUG_PRINT(("getNextPageFrame err = %d\n", err)); return NULL;}/* * Obtain any of the page frames. * When "nowrite = TRUE", search for pages to be allocated, except for pages that * needed to be written to the disk (paged out). */LOCAL PFE* getFreePageFrame( BOOL nowrite ){ PFE *pfe; ER err; /* Search for uninitialized page */ pfe = GetUninitPFE(); if ( pfe != NULL ) { return pfe; } /* Search for free page queue */ pfe = NULL; while ( (pfe = NextPFE_Q(&FreePFE_Q, pfe)) != NULL ) { /* Page out. */ err = PageOut(pfe, nowrite); if ( err == E_OK ) { /* Move queue top */ SetTopPFE_Q(&FreePFE_Q, pfe); /* Deregister from DBH and separate from queue. */ RemoveDBH(pfe); RemovePFE_Q(&FreePFE_Q, pfe); return pfe; } } /* Search for queue for page in use */ pfe = NULL; while ( (pfe = NextPFE_Q(&UsePFE_Q, pfe)) != NULL ) { /* Page out. */ err = PageOut(pfe, nowrite); if ( err == E_OK ) { /* Move queue top */ SetTopPFE_Q(&UsePFE_Q, pfe); /* Deregister from DBH and separate from queue. */ RemoveDBH(pfe); RemovePFE_Q(&UsePFE_Q, pfe); return pfe; } } return NULL;}/* * Obtain page frame * 1. A page frames that has dbn blocks * 2. If not found, obtain a page frame whose next page is below rank. * 3. If not found, obtain any other frame. * When "dbn.id = dbn.no = 0", remove 1. * When "ppfe = NULL", remove 2. * * The obtained frame is an independent one that does not belong to any queue. * If the obtained frame has dbn blocks, return 1 as a return value. * If other page frame type was found, return 0. * If no page frame was found, return E_NOMEM. */EXPORT W GetPageFrame( PFE **pfe_p, DBN dbn, PFE *ppfe, UW rank ){ PFE *pfe = NULL; W hit = 0; if ( !((dbn.no == 0 )&&( dbn.id == 0))) { /* Search for DBH */ pfe = SearchDBH(dbn); if ( pfe != NULL ) { /* Temporarily deregister from DBH and separate from queue. */ RemoveDBH(pfe); removePageFrameQue(pfe); pfe->reg = FALSE; if ( rank < pfe->rank ) { pfe->rank = rank; } hit = 1; HashHitCount++; } else { HashMissCount++; } } if ( hit == 0 ) { /* New page */ if ( ppfe != NULL ) { /* Next page */ pfe = getNextPageFrame(ppfe, rank); } if ( pfe == NULL ) { /* Any page */ pfe = getFreePageFrame(FALSE); } if ( pfe == NULL ) { goto err_ret; } /* Initialize PFE content. */ bzero(pfe, (size_t)sizeof(PFE)); pfe->dbn_id = dbn.id; pfe->dbn_no = dbn.no; pfe->rank = rank; pfe->stat = PFS_free; /* Cancel cache content. */ InvalidateCachePage(PFEtoLADR(pfe), 0); } *pfe_p = pfe; return hit;err_ret: DEBUG_PRINT(("GetPageFrame err = %d\n", E_NOMEM)); return E_NOMEM;}/* * Uninitialize page frames obtained by GetPageFrame() and return. */EXPORT void UngetPageFrame( PFE *pfe ){ /* Deregister from DBH. */ RemoveDBH(pfe); /* Register in uninitialized page */ PutUninitPFE(pfe);}/* * Obtain page frame * When "nowrite = TRUE", search for pages to be allocated, except for pages that * needed to be written to the disk (paged out). */EXPORT PFE* GetPFM( PFS stat, BOOL nowrite ){ PFE *pfe; /* Obtain any of the pages. */ pfe = getFreePageFrame(nowrite); if ( pfe == NULL ) { goto err_ret; } /* Initialize PFE content. */ bzero(pfe, (size_t)sizeof(PFE)); /* Register in queue */ RegistPageFrame(pfe, stat); /* Cancel cache content. */ InvalidateCachePage(PFEtoLADR(pfe), 0); return pfe;err_ret: DEBUG_PRINT(("GetPFM err = %d\n", E_NOMEM)); return NULL;}/* ------------------------------------------------------------------------ *//* * Allocate special page frame *//* * Adaptability to allocation */Inline UW MATCH( PFE *pfe ){ return ((UW)pfe->stat << TSD_MAT_SFT_4) | ((TSD_MAT_VAL_7 - (UW)pfe->rank) << 1) | (UW)pfe->upd;}/* * Search for consecutive free areas * Allocate areas in such a way as to minimize unnecessary page-out processing. */LOCAL PFE* searchContinuousFreePFE( UW npage ){ PFE *pfe, *top, *end; UW np, match, n, i; struct { UW match; PFE *pfe; } best; best.match = TSD_SCP_MAT_0XFFFFFFFF; best.pfe = NULL; pfe = PageFrameEntry + 1; for ( i = 0; i < (UW)MemInfo->n; i++ ) { n = MemInfo->a[i].p.npage; if ( n < npage ) { pfe += n; continue; } end = pfe + n; match = np = 0; while ( pfe < end ) { if ( pfe->stat == PFS_uninit ) { n = (UW)pfe->dbn_no; /* Number of consecutive free pages */ if ( n >= npage ) { return pfe; } np += n; pfe += n; } else { if (( pfe->stat == PFS_lock )|| !pfe->reg ) { /* Pages that cannot be allocated */ match = np = 0; pfe++; continue; } match += MATCH(pfe); np++; pfe++; } while ( np >= npage ) { top = pfe - np; if ( match < best.match ) { best.match = match; best.pfe = top; } if ( top->stat == PFS_uninit ) { np -= (UW)top->dbn_no; } else { match -= MATCH(top); np--; } } } } return best.pfe;}/* * Obtain page frames that have consecutive physical addresses. */EXPORT VP AllocPhysicalMem( UW npage ){ PFE *pfe, *top; /* Check if the upper size limit of resident memory is not exceeded. */ if ( (W)npage > LockablePages(NULL) ) { goto err_ret; } /* Search for consecutive free areas */ top = searchContinuousFreePFE(npage); if ( top == NULL ) { goto err_ret; } /* Obtain free areas and set them to PFS_lock state. */ pfe = top - 1U; while ( npage-- > 0U ) { /* Obtain page */ pfe = getNextPageFrame(pfe, 0); if ( pfe == NULL ) { goto err_ret; } /* Initialize PFE content. */ bzero(pfe, (size_t)sizeof(PFE)); /* Register in queue */ RegistPageFrame(pfe, PFS_lock); /* Cancel cache content. */ InvalidateCachePage(PFEtoLADR(pfe), 0); } return toPhysicalAddress(PFEtoLADR(top));err_ret: DEBUG_PRINT(("AllocPhysicalMem err = %d\n", E_NOMEM)); return NULL;}/* ------------------------------------------------------------------------ *//* * Control related to logical space (page table) and page frame *//* * Discontinue relations of pages (PTE). * pinfo For unique space, specify processes to use. * For shared space, return NULL. */EXPORT ER UnlinkPage( PTE pte, PINFO *pinfo ){ if ( isPresentP(pte.w) || isValidP(pte.w)) { /* Page frame is present. */ PFE *pfe = PFAtoPFE(pte.c.pfa); if ( pfe == NULL ) { return E_OK; /* Not to be managed */ } if ( pfe->dbn_id == PAGEFILE_ID ) { /* Page file * Release, if any, obtained page files. * Release page frames. */ if ( pfe->dbn_no > 0 ) { FreePageFile(pfe->dbn_no); } DiscardPageFrame(pfe); } else { /* Disk map * Check update flag * Write-protect pages are sometimes * updated by BMS. In such a case, * do not write them to the disk. * Return an error so that such pages * do not remain on the disk cache. */ if ( isUpdateP(pte.w) ) { if ( isWritableP(pte.w) ) { pfe->upd = TRUE; }else{ pfe->err = TRUE; } } } /* Update process statistical information */ if ( pinfo != NULL ) { pinfo->allocpage--; } } else { /* Page frame is absent. * Disk map: Nothing has to be done.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -