一:uloop概述
- uloop有三个功能: 文件描述符触发事件的监控, timeout定时器处理, 当前进程的子进程的维护
二: uloop的整体框架
1: /**
2: * 初始化事件循环
3: *主要工作是poll_fd = epoll_create(32);/* 创建一个epoll的文件描述符监控句柄。最多监控32个文件描述符
4: **/
5: int uloop_init(void)
6: {
7: if (poll_fd >= 0)
8: return 0;
9:
10: poll_fd = epoll_create(32);/* 创建一个epoll的句柄。最多监控32个文件描述符 */
11: if (poll_fd < 0)
12: return -1;
13:
14: fcntl(poll_fd, F_SETFD, fcntl(poll_fd, F_GETFD) | FD_CLOEXEC); /* fd_cloexecs */
15: return 0;
16: }
17:
18:
19: /**
20: * 事件循环主处理入口
21: *1.当某一个进程第一次调用uloop_run时,注册sigchld和sigint信号
22: *2.循环获取当前时间,把超时的timeout处理掉,有一条timeout链表在维护
23: *3.循环检测是否收到一个sigchld信号,如果收到,删除对应的子进程,有一条process子进程链表在维护
24: *4.循环调用epoll_wait 监相应的触发事件文件描述符fd
25: **/
26: void uloop_run(void)
27: {
28: static int recursive_calls = 0; /* static value */
29: struct timeval tv;
30:
31: /*
32: * Handlers are only updated for the first call to uloop_run() (and restored
33: * when this call is done).
34: */
35: if (!recursive_calls++) /* 第一次运行uloop_run时调用, 注册信号处理函数 */
36: uloop_setup_signals(true);
37:
38: uloop_cancelled = false;
39: while(!uloop_cancelled)
40: {
41: uloop_gettime(&tv); /* 获取当前时间 */
42: uloop_process_timeouts(&tv); /* 把超时的timeout清理掉 */
43: if (uloop_cancelled)
44: break;
45:
46: if (do_sigchld) /* 收到一个sigchld的信号 */
47: uloop_handle_processes(); /* 销毁该进程的uloop_process */
48: uloop_gettime(&tv);
49: uloop_run_events(uloop_get_next_timeout(&tv));/* 处理相应的触发事件fd */
50: }
51:
52: if (!--recursive_calls)
53: uloop_setup_signals(false);
54: }
55:
56:
57: /**
58: * 销毁事件循环
59: * 关闭epoll描述符
60: * 销毁子进程链表
61: * 销毁timeout链表
62: **/
63: void uloop_done(void)
64: {
65: if (poll_fd < 0)
66: return;
67:
68: close(poll_fd);
69: poll_fd = -1;
70:
71: uloop_clear_timeouts();
72: uloop_clear_processes();
73: }
三:uloop文件描述符触发事件的监控
1: #define ULOOP_READ (1 << 0)
2: #define ULOOP_WRITE (1 << 1)
3: #define ULOOP_EDGE_TRIGGER (1 << 2)
4: #define ULOOP_BLOCKING (1 << 3)
5:
6: #define ULOOP_EVENT_MASK (ULOOP_READ | ULOOP_WRITE)
7: /* internal flags */
8: #define ULOOP_EVENT_BUFFERED (1 << 4)
9: #define ULOOP_ERROR_CB (1 << 6)
10: struct uloop_fd
11: {
12: uloop_fd_handler cb; /* 文件描述符对应的处理函数 */
13: int fd; /*文件描述符*/
14: bool eof; /*EOF*/
15: bool error; /*出错*/
16: bool registered; /*是否已经添加到epoll的监控队列*/
17: uint8_t flags; /*ULOOP_READ | ULOOP_WRITE | ULOOP_BLOCKING等*/
18: };
19:
20: /**
21: * 注册一个新描述符到事件处理循环
22: */
23: int uloop_fd_add(struct uloop_fd *sock, unsigned int flags)
24:
25: /**
26: * 从事件处理循环中销毁指定描述符
27: */
28: int uloop_fd_delete(struct uloop_fd *sock)
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
例子:
1: #include <stdio.h>
2: #include <stdlib.h>
3: #include <string.h>
4: #include <unistd.h>
5: #include <sys/types.h> /* See NOTES */
6: #include <sys/stat.h>
7: #include <fcntl.h>
8: #include <sys/socket.h>
9: #include <netinet/in.h>
10: #include <arpa/inet.h>
11: #include <libubox/usock.h>
12: #include <libubox/uloop.h>
13: static void recv_string(struct uloop_fd *u, unsigned int events)
14: {
15: char buf[1024] = {0};
16: if (events & ULOOP_READ) {
17: if ( recv(u->fd, buf, 1024, 0) > 0) {
18: printf("recv_buf: %s\n", buf);
19: send(u->fd, "helloworld from server", strlen("helloworld from server"), 0);
20: }
21: }
22: }
23:
24: static void read_std(struct uloop_fd *u, unsigned int events)
25: {
26: char buf[1024] = {0};
27: if (events & ULOOP_READ) {
28: if ( read(u->fd, buf, 1024) > 0) {
29: printf("read_std: %s\n", buf);
30: }
31: }
32: }
33:
34: int main()
35: {
36: struct sockaddr_in cli_addr;
37: socklen_t len = sizeof(struct sockaddr);
38: int type = USOCK_TCP | USOCK_SERVER | USOCK_NOCLOEXEC | USOCK_IPV4ONLY;
39: const char *host = "CarRadio";
40: const char *service = "8000";
41: char recv_buf[1024] = {0};
42: int connect_fd, u_fd = usock(type, host, service);
43: if (u_fd < 0) {
44: perror("usock");
45: return -1;
46: }
47:
48: connect_fd = accept(u_fd, (struct sockaddr *)(&cli_addr), &len);
49: if (connect_fd < 0) {
50: perror("accept");
51: return -1;
52: }
53: struct uloop_fd fd[2] = {
54: {
55: .cb = recv_string,
56: .fd = connect_fd,
57: .registered = false,
58: .flags = ULOOP_READ,
59: },
60: {
61: .cb = read_std,
62: .fd = STDIN_FILENO,
63: .registered = false,
64: .flags = ULOOP_READ,
65: }
66: };
67: uloop_init();
68: /*添加uloop_fd*/
69: uloop_fd_add(&fd[0], ULOOP_READ);
70: uloop_fd_add(&fd[1], ULOOP_READ);
71: uloop_run();
72:
73: uloop_fd_delete(&fd[0]);
74: uloop_done();
75:
76: return 0;
77: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
四:timeout定时器处理
建立一条链表管理所有的timeout节点
1: struct uloop_timeout
2: {
3: struct list_head list; //链表节点
4: bool pending; //添加一个新的timeout pending是true, false删除该节点timeout
5:
6: uloop_timeout_handler cb; //超时处理函数
7: struct timeval time; //超时时间
8: };
9:
10: /**
11: * 注册一个新定时器
12: */
13: int uloop_timeout_add(struct uloop_timeout *timeout);
14:
15: /**
16: * 设置定时器超时时间(毫秒),并添加
17: */
18: int uloop_timeout_set(struct uloop_timeout *timeout, int msecs);
19:
20: /**
21: * 销毁指定定时器
22: */
23: int uloop_timeout_cancel(struct uloop_timeout *timeout);
24:
25: /**
26: * 获取定时器还剩多长时间超时
27: */
28: int uloop_timeout_remaining(struct uloop_timeout *timeout);
例子:
1: #include <stdio.h>
2: #include <stdlib.h>
3: #include <string.h>
4: #include <sys/types.h> /* See NOTES */
5: #include <sys/socket.h>
6: #include <libubox/usock.h>
7: #include <libubox/uloop.h>
8: int g_fd = -1;
9: void send_sock(struct uloop_timeout *t);
10:
11: struct uloop_timeout tm = {
12: .cb = send_sock,
13: };
14: void send_sock(struct uloop_timeout *t)
15: {
16: char buf[1024] = {0};
17: send(g_fd, "hello world from cilent", strlen("hello world from cilent"), 0);
18: if ( recv(g_fd, buf, 1024, 0) > 0) {
19: printf("\nrecv_buf: %s\n", buf);
20: }
21: /* 添加uloop_timeout 实现循环定时 */
22: uloop_timeout_set(&tm, 5000);
23: }
24: int main()
25: {
26: struct sockaddr cli_addr;
27: socklen_t len = sizeof(struct sockaddr);
28: int type = USOCK_TCP | USOCK_NOCLOEXEC | USOCK_IPV4ONLY;
29: const char *host = "CarRadio";
30: const char *service = "8000";
31: char recv_buf[1024] = {0};
32: g_fd = usock(type, host, service); /* create a linker socket*/
33: if (g_fd < 0) {
34: perror("usock");
35: return -1;
36: }
37: uloop_init();
38: /*添加uloop_timeout*/
39: uloop_timeout_set(&tm, 5000);
40: uloop_run();
41: uloop_done();
42:
43: close(g_fd);
44: return 0;
45: }
46:
五:当前进程的子进程的维护
建立一条process链表管理所有的进程id
1: struct uloop_process {
2: struct list_head list;
3: bool pending;
4: uloop_process_handler cb; /** 文件描述符, 调用者初始化 */
5: pid_t pid; /** 文件描述符, 调用者初始化 */
6: };
7: /* 进程退出时回调函数 */
8: typedef void (*uloop_process_handler)(struct uloop_process *c, int ret) ;
9: /**
10: * 注册新进程到事件处理循环
11: */
12: int uloop_process_add(struct uloop_process *p);
13:
14: /**
15: * 从事件处理循环中销毁指定进程
16: */
17: int uloop_process_delete(struct uloop_process *p);
例子:
1: #include <stdio.h>
2: #include <stdlib.h>
3: #include <string.h>
4: #include <sys/types.h> /* See NOTES */
5: #include <unistd.h>
6: #include <libubox/uloop.h>
7:
8: struct uloop_process *u_process = NULL;
9: /*c: 代表推出的进程, ret:代表推出的状态*/
10: void process_exit(struct uloop_process *c, int ret)
11: {
12: printf("child process exit id[%d], status[%#x]\n", c->pid, ret);
13: free(c);
14: }
15:
16: void child_process(int t)
17: {
18: printf(" process pid: %d is runing\n", getpid());
19: if (t > 0)
20: sleep(t);
21: printf("process id[%d] will exit...\n", getpid());
22:
23: exit(t);
24: }
25:
26: int main()
27: {
28: int i;
29: pid_t pid;
30: uloop_init();
31: for (i = 0 ; i < 10; i++) {
32: usleep(500);
33: pid = fork();
34: if (pid == 0) {//子进程
35: child_process( (i+1)*10 ); //子进程休眠(i+1)*10s
36: }
37: else {
38: u_process =
39: (struct uloop_process *)malloc(sizeof(struct uloop_process));
40: if (NULL == u_process) {
41: perror("malloc");
42: exit(-1);
43: }
44: u_process->pid = pid;
45: u_process->cb = process_exit;
46: u_process->pending = false;
47: if (uloop_process_add(u_process) < 0) {
48: printf("uloop_process_add failed...\n");
49: }
50: printf("success create process pid: %d\n", pid);
51: }
52: }
53: printf("uloop_runing....\n");
54: uloop_run();
55: uloop_done();
56:
57: return 0;
58: }
59:
60:
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }