1,adb中fdevent系统的学习
由于一台电脑可以连多个手机或者多个android模拟器,所以adb server可能同时监听多个文件描述符是否有数据可读或者可写,
fdevent就是处理这样情况,先将需要监听的文件描述符fd注册到fdevent系统中,然后设定是要监听的类型(可读,可写)等,最后
开始监听并调用相应的回调处理函数。
首先定义一个fdevent结构体
struct fdevent{
fdevent *next;
fdevent *prev;
int fd;
int force_eof;
unsigned short state;
unsigned short events;
fd_func func;
void *arg;
};
typedef void (fd_func*)(int fd,unsigned events,void*userdata);
static fdevent **fd_table=0;
static int fd_table_max=0;
static int epoll_fd = -1;
#define FDE_ACTIVE 0x0100
#define FDE_PENDING 0x0200
#define FDE_CREDED 0x0400
#define FDE_READ 0x0001
#define FDE_WRITE 0x0002
#define FDE_ERROR 0x0004
#define FDE_TIMEOUT 0x0008
首先利用fdevent_install()函数初始化fdevent结构体,将要监听的fdevent注册进fd_table中,
void fdevent_install(fdevent *fde,int fd,fd_func func,void *arg)
{
memset(fde,0,sizeof(fdevent));
fde->fd=fd;
fde->force_eof=0;
fde->func=func;
fde->arg=arg;
fde->state=FDE_ACTIVE;
fdevent_register(fde);
fdevent_connect(fde);
fde->state |= FDE_ACTIVE;
}
/*
根据fdevent->fd的大小动态创建fd_table
*/
static void fdevent_register(fdevent *fde)
{
if((fde->fd)<0)
{
printf("Error:negative fd\n")
}
if(fde->fd >= fd_table_max)
{
int oldmax=fd_table_max;
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)
{
printf("Error:realloc fd_table error\n");
}
memset(fd_table+oldmax,0,sizeof(fd_table_max-oldmax));
}
}
/*
因为fdevent底层还是利用了epoll的系统调用,这里先创建epoll_fd文件描述符
*/
static void fdevent_init()
{
epoll_fd=epoll_creat(256);
if(epoll_fd < 0)
{
printf("epoll_creat error\n")
exit(1);
}
fcntl(epoll_fd,F_SETFD,FD_CLOEXEC); //FD_CLOEXEC表示在通过exec()时fd失效
}
static void fdevent_connect(fdevent *fde)
{
struct epoll_event ev;
memset(&ev,0,sizeof(ev));
ev.events=0;
ev.data.ptr=fde;
}
void fdevent_set(fdevent *fde, unsigned events)
{
events &= FDE_EVENTMASK;
if((fde->state & FDE_EVENTMASK) == events) return;
if(fde->state & FDE_ACTIVE) {
fdevent_update(fde, events);
dump_fde(fde, "update");
}
fde->state = (fde->state & FDE_STATEMASK) | events;
if(fde->state & FDE_PENDING) {
/* if we're pending, make sure
** we don't signal an event that
** is no longer wanted.
*/
fde->events &= (~events);
if(fde->events == 0) {
fdevent_plist_remove(fde);
fde->state &= (~FDE_PENDING);
}
}
}
static void fdevent_update(fdevent *fde, unsigned events)
{
struct epoll_event ev;
int active;
active = (fde->state & FDE_EVENTMASK) != 0;
memset(&ev, 0, sizeof(ev));
ev.events = 0;
ev.data.ptr = fde;
if(events & FDE_READ) ev.events |= EPOLLIN;
if(events & FDE_WRITE) ev.events |= EPOLLOUT;
if(events & FDE_ERROR) ev.events |= (EPOLLERR | EPOLLHUP);
fde->state = (fde->state & FDE_STATEMASK) | events;
if(active) {
if(ev.events) {
if(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fde->fd, &ev)) {
perror("epoll_ctl() failed\n");
exit(1);
}
} else {
if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev)) {
perror("epoll_ctl() failed\n");
exit(1);
}
}
} else {
if(ev.events) {
if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
perror("epoll_ctl() failed\n");
exit(1);
}
}
}
}