前文主要介紹了SylixOS中的塊設備CACHE管理,本章主要介紹磁盤高速傳輸。在CAHCE回寫中SyilxOS採起了兩種方式,即直接回寫和多管線併發回寫。併發寫管線經過多線程併發處理CACHE提交的寫請求,實現磁盤高速傳輸。緩存
SylixOS中經過LW_DISKCACHE_WP結構體管理併發寫管線,該結構體的具體內容如程序清單 1-1所示。多線程
程序清單 1-1併發
typedef struct { BOOL DISKCWP_bExit; /* 是否須要退出 */ BOOL DISKCWP_bCacheCoherence; /* CACHE 一致性標誌 */ BOOL DISKCWP_bParallel; /* 並行化讀寫支持 */ INT DISKCWP_iPipeline; /* 寫管線線程數 */ INT DISKCWP_iMsgCount; /* 寫消息緩衝個數 */ PVOID DISKCWP_pvRBurstBuffer; /* 管線緩存 */ PVOID DISKCWP_pvWBurstBuffer; /* 管線緩存 */ LW_OBJECT_HANDLE DISKCWP_hMsgQueue; /* 管線刷新隊列 */ LW_OBJECT_HANDLE DISKCWP_hCounter; /* 計數信號量 */ LW_OBJECT_HANDLE DISKCWP_hPart; /* 管線緩存管理 */ LW_OBJECT_HANDLE DISKCWP_hSync; /* 排空信號 */ LW_OBJECT_HANDLE DISKCWP_hDev; /* 非併發設備鎖 */ LW_OBJECT_HANDLE DISKCWP_hWThread[LW_CFG_DISKCACHE_MAX_PIPELINE]; /* 管線寫任務表 */ } LW_DISKCACHE_WP; typedef LW_DISKCACHE_WP *PLW_DISKCACHE_WP;
DISKCWP_bExit:爲LW_TRUE時,寫管線線程將會退出;函數
DISKCWP_bCacheCoherence:爲LW_TRUE時,管線緩存將使用非緩衝的內存;spa
DISKCWP_bParallel:並行化讀寫支持,若是不支持則須要在操做設備前調用設備鎖,防止併發操做;線程
DISKCWP_iPipeline:寫管線線程數,爲0時表示不是用併發寫管線;接口
DISKCWP_iMsgCount:寫消息緩衝個數,最小爲DCATTR_iPipeline, 能夠爲 DCATTR_iPipeline 的2 ~ 8 倍;隊列
DISKCWP_hMsgQueue:管線刷新隊列,上層經過發送一個消息,發起一個寫請求;ip
DISKCWP_hCounter:計數信號量,用於計數當前緩衝塊,發起寫請求時申請,完成回寫時釋放;內存
DISKCWP_hPart:經過定長內存管理管線緩存;
DISKCWP_hDev:非併發設備鎖;
DISKCWP_hWThread:管線寫任務表;
DISKCWP_hSync:排空信號,用於回寫完成後同步。
寫管線的建立經過調用__diskCacheWpCreate函數來完成,其函數原型如程序清單 1-2所示。
程序清單 1-2
INT __diskCacheWpCreate(PLW_DISKCACHE_CB pdiskc, PLW_DISKCACHE_WP pwp, BOOL bCacheCoherence, BOOL bParallel, INT iPipeline, INT iMsgCount, INT iMaxRBurstSector, INT iMaxWBurstSector, ULONG ulBytesPerSector);
函數__diskCacheWpCreate原型分析:
pdiskc: 緩衝控制塊
pwp: 併發寫管線控制塊
bCacheCoherence: CACHE 一致性需求
bParallel: 併發讀寫支持
iPipeline: 寫管線線程數
iMsgCount: 管線總消息個數
iMaxRBurstSector: 讀猝發長度
iMaxWBurstSector: 寫猝發長度
ulBytesPerSector: 每扇區大小
函數__diskCacheWpCreate根據入參建立對應的寫管線,並填充相關信息到併發寫管線控制控制結構體,其建立流程以下所示。
建立管線緩存
建立管線刷新隊列
建立計數信號量
建立內存分區緩存管理
建立排空信號
建立非併發設備鎖
建立寫管線線程組
寫管線線程的函數原型如程序清單 1-3所示。
程序清單 1-3
static PVOID __diskCacheWpThread (PVOID pvArg)
參數pvArg爲PLW_DISKCACHE_CB類型的磁盤緩衝控制塊。管線線程運行後,循環等待接收管線刷新消息。其中消息類型如程序清單 1-4所示。
程序清單 1-4
typedef struct { ULONG DISKCWPM_ulStartSector; /* 起始扇區 */ ULONG DISKCWPM_ulNSector; /* 扇區數量 */ PVOID DISKCWPM_pvBuffer; /* 扇區緩衝 */ } LW_DISKCACHE_WPMSG; typedef LW_DISKCACHE_WPMSG *PLW_DISKCACHE_WPMSG;
當線程接收到消息後,根據消息中的信息調用具體的硬件接口進行寫操做。完成寫操做後,須要釋放消息中的內存塊以及計數信號量和同步信號,接着進入下一次循環等待接收消息。
當支持併發寫管線時,能夠經過調用__diskCacheWpGetBuffer函數在已初始化後的內存分區中申請一個內存塊,該函數的具體實現如程序清單 2-1所示。
程序清單 2-1
PVOID __diskCacheWpGetBuffer (PLW_DISKCACHE_WP pwp, BOOL bRead) { PVOID pvRet; if (bRead) { return (pwp->DISKCWP_pvRBurstBuffer); } if (pwp->DISKCWP_iPipeline == 0) { return (pwp->DISKCWP_pvWBurstBuffer); } if (API_SemaphoreCPend(pwp->DISKCWP_hCounter, LW_OPTION_WAIT_INFINITE)) { _BugHandle(LW_TRUE, LW_TRUE, "diskcache pipeline error!\r\n"); } pvRet = API_PartitionGet(pwp->DISKCWP_hPart); _BugHandle((pvRet == LW_NULL), LW_TRUE, "diskcache pipeline error!\r\n"); return (pvRet); }
在申請內存塊前,須要先請求計數信號量,計數信號量與內存塊數量相等。當內存分區中已沒有剩餘的內存塊時,線程沒法得到計數信號量進入休眠。當管線線程完成寫操做後會釋放接收到的內存塊,並釋放計數信號量,此時休眠線程成功申請信號量進入就緒態,並順利得到內存塊。
接着須要將CACHE中的緩衝數據拷貝到內存塊中,並提交一個寫請求。管線線程接收到消息後進行具體的寫操做和資源釋放。寫請求函數如程序清單 2-2所示。
程序清單 2-2
INT __diskCacheWpWrite (PLW_DISKCACHE_CB pdiskc, PLW_BLK_DEV pblkdDisk, PVOID pvBuffer, ULONG ulStartSector, ULONG ulNSector) { LW_DISKCACHE_WPMSG diskcwpm; PLW_DISKCACHE_WP pwp = &pdiskc->DISKC_wpWrite; if (pwp->DISKCWP_iPipeline == 0) { return (pdiskc->DISKC_pblkdDisk->BLKD_pfuncBlkWrt(pblkdDisk, pvBuffer, ulStartSector, ulNSector)); } diskcwpm.DISKCWPM_ulStartSector = ulStartSector; diskcwpm.DISKCWPM_ulNSector = ulNSector; diskcwpm.DISKCWPM_pvBuffer = pvBuffer; API_MsgQueueSend2(pwp->DISKCWP_hMsgQueue, &diskcwpm, sizeof(LW_DISKCACHE_WPMSG), LW_OPTION_WAIT_INFINITE); return (ERROR_NONE); }
發起寫請求後可經過調用__diskCacheWpSync函數進行寫同步,該函數經過寫管線控制塊中的DISKCWP_hSync信號量實現同步功能。
無