本篇分析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; }