全部博文(51)
分类: C/C++
2016-08-22 15:41:40
源文件uloop.c
创建epoll句柄,监听最大数目为32;并设置句柄FD_CLOEXEC属性;对描述符设置了FD_CLOEXEC,使用execl执行的程序里,此描述符被关闭,不能再使用它,但是在使用fork调用的子进程中,此描述符并不关闭,仍可使用。
struct uloop_process { struct list_head list; bool pending; //成功加入链表的标志; uloop_process_handler cb; //回调处理函数 pid_t pid; //fork出新进程的id号; }; |
将当前uloop_process结构加入到processes双向列表,按照pid由小到大的顺序排列;最后置p->pending标记位为true;
struct uloop_timeout { struct list_head list; bool pending; //成功加入链表的标志; uloop_timeout_handler cb; //回调处理函数 struct timeval time; //超时时间 }; |
-->设置超时时间;
-->uloop_timeout_add 添加到timeouts列表;按照超时时间由小到大的顺序排列;
点击(此处)折叠或打开
-->static变量recursive_calls记录了是否该函数次数;若首次调用通过uloop_setup_signals设置信号处理函数;
-->uloop_setup_signals
对SIGINT、SIGTERM、SIGCHLD设置处理函数,并记录了信号修改前的处理状态,以便之后恢复;
SIGINT、SIGTERM处理函数将全局变量uloop_cancelled 设置为true;
SIGCHLD处理函数将全局变量do_sigchld设置为true;当子进程终止或停止时,将SIGCHLD信号发送给其父进程,系统默认忽略此信号;
忽略SIGPIPE信号;
-->接着进程会进入一个while循环来处理定时器和信号事件;
-->uloop_gettime获取当前系统时间;
-->uloop_process_timeouts(&tv); 遍历timeouts链表内节点,检测到存在当前时间点可以触发的事件则触发回调函数,并从链表中移除该事件;
-->若运行期间存在SIGCHLD事件,则do_sigchld置为true,调用函数uloop_handle_processes处理
-->首先将do_sigchld置为false,等待下次信号产生再激活该函数;
-->调用waitpid来获取已经结束的子进程的PID,并通过该pid在processes链表内寻找对应节点,从链表中删除并执行其回调函数;
-->uloop_gettime(&tv);再次获取当前时间;
-->uloop_get_next_timeout(&tv)通过查找timeouts链表,计算下一个超时事件的时间间隔;若链表为空返回-1;若存在立刻应该触发的时间返回0;
-->uloop_get_next_timeout返回值作为uloop_run_events的入参,利用epoll_wait的超时机制来实现定时器的操作;epoll_wait超时返回则再次执行while循环;
uloop_run_events同时还监听已经注册到poll_fd内的描述符,通过返回的struct epoll_event events数组来判断发生的事件,并执行其cb函数;
while循环只有在uloop_cancelled为true时,才会break;也就是只有发送SIGINT、SIGTERM信号时,才会退出循环;
-->关闭描述符poll_fd;
-->清空timeouts、processes链表;