flashsim源码阅读(intq队列操作)7-8
来源:互联网 发布:淘宝店免费开店要钱吗 编辑:程序博客网 时间:2024/06/03 22:06
推荐源码阅读的的工具是sourceInsight3.5,直接将源码文件导入,就会生成一个各文件关联的工程,这个工具可自行百度,配合Nodepad++修改注释阅读更好,因为SI不知道为什么对中文注释输入的支持不是很好。继续昨天的源码阅读。
昨天研究到disksim.c中的extarq队列的操作函数,extraq队列就像是预先申请的空的内存,今天看的是intq队列操作函数,intq是处理调度event的队列。
开始介绍intq的相关函数:
disksim_dumpintq ()
函数
先给出该函数在disksim.c
中的的原代码段:
static void disksim_dumpintq (){ event *tmp; int i = 0; tmp = disksim->intq; while (tmp != NULL) { i++; fprintf (outputfile, "time %f, type %d\n", tmp->time, tmp->type); tmp = tmp->next; }}
disksim->inq
和disksim->extraq
一样都是指向队列的头部元素。这个函数就是遍历intq队列,将intq队列里面每个event的信息(队列中的event的time,Type)输出到outputfile中去,可能是为了之后的调试使用的函数。
INLINE void addtointq (event *newint)
函数
一看这个函数也是一个内联函数,和之前的addtoextraq
很像,先看其函数原代码段:
INLINE void addtointq (event *newint){ /* WARNING -- HORRIBLE HACK BELOW * In order to make the Memulator run (which sometimes has events arrive * "late") I've (JLG) commented out the following snippet. A better * solution should be arrived at... */#if 0 if ((temp->time + DISKSIM_TIME_THRESHOLD) < simtime) { //如果当前的event的时间比simtime还要早,就是已经错过了调度 fprintf(stderr, "Attempting to addtointq an event whose time has passed\n"); fprintf(stderr, "simtime %f, curr->time %f, type = %d\n", simtime, temp->time, temp->type); exit(1); }#endif switch(disksim->trace_mode) { //这边关于disksim->trace_mode指的是负载还是?有待考证 case DISKSIM_MASTER: //这个Master模式下把,新加入的newint写入到tracepipes[1]中 if(write(disksim->tracepipes[1], (char *)newint, sizeof(event)) <= 0) { // printf("addtointq() -- master write fd = %d\n", disksim->tracepipes[1]); // perror("addtointq() -- master write"); } break; case DISKSIM_SLAVE: //这个SLAVE模式下把tracepipes[0]中的内容传到tmpevt(event类型)中去 { event tmpevt; double timediff; // printf("addtointq() -- slave read\n"); ddbg_assert(read(disksim->tracepipes[0], (char *)&tmpevt, sizeof(event)) > 0); timediff = fabs(tmpevt.time - newint->time);//计算tmpevt和newint的时间差/* printf("remote event: %d %f, local event: %d %f\n", *//* tmpevt.type, *//* newint->type, *//* newint->time); */ ddbg_assert(tmpevt.type == newint->type); // ddbg_assert(timediff <= 0.001); newint->time = tmpevt.time; if(timediff > 0.000001) { printf("*** SLAVE: addtointq() timediff = %f\n", timediff); } fflush(stdout); } break; case DISKSIM_NONE: default: break; } //如果队列为空,直接将newint加入到intq队列中 if (disksim->intq == NULL) { disksim->intq = newint; newint->next = NULL; newint->prev = NULL; } //队列非空,比较newint时间和intq当前头部event的时间 //如果newint时间小,则直接将其插入到intq队列的头部 else if (newint->time < disksim->intq->time) { newint->next = disksim->intq; disksim->intq->prev = newint; disksim->intq = newint; newint->prev = NULL; } else { //否则寻找intq队列中前一项event时间比newint小的位置插入 //也就是说intq队列中的event是按照time依次递增排序的 event *run = disksim->intq; assert(run->next != run); while (run->next != NULL) { if (newint->time < run->next->time) { break; } run = run->next; } newint->next = run->next; run->next = newint; newint->prev = run; if (newint->next != NULL) { newint->next->prev = newint; } }}
代码段第一段:
#if 0 if ((temp->time + DISKSIM_TIME_THRESHOLD) < simtime) { //如果当前的event的时间比simtime还要早,就是已经错过了调度 fprintf(stderr, "Attempting to addtointq an event whose time has passed\n"); fprintf(stderr, "simtime %f, curr->time %f, type = %d\n", simtime, temp->time, temp->type); exit(1); }#endif
这是个宏定义主要是为了处理当调度的当前event时间过了系统时间不能被服务的,即不能加入intq队列里面的一个操作,看下#define DISKSIM_TIME_THRESHOLD 0.0013
这个参数在disksim_global.h中定义,这个阈值允许disksim的一些区别内部时间和simos的时间。这是由试验和错误,可能需要一些调整。
代码段第二段:
switch(disksim->trace_mode) { case DISKSIM_MASTER: if(write(disksim->tracepipes[1], (char *)newint, sizeof(event)) <= 0) { // printf("addtointq() -- master write fd = %d\n", disksim->tracepipes[1]); // perror("addtointq() -- master write"); } break; case DISKSIM_SLAVE: { event tmpevt; double timediff; // printf("addtointq() -- slave read\n"); ddbg_assert(read(disksim->tracepipes[0], (char *)&tmpevt, sizeof(event)) > 0); timediff = fabs(tmpevt.time - newint->time);/* printf("remote event: %d %f, local event: %d %f\n", *//* tmpevt.type, *//* tmpevt.time, *//* newint->type, *//* newint->time); */ ddbg_assert(tmpevt.type == newint->type); // ddbg_assert(timediff <= 0.001); newint->time = tmpevt.time; if(timediff > 0.000001) { printf("*** SLAVE: addtointq() timediff = %f\n", timediff); } fflush(stdout); } break; case DISKSIM_NONE: default: break; }
这里的disksim->trace_mode
的有关参数在disksim结构体的定义:
int tracepipes[2]; enum { DISKSIM_MASTER, DISKSIM_SLAVE, DISKSIM_NONE } trace_mode;
最早看到trace_mode的调用是在之前的disksim_simulate_event
相关的代码段:
if ((curr = getnextevent()) == NULL) { disksim_simstop (); } else { switch(disksim->trace_mode) { case DISKSIM_NONE: case DISKSIM_MASTER:// fprintf(outputfile, "*** DEBUG TRACE\t%f\t%d\t%d\n", // simtime, curr->type, num); // fflush(outputfile); break; case DISKSIM_SLAVE: break; }
在disksim_simulate_event
只是调试用的语句,但在addtointq
函数得仔细看看。首先介绍C里面的两个函数write,read函数。
write:
write函数的定义在C的 头文件:<unistd.h>
:
ssize_t write(int fd, const void *buf, size_t nbyte);fd:文件描述符;buf:指定的缓冲区,即指针,指向一段内存单元;nbyte:要写入文件指定的字节数;返回值:写入文档的字节数(成功);-1(出错)write函数把buf中nbyte写入文件描述符handle所指的文档,成功时返回写的字节数,错误时返回-1.
read
ssize_t read(int fd, void * buf, size_t count);定义函数:ssize_t read(int fd, void * buf, size_t count);函数说明:read()会把参数fd 所指的文件传送count 个字节到buf 指针所指的内存中. 若参数count 为0, 则read()不会有作用并返回0. 返回值为实际读取到的字节数, 如果返回0, 表示已到达文件尾或是无可读取的数据,此外文件读写位置会随读取到的字节移动.
理解这两个函数以后,再看上面的trace_mode可以发现,mode其实分为主动(Master),从动(Slave),另一个(None)其实什么也不做。
主动模式下就是将(函数入口参数)newint指针指向的内容写入到tracepipes[1]中去,从动模式下将把tracepipes[0]中的内容传到tmpevt(event类型)中去,并比较了读到内容(存在tmpevt中)和newint指向内容的时间差,请求类型(type)。
函数最后面的代码
//如果队列为空,直接将newint加入到intq队列中 if (disksim->intq == NULL) { disksim->intq = newint; newint->next = NULL; newint->prev = NULL; } //队列非空,比较newint时间和intq当前头部event的时间 //如果newint时间小,则直接将其插入到intq队列的头部 else if (newint->time < disksim->intq->time) { newint->next = disksim->intq; disksim->intq->prev = newint; disksim->intq = newint; newint->prev = NULL; } else { //否则寻找intq队列中前一项event时间比newint小的位置插入 //也就是说intq队列中的event是按照time依次递增排序的 event *run = disksim->intq; assert(run->next != run); while (run->next != NULL) { if (newint->time < run->next->time) { break; } run = run->next; } newint->next = run->next; run->next = newint; newint->prev = run; if (newint->next != NULL) { newint->next->prev = newint; } }
其实就是依据newint指针指向的event的时间大小插入到intq队列中去,intq队列中的event是按时间大小从小到大依次排序的。从插入过程可以理解,inqt和extraq是不一样的,是个双链表。
总结addtointq()
函数是将一个event加入到intq队列中去,time表示event发生时间,intq队列中的event是按时间的升序排列的函数输出参数是新加入的event的指针。
getfromintq ()函数:
INLINE static event * getfromintq (){ event *temp = NULL; if (disksim->intq == NULL) { return(NULL); } temp = disksim->intq; disksim->intq = disksim->intq->next; if (disksim->intq != NULL) { disksim->intq->prev = NULL; } temp->next = NULL; temp->prev = NULL; return(temp);}
该函数从intq头部取出下一次要调度服务的event,(get-from-intq),disksim->intq指向队列的下一个位置的event,并且切断对上一个event指向,相当于从intq中移除该event,函数返回的是event 指针。
removefromintq ()函数
INLINE int removefromintq (event *curr){ event *tmp; tmp = disksim->intq; while (tmp != NULL) { if (tmp == curr) { break; } tmp = tmp->next; } if (tmp == NULL) { return(FALSE); } if (curr->next != NULL) { curr->next->prev = curr->prev; } if (curr->prev == NULL) { disksim->intq = curr->next; } else { curr->prev->next = curr->next; } curr->next = NULL; curr->prev = NULL; return(TRUE);}
从intq(调度表)队列中移除指定的event项,函数返回Ture表示找到该项event,FALSE表示没有找到,其实就是双链表删除操作。
对intq(event调度队列)的函数总结
disksim_dumpintq ()
无
void
遍历intq队列,将intq队列里面每个event的信息(队列中的event的time,Type)输出到outputfile中去,可能是为了之后的调试使用的函数。 addtointq ()
event *newint
void
将一个event加入到intq队列中去,time表示event发生时间,intq队列中的event是按时间的升序排列的函数输出参数是新加入的event的指针。 getfromintq ()
无
event类型的指针
从intq头部取出下一次要调度服务的event,disksim->intq指向队列的下一个位置的event,并且切断对上一个event指向,相当于从intq中移除该event,函数返回的是event 指针。 removefromintq()
event *curr
int
从intq队列中移除指定的event项,函数返回Ture表示找到该项event,FALSE表示没有找到,其实就是双链表删除操作- flashsim源码阅读(intq队列操作)7-8
- flashsim源码阅读7-8(2)
- flashsim源码阅读7-8(3)
- flashsim源码阅读7-4
- flashsim源码阅读7-7笔记
- flashsim源码阅读笔记1
- flashsim源码阅读笔记2
- flashsim源码阅读笔记3
- skynet底层源码阅读(2)-消息队列
- freeDiameter源码阅读之消息队列和消息处理流程
- libevent源码阅读笔记——通用时间队列
- Volley源码阅读之请求队列(RequestQueue)工作原理
- Suricata 3.2.1 源码阅读笔记:数据包队列
- jQuery源码阅读(十三)---jQuery异步队列模块
- Flashsim安装以及支持4KB,8KB闪存页
- Vector源码阅读(JDK 8)
- Java1.8源码阅读-DualPivotQuicksort
- lua源码阅读(8)-虚拟机
- 终端模拟器Xshell如何编辑和重命名会话
- #HDU4248#A Famous Stone Collector(组合数)
- 【机器人学】机器人开源项目KDL源码学习:(6)笛卡尔空间轨迹规划、圆弧过渡、姿态插值、梯形速度、pathlength
- JavaSE基本语法阶段
- Linux 套接字编程中 bind 错误:bind fail:Address already in use 解决方法
- flashsim源码阅读(intq队列操作)7-8
- 非分区表是否可以创建分区索引?
- 在virtualenv 下安装django
- 数据库中如何实现批量插入
- ecjtu-summer training #3 D Gym 100952A 签到题
- Java基础入门1
- 迷宫--搜索
- ORB-SLAM(一)简介
- ecjtu-summer training #3 F HDU 1312 Red and Black