flashsim源码阅读-2

#disksim_simulate_event()代码段继续学习
现给出之前未读完的代码段:

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
33
if (curr->type == INTR_EVENT) {
intr_acknowledge (curr);
}
else if ((curr->type >= IO_MIN_EVENT) && (curr->type <= IO_MAX_EVENT)) {
io_internal_event ((ioreq_event *)curr);
}
else if ((curr->type >= PF_MIN_EVENT) && (curr->type <= PF_MAX_EVENT)) {
pf_internal_event(curr);
}
else if (curr->type == TIMER_EXPIRED) {
timer_event *timeout = (timer_event *) curr;
(*timeout->func) (timeout);
}
else if ((curr->type >= MEMS_MIN_EVENT)
&& (curr->type <= MEMS_MAX_EVENT)) {
io_internal_event ((ioreq_event *)curr);
}
else if (curr->type == CHECKPOINT) {
if (disksim->checkpoint_interval) {
disksim_register_checkpoint(simtime + disksim->checkpoint_interval);
}
disksim_checkpoint (disksim->checkpointfilename);
}
else if (curr->type == STOP_SIM) {
disksim_simstop ();
}
else if (curr->type == EXIT_DISKSIM) {
exit (0);
}
else {
fprintf(stderr, "Unrecognized event in simulate: %d\n", curr->type);
exit(1);
}

还是没有理解清楚,今天继续探究。应该回过头把event结构体重新搞懂,还有其相关操作:

1
2
3
4
5
6
7
8
struct ev {
double time;
int type;
struct ev *next;
struct ev *prev;
int temp;
char space[DISKSIM_EVENT_SPACESIZE];
} event;

这里需要有个疑问就是DISKSIM_EVENT_SPACESIZE是多大,需要看下有关它的宏定义:

1
#define DISKSIM_EVENT_SPACESIZE	(DISKSIM_EVENT_SIZE - sizeof(struct foo))

这里就又扯到了结构体foo。看下这个结构体的定义:

1
2
3
4
5
6
7
typedef struct foo {
double time;
int type;
struct ev *next;
struct ev *prev;
int temp;
} foo;

foo应该是表示event结构体除了char型的space以外所有信息,关于上面的DISKSIM_EVENT_SIZE大小也有一个宏定义:

1
#define DISKSIM_EVENT_SIZE 128

对event的space干什么用的不知道,我们目前知道type类型,time的作用,temp干什么用也不知道。看下以event为参数的函数去理解下
static void allocateextra ()函数里面有段代码:

1
StaticAssert (sizeof(event) == DISKSIM_EVENT_SIZE);

sizeof计算数据(包括数组、变量、类型、结构体等)所占内存空间,用字节数表示,也就是说event结构体所占的内存空间大小是128字节。
在disksim结构体声明里面有这么一个定义:

1
2
3
4
5
event *intq;
event *intqhint;
event *extraq;
int intqlen;
int extraqlen;

这里定义三个以event为节点的三个链表intq,intqhint,extraq。extraq就是一个空置的内存区域,一开始分配64个DISKSIM_EVENT_SIZE大小的event,intq应该是当前排队请求服务的队列?

##下面针对extraq队列操作的相关函数理解:
Allocateextra()函数该函数的原文的英文注释为:

1
2
/* Creates new, empty events (using malloc) and puts them on the extraq. */
/* Called by getfromextraq when the queue is found to be empty. */

创建分配extraq的函数是allocateextra (),这个函数就是创建分配ALLOCSIZE / DISKSIM_EVENT_SIZE个event给extraq队列,在getfromextraq处理extraq队列时发现队列时才调用。ALLOCSIZE是个宏定义:
#define ALLOCSIZE 8192
也就是每次extraq队列为空时,创建分配64个空event添加进队列,allocateextra ()结尾处:

1
2
3
temp[((ALLOCSIZE/DISKSIM_EVENT_SIZE)-1)].next = disksim->extraq;
disksim->extraq = temp;
disksim->extraqlen = ALLOCSIZE / DISKSIM_EVENT_SIZE;

新添加的连续64个event内存尾部指向原来extraq的内存地址,extraq指向新添加的连续内存地址的头部。
这里写图片描述
Addtoextraq()函数:
这个函数的定义:INLINE void addtoextraq (event *temp);
Inline是C,C++中的内联函数标识:
内联inline是给编译器的优化提示,如果一个函数被编译成inline的话,那么就会把函数里面的代码直接插入到调用这个函数的地方,而不是用调用函数的形式。如果函数体代码很短的话,这样会比较有效率,因为调用函数的过程也是需要消耗资源的。但是你inline只是给编译器的提示,编译器会根据实际情况自己决定到底要不要进行内联,如果函数过大、有函数指针指向这个函数或者有递归的情况下编译器都不会进行内联。
内联简而言之,就是函数运行多占内存,降低时间开销。
言归正传,看addtoextraq()函数,重新分配一个event内存单元,并把它加到extraq队列的头部,disksim->extraq指向的是队列的头部
该函数的英文注释为:Deallocates an event structure, adding it to the extraq free pool
Getfromextraq ()函数:NLINE event * getfromextraq ()也是一个内联函数,该函数的英文注释:/* Allocates an event structure from the extraq free pool; if empty, calls allocateextra to create some more. */
这个函数从extraq队列中取出disksim->extraq指向的event(头部位置的数据),函数范围返回的是调取的event类型的指针,如果extraq为空,则调用allocateextra()创建新的extraq队列,并调取头部元素。
void addlisttoextraq (event **headptr)函数:该函数的英文注释:Deallocates a list of event structures to the extraq free pool.
这个函数是将一个event列表整个加入(调用了前面的addtoextarq()函数)到extraq队列头部,输入参数是加入列表的头部指针。从这个函数也可以看出extraq是一个单链表。
event *event_copy (event *orig)函数:
该函数的英文注释:/* Returns a pointer to a copy of event passed as a parameter. */
就是从extraq取一个空闲event出来,作为orig指向的evnet的一个副本,并返回指向这个副本的指针。
这个函数里面用了memmove函数:

1
void *memmove( void* dest, const void* src, size_t count );

src所指内存区域复制count个字节到dest所指内存区域。详细解释:
memmove用于从src拷贝count个字节到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。但复制后src内容会被更改。但是当目标区域与源区域没有重叠则和memcpy函数功能相同。
Event_copy函数内部的代码是这么写的:

1
2
3
event *new = getfromextraq();
memmove((char *)new, (char *)orig, DISKSIM_EVENT_SIZE);
return((event *) new);

####针对extraq队列(单链表)的函数归纳总结:
| 函数名字 | 输入参数 | 返回参数 | 完成的操作 |
|:-:|:-|:-:|:-|
|allocateextra ()|无|void|当extrq队列为空时,一次分配给extraq64个event大小的内存段|
|Addtoextraq()|Event 类型的指针|void|重新申请一个event大小的内存,将其添加到extraq队列的头部。注意disksim->指向的是队列的头部|
|Getfromextraq()|无|Event类型的指针|该函数从extraq队列中取出头部位置的event内存段,如果extrq为空,调用allocateextra()函数分配内存,再取头部的内存段|
|Addlisttoextraq()|Event类型的指针|void|这个函数是将一个event列表整个加入(调用了addtoextraq()函数)到extraq队列头部,输入参数是加入列表的头部指针|
|event_copy()|Event类型的指针|Event类型的指针|就是从extraq取一个空闲event出来,作为orig指向的evnet的一个副本,并返回指向这个副本的event指针|
Extraq内存队列都是空的,没有存数据!!!

热评文章