源文件uloop.c
uloop_init
创建epoll句柄,监听最大数目为32;并设置句柄FD_CLOEXEC属性;对描述符设置了FD_CLOEXEC,使用execl执行的程序里,此描述符被关闭,不能再使用它,但是在使用fork调用的子进程中,此描述符并不关闭,仍可使用。
uloop_process_add
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;
uloop_timeout_set
struct uloop_timeout { struct list_head list; bool pending; //成功加入链表的标志; uloop_timeout_handler cb; //回调处理函数 struct timeval time; //超时时间 }; |
-->设置超时时间;
-->uloop_timeout_add 添加到timeouts列表;按照超时时间由小到大的顺序排列;
uloop_run
点击(此处)折叠或打开
-
void uloop_run(void)
-
{
-
static int recursive_calls = 0;
-
struct timeval tv;
-
-
/*
-
* Handlers are only updated for the first call to uloop_run() (and restored
-
* when this call is done).
-
*/
-
if (!recursive_calls++)
-
uloop_setup_signals(true);
-
-
uloop_cancelled = false;
-
while(!uloop_cancelled)
-
{
-
uloop_gettime(&tv);
-
uloop_process_timeouts(&tv);
-
-
if (do_sigchld)
-
uloop_handle_processes();
-
-
if (uloop_cancelled)
-
break;
-
-
uloop_gettime(&tv);
-
uloop_run_events(uloop_get_next_timeout(&tv));
-
}
-
-
if (!--recursive_calls)
-
uloop_setup_signals(false);
- }
-->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信号时,才会退出循环;
uloop_done
-->关闭描述符poll_fd;
-->清空timeouts、processes链表;