本篇分析fdevent.c的源代码。
这个源代码文件的工作时创建、监听和处理读写事件。
static fdevent **fd_table = 0;
static int fd_table_max = 0;
fd_table保存的是以fdevent->fd为索引保存的fdevent指针,即
the_fdevent的值等于fd_table[the_fdevent->fd]。
static void fdevent_register(fdevent *fde) //即将fde添加到fd_table
{
if(fde->fd < 0) {
FATAL("bogus negative fd (%d)\n", fde->fd);
}
if(fde->fd >= fd_table_max) { //这段代码即初始化或自动增长fd_table
int oldmax = fd_table_max;
if(fde->fd > 32000) {
FATAL("bogus huuuuge fd (%d)\n", fde->fd);
}
if(fd_table_max == 0) {
fdevent_init();
fd_table_max = 256;
}
while(fd_table_max <= fde->fd) {
fd_table_max *= 2;
}
fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
if(fd_table == 0) {
FATAL("could not expand fd_table to %d entries\n", fd_table_max);
}
memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
}
fd_table[fde->fd] = fde; //将fde添加到fd_table
}
static void fdevent_unregister(fdevent *fde) //这个函数即将fde从fd_table中删除
{
if((fde->fd < 0) || (fde->fd >= fd_table_max)) {
FATAL("fd out of range (%d)\n", fde->fd);
}
if(fd_table[fde->fd] != fde) {
FATAL("fd_table out of sync [%d]\n", fde->fd);
}
fd_table[fde->fd] = 0;
if(!(fde->state & FDE_DONT_CLOSE)) { //如果fde->fd打开了并没有关闭,需要执行关闭操作
dump_fde(fde, "close");
adb_close(fde->fd);
}
}
fdevent是代码处理事件的载体,它的定义如下:
struct fdevent
{
fdevent *next; //循环链表
fdevent *prev;
int fd; //句柄
int force_eof;
unsigned short state; //低8位表示事件,高8位表示状态
unsigned short events; //需要处理的事件
fd_func func; //事件处理回调函数
void *arg; //参数
};
其中事件可以是:
#define FDE_READ 0x0001
#define FDE_WRITE 0x0002
#define FDE_ERROR 0x0004
#define FDE_TIMEOUT 0x0008
#define FDE_DONT_CLOSE 0x0080
//掩码
#define FDE_EVENTMASK 0x00ff
状态可以是:
#define FDE_ACTIVE 0x0100
#define FDE_PENDING 0x0200
#define FDE_CREATED 0x0400
//掩码
#define FDE_STATEMASK 0xff00
注意,这些状态是可以同时存在的。
当调用fdevent_create()后,FDE_CREATED标志被设置,当调用fdevent_install()后, FDE_CREATED标志被设置,但在fdevent_create()内部调用了fdevent_install(),所以调用fdevent_create()都被设置了。当有事件在调用select发生后,相应的事件state会设置为FDE_PENDING,当事件处理完后这个标志又被删除。相应的代码是:
void fdevent_loop()
{
fdevent *fde;
fdevent_subproc_setup();
for(;;) {
D("--- ---- waiting for events\n");
fdevent_process(); //在这个函数中调用select,当有事件发生时,state被设置为FDE_PENDING,event也会被设置。所有的pending事件都会被保存在全局变量list_pending中。
while((fde = fdevent_plist_dequeue())) { //处理list_pending变量的事件
fdevent_call_fdfunc(fde);
}
}
}
list_pending的相关代码:
//变量定义和初始化
static fdevent list_pending = {
.next = &list_pending,
.prev = &list_pending,
};
//添加一个元素
static void fdevent_plist_enqueue(fdevent *node)
{
fdevent *list = &list_pending;
node->next = list;
node->prev = list->prev;
node->prev->next = node;
list->prev = node;
}
//删除一个指定元素
static void fdevent_plist_remove(fdevent *node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
node->next = 0;
node->prev = 0;
}
//从list中取出一个元素
static fdevent *fdevent_plist_dequeue(void)
{
fdevent *list = &list_pending;
fdevent *node = list->next;
if(node == list) return 0;
list->next = node->next;
list->next->prev = list;
node->next = 0;
node->prev = 0;
return node;
}
事件的处理是阻塞方式的,可以有两种代码实现方法。定义宏CRAPTASTIC表示使用epoll的方式,否则使用select方式。我这里只讲select的处理方式:
static fd_set read_fds; //读事件集合
static fd_set write_fds; //写事件集合
static fd_set error_fds; //发生错误事件集合
static int select_n = 0;
static void fdevent_init(void) //初始化
{
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&error_fds);
}
static void fdevent_connect(fdevent *fde) //添加
{
if(fde->fd >= select_n) {
select_n = fde->fd + 1;
}
}
static void fdevent_disconnect(fdevent *fde) //从所有事件集合删除fde
{
int i, n;
FD_CLR(fde->fd, &read_fds);
FD_CLR(fde->fd, &write_fds);
FD_CLR(fde->fd, &error_fds);
for(n = 0, i = 0; i < select_n; i++) {
if(fd_table[i] != 0) n = i;
}
select_n = n + 1;
}
static void fdevent_update(fdevent *fde, unsigned events)//根据events设置事件集合
{
if(events & FDE_READ) {
FD_SET(fde->fd, &read_fds);
} else {
FD_CLR(fde->fd, &read_fds);
}
if(events & FDE_WRITE) {
FD_SET(fde->fd, &write_fds);
} else {
FD_CLR(fde->fd, &write_fds);
}
if(events & FDE_ERROR) {
FD_SET(fde->fd, &error_fds);
} else {
FD_CLR(fde->fd, &error_fds);
}
fde->state = (fde->state & FDE_STATEMASK) | events;
}
/* Looks at fd_table[] for bad FDs and sets bit in fds.
** Returns the number of bad FDs.
*/
static int fdevent_fd_check(fd_set *fds) //通过调用fcntl来判断是否是一个有效的fdevent
{
int i, n = 0;
fdevent *fde;
for(i = 0; i < select_n; i++) {
fde = fd_table[i];
if(fde == 0) continue;
if(fcntl(i, F_GETFL, NULL) < 0) {
FD_SET(i, fds);
n++;
// fde->state |= FDE_DONT_CLOSE;
}
}
return n;
}