Chinaunix首页 | 论坛 | 博客
  • 博客访问: 96017
  • 博文数量: 31
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 380
  • 用 户 组: 普通用户
  • 注册时间: 2014-02-24 22:04
文章分类

全部博文(31)

文章存档

2014年(31)

我的朋友

分类: C/C++

2014-06-06 11:49:12


IO事件的执行流程以Event-test.c中的函数进行分析

点击(此处)折叠或打开

  1. static void //事件触发后的回调函数
  2. fifo_read(int fd, short event, void *arg)
  3. {
  4.     char buf[255];
  5.     int len;
  6.     struct event *ev = arg;
  7. #ifdef WIN32
  8.     DWORD dwBytesRead;
  9. #endif

  10.     /* Reschedule this event */
  11.     event_add(ev, NULL);    //重新绑定事件

  12.     fprintf(stderr, "fifo_read called with fd: %d, event: %d, arg: %p\n",    //在标准错误上打印
  13.         fd, event, arg);
  14. #ifdef WIN32
  15.     len = ReadFile((HANDLE)fd, buf, sizeof(buf) - 1, &dwBytesRead, NULL);

  16.     // Check for end of file.
  17.     if(len && dwBytesRead == 0) {
  18.         fprintf(stderr, "End Of File");
  19.         event_del(ev);
  20.         return;
  21.     }

  22.     buf[dwBytesRead] = '\0';
  23. #else
  24.     len = read(fd, buf, sizeof(buf) - 1);    //从文件描述符fd中读取数据

  25.     if (len == -1) {
  26.         perror("read");
  27.         return;
  28.     } else if (len == 0) {
  29.         fprintf(stderr, "Connection closed\n");
  30.         return;
  31.     }

  32.     buf[len] = '\0';    //增加末尾字符
  33. #endif
  34.     fprintf(stdout, "Read: %s\n", buf);   //在标准输出上打印
  35. }




点击(此处)折叠或打开

  1. int
  2. main (int argc, char **argv)
  3. {
  4.     struct event evfifo; //定义一个事件
  5. #ifdef WIN32
  6.     HANDLE socket;
  7.     // Open a file.
  8.     socket = CreateFileA("test.txt", // open File
  9.             GENERIC_READ, // open for reading
  10.             0, // do not share
  11.             NULL, // no security
  12.             OPEN_EXISTING, // existing file only
  13.             FILE_ATTRIBUTE_NORMAL, // normal file
  14.             NULL); // no attr. template

  15.     if(socket == INVALID_HANDLE_VALUE)
  16.         return 1;

  17. #else
  18.     struct stat st; //linux文件属性结构
  19.     const char *fifo = "event.fifo";    //文件名
  20.     int socket;
  21.  
  22.     if (lstat (fifo, &st) == 0) { //获取文件属性到st结构
  23.         if ((st.st_mode & S_IFMT) == S_IFREG) {
  24.             errno = EEXIST;
  25.             perror("lstat");
  26.             exit (1);
  27.         }
  28.     }

  29.     unlink (fifo);
  30.     if (mkfifo (fifo, 0600) == -1) { //设置文件读,写权限
  31.         perror("mkfifo");
  32.         exit (1);
  33.     }

  34.     /* Linux pipes are broken, we need O_RDWR instead of O_RDONLY */
  35. #ifdef __linux
  36.     socket = open (fifo, O_RDWR | O_NONBLOCK, 0); //打开文件,以读写,非阻塞方式
  37. #else
  38.     socket = open (fifo, O_RDONLY | O_NONBLOCK, 0);
  39. #endif

  40.     if (socket == -1) {   //打开失败
  41.         perror("open");
  42.         exit (1);
  43.     }

  44.     fprintf(stderr, "Write data to %s\n", fifo);   //输出到标准错误
  45. #endif
  46.     /* Initalize the event library */
  47.     event_init(); //初始化event_base

  48.     /* Initalize one event */
  49. #ifdef WIN32
  50.     event_set(&evfifo, (int)socket, EV_READ, fifo_read, &evfifo);    
  51. #else
  52.     event_set(&evfifo, socket, EV_READ, fifo_read, &evfifo); //设置event
  53. #endif

  54.     /* Add it to the active events, without a timeout */
  55.     event_add(&evfifo, NULL); //绑定event到event_base
  56.     
  57.     event_dispatch(); //事件调度
  58. #ifdef WIN32
  59.     CloseHandle(socket);
  60. #endif
  61.     return (0);
  62. }

IO事件的读写过程可以分为以下几个步骤
(1) 打开文件,并获取指定文件的文件描述符socket
(2) 调用event_set()函数,设置IO事件evfifo,指定事件的文件描述符socket,事件的类型EV_READ,事件的回调函数fifo_read,回调函数的参数evfifo。
(3) 调用event_add()函数,绑定evififo到全局eventbase。在add函数中,evfifo被加入到eventbase的eventqueue链表之中,并且指定了evfifo所处的链表类型是EVLIST_INSERTED
(4) 调用event_dispatch()函数,执行事件分发
        (a)在分发函数中,先执行evsel->dispatch,evsel是绑定到IO多路复用技术中的一种的指针,这里假设为EPOLL,则这里将调用epoll_dispatch。
        (b)在执行epoll_dispatch过程中,系统检测出文件描述符socket已经就绪,则会把evfifo加入到active链表中,active链表实际上对应的eventbase中的activequeue[i]链表,i是evfifo在初始化时确定的优先级。
        (c)系统继续执行event_process_active()函数,处理active中的事件evfifo,执行evfifo的回调函数。
        (d)当所有的active事件都处理完毕之后,系统退出dispatch函数。
在上面的例子中,在执行evfifo的回调函数过程中,再次把evfifo绑定到eventbase,所以程序会一直去读文件描述符socket对应文件中的前254个字符。
        







阅读(1029) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~