Lighttpd1.4.20源码分析 笔记 fdevent系统-初始化
2016-01-15 11:30
239 查看
C程序在进行真正的编译之前都要进行预编译。
我们看看fdevent系统中的一些宏:
上面的宏判断系统中是否有对应的多路IO系统,如果有,就定义对应的USE_XXX宏。
预编译完这些宏以后,对于当前系统中有的多路IO系统,就会有对应的USE_XXX符号被定义。预编译器接着运行,将那些不需要的代码都忽略。
fdevent.h中对所有可能的多路IO系统都定义了初始化函数:
因此,对于系统中没有的多路IO系统对应的初始化函数,预编译结束后,这些初始化函数被定义为报错函数。如epoll对应的为:
预编译后,开始真正的编译。我们假设系统中只有epoll。
首先,我们看一看配置中有关fdevent的设置。进入configfile.c文件中的config_set_defaults()函数。函数的一开始就有这么一个定义:
上面定义了一个struct ev_map类型的数组。数组的内容是当前系统中存在的多路IO系统的类型和名称。这里排序很有意思,从注释中可以看出,poll排在最前因为最可靠,select其次因为支持最广泛,epoll第三因为是最好的。
在这里,如果配置文件有配置,那么按配置文件来,如果没配置,则取上面数组中的第一个。以下是配置文件的格式:
接下来我们看server.c中的main函数。
前面有一些是设置fd数量的,其中select比较特殊需要特别处理,fd数量一个是系统的限制,一个是用户配置的限制。
当程序产生子进程后,在子进程中执行的第一条语句就是初始化fdevent系统:
进入fdevent_init()函数:
fdevent_init()函数根据fdevent_handler_t的值调用相应的初始化函数。我们进入fdevent_linux_sysepoll_init()函数:
至此fdevent的初始化工作全部完成。
我们看看fdevent系统中的一些宏:
[code]#if defined(H***E_EPOLL_CTL) && defined(H***E_SYS_EPOLL_H) # if defined H***E_STDINT_H # include <stdint.h> # endif # define USE_LINUX_EPOLL # include <sys/epoll.h> #endif #if defined H***E_POLL && (defined(H***E_SYS_POLL_H) || defined(H***E_POLL_H)) # define USE_POLL # ifdef H***E_POLL_H # include <poll.h> # else # include <sys/poll.h> # endif # if defined H***E_SIGTIMEDWAIT && defined(__linux__) # define USE_LINUX_SIGIO # include <signal.h> # endif #endif //……
上面的宏判断系统中是否有对应的多路IO系统,如果有,就定义对应的USE_XXX宏。
预编译完这些宏以后,对于当前系统中有的多路IO系统,就会有对应的USE_XXX符号被定义。预编译器接着运行,将那些不需要的代码都忽略。
fdevent.h中对所有可能的多路IO系统都定义了初始化函数:
[code] int fdevent_select_init(fdevents * ev); int fdevent_poll_init(fdevents * ev); int fdevent_linux_rtsig_init(fdevents * ev); int fdevent_linux_sysepoll_init(fdevents * ev); int fdevent_solaris_devpoll_init(fdevents * ev); int fdevent_freebsd_kqueue_init(fdevents * ev);
因此,对于系统中没有的多路IO系统对应的初始化函数,预编译结束后,这些初始化函数被定义为报错函数。如epoll对应的为:
[code]#ifdef USE_LINUX_EPOLL /* 当定义了epoll时,epoll的函数实现代码 */ #else /* 当未定义epoll时,epoll只实现init函数(这是必须的,因为该函数在fdevent.h中定义了),并将它实现为报错函数 */ int fdevent_linux_sysepoll_init(fdevents *ev) { UNUSED(ev); fprintf(stderr, "%s.%d: linux-sysepoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__); return -1; } #endif
预编译后,开始真正的编译。我们假设系统中只有epoll。
首先,我们看一看配置中有关fdevent的设置。进入configfile.c文件中的config_set_defaults()函数。函数的一开始就有这么一个定义:
[code] struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] = { /* * - poll is most reliable - select works everywhere - * linux-* are experimental */ #ifdef USE_POLL {FDEVENT_HANDLER_POLL, "poll"}, #endif #ifdef USE_SELECT {FDEVENT_HANDLER_SELECT, "select"}, #endif #ifdef USE_LINUX_EPOLL {FDEVENT_HANDLER_LINUX_SYSEPOLL, "linux-sysepoll"}, #endif #ifdef USE_LINUX_SIGIO {FDEVENT_HANDLER_LINUX_RTSIG, "linux-rtsig"}, #endif #ifdef USE_SOLARIS_DEVPOLL {FDEVENT_HANDLER_SOLARIS_DEVPOLL, "solaris-devpoll"}, #endif #ifdef USE_FREEBSD_KQUEUE {FDEVENT_HANDLER_FREEBSD_KQUEUE, "freebsd-kqueue"}, {FDEVENT_HANDLER_FREEBSD_KQUEUE, "kqueue"}, #endif {FDEVENT_HANDLER_UNSET, NULL} };
上面定义了一个struct ev_map类型的数组。数组的内容是当前系统中存在的多路IO系统的类型和名称。这里排序很有意思,从注释中可以看出,poll排在最前因为最可靠,select其次因为支持最广泛,epoll第三因为是最好的。
在这里,如果配置文件有配置,那么按配置文件来,如果没配置,则取上面数组中的第一个。以下是配置文件的格式:
[code]## set the event-handler (read the performance ##section in the manual) server.event-handler = "freebsd-kqueue" # needed on OS X
接下来我们看server.c中的main函数。
前面有一些是设置fd数量的,其中select比较特殊需要特别处理,fd数量一个是系统的限制,一个是用户配置的限制。
当程序产生子进程后,在子进程中执行的第一条语句就是初始化fdevent系统:
[code] if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) { log_error_write(srv, __FILE__, __LINE__, "s", "fdevent_init failed"); return -1; }
进入fdevent_init()函数:
[code]/** * 初始化文件描述符事件数组fdevent */ fdevents *fdevent_init(size_t maxfds, fdevent_handler_t type) { fdevents *ev; //内存被初始化为0 ev = calloc(1, sizeof(*ev)); //分配数组 ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray)); ev->maxfds = maxfds; //根据设定的多路IO的类型进行初始化。 switch (type) { case FDEVENT_HANDLER_POLL: if (0 != fdevent_poll_init(ev)) { fprintf(stderr, "%s.%d: event-handler poll failed\n", __FILE__, __LINE__); return NULL; } break; case FDEVENT_HANDLER_SELECT: if (0 != fdevent_select_init(ev)) { fprintf(stderr, "%s.%d: event-handler select failed\n", __FILE__, __LINE__); return NULL; } break; case FDEVENT_HANDLER_LINUX_RTSIG: if (0 != fdevent_linux_rtsig_init(ev)) { fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__); return NULL; } break; case FDEVENT_HANDLER_LINUX_SYSEPOLL: if (0 != fdevent_linux_sysepoll_init(ev)) { fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__); return NULL; } break; case FDEVENT_HANDLER_SOLARIS_DEVPOLL: if (0 != fdevent_solaris_devpoll_init(ev)) { fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__); return NULL; } break; case FDEVENT_HANDLER_FREEBSD_KQUEUE: if (0 != fdevent_freebsd_kqueue_init(ev)) { fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__); return NULL; } break; default: fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__); return NULL; } return ev; }
fdevent_init()函数根据fdevent_handler_t的值调用相应的初始化函数。我们进入fdevent_linux_sysepoll_init()函数:
[code]int fdevent_linux_sysepoll_init(fdevents * ev) { ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL; #define SET(x) \ ev->x = fdevent_linux_sysepoll_##x; /* 通过SET宏对fdevents结构体中的函数指针赋值。然后创建epoll,最后做一些设置。*/ SET(free); SET(poll); SET(event_del); SET(event_add); SET(event_next_fdndx); SET(event_get_fd); SET(event_get_revent); //创建epoll if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) { fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__, strerror(errno)); return -1; } //设置epoll_fd为运行exec()函数时关闭。 if (-1 == fcntl(ev->epoll_fd, F_SETFD, FD_CLOEXEC)) { fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__, strerror(errno)); close(ev->epoll_fd); return -1; } //创建fd事件数组。在epoll_wait函数中使用。 //存储发生了IO事件的fd和对应的IO事件。 ev->epoll_events = malloc(ev->maxfds * sizeof(*ev->epoll_events)); return 0; }
至此fdevent的初始化工作全部完成。
相关文章推荐
- 详解Android异步请求之 android-async-http开源框架
- HTTP状态管理机制之Cookie
- zz bond配置网络: 两个网卡一个ip
- 比较牛逼的 博客 (关于音视频的)http://www.cnblogs.com/kenshincui/p/4186022.html
- Nginx发布1.9.0版本,新增支持TCP代理和负载均衡的stream模块
- Lighttpd1.4.20源码分析 笔记 fdevent系统-结构体及对外接口
- 2.4 语义网络表示
- 网络篇-NSJSONSerialization转JSON
- 网络(十)WebKit初识
- 网络(九)进程和线程
- 【wampserver】安装后访问localhost出现http403错误
- Get 和 Post 的区别
- 网络(八)TCP(二)
- 网络异步请求
- 网络(七)TCP(一)
- 网络(六)UDP
- 网络(五)获取本机网络信息
- 网络(四)FTP(二)
- 网络(三)FTP(一)
- IdHTTP代理设置