推荐源码阅读的的工具是sourceInsight3.5,直接将源码文件导入,就会生成一个各文件关联的工程,这个工具可自行百度,配合Nodepad++修改注释阅读更好,因为SI不知道为什么对中文注释输入的支持不是很好。继续昨天的源码阅读。
昨天研究到disksim.c中的extarq队列的操作函数,extraq队列就像是预先申请的空的内存,今天看的是intq队列操作函数,intq是处理调度event的队列。
开始介绍intq的相关函数:
disksim_dumpintq ()
函数
先给出该函数在disksim.c
中的的原代码段:
1 | static void disksim_dumpintq () |
disksim->inq
和disksim->extraq
一样都是指向队列的头部元素。这个函数就是遍历intq队列,将intq队列里面每个event的信息(队列中的event的time,Type)输出到outputfile中去,可能是为了之后的调试使用的函数。
###INLINE void addtointq (event *newint)
函数
一看这个函数也是一个内联函数,和之前的addtoextraq
很像,先看其函数原代码段:
1 | INLINE void addtointq (event *newint) |
代码段第一段:
1 | #if 0 |
这是个宏定义主要是为了处理当调度的当前event时间过了系统时间不能被服务的,即不能加入intq队列里面的一个操作,看下#define DISKSIM_TIME_THRESHOLD 0.0013
这个参数在disksim_global.h中定义,这个阈值允许disksim的一些区别内部时间和simos的时间。这是由试验和错误,可能需要一些调整。
代码段第二段:
1 | switch(disksim->trace_mode) { |
这里的disksim->trace_mode
的有关参数在disksim结构体的定义:
1 | int tracepipes[2]; |
最早看到trace_mode的调用是在之前的disksim_simulate_event
相关的代码段:
1 | if ((curr = getnextevent()) == NULL) { |
在disksim_simulate_event
只是调试用的语句,但在addtointq
函数得仔细看看。首先介绍C里面的两个函数write,read函数。
write:
write函数的定义在C的 头文件:<unistd.h>
:
1 | ssize_t write(int fd, const void *buf, size_t nbyte); |
read
1 | ssize_t read(int fd, void * buf, size_t count); |
理解这两个函数以后,再看上面的trace_mode可以发现,mode其实分为主动(Master),从动(Slave),另一个(None)其实什么也不做。
主动模式下就是将(函数入口参数)newint指针指向的内容写入到tracepipes[1]中去,从动模式下将把tracepipes[0]中的内容传到tmpevt(event类型)中去,并比较了读到内容(存在tmpevt中)和newint指向内容的时间差,请求类型(type)。
函数最后面的代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32//如果队列为空,直接将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 ()函数:
1 | INLINE static event * getfromintq () |
该函数从intq头部取出下一次要调度服务的event,(get-from-intq),disksim->intq指向队列的下一个位置的event,并且切断对上一个event指向,相当于从intq中移除该event,函数返回的是event 指针。
###removefromintq ()函数
1 | INLINE int removefromintq (event *curr) |
从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表示没有找到,其实就是双链表删除操作|