📄 segio.c
字号:
/* *---------------------------------------------------------------------- * T-Kernel / Standard Extension * * Copyright (C) 2006 by Ken Sakamura. All rights reserved. * T-Kernel / Standard Extension is distributed * under the T-License for T-Kernel / Standard Extension. *---------------------------------------------------------------------- * * Version: 1.00.00 * Released by T-Engine Forum(http://www.t-engine.org) at 2006/8/11. * *---------------------------------------------------------------------- *//* * segio.c (memory) * * Segment management (Virtual storage version) * Disk input/output and page file management */#include "segmgr.h"#include <bitop.h>#define TSD_ISI_VAL_5 5#define TSD_DPF_VAL_100 100#define TSD_OPF_VAL_7 7U#define TSD_OPF_VAL_8 8U#define TSD_EBN_RTN_M1 (-1)Inline void releaseDiskEntry( DE *de );LOCAL DBN PageFileDBN( DBN pf_dbn );LOCAL W AllocPageFile( void );LOCAL W getErrorBlockNo( DBN dbn, PhyBlk *pb );LOCAL void CallErrHdr( PFE *pfe, ER err );LOCAL DE* getDiskEntry( void );LOCAL UW MaxDiskEntry; /* Maximum number of DiskEntry */EXPORT DE *DiskEntryTable; /* DiskEntry table */LOCAL UW MaxErrHdrEntry; /* Maximum number of ErrorHandlerEntry */LOCAL EHE *ErrHdrEntryTable; /* ErrorHandlerEntry table *//* * The device is removable: TRUE */EXPORT BOOL isRemovableDisk( ID did ){ DE *de = toDiskEntry(did); return (BOOL)de->info.removable;}/* * The memory disk can be directly mapped: TRUE */EXPORT BOOL isMemoryDisk( ID did ){ DE *de = toDiskEntry(did); return ( de->memadr != INVADR );}/* * Narrow down blocks * Starting from pgofs-th page of pb block list, narrow down to pgsiz pages, * and return the block list as a return value. * If the blocks cannot be narrowed down, return NULL. * It is necessary to use Ifree() to free the returned block list after it is used. */EXPORT PhyBlk* CutPhyBlks( ID did, PhyBlk *pb, UW pgofs, UW pgsiz ){ DE *de = toDiskEntry(did); PhyBlk *cut_pb, *top; UW n1, n2, i;#define TSD_CPB_VAL_2 2U n1 = pgofs * de->blkcnt; while ( n1 >= pb->len ) { if ( pb->len == 0U ) { goto err_ret; } n1 -= pb->len; pb++; } top = pb; n2 = n1 + (pgsiz * de->blkcnt); while ( n2 > pb->len ) { if ( pb->len == 0U ) { goto err_ret; } n2 -= pb->len; pb++; } i = (UW)(pb - top); cut_pb = Imalloc((i + TSD_CPB_VAL_2) * sizeof(PhyBlk)); if ( cut_pb == NULL ) { goto err_ret; } memcpy(cut_pb, top, (size_t)((i + 1U) * sizeof(PhyBlk))); cut_pb[i].len = n2; cut_pb[0].len -= n1; cut_pb[0].blk += n1; cut_pb[i + 1].len = 0U; return cut_pb;err_ret: DEBUG_PRINT(("CutPhyBlks Error\n")); return NULL;}/* ------------------------------------------------------------------------ *//* * Page file management *//* * Page file management information */typedef struct { W fd; /* File descriptor */ PhyBlk *pb; /* Physical block structure */ UW npage; /* Total number of pages */ UW use; /* Number of pages in use */ UB *usemap; /* Bit map of pages in use */ DE *de; /* Disk information */} PageFileInfo;LOCAL PageFileInfo pfinfo;/* * Upper number limit of pages per page file * Upper limit depends on the structure of PTE and DBN. */#define PageFileLimit ( (((UW)MAX_PFA) - ((UW)PB_BASE) - 1U) & 0x7fffffffU )/* * Information on disk that contains page files */#define PageFileDE() ( pfinfo.de )/* * Obtain usage state of page files */EXPORT void GetPageFileInfo( UW *total, UW *use ){ *total = pfinfo.npage; *use = pfinfo.use;}/* * Determine DBN of real disk block from page file DBN. */LOCAL DBN PageFileDBN( DBN pf_dbn ){ PhyBlk *pb = pfinfo.pb; W blk = (pf_dbn.no - 1) * pfinfo.de->blkcnt; DBN dbn; while ( (UW)blk >= pb->len ) { blk -= (W)pb->len; pb++; } dbn.no = (W)pb->blk + blk; dbn.id = (UB)toDiskID(pfinfo.de); return dbn;}/* * Obtain page file * Return page file block number. */LOCAL W AllocPageFile( void ){ W i; ER err; /* To increase processing speed when page files are used up */ if ( pfinfo.use >= pfinfo.npage ) { err = E_NOMEM; goto err_ret; } i = BitSearch0(pfinfo.usemap, 0, (W)pfinfo.npage); if ( i < 0 ) { err = E_NOMEM; goto err_ret; } BitSet(pfinfo.usemap, (UW)i); pfinfo.use++; return i + 1;err_ret: DEBUG_PRINT(("AllocPageFile err = %d\n", err)); return err;}/* * Release page file */EXPORT void FreePageFile( W pfbn ){ BitClr(pfinfo.usemap, (UW)(pfbn - 1)); pfinfo.use--;}/* * Open page file * Called from system initialization process (INIT=IMS). */EXPORT ER OpenPageFile( LINK *lnk ){ W fd; PhyBlk *pb; UW npage; UB *usemap; DE *de; W nent, ofs, rsz, i, n; ER err; if ( pfinfo.fd > 0 ) { err = E_BUSY; goto err_ret1; } /* Open page file */ fd = tkse_opn_fil(lnk, F_UPDATE|F_EXCL, NULL); if ( fd < E_OK ) { err = fd; goto err_ret1; } /* Obtain disk block structure. */ err = tkse_GetRecInfo(fd, NULL, NULL, NULL, 0, &nent); if ( err < E_OK ) { goto err_ret2; } if ( nent <= 0 ) { err = E_REC; goto err_ret2; } pb = Imalloc((UW)nent * sizeof(PhyBlk)); if ( pb == NULL ) { err = E_SYSMEM; goto err_ret2; } err = tkse_GetRecInfo(fd, &ofs, &rsz, pb, nent, &nent); if ( err < E_OK ) { goto err_ret3; } /* Obtain disk information (Obtain AttachFS information). */ de = toDiskEntry((ID)err); /* Combine blocks on a page basis, and discard the remaining blocks. */ npage = 0; i = (ofs + de->info.blocksize - 1) / de->info.blocksize; rsz -= (i * de->info.blocksize) - ofs; rsz /= de->info.blocksize; /* Number of valid record blocks */ pb[0].blk += (UW)i; /* Discard remaining blocks. */ pb[0].len -= (UW)i; for ( i = 0; i < nent; ++i ) { n = (W)pb[i].len; if ( n > rsz ) { n = rsz; } rsz -= n; n /= de->blkcnt; /* Number of valid pages */ pb[i].len = (UW)n * (UW)de->blkcnt; /* Discard remaining blocks. */ npage += (UW)n; } if ( npage > PageFileLimit ) { npage = PageFileLimit; } /* Generate bit map of pages in use */ usemap = Icalloc(1, (npage + TSD_OPF_VAL_7) / TSD_OPF_VAL_8); if ( usemap == NULL ) { err = E_SYSMEM; goto err_ret3; } /* Set page file management information */ LockSEG(); pfinfo.fd = fd; pfinfo.pb = pb; pfinfo.npage = npage; pfinfo.use = 0; pfinfo.usemap = usemap; pfinfo.de = de; UnlockSEG(); return E_OK;err_ret3: Ifree(pb);err_ret2: (void)tkse_cls_fil(fd) ;err_ret1: DEBUG_PRINT(("OpenPageFile err = %d\n", err)); return err;}/* * Close page file * Called form system initialization process (INIT=IMS) * * force = FALSE Do not close if remaining blocks are in use. * force = TRUE Forcedly close even if remaining blocks are in use. * However, subsequent operation is not guaranteed. * System must be shut down immediately. */EXPORT ER ClosePageFile( BOOL force ){ W fd; ER err, error = E_OK; LockSEG(); if ( !force &&( pfinfo.use > 0U )) { /* File pages cannot be closed because remaining blocks are in use. */ error = E_BUSY; fd = 0; } else { /* Clear page file management information. */ fd = pfinfo.fd; pfinfo.fd = 0; pfinfo.npage = 0; } UnlockSEG(); if ( fd > 0 ) { /* Close page file. */ err = tkse_cls_fil(fd); if ( err < E_OK ) { error = err; } Ifree(pfinfo.pb); Ifree(pfinfo.usemap); }#ifdef DEBUG if ( error < E_OK ) { DEBUG_PRINT(("ClosePageFile err = %d\n", error)); }#endif return error;}/* * Page in from page file. */EXPORT ER PageInPageFile( PTH *pth, VP laddr, UW lsid ){ PTE pte; DBN dbn; PFE *pfe; VP p; ER err; pte.w = GetPTE(pth); dbn.id = PAGEFILE_ID; dbn.no = pte.c.pfa - PB_BASE; /* Obtain page frame. */ err = GetPageFrame(&pfe, dbn, NULL, MapRankMM0); if ( err < E_OK ) { goto err_ret1; } /* Update page frame information. */ pfe->md.page.lsid = lsid; pfe->md.page.pn = (UW)laddr / (UW)PAGESIZE; if ( isClearP(pte.w) ) { /* Clear page frame. */ bzero(p = PFEtoLADR(pfe), (size_t)PAGESIZE); WriteBackDCachePage(p, 0); pfe->upd = TRUE; } else if (( err == 0 )&&( dbn.no > 0 )) { /* Load from page file. */ err = ReadWritePFE(pfe, TDC_READ); if ( err < E_OK ) { goto err_ret2; } }#if PT_Update == 0 /* If MMU does not have update flags, release page files to be written at the time of page-out. */ pfe->upd = TRUE; if ( dbn.no > 0 ) {#else /* If page files have been used up, actively release page files. */ if (( dbn.no > 0 )&&( pfinfo.use >= pfinfo.npage )) {#endif FreePageFile(dbn.no); pfe->dbn_no = 0; /* Page file not allocated */ pfe->upd = TRUE; /* Need to write at the time of page-out. */ } if ( isLocalSpace(laddr) != 0 ) { /* Update process statistical information */ PINFO *pinfo = GetPINFO_lsid(lsid); if ( pinfo != NULL ) { pinfo->allocpage++; } } /* Register page frame */ RegistPageFrame(pfe, PFS_use); /* Update page table */ pte.c.pfa = PFEtoPFA(pfe); pte.w &= ~(UW)(PT_Clear | PT_Update); pte.w |= (PT_Present | PT_Valid); SetPTE(pth, pte.w, TRUE); return E_OK;err_ret2: UngetPageFrame(pfe);err_ret1: DEBUG_PRINT(("PageInPageFile err = %d\n", err)); return err;}/* * Page out to page file * When "nowrite = TRUE", return E_BUSY instead of * writing page frames to the disk (page-out). */EXPORT ER PageOutPageFile( PFE *pfe, BOOL nowrite ){ VP laddr; UW lsid; PTH pth; PTE pte; ER err; /* Logical address */ laddr = (VP)(pfe->md.page.pn * PAGESIZE); lsid = pfe->md.page.lsid; InitPTH(&pth, laddr, lsid); err = NextPTE(&pth); if ( err < E_OK ) { goto err_ret1; } /* Set pages to absent. */ pte.w = ChgPTE(&pth, 0U, ~(UW)(PT_Present|PT_Valid|PT_Update), TRUE); if ( isUpdateP(pte.w) ) { pfe->upd = TRUE; } /* If no change has been made, it is unnecessary to write. */ if ( pfe->upd != 0 ) { if ( nowrite != 0 ) { err = E_BUSY; goto err_ret2; } if ( pfe->dbn_no == 0 ) { /* Allocate new page file */ err = AllocPageFile(); if ( err < E_OK ) { goto err_ret2; } pfe->dbn_no = err; RegistDBH(pfe); } /* Write to page file */ err = ReadWritePFE(pfe, TDC_WRITE); if ( err < E_OK ) { goto err_ret2; } } if ( isLocalSpace(laddr) != 0 ) { /* Update process statistical information */ PINFO *pinfo = GetPINFO_lsid(lsid); if ( pinfo != NULL ) { pinfo->allocpage--; pinfo->poutcount++; } } /* Update map identification information */ pfe->md.w = 0; /* Update page table */ pte.w = 0; pte.c.pfa = pfe->dbn_no + PB_BASE; (void)ChgPTE(&pth, pte.w, ~(UW)PT_Address, TRUE); EndPTH(&pth, FALSE); return E_OK;err_ret2: /* Reset page table */ (void)ChgPTE(&pth, pte.w & (PT_Present|PT_Valid|PT_Update), ~0U, TRUE);err_ret1:#ifdef DEBUG if ( !(nowrite &&( err == E_BUSY)) ) { DEBUG_PRINT(("PageOutPageFile nowrite = %d err = %d\n", nowrite, err)); }#endif return err;}/* * Check the state of access by pfe (PFS_use) page frames, and if there is no access, * link pfe again to an unused (PFS_free) page frame queue. * PT_Accessed in the page table is cleared. * * If page tables have been updated, release page files. */EXPORT void CheckAccessPageFile( PFE *pfe ){ VP laddr; PTE pte; laddr = (VP)(pfe->md.page.pn * PAGESIZE); pte.w = CHG_PTE(laddr, pfe->md.page.lsid, 0U, ~(UW)PT_Accessed, TRUE); if ( !isAccessedP(pte.w) ) { /* Since there was no access, suspend pages. */ (void)CHG_PTE(laddr, pfe->md.page.lsid, 0, ~(UW)PT_Present, TRUE); MovePageFrame(pfe, PFS_free); } if ( isUpdateP(pte.w) &&( pfe->dbn_no > 0 )) { /* If page tables have been updated, release page files. */ FreePageFile(pfe->dbn_no); RemoveDBH(pfe); pfe->dbn_no = 0; /* Page file not allocated */ }}/* ------------------------------------------------------------------------ *//* * Error handler-related *//* * Search for error handler */EXPORT FP SearchErrHdr( ID tid ){ EHE *ehe; for ( ehe = ErrHdrEntryTable; ehe < &ErrHdrEntryTable[MaxErrHdrEntry]; ++ehe ) { if ( ehe->tid == tid ) { return ehe->errhdr; } } return NULL; /* Unregistered */}/* * Fetch error occurrence block number */LOCAL W getErrorBlockNo( DBN dbn, PhyBlk *pb ){ DE *de = toDiskEntry(dbn.id); W no = dbn.no; W top, end; while ( pb->len > 0U ) { top = (W)pb->blk; end = (W)(pb->blk + pb->len - 1U); /* For an unmapped block, use a mapped block number in the same page. */ if (( no >= BLKTOP(de, top)) &&( no < (BLKTOP(de, end) + de->blkcnt) )) { if ( no < top ) { return top; } if ( no > end ) { return end; } return no; } pb++; } return TSD_EBN_RTN_M1;}/* * Call error handler */LOCAL void CallErrHdr( PFE *pfe, ER err ){ DiskErrInfo errinfo; FP errhdr; MEL *mel; ME *me; DBN dbn; dbn.id = pfe->dbn_id; dbn.no = pfe->dbn_no; /* Common section of error information */ errinfo.err = ERtoERR(err); errinfo.diskid = (ID)dbn.id; /* Call the error handler for each MapEntry where pfe are mapped. */ for ( mel = pfe->md.mel; mel != NULL; mel = mel->next_me ) { me = mel->me; /* Check if the error handler has been registered. */ errhdr = SearchErrHdr(me->tid); if ( errhdr == NULL ) { continue; /* Unregistered */ } /* Set error information and call the error handler. */ errinfo.taskid = me->tid; errinfo.mode = me->mode; errinfo.mode.addr = mappingAddress(me, pfe); errinfo.blk = (UW)getErrorBlockNo(dbn, me->pb); (*errhdr)(&errinfo); }}/* * Register/deregister disk error handler * Define disk error handler * When "errhdr = NULL", reset definitions of error handler. */EXPORT ER _NotifyDiskErr( FP errhdr ){ EHE *ehe, *free; ID mytid = GetMyTid(); ER err; LockSEG(); /* Search for free entry */ free = NULL; for ( ehe = ErrHdrEntryTable; ehe < &ErrHdrEntryTable[MaxErrHdrEntry]; ++ehe ) { if ( ehe->tid == mytid ) { if ( errhdr != NULL ) { /* Reregister */ ehe->errhdr = errhdr; } else { /* Deregister */ ehe->tid = 0; } UnlockSEG(); return E_OK; } if ( ehe->tid == 0 ) { free = ehe; } } if ( errhdr == NULL ) { err = E_NOEXS; goto err_ret; } if ( free == NULL ) { err = E_LIMIT; goto err_ret;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -