前文主要介绍了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时,管线缓存将使用非缓冲的内存;
DISKCWP_bParallel:并行化读写支持,如果不支持则需要在操作设备前调用设备锁,防止并发操作;
DISKCWP_iPipeline:写管线线程数,为0时表示不是用并发写管线;
DISKCWP_iMsgCount:写消息缓冲个数,最小为DCATTR_iPipeline, 可以为 DCATTR_iPipeline 的2 ~ 8 倍;
DISKCWP_hMsgQueue:管线刷新队列,上层通过发送一个消息,发起一个写请求;
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信号量实现同步功能。
无
原文地址:http://12557713.blog.51cto.com/12547713/1936781